@uniai-fe/uds-primitives 0.1.12 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/README.md +2 -2
  2. package/dist/styles.css +1196 -511
  3. package/package.json +12 -15
  4. package/src/components/button/index.scss +1 -0
  5. package/src/components/button/markup/{ButtonRounded.tsx → Rounded.tsx} +1 -1
  6. package/src/components/button/markup/{ButtonText.tsx → Text.tsx} +1 -1
  7. package/src/components/button/markup/index.ts +3 -3
  8. package/src/components/button/styles/button.scss +336 -437
  9. package/src/components/button/styles/round-button.scss +60 -50
  10. package/src/components/button/styles/text-button.scss +93 -81
  11. package/src/components/button/styles/variables.scss +145 -0
  12. package/src/components/dropdown/index.tsx +3 -3
  13. package/src/components/dropdown/markup/Template.tsx +61 -0
  14. package/src/components/dropdown/markup/foundation/Container.tsx +97 -0
  15. package/src/components/dropdown/markup/foundation/MenuItem.tsx +107 -0
  16. package/src/components/dropdown/markup/foundation/MenuList.tsx +27 -0
  17. package/src/components/dropdown/markup/foundation/Provider.tsx +46 -0
  18. package/src/components/dropdown/markup/foundation/Root.tsx +30 -0
  19. package/src/components/dropdown/markup/foundation/Trigger.tsx +34 -0
  20. package/src/components/dropdown/markup/foundation/index.tsx +25 -0
  21. package/src/components/dropdown/markup/index.tsx +8 -2
  22. package/src/components/dropdown/styles/dropdown.scss +166 -0
  23. package/src/components/dropdown/styles/index.scss +2 -0
  24. package/src/components/dropdown/styles/variables.scss +40 -0
  25. package/src/components/dropdown/types/base.ts +18 -0
  26. package/src/components/dropdown/types/index.ts +2 -4
  27. package/src/components/dropdown/types/props.ts +174 -0
  28. package/src/components/dropdown/utils/index.ts +1 -4
  29. package/src/components/dropdown/utils/refs.ts +20 -0
  30. package/src/components/form/index.scss +1 -0
  31. package/src/components/form/index.tsx +18 -2
  32. package/src/components/form/markup/form-field/Body.tsx +18 -0
  33. package/src/components/form/markup/form-field/Container.tsx +58 -0
  34. package/src/components/form/markup/form-field/Footer.tsx +21 -0
  35. package/src/components/form/markup/form-field/Header.tsx +39 -0
  36. package/src/components/form/markup/form-field/Template.tsx +56 -0
  37. package/src/components/form/markup/form-field/index.tsx +22 -0
  38. package/src/components/form/styles/form-field/layout.scss +67 -0
  39. package/src/components/form/styles/form-field/variables.scss +17 -0
  40. package/src/components/form/styles/index.scss +2 -0
  41. package/src/components/form/types/index.ts +1 -0
  42. package/src/components/form/types/props.ts +125 -0
  43. package/src/components/form/utils/form-field.ts +42 -0
  44. package/src/components/input/hooks/index.ts +1 -4
  45. package/src/components/input/hooks/useDigitField.ts +63 -0
  46. package/src/components/input/img/calendar/calendar.svg +7 -0
  47. package/src/components/input/img/calendar/chevron-down.svg +3 -0
  48. package/src/components/input/img/calendar/chevron-left.svg +3 -0
  49. package/src/components/input/img/calendar/chevron-right.svg +3 -0
  50. package/src/components/input/img/calendar/chevron-up.svg +3 -0
  51. package/src/components/input/index.tsx +2 -1
  52. package/src/components/input/markup/calendar/Base.tsx +329 -0
  53. package/src/components/input/markup/calendar/index.tsx +8 -0
  54. package/src/components/input/markup/{text/InputUtilityButton.tsx → foundation/Button.tsx} +5 -15
  55. package/src/components/input/markup/foundation/Input.tsx +245 -0
  56. package/src/components/input/markup/foundation/SideSlot.tsx +30 -0
  57. package/src/components/input/markup/foundation/StatusIcon.tsx +21 -0
  58. package/src/components/input/markup/foundation/Utility.tsx +103 -0
  59. package/src/components/input/markup/foundation/index.tsx +15 -0
  60. package/src/components/input/markup/index.tsx +11 -1
  61. package/src/components/input/markup/text/AuthCode.tsx +41 -59
  62. package/src/components/input/markup/text/Email.tsx +25 -115
  63. package/src/components/input/markup/text/Password.tsx +30 -39
  64. package/src/components/input/markup/text/Phone.tsx +35 -122
  65. package/src/components/input/markup/text/Search.tsx +17 -18
  66. package/src/components/input/markup/text/index.ts +15 -12
  67. package/src/components/input/styles/calendar.scss +110 -0
  68. package/src/components/input/styles/foundation.scss +345 -0
  69. package/src/components/input/styles/index.scss +4 -476
  70. package/src/components/input/styles/text.scss +89 -0
  71. package/src/components/input/styles/variables.scss +41 -0
  72. package/src/components/input/types/calendar.ts +208 -0
  73. package/src/components/input/types/foundation.ts +194 -0
  74. package/src/components/input/types/hooks.ts +43 -0
  75. package/src/components/input/types/index.ts +5 -87
  76. package/src/components/input/types/text.ts +203 -0
  77. package/src/components/input/types/verification.ts +23 -0
  78. package/src/components/input/utils/index.tsx +1 -0
  79. package/src/components/input/utils/verification.tsx +35 -0
  80. package/src/components/select/hooks/index.ts +43 -2
  81. package/src/components/select/img/chevron/primary/large.svg +3 -0
  82. package/src/components/select/img/chevron/primary/medium.svg +3 -0
  83. package/src/components/select/img/chevron/primary/small.svg +3 -0
  84. package/src/components/select/img/chevron/secondary/large.svg +3 -0
  85. package/src/components/select/img/chevron/secondary/medium.svg +3 -0
  86. package/src/components/select/img/chevron/secondary/small.svg +3 -0
  87. package/src/components/select/img/remove.svg +3 -0
  88. package/src/components/select/index.scss +2 -1
  89. package/src/components/select/index.tsx +5 -0
  90. package/src/components/select/markup/Default.tsx +154 -0
  91. package/src/components/select/markup/foundation/Base.tsx +90 -0
  92. package/src/components/select/markup/foundation/Container.tsx +30 -0
  93. package/src/components/select/markup/foundation/Icon.tsx +78 -0
  94. package/src/components/select/markup/foundation/Selected.tsx +34 -0
  95. package/src/components/select/markup/foundation/index.ts +2 -0
  96. package/src/components/select/markup/index.tsx +36 -2
  97. package/src/components/select/markup/multiple/Multiple.tsx +205 -0
  98. package/src/components/select/markup/multiple/SelectedChip.tsx +58 -0
  99. package/src/components/select/markup/multiple/index.ts +2 -0
  100. package/src/components/select/styles/select.scss +316 -0
  101. package/src/components/select/styles/variables.scss +91 -0
  102. package/src/components/select/types/base.ts +34 -0
  103. package/src/components/select/types/icon.ts +45 -0
  104. package/src/components/select/types/index.ts +5 -4
  105. package/src/components/select/types/multiple.ts +57 -0
  106. package/src/components/select/types/props.ts +208 -0
  107. package/src/components/select/types/trigger.ts +196 -0
  108. package/src/index.scss +3 -2
  109. package/src/components/input/markup/text/Base.tsx +0 -454
  110. package/src/components/input/utils/index.ts +0 -60
  111. package/src/components/select/styles/index.scss +0 -0
  112. /package/src/components/button/markup/{ButtonDefault.tsx → Base.tsx} +0 -0
  113. /package/src/components/form/{Provider.tsx → markup/Provider.tsx} +0 -0
@@ -0,0 +1,107 @@
1
+ "use client";
2
+
3
+ import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
4
+ import clsx from "clsx";
5
+ import { forwardRef } from "react";
6
+
7
+ import type { DropdownMenuItemProps } from "../../types/props";
8
+ import { Checkbox } from "../../../checkbox/markup/Checkbox";
9
+ import type { CheckboxProps } from "../../../checkbox/types";
10
+
11
+ /**
12
+ * Dropdown menu item; label/description/slot 구성을 처리한다.
13
+ * @component
14
+ * @param {DropdownMenuItemProps} props dropdown menu option props
15
+ * @param {boolean} [props.isSelected] 선택 상태
16
+ * @param {boolean} [props.multiple] multi select 스타일 여부
17
+ */
18
+ const DropdownMenuItem = forwardRef<HTMLDivElement, DropdownMenuItemProps>(
19
+ (
20
+ {
21
+ label,
22
+ description,
23
+ leftSlot,
24
+ rightSlot,
25
+ isSelected = false,
26
+ multiple = false,
27
+ className,
28
+ checkboxProps,
29
+ children,
30
+ onSelect: onSelectHandler,
31
+ ...rest
32
+ },
33
+ ref,
34
+ ) => {
35
+ const labelContent = label ?? children;
36
+ const hasDescription = Boolean(description);
37
+ const shouldRenderCheckbox = multiple && !leftSlot;
38
+
39
+ const renderPrefix = () => {
40
+ if (shouldRenderCheckbox) {
41
+ const checkboxClassName = clsx(
42
+ "dropdown-menu-item-checkbox",
43
+ checkboxProps?.className,
44
+ );
45
+
46
+ const checkboxAdditionalProps: CheckboxProps = {
47
+ ...checkboxProps,
48
+ checked: isSelected,
49
+ onCheckedChange: checkboxProps?.onCheckedChange ?? (() => {}),
50
+ tabIndex: -1,
51
+ "aria-hidden": true,
52
+ className: checkboxClassName,
53
+ } as CheckboxProps;
54
+
55
+ return (
56
+ <span className="dropdown-menu-item-prefix" aria-hidden="true">
57
+ <Checkbox size="medium" {...checkboxAdditionalProps} />
58
+ </span>
59
+ );
60
+ }
61
+
62
+ if (leftSlot) {
63
+ return <span className="dropdown-menu-item-prefix">{leftSlot}</span>;
64
+ }
65
+
66
+ return null;
67
+ };
68
+
69
+ return (
70
+ <li className="dropdown-menu-item">
71
+ <DropdownMenu.Item
72
+ {...rest}
73
+ ref={ref}
74
+ className={clsx("dropdown-menu-item-trigger", className)}
75
+ data-state={isSelected ? "selected" : undefined}
76
+ data-multiple={multiple ? "true" : undefined}
77
+ data-has-description={hasDescription ? "true" : undefined}
78
+ onSelect={event => {
79
+ if (multiple) {
80
+ event.preventDefault();
81
+ }
82
+ onSelectHandler?.(event);
83
+ }}
84
+ >
85
+ {renderPrefix()}
86
+ <span className="dropdown-menu-item-body">
87
+ {labelContent ? (
88
+ <span className="dropdown-menu-item-label">{labelContent}</span>
89
+ ) : null}
90
+ {description ? (
91
+ <span className="dropdown-menu-item-description">
92
+ {description}
93
+ </span>
94
+ ) : null}
95
+ </span>
96
+ {rightSlot ? (
97
+ <span className="dropdown-menu-item-suffix">{rightSlot}</span>
98
+ ) : null}
99
+ </DropdownMenu.Item>
100
+ </li>
101
+ );
102
+ },
103
+ );
104
+
105
+ DropdownMenuItem.displayName = "DropdownMenuItem";
106
+
107
+ export default DropdownMenuItem;
@@ -0,0 +1,27 @@
1
+ "use client";
2
+
3
+ import clsx from "clsx";
4
+ import { forwardRef } from "react";
5
+
6
+ import type { DropdownMenuListProps } from "../../types/props";
7
+
8
+ /**
9
+ * Dropdown option list wrapper
10
+ * @component
11
+ * @param {DropdownMenuListProps} props list attributes
12
+ */
13
+ const DropdownMenuList = forwardRef<HTMLUListElement, DropdownMenuListProps>(
14
+ ({ className, ...rest }, ref) => {
15
+ return (
16
+ <ul
17
+ {...rest}
18
+ ref={ref}
19
+ className={clsx("dropdown-menu-list", className)}
20
+ />
21
+ );
22
+ },
23
+ );
24
+
25
+ DropdownMenuList.displayName = "DropdownMenuList";
26
+
27
+ export default DropdownMenuList;
@@ -0,0 +1,46 @@
1
+ "use client";
2
+
3
+ import {
4
+ createContext,
5
+ useContext,
6
+ useMemo,
7
+ useRef,
8
+ type ReactNode,
9
+ } from "react";
10
+
11
+ import type { DropdownContextValue } from "../../types";
12
+
13
+ /**
14
+ * Dropdown 전용 context; trigger ref를 공유한다.
15
+ */
16
+ const DropdownContext = createContext<DropdownContextValue | null>(null);
17
+
18
+ /**
19
+ * Dropdown context provider
20
+ * @component
21
+ * @param {ReactNode} props.children dropdown 하위 노드
22
+ */
23
+ const DropdownProvider = ({ children }: { children: ReactNode }) => {
24
+ const triggerRef = useRef<HTMLElement | null>(null);
25
+ const value = useMemo<DropdownContextValue>(() => ({ triggerRef }), []);
26
+
27
+ return (
28
+ <DropdownContext.Provider value={value}>
29
+ {children}
30
+ </DropdownContext.Provider>
31
+ );
32
+ };
33
+
34
+ /**
35
+ * Dropdown context hook; scope 내에서만 호출해야 한다.
36
+ * @param {string} componentName 오류 메시지용 컴포넌트 명
37
+ */
38
+ const useDropdownContext = (componentName: string) => {
39
+ const context = useContext(DropdownContext);
40
+ if (!context) {
41
+ throw new Error(`${componentName} must be used within Dropdown.Container`);
42
+ }
43
+ return context;
44
+ };
45
+
46
+ export { DropdownContext, DropdownProvider, useDropdownContext };
@@ -0,0 +1,30 @@
1
+ "use client";
2
+
3
+ import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
4
+ import type { ReactNode } from "react";
5
+
6
+ import type { DropdownRootProps } from "../../types/base";
7
+ import { DropdownProvider } from "./Provider";
8
+
9
+ /**
10
+ * Dropdown root; Provider와 Radix Root를 래핑한다.
11
+ * @component
12
+ * @param {DropdownRootProps} props Dropdown Root props
13
+ * @param {ReactNode} props.children Dropdown 하위 node
14
+ * @param {boolean} [props.modal=false] Radix modal 모드
15
+ */
16
+ const DropdownRoot = ({
17
+ children,
18
+ modal = false,
19
+ ...rootProps
20
+ }: DropdownRootProps & { children: ReactNode }) => {
21
+ return (
22
+ <DropdownProvider>
23
+ <DropdownMenu.Root modal={modal} {...rootProps}>
24
+ {children}
25
+ </DropdownMenu.Root>
26
+ </DropdownProvider>
27
+ );
28
+ };
29
+
30
+ export default DropdownRoot;
@@ -0,0 +1,34 @@
1
+ "use client";
2
+
3
+ import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
4
+ import { forwardRef } from "react";
5
+
6
+ import type { DropdownTriggerProps } from "../../types/props";
7
+ import { mergeRefs } from "../../utils";
8
+ import { useDropdownContext } from "./Provider";
9
+
10
+ /**
11
+ * Dropdown trigger; trigger ref를 context에 공유한다.
12
+ * @component
13
+ * @param {DropdownTriggerProps} props Dropdown trigger props
14
+ * @param {boolean} [props.asChild=true] asChild 패턴 유지 여부
15
+ */
16
+ const DropdownTrigger = forwardRef<HTMLElement, DropdownTriggerProps>(
17
+ ({ asChild = true, children, ...rest }, ref) => {
18
+ const { triggerRef } = useDropdownContext("Dropdown.Trigger");
19
+
20
+ return (
21
+ <DropdownMenu.Trigger
22
+ {...rest}
23
+ asChild={asChild}
24
+ ref={mergeRefs(ref, triggerRef)}
25
+ >
26
+ {children}
27
+ </DropdownMenu.Trigger>
28
+ );
29
+ },
30
+ );
31
+
32
+ DropdownTrigger.displayName = "DropdownTrigger";
33
+
34
+ export default DropdownTrigger;
@@ -0,0 +1,25 @@
1
+ import DropdownContainer from "./Container";
2
+ import DropdownMenuItem from "./MenuItem";
3
+ import DropdownMenuList from "./MenuList";
4
+ import DropdownRoot from "./Root";
5
+ import { DropdownProvider } from "./Provider";
6
+ import DropdownTrigger from "./Trigger";
7
+
8
+ /**
9
+ * Dropdown; 기초 컴포넌트
10
+ * - Provider
11
+ * - Root
12
+ * - Container
13
+ * - Menu
14
+ * - Item
15
+ * - List
16
+ * - Panel
17
+ * - Trigger
18
+ */
19
+ export const DropdownFoundation = {
20
+ Provider: DropdownProvider,
21
+ Root: DropdownRoot,
22
+ Container: DropdownContainer,
23
+ Menu: { Item: DropdownMenuItem, List: DropdownMenuList },
24
+ Trigger: DropdownTrigger,
25
+ };
@@ -1,4 +1,10 @@
1
+ import { DropdownFoundation } from "./foundation";
2
+ import DropdownTemplate from "./Template";
3
+
1
4
  /**
2
- * TODO(dropdown): SOT 및 사용자 제약에 따라 컴포넌트를 구현한다.
5
+ * Dropdown namespace export
3
6
  */
4
- export {};
7
+ export const Dropdown = {
8
+ ...DropdownFoundation,
9
+ Template: DropdownTemplate,
10
+ };
@@ -0,0 +1,166 @@
1
+ .dropdown-panel {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--dropdown-panel-gap);
5
+ padding: var(--dropdown-panel-padding);
6
+ border-radius: var(--dropdown-panel-radius);
7
+ border: 1px solid var(--dropdown-panel-border-color);
8
+ background-color: var(--dropdown-panel-background);
9
+ box-shadow: var(--dropdown-panel-shadow);
10
+ max-height: var(--dropdown-panel-max-height);
11
+ overflow-y: auto;
12
+ }
13
+
14
+ .dropdown-panel-small {
15
+ --dropdown-option-height-current: var(--dropdown-option-height-small);
16
+ --dropdown-text-size-current: var(--dropdown-text-small-size);
17
+ --dropdown-text-line-height-current: var(--dropdown-text-small-line-height);
18
+ --dropdown-text-letter-spacing-current: var(
19
+ --dropdown-text-small-letter-spacing
20
+ );
21
+ }
22
+
23
+ .dropdown-panel-medium {
24
+ --dropdown-option-height-current: var(--dropdown-option-height-medium);
25
+ --dropdown-text-size-current: var(--dropdown-text-medium-size);
26
+ --dropdown-text-line-height-current: var(--dropdown-text-medium-line-height);
27
+ --dropdown-text-letter-spacing-current: var(
28
+ --dropdown-text-medium-letter-spacing
29
+ );
30
+ }
31
+
32
+ .dropdown-panel-large {
33
+ --dropdown-option-height-current: var(--dropdown-option-height-large);
34
+ --dropdown-text-size-current: var(--dropdown-text-large-size);
35
+ --dropdown-text-line-height-current: var(--dropdown-text-large-line-height);
36
+ --dropdown-text-letter-spacing-current: var(
37
+ --dropdown-text-large-letter-spacing
38
+ );
39
+ }
40
+
41
+ .dropdown-menu-list {
42
+ display: flex;
43
+ flex-direction: column;
44
+ gap: var(--dropdown-panel-gap);
45
+ list-style: none;
46
+ padding: 0;
47
+ margin: 0;
48
+ }
49
+
50
+ .dropdown-menu-item {
51
+ width: 100%;
52
+ }
53
+
54
+ .dropdown-menu-item-trigger {
55
+ display: flex;
56
+ align-items: center;
57
+ gap: var(--dropdown-option-gap-inline);
58
+ width: 100%;
59
+ min-height: var(
60
+ --dropdown-option-height-current,
61
+ var(--dropdown-option-height-medium)
62
+ );
63
+ padding: var(--dropdown-option-padding-block)
64
+ var(--dropdown-option-padding-inline);
65
+ border-radius: var(--dropdown-option-radius);
66
+ background-color: transparent;
67
+ color: var(--dropdown-option-color);
68
+ cursor: pointer;
69
+ font-size: var(--dropdown-option-font-size, var(--dropdown-text-medium-size));
70
+ font-weight: var(--dropdown-option-font-weight, var(--dropdown-text-weight));
71
+ line-height: var(
72
+ --dropdown-option-line-height,
73
+ var(--dropdown-text-medium-line-height)
74
+ );
75
+
76
+ &[data-state="selected"] {
77
+ background-color: var(--dropdown-option-bg-selected);
78
+ color: var(--dropdown-option-color-selected);
79
+ }
80
+
81
+ &[data-highlighted],
82
+ &:hover {
83
+ background-color: var(--dropdown-option-bg-hover);
84
+ color: var(--dropdown-option-color-hover);
85
+ }
86
+
87
+ &[data-state="selected"]:hover {
88
+ background-color: var(--dropdown-option-bg-selected);
89
+ color: var(--dropdown-option-color-selected);
90
+ }
91
+
92
+ &[data-disabled],
93
+ &:disabled {
94
+ color: var(--dropdown-option-color-disabled);
95
+ cursor: not-allowed;
96
+ background-color: var(--dropdown-option-bg-disabled);
97
+ }
98
+
99
+ &[data-disabled] .dropdown-menu-item-label,
100
+ &:disabled .dropdown-menu-item-label {
101
+ color: var(--dropdown-option-color-disabled);
102
+ }
103
+
104
+ &[data-disabled] .dropdown-menu-item-description,
105
+ &:disabled .dropdown-menu-item-description {
106
+ color: var(--dropdown-option-color-disabled);
107
+ }
108
+ }
109
+
110
+ .dropdown-menu-item-prefix,
111
+ .dropdown-menu-item-suffix {
112
+ display: inline-flex;
113
+ align-items: center;
114
+ color: inherit;
115
+ }
116
+
117
+ .dropdown-menu-item-body {
118
+ display: flex;
119
+ flex-direction: column;
120
+ gap: 0.2rem;
121
+ flex: 1 1 auto;
122
+ min-width: 0;
123
+ }
124
+
125
+ .dropdown-menu-item-label {
126
+ display: inline-flex;
127
+ align-items: center;
128
+ min-width: 0;
129
+ color: inherit;
130
+ font-size: var(
131
+ --dropdown-text-size-current,
132
+ var(--dropdown-text-medium-size)
133
+ );
134
+ line-height: var(
135
+ --dropdown-text-line-height-current,
136
+ var(--dropdown-text-medium-line-height)
137
+ );
138
+ letter-spacing: var(
139
+ --dropdown-text-letter-spacing-current,
140
+ var(--dropdown-text-medium-letter-spacing)
141
+ );
142
+ font-weight: var(--dropdown-text-weight);
143
+ overflow: hidden;
144
+ text-overflow: ellipsis;
145
+ white-space: nowrap;
146
+ }
147
+
148
+ .dropdown-menu-item-description {
149
+ font-size: var(--dropdown-description-size);
150
+ line-height: var(--dropdown-description-line-height);
151
+ color: var(--dropdown-description-color);
152
+ overflow: hidden;
153
+ text-overflow: ellipsis;
154
+ white-space: nowrap;
155
+ }
156
+ .dropdown-menu-item-trigger[data-state="selected"] .dropdown-menu-item-label {
157
+ font-weight: var(--dropdown-text-weight-selected);
158
+ }
159
+ .dropdown-menu-item-trigger[data-multiple="true"] {
160
+ align-items: center;
161
+ }
162
+ .dropdown-menu-item-checkbox {
163
+ width: var(--theme-checkbox-frame-size-medium);
164
+ height: var(--theme-checkbox-frame-size-medium);
165
+ padding: 0;
166
+ }
@@ -0,0 +1,2 @@
1
+ @use "./variables.scss";
2
+ @use "./dropdown.scss";
@@ -0,0 +1,40 @@
1
+ :root {
2
+ --dropdown-panel-background: var(--color-common-100);
3
+ --dropdown-panel-border-color: var(--color-border-standard-cool-gray);
4
+ --dropdown-panel-radius: var(--theme-radius-large-1);
5
+ --dropdown-panel-shadow: 0px 4px 22px rgba(19, 22, 32, 0.12);
6
+ --dropdown-panel-padding: var(--spacing-padding-3);
7
+ --dropdown-panel-gap: var(--spacing-gap-2);
8
+ --dropdown-panel-max-height: 32rem;
9
+
10
+ --dropdown-option-radius: var(--theme-radius-medium-1);
11
+ --dropdown-option-gap-inline: var(--spacing-gap-3);
12
+ --dropdown-option-padding-inline: var(--spacing-padding-6);
13
+ --dropdown-option-padding-block: var(--spacing-padding-2);
14
+ --dropdown-option-color: var(--color-label-standard);
15
+ --dropdown-option-color-hover: var(--color-label-strong);
16
+ --dropdown-option-color-selected: var(--color-primary-default);
17
+ --dropdown-option-color-disabled: var(--color-label-disabled);
18
+ --dropdown-option-bg-hover: var(--color-surface-standard);
19
+ --dropdown-option-bg-selected: var(--color-surface-static-blue);
20
+ --dropdown-option-bg-disabled: transparent;
21
+
22
+ --dropdown-text-small-size: 15px;
23
+ --dropdown-text-small-line-height: 24px;
24
+ --dropdown-text-small-letter-spacing: 0;
25
+ --dropdown-text-medium-size: 16px;
26
+ --dropdown-text-medium-line-height: 24px;
27
+ --dropdown-text-medium-letter-spacing: 0;
28
+ --dropdown-text-large-size: 17px;
29
+ --dropdown-text-large-line-height: 26px;
30
+ --dropdown-text-large-letter-spacing: 0;
31
+ --dropdown-text-weight: 400;
32
+ --dropdown-text-weight-selected: 600;
33
+ --dropdown-description-color: var(--color-label-neutral);
34
+ --dropdown-description-size: 14px;
35
+ --dropdown-description-line-height: 22px;
36
+
37
+ --dropdown-option-height-small: 32px;
38
+ --dropdown-option-height-medium: 40px;
39
+ --dropdown-option-height-large: 48px;
40
+ }
@@ -0,0 +1,18 @@
1
+ import type { DropdownMenuProps } from "@radix-ui/react-dropdown-menu";
2
+
3
+ /**
4
+ * Dropdown size scale
5
+ * @typedef {"small" | "medium" | "large"} DropdownSize
6
+ */
7
+ export type DropdownSize = "small" | "medium" | "large";
8
+
9
+ /**
10
+ * Dropdown root props
11
+ * @property {boolean} [modal] Radix modal 모드 여부
12
+ */
13
+ export interface DropdownRootProps extends DropdownMenuProps {
14
+ /**
15
+ * Radix modal 모드 여부
16
+ */
17
+ modal?: DropdownMenuProps["modal"];
18
+ }
@@ -1,4 +1,2 @@
1
- /**
2
- * TODO(dropdown): variant/slot 타입 정의를 작성한다.
3
- */
4
- export {};
1
+ export type * from "./base";
2
+ export type * from "./props";
@@ -0,0 +1,174 @@
1
+ import type {
2
+ DropdownMenuContentProps,
3
+ DropdownMenuItemProps as RadixDropdownMenuItemProps,
4
+ DropdownMenuTriggerProps,
5
+ } from "@radix-ui/react-dropdown-menu";
6
+ import type { HTMLAttributes, MutableRefObject, ReactNode } from "react";
7
+
8
+ import type { CheckboxProps } from "../../checkbox/types";
9
+ import type { DropdownRootProps, DropdownSize } from "./base";
10
+
11
+ /**
12
+ * Dropdown trigger props
13
+ * @property {boolean} [asChild=true] trigger를 asChild 패턴으로 감쌀지 여부
14
+ */
15
+ export interface DropdownTriggerProps extends DropdownMenuTriggerProps {
16
+ /**
17
+ * trigger를 asChild 패턴으로 감쌀지 여부
18
+ */
19
+ asChild?: DropdownMenuTriggerProps["asChild"];
20
+ }
21
+
22
+ /**
23
+ * Dropdown Container props
24
+ * @property {DropdownSize} [size="medium"] option 높이 스케일
25
+ * @property {boolean} [matchTriggerWidth=true] trigger 너비에 맞춰 dropdown 너비를 맞출지 여부
26
+ * @property {HTMLElement | null} [portalContainer] portal을 렌더링할 DOM 컨테이너
27
+ */
28
+ export interface DropdownContainerProps extends DropdownMenuContentProps {
29
+ /**
30
+ * option 높이 스케일
31
+ */
32
+ size?: DropdownSize;
33
+ /**
34
+ * trigger 너비에 맞춰 dropdown 너비를 맞출지 여부
35
+ */
36
+ matchTriggerWidth?: boolean;
37
+ /**
38
+ * portal을 렌더링할 DOM 컨테이너
39
+ */
40
+ portalContainer?: HTMLElement | null;
41
+ }
42
+
43
+ /**
44
+ * Dropdown menu item props
45
+ * @property {ReactNode} [label] 옵션 라벨
46
+ * @property {ReactNode} [description] 보조 텍스트
47
+ * @property {ReactNode} [leftSlot] 좌측 슬롯
48
+ * @property {ReactNode} [rightSlot] 우측 슬롯
49
+ * @property {boolean} [isSelected] 선택 상태 여부
50
+ * @property {boolean} [multiple] multi select 스타일 여부
51
+ * @property {CheckboxProps} [checkboxProps] multiple 시 Checkbox 커스터마이징 옵션
52
+ */
53
+ export interface DropdownMenuItemProps extends RadixDropdownMenuItemProps {
54
+ /**
55
+ * 옵션 라벨
56
+ */
57
+ label?: ReactNode;
58
+ /**
59
+ * 보조 텍스트
60
+ */
61
+ description?: ReactNode;
62
+ /**
63
+ * 좌측 슬롯
64
+ */
65
+ leftSlot?: ReactNode;
66
+ /**
67
+ * 우측 슬롯
68
+ */
69
+ rightSlot?: ReactNode;
70
+ /**
71
+ * 선택 상태 여부
72
+ */
73
+ isSelected?: boolean;
74
+ /**
75
+ * multi select 스타일 여부
76
+ */
77
+ multiple?: boolean;
78
+ /**
79
+ * Checkbox 커스터마이징 props
80
+ */
81
+ checkboxProps?: CheckboxProps;
82
+ }
83
+
84
+ /**
85
+ * Dropdown menu list props
86
+ */
87
+ export interface DropdownMenuListProps extends HTMLAttributes<HTMLUListElement> {}
88
+
89
+ /**
90
+ * Dropdown context value; trigger ref 공유용
91
+ * @property {React.MutableRefObject<HTMLElement | null>} triggerRef trigger DOM ref
92
+ */
93
+ export interface DropdownContextValue {
94
+ /**
95
+ * trigger DOM ref
96
+ */
97
+ triggerRef: MutableRefObject<HTMLElement | null>;
98
+ }
99
+
100
+ /**
101
+ * Dropdown template item
102
+ * @property {string} id 고유 식별자
103
+ * @property {ReactNode} label 옵션 라벨
104
+ * @property {ReactNode} [description] 보조 텍스트
105
+ * @property {boolean} [disabled] 비활성 여부
106
+ * @property {ReactNode} [leftSlot] 좌측 슬롯
107
+ * @property {ReactNode} [rightSlot] 우측 슬롯
108
+ * @property {boolean} [multiple] multi select 스타일 여부
109
+ */
110
+ export interface DropdownTemplateItem {
111
+ /**
112
+ * 고유 식별자
113
+ */
114
+ id: string;
115
+ /**
116
+ * 옵션 라벨
117
+ */
118
+ label: ReactNode;
119
+ /**
120
+ * 보조 텍스트
121
+ */
122
+ description?: ReactNode;
123
+ /**
124
+ * 비활성 여부
125
+ */
126
+ disabled?: boolean;
127
+ /**
128
+ * 좌측 슬롯
129
+ */
130
+ leftSlot?: ReactNode;
131
+ /**
132
+ * 우측 슬롯
133
+ */
134
+ rightSlot?: ReactNode;
135
+ /**
136
+ * multi select 스타일 여부
137
+ */
138
+ multiple?: boolean;
139
+ }
140
+
141
+ /**
142
+ * Dropdown template props
143
+ * @property {ReactNode} trigger trigger 요소
144
+ * @property {DropdownTemplateItem[]} items 렌더링할 menu item 리스트
145
+ * @property {string[]} [selectedIds] 선택된 item id 배열
146
+ * @property {DropdownSize} [size="medium"] surface height scale
147
+ * @property {boolean} [matchTriggerWidth=true] trigger width 동기화 여부
148
+ * @property {DropdownRootProps} [rootProps] Root 에 전달할 props
149
+ * @property {DropdownContainerProps} [containerProps] Container 에 전달할 props
150
+ * @property {DropdownMenuListProps} [menuListProps] MenuList 에 전달할 props
151
+ */
152
+ export interface DropdownTemplateProps {
153
+ trigger: ReactNode;
154
+ items: DropdownTemplateItem[];
155
+ selectedIds?: string[];
156
+ onSelect?: (item: DropdownTemplateItem) => void;
157
+ size?: DropdownSize;
158
+ matchTriggerWidth?: boolean;
159
+ /**
160
+ * Root 에 전달할 props
161
+ */
162
+ rootProps?: DropdownRootProps;
163
+ /**
164
+ * Container 에 전달할 props
165
+ */
166
+ containerProps?: Omit<
167
+ DropdownContainerProps,
168
+ "children" | "size" | "matchTriggerWidth"
169
+ >;
170
+ /**
171
+ * MenuList 에 전달할 props
172
+ */
173
+ menuListProps?: DropdownMenuListProps;
174
+ }