diff --git a/.changeset/lazy-sheep-pull.md b/.changeset/lazy-sheep-pull.md new file mode 100644 index 00000000..ddbcb186 --- /dev/null +++ b/.changeset/lazy-sheep-pull.md @@ -0,0 +1,5 @@ +--- +"wowds-ui": patch +--- + +RangeDatePicker, SingleDatePicker, TimePicker 컴포넌트를 구현합니다. diff --git a/.changeset/sour-swans-wait.md b/.changeset/sour-swans-wait.md new file mode 100644 index 00000000..e676ff48 --- /dev/null +++ b/.changeset/sour-swans-wait.md @@ -0,0 +1,5 @@ +--- +"wowds-icons": patch +--- + +LeftArrow 아이콘을 추가합니다. diff --git a/packages/scripts/generateBuildConfig.ts b/packages/scripts/generateBuildConfig.ts index 36a68f74..c9bed9e1 100644 --- a/packages/scripts/generateBuildConfig.ts +++ b/packages/scripts/generateBuildConfig.ts @@ -25,6 +25,7 @@ const excludedComponents = [ "DropDownWrapper", "CollectionContext", "DropDownOptionList", + "pickerComponents", ]; const getFilteredComponentFiles = async (directoryPath: string) => { diff --git a/packages/wow-icons/src/component/Calendar.tsx b/packages/wow-icons/src/component/Calendar.tsx new file mode 100644 index 00000000..98b3601c --- /dev/null +++ b/packages/wow-icons/src/component/Calendar.tsx @@ -0,0 +1,50 @@ +import { forwardRef } from "react"; +import { color } from "wowds-tokens"; + +import type { IconProps } from "@/types/Icon.ts"; + +const Calendar = forwardRef( + ( + { + className, + width = "24", + height = "24", + viewBox = "0 0 24 24", + stroke = "white", + ...rest + }, + ref + ) => { + return ( + + + + + + + + + ); + } +); + +Calendar.displayName = "Calendar"; +export default Calendar; diff --git a/packages/wow-icons/src/component/LeftArrow.tsx b/packages/wow-icons/src/component/LeftArrow.tsx new file mode 100644 index 00000000..10aad208 --- /dev/null +++ b/packages/wow-icons/src/component/LeftArrow.tsx @@ -0,0 +1,42 @@ +import { forwardRef } from "react"; +import { color } from "wowds-tokens"; + +import type { IconProps } from "@/types/Icon.ts"; + +const LeftArrow = forwardRef( + ( + { + className, + width = "20", + height = "20", + viewBox = "0 0 20 20", + stroke = "white", + ...rest + }, + ref + ) => { + return ( + + + + ); + } +); + +LeftArrow.displayName = "LeftArrow"; +export default LeftArrow; diff --git a/packages/wow-icons/src/component/index.ts b/packages/wow-icons/src/component/index.ts index ef0816dd..11ab8e7f 100644 --- a/packages/wow-icons/src/component/index.ts +++ b/packages/wow-icons/src/component/index.ts @@ -1,8 +1,10 @@ +export { default as Calendar } from "./Calendar.tsx"; export { default as Check } from "./Check.tsx"; export { default as Close } from "./Close.tsx"; export { default as DownArrow } from "./DownArrow.tsx"; export { default as Edit } from "./Edit.tsx"; export { default as Help } from "./Help.tsx"; +export { default as LeftArrow } from "./LeftArrow.tsx"; export { default as Link } from "./Link.tsx"; export { default as Plus } from "./Plus.tsx"; export { default as Reload } from "./Reload.tsx"; diff --git a/packages/wow-icons/src/svg/calendar.svg b/packages/wow-icons/src/svg/calendar.svg new file mode 100644 index 00000000..e7ea74b1 --- /dev/null +++ b/packages/wow-icons/src/svg/calendar.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/packages/wow-icons/src/svg/left-arrow.svg b/packages/wow-icons/src/svg/left-arrow.svg new file mode 100644 index 00000000..2d9aed25 --- /dev/null +++ b/packages/wow-icons/src/svg/left-arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/wow-ui/package.json b/packages/wow-ui/package.json index cd521102..8c17bdc1 100644 --- a/packages/wow-ui/package.json +++ b/packages/wow-ui/package.json @@ -70,6 +70,31 @@ "require": "./dist/RadioGroup.cjs", "import": "./dist/RadioGroup.js" }, + "./DateDropDown": { + "types": "./dist/components/Picker/DateDropDown.d.ts", + "require": "./dist/DateDropDown.cjs", + "import": "./dist/DateDropDown.js" + }, + "./PickerGroup": { + "types": "./dist/components/Picker/PickerGroup.d.ts", + "require": "./dist/PickerGroup.cjs", + "import": "./dist/PickerGroup.js" + }, + "./RangeDatePicker": { + "types": "./dist/components/Picker/RangeDatePicker.d.ts", + "require": "./dist/RangeDatePicker.cjs", + "import": "./dist/RangeDatePicker.js" + }, + "./SingleDatePicker": { + "types": "./dist/components/Picker/SingleDatePicker.d.ts", + "require": "./dist/SingleDatePicker.cjs", + "import": "./dist/SingleDatePicker.js" + }, + "./TimePicker": { + "types": "./dist/components/Picker/TimePicker.d.ts", + "require": "./dist/TimePicker.cjs", + "import": "./dist/TimePicker.js" + }, "./MultiGroup": { "types": "./dist/components/MultiGroup/index.d.ts", "require": "./dist/MultiGroup.cjs", @@ -154,6 +179,7 @@ "dependencies": { "clsx": "^2.1.1", "lottie-react": "^2.4.0", + "react-day-picker": "^9.0.8", "wowds-icons": "workspace:^" }, "peerDependencies": { diff --git a/packages/wow-ui/rollup.config.js b/packages/wow-ui/rollup.config.js index f03811d6..2113035a 100644 --- a/packages/wow-ui/rollup.config.js +++ b/packages/wow-ui/rollup.config.js @@ -30,6 +30,11 @@ export default { SearchBar: "./src/components/SearchBar", RadioButton: "./src/components/RadioGroup/RadioButton", RadioGroup: "./src/components/RadioGroup/RadioGroup", + DateDropDown: "./src/components/Picker/DateDropDown", + PickerGroup: "./src/components/Picker/PickerGroup", + RangeDatePicker: "./src/components/Picker/RangeDatePicker", + SingleDatePicker: "./src/components/Picker/SingleDatePicker", + TimePicker: "./src/components/Picker/TimePicker", MultiGroup: "./src/components/MultiGroup", DropDownOption: "./src/components/DropDown/DropDownOption", DropDown: "./src/components/DropDown", diff --git a/packages/wow-ui/src/components/Button/index.tsx b/packages/wow-ui/src/components/Button/index.tsx index 51b369b0..ea6fad1e 100644 --- a/packages/wow-ui/src/components/Button/index.tsx +++ b/packages/wow-ui/src/components/Button/index.tsx @@ -134,7 +134,7 @@ const ButtonStyle = cva({ _disabled: { borderColor: "darkDisabled", color: "darkDisabled", - cursor: "not-allowed", + pointerEvents: "none", }, _hover: { borderColor: "blueHover", @@ -152,7 +152,7 @@ const ButtonStyle = cva({ _disabled: { color: "blueDisabled", - cursor: "not-allowed", + pointerEvents: "none", }, _hover: { shadow: "blue", diff --git a/packages/wow-ui/src/components/Picker/DateDropDown.tsx b/packages/wow-ui/src/components/Picker/DateDropDown.tsx new file mode 100644 index 00000000..454dfe47 --- /dev/null +++ b/packages/wow-ui/src/components/Picker/DateDropDown.tsx @@ -0,0 +1,115 @@ +"use client"; + +import { cva } from "@styled-system/css"; +import { Flex, styled } from "@styled-system/jsx"; +import { Calendar } from "wowds-icons"; + +interface DateDropDownPropsBase { + label?: string; + placeholder?: string; + onClick: () => void; +} + +interface SingleDateDropDownProps extends DateDropDownPropsBase { + mode: "single"; + selectedValue?: string; +} + +interface RangeDateDropDownProps extends DateDropDownPropsBase { + mode: "range"; + selectedValue?: { start?: string; end?: string }; +} + +type DateDropDownProps = SingleDateDropDownProps | RangeDateDropDownProps; + +const DateDropDown = ({ + mode, + placeholder, + label, + selectedValue, + onClick, +}: DateDropDownProps) => { + const formatSelectedValue = () => { + if (!selectedValue) return placeholder; + if (mode === "range" && selectedValue.start) return selectedValue.start; + if (mode === "single") return selectedValue; + }; + + return ( + + {label && ( + + {label} + + )} + + + ); +}; + +export default DateDropDown; + +const dropdownStyle = cva({ + base: { + lg: { + maxWidth: "22.375rem", + }, + smDown: { + width: "100%", + }, + display: "flex", + alignItems: "center", + justifyContent: "space-between", + + border: "1px solid", + borderRadius: "sm", + borderColor: "outline", + outline: "none", + + paddingY: "xs", + paddingX: "sm", + + backgroundColor: "background", + cursor: "pointer", + }, +}); + +const placeholderStyle = cva({ + base: { + textStyle: "body1", + }, + variants: { + type: { + default: { + color: "outline", + _hover: { + color: "sub", + }, + }, + focused: { + color: "primary", + }, + selected: { + color: "textBlack", + }, + }, + }, +}); diff --git a/packages/wow-ui/src/components/Picker/DatePicker.stories.tsx b/packages/wow-ui/src/components/Picker/DatePicker.stories.tsx new file mode 100644 index 00000000..35c8b21f --- /dev/null +++ b/packages/wow-ui/src/components/Picker/DatePicker.stories.tsx @@ -0,0 +1,110 @@ +import type { Meta } from "@storybook/react"; +import { Flex } from "@styled-system/jsx"; +import { useState } from "react"; + +import type { Time } from "@/components/Picker/PickerContext"; +import PickerGroup from "@/components/Picker/PickerGroup"; +import RangeDatePicker from "@/components/Picker/RangeDatePicker"; +import DatePicker from "@/components/Picker/SingleDatePicker"; +import TimePicker from "@/components/Picker/TimePicker"; + +const meta = { + title: "UI/DatePicker", + component: DatePicker, + tags: ["autodocs"], + parameters: { + componentSubtitle: "DatePicker 컴포넌트", + a11y: { + config: { + rules: [{ id: "color-contrast", enabled: false }], + }, + }, + }, + argTypes: { + label: { + description: "DatePicker의 라벨을 나타냅니다.", + table: { + type: { summary: "string" }, + defaultValue: { summary: undefined }, + }, + }, + selected: { + description: "DatePicker의 선택된 날짜 값을 나타냅니다.", + table: { + type: { summary: "Date" }, + defaultValue: { summary: undefined }, + }, + }, + onSelect: { + description: "DatePicker의 날짜를 선택할 수 있는 함수를 나타냅니다.", + table: { + type: { summary: "function" }, + defaultValue: { + summary: undefined, + }, + }, + }, + placeholder: { + description: + "DatePicker의 드롭다운에 들어갈 placeholder 텍스트를 나타냅니다.", + table: { + type: { summary: "string" }, + defaultValue: { summary: undefined }, + }, + }, + }, +} satisfies Meta; + +export default meta; + +export const Default = () => { + const [selected, setSelected] = useState(); + return ( + + ); +}; + +export const WithInitialDate = () => { + const [selected, setSelected] = useState(new Date()); + return ( + + ); +}; + +export const WithTimePicker = () => { + const [selected, setSelected] = useState(new Date()); + + return ( + + + + + ); +}; + +export const DateRange = () => { + // DateRange 타입 + const [selected, setSelected] = useState< + { from: Date | undefined; to?: Date | undefined } | undefined + >(); + return ( + + ); +}; + +export const TimeRange = () => { + const [start, setStart] = useState