Quantity Picker 정수 단위의 수량을 늘리거나 줄일 때 사용하는 컴포넌트입니다.
import { QuantityPicker } from "seed-design/ui/quantity-picker" ;
export default function QuantityPickerPreview () {
return (
< QuantityPicker
min = { 1 }
max = { 99 }
defaultValue = { 1 }
aria-label = "상품 수량"
getValueText = {( value ) => `${ value }개` }
/>
);
}
npx @seed-design/cli@latest add ui:quantity-picker pnpm dlx @seed-design/cli@latest add ui:quantity-picker yarn dlx @seed-design/cli@latest add ui:quantity-picker bun x @seed-design/cli@latest add ui:quantity-picker
의존성 설치
npm install @karrotmarket/react-monochrome-icon @seed-design/react yarn add @karrotmarket/react-monochrome-icon @seed-design/react pnpm add @karrotmarket/react-monochrome-icon @seed-design/react bun add @karrotmarket/react-monochrome-icon @seed-design/react 아래 코드를 복사 후 붙여넣고 사용하세요 /**
* @file ui:quantity-picker
* @requires @seed-design/react@^2.1.0
* @requires @seed-design/css@^2.3.0
**/
"use client" ;
import {
IconMinusLine,
IconPlusLine,
IconTrashcanLine,
} from "@karrotmarket/react-monochrome-icon" ;
import { QuantityPicker as SeedQuantityPicker } from "@seed-design/react" ;
import * as React from "react" ;
import { ProgressCircle } from "./progress-circle" ;
export interface QuantityPickerProps extends Omit < SeedQuantityPicker . RootProps , "children" > {
decrementAriaLabel ?: string ;
incrementAriaLabel ?: string ;
decrementIcon ?: React . ReactNode ;
incrementIcon ?: React . ReactNode ;
removeIcon ?: React . ReactNode ;
loadingIndicator ?: React . ReactNode ;
inputProps ?: SeedQuantityPicker . HiddenInputProps ;
}
/**
* @see https://seed-design.io/react/components/quantity-picker
*/
export const QuantityPicker = React.forwardRef <
React.ElementRef <typeof SeedQuantityPicker.Root > ,
QuantityPickerProps
> (
(
{
decrementAriaLabel = "수량 줄이기" ,
incrementAriaLabel = "수량 늘리기" ,
removeAriaLabel = "상품 삭제" ,
decrementIcon = < IconMinusLine />,
incrementIcon = < IconPlusLine />,
removeIcon = < IconTrashcanLine />,
loadingIndicator = < ProgressCircle size = "inherit" tone = "inherit" />,
inputProps,
... rootProps
},
ref,
) => {
return (
< SeedQuantityPicker.Root ref = {ref} removeAriaLabel = {removeAriaLabel} { ... rootProps}>
< SeedQuantityPicker.DecrementButton
aria-label = {decrementAriaLabel}
icon = {decrementIcon}
loadingIndicator = {loadingIndicator}
removeIcon = {removeIcon}
/>
< SeedQuantityPicker.ValueDisplay />
< SeedQuantityPicker.IncrementButton
aria-label = {incrementAriaLabel}
icon = {incrementIcon}
loadingIndicator = {loadingIndicator}
/>
< SeedQuantityPicker.HiddenInput { ... inputProps} />
</ SeedQuantityPicker.Root >
);
},
);
QuantityPicker.displayName = "QuantityPicker" ;
/**
* This file is a snippet from SEED Design, helping you get started quickly with @seed-design/* packages.
* You can extend this snippet however you want.
*/
decrementAriaLabel?string | undefined
incrementAriaLabel?string | undefined
decrementIcon?React.ReactNode
incrementIcon?React.ReactNode
removeIcon?React.ReactNode
loadingIndicator?React.ReactNode
inputProps?SeedQuantityPicker.HiddenInputProps | undefined
defaultValue?number | undefined
value?number | undefined
onValueChange?(( value : number ) => void ) | undefined
minnumber
maxnumber
loading?QuantityPickerLoading | undefined
onRemove?(() => void ) | undefined
getValueText?QuantityPickerGetValueText | undefined
removeAriaLabel?string | undefined
value와 onValueChange를 사용해 수량 상태를 외부에서 제어할 수 있습니다.
import { Text, VStack } from "@seed-design/react" ;
import { useState } from "react" ;
import { QuantityPicker } from "seed-design/ui/quantity-picker" ;
export default function QuantityPickerControlled () {
const [ quantity , setQuantity ] = useState ( 2 );
return (
< VStack gap = "x3" align = "center" >
< QuantityPicker
min = { 1 }
max = { 99 }
value = {quantity}
onValueChange = {setQuantity}
aria-label = "상품 수량"
getValueText = {( value ) => `${ value }개` }
/>
< Text textStyle = "t4Regular" >현재 수량: {quantity}개</ Text >
</ VStack >
);
}
removable을 사용하면 값이 min에 도달했을 때 Decrement 버튼이 Remove 버튼으로 전환됩니다. onRemove에서 제거 동작을 처리하세요.
import { Text, VStack } from "@seed-design/react" ;
import { useState } from "react" ;
import { QuantityPicker } from "seed-design/ui/quantity-picker" ;
export default function QuantityPickerRemovable () {
const [ removed , setRemoved ] = useState ( false );
if (removed) {
return < Text textStyle = "t4Regular" >상품을 삭제했습니다.</ Text >;
}
return (
< VStack gap = "x3" align = "center" >
< QuantityPicker
min = { 1 }
max = { 99 }
defaultValue = { 1 }
removable
aria-label = "상품 수량"
removeAriaLabel = "상품 삭제"
onRemove = {() => setRemoved ( true )}
getValueText = {( value ) => `${ value }개` }
/>
< Text textStyle = "t4Regular" >최소 수량에서 Decrement 버튼이 Remove 버튼으로 전환됩니다.</ Text >
</ VStack >
);
}
loading으로 모든 action 또는 특정 action의 실행을 일시적으로 막고 loading indicator를 표시할 수 있습니다.
import { VStack } from "@seed-design/react" ;
import { useState } from "react" ;
import { ActionButton } from "seed-design/ui/action-button" ;
import { QuantityPicker } from "seed-design/ui/quantity-picker" ;
export default function QuantityPickerLoading () {
const [ loading , setLoading ] = useState ( false );
function toggleLoading () {
setLoading (( current ) => ! current);
}
return (
< VStack gap = "x3" align = "flex-start" >
< QuantityPicker
min = { 1 }
max = { 99 }
defaultValue = { 2 }
loading = {{ increment: loading }}
aria-label = "상품 수량"
getValueText = {( value ) => `${ value }개` }
/>
< ActionButton variant = "neutralWeak" onClick = {toggleLoading}>
Increment loading 전환
</ ActionButton >
</ VStack >
);
}
inputProps에 name을 전달하면 현재 수량이 hidden input으로 제출됩니다.
import { HStack, Text, VStack } from "@seed-design/react" ;
import { useState, type FormEvent } from "react" ;
import { ActionButton } from "seed-design/ui/action-button" ;
import { QuantityPicker } from "seed-design/ui/quantity-picker" ;
export default function QuantityPickerForm () {
const [ submittedQuantity , setSubmittedQuantity ] = useState < number | null >( null );
function handleSubmit ( event : FormEvent < HTMLFormElement >) {
event. preventDefault ();
const formData = new FormData (event.currentTarget);
setSubmittedQuantity ( Number (formData. get ( "quantity" )));
}
return (
< VStack asChild gap = "x3" align = "flex-start" >
< form onSubmit = {handleSubmit}>
< QuantityPicker
min = { 1 }
max = { 99 }
defaultValue = { 1 }
aria-label = "상품 수량"
inputProps = {{ name: "quantity" }}
getValueText = {( value ) => `${ value }개` }
/>
< HStack gap = "x2" >
< ActionButton type = "submit" variant = "neutralSolid" >
제출
</ ActionButton >
{submittedQuantity !== null && (
< Text textStyle = "t4Regular" >제출한 수량: {submittedQuantity}개</ Text >
)}
</ HStack >
</ form >
</ VStack >
);
}
Root에는 Quantity Picker의 용도를 설명하는 aria-label 또는 aria-labelledby를 제공하세요. 필요하면 decrementAriaLabel, incrementAriaLabel, removeAriaLabel로 각 action의 접근성 이름을 맥락에 맞게 변경할 수 있습니다.
getValueText를 사용하면 ValueDisplay의 숫자를 사람이 읽기 쉬운 텍스트로 제공할 수 있습니다. 이 값은 hidden input에 제출되는 raw integer 값에 영향을 주지 않습니다.