@uniai-fe/uds-primitives 0.3.59 → 0.4.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.
- package/README.md +209 -3
- package/dist/styles.css +91 -76
- package/package.json +1 -1
- package/src/components/alternate/index.tsx +7 -1
- package/src/components/alternate/markup/Label.tsx +10 -5
- package/src/components/alternate/markup/empty/Data.tsx +9 -6
- package/src/components/alternate/markup/index.tsx +8 -0
- package/src/components/alternate/markup/loading/Default.tsx +10 -6
- package/src/components/alternate/markup/loading/Icon.tsx +11 -4
- package/src/components/alternate/types/index.ts +75 -2
- package/src/components/badge/index.tsx +4 -1
- package/src/components/badge/markup/Badge.tsx +10 -8
- package/src/components/badge/types/index.ts +26 -2
- package/src/components/button/index.tsx +6 -1
- package/src/components/button/markup/Base.tsx +20 -18
- package/src/components/button/markup/Rounded.tsx +7 -4
- package/src/components/button/markup/Text.tsx +7 -4
- package/src/components/calendar/index.tsx +8 -0
- package/src/components/calendar/markup/index.tsx +7 -7
- package/src/components/carousel/index.tsx +8 -0
- package/src/components/carousel/markup/index.tsx +9 -0
- package/src/components/checkbox/index.tsx +7 -0
- package/src/components/chip/index.tsx +7 -1
- package/src/components/chip/markup/index.tsx +9 -0
- package/src/components/divider/index.tsx +4 -0
- package/src/components/divider/markup/Divider.tsx +11 -7
- package/src/components/divider/types/index.ts +1 -0
- package/src/components/divider/types/props.ts +27 -0
- package/src/components/drawer/index.tsx +7 -0
- package/src/components/drawer/markup/index.tsx +6 -0
- package/src/components/dropdown/index.tsx +7 -0
- package/src/components/dropdown/markup/Template.tsx +9 -2
- package/src/components/dropdown/markup/foundation/Container.tsx +30 -12
- package/src/components/dropdown/markup/index.tsx +9 -10
- package/src/components/dropdown/types/base.ts +13 -0
- package/src/components/dropdown/types/props.ts +19 -2
- package/src/components/form/index.tsx +7 -0
- package/src/components/form/markup/index.tsx +6 -2
- package/src/components/info-box/index.tsx +7 -0
- package/src/components/info-box/markup/InfoBox.tsx +1 -1
- package/src/components/info-box/markup/index.ts +6 -0
- package/src/components/info-box/types/props.ts +2 -2
- package/src/components/input/index.tsx +6 -1
- package/src/components/input/markup/foundation/Input.tsx +2 -2
- package/src/components/input/styles/foundation.scss +57 -54
- package/src/components/input/types/foundation.ts +1 -1
- package/src/components/navigation/index.tsx +7 -0
- package/src/components/navigation/markup/index.tsx +6 -0
- package/src/components/pagination/index.tsx +6 -1
- package/src/components/pagination/markup/index.tsx +7 -0
- package/src/components/pop-over/index.tsx +7 -0
- package/src/components/pop-over/markup/index.tsx +5 -4
- package/src/components/radio/index.tsx +5 -1
- package/src/components/scrollbar/hooks/index.ts +1 -1
- package/src/components/scrollbar/index.tsx +1 -1
- package/src/components/scrollbar/markup/index.tsx +1 -1
- package/src/components/scrollbar/types/index.ts +1 -1
- package/src/components/scrollbar/utils/index.ts +1 -1
- package/src/components/segmented-control/index.tsx +5 -1
- package/src/components/segmented-control/markup/index.ts +6 -0
- package/src/components/select/index.tsx +6 -1
- package/src/components/select/markup/Default.tsx +10 -13
- package/src/components/select/markup/foundation/Selected.tsx +31 -26
- package/src/components/select/markup/index.tsx +1 -1
- package/src/components/select/markup/multiple/Multiple.tsx +32 -15
- package/src/components/select/styles/select.scss +15 -6
- package/src/components/select/styles/variables.scss +4 -0
- package/src/components/select/types/multiple.ts +19 -0
- package/src/components/select/types/props.ts +19 -6
- package/src/components/select/utils/display.tsx +41 -0
- package/src/components/select/utils/index.ts +1 -4
- package/src/components/slot/index.tsx +7 -0
- package/src/components/slot/markup/index.tsx +6 -0
- package/src/components/spinner/hooks/index.ts +1 -1
- package/src/components/spinner/index.tsx +1 -1
- package/src/components/spinner/markup/index.tsx +1 -1
- package/src/components/spinner/types/index.ts +1 -1
- package/src/components/spinner/utils/index.ts +1 -1
- package/src/components/tab/index.tsx +5 -1
- package/src/components/tab/markup/index.tsx +8 -0
- package/src/components/table/index.tsx +3 -0
- package/src/components/tooltip/index.tsx +7 -0
- package/src/components/tooltip/markup/index.tsx +7 -6
|
@@ -27,8 +27,9 @@ import {
|
|
|
27
27
|
* @param {ReactNode} props.trigger trigger 요소
|
|
28
28
|
* @param {DropdownTemplateItem[]} props.items 렌더링할 menu item 리스트
|
|
29
29
|
* @param {(payload: DropdownTemplateChangePayload) => void} [props.onChange] 선택 결과 변경 콜백
|
|
30
|
-
* @param {"small" | "medium" | "large"} [props.size="medium"] menu size scale
|
|
30
|
+
* @param {"xsmall" | "small" | "medium" | "large"} [props.size="medium"] menu size scale
|
|
31
31
|
* @param {"match" | "fit-content" | "max-content" | string | number} [props.width="match"] panel width 옵션
|
|
32
|
+
* @param {"match" | "fit-content" | "max-content" | string | number} [props.minWidth] panel 최소 너비 옵션
|
|
32
33
|
* @param {DropdownMenuProps} [props.rootProps] Dropdown.Root 전달 props
|
|
33
34
|
* @param {DropdownContainerProps} [props.containerProps] Dropdown.Container 전달 props
|
|
34
35
|
* @param {DropdownMenuListProps} [props.menuListProps] Dropdown.Menu.List 전달 props
|
|
@@ -40,6 +41,7 @@ const DropdownTemplate = ({
|
|
|
40
41
|
onChange,
|
|
41
42
|
size = "medium",
|
|
42
43
|
width = "match",
|
|
44
|
+
minWidth,
|
|
43
45
|
rootProps,
|
|
44
46
|
containerProps,
|
|
45
47
|
menuListProps,
|
|
@@ -199,7 +201,12 @@ const DropdownTemplate = ({
|
|
|
199
201
|
return (
|
|
200
202
|
<DropdownRoot {...rootProps}>
|
|
201
203
|
<DropdownTrigger asChild>{trigger}</DropdownTrigger>
|
|
202
|
-
<DropdownContainer
|
|
204
|
+
<DropdownContainer
|
|
205
|
+
{...containerProps}
|
|
206
|
+
size={size}
|
|
207
|
+
width={width}
|
|
208
|
+
minWidth={minWidth}
|
|
209
|
+
>
|
|
203
210
|
<DropdownMenuList {...menuListProps}>
|
|
204
211
|
{items.length > 0 ? (
|
|
205
212
|
<>
|
|
@@ -15,6 +15,7 @@ import { useDropdownContext } from "./Provider";
|
|
|
15
15
|
* @param {string} [props.className] panel className
|
|
16
16
|
* @param {DropdownSize} [props.size="medium"] option height scale
|
|
17
17
|
* @param {DropdownPanelWidth} [props.width="match"] panel width 옵션
|
|
18
|
+
* @param {DropdownPanelMinWidth} [props.minWidth] panel 최소 너비 옵션
|
|
18
19
|
* @param {HTMLElement | null} [props.portalContainer] portal 컨테이너
|
|
19
20
|
* @param {"start" | "center" | "end"} [props.align="start"] 정렬 기준
|
|
20
21
|
* @param {"top" | "right" | "bottom" | "left"} [props.side="bottom"] 패널 위치
|
|
@@ -33,6 +34,7 @@ const DropdownContainer = forwardRef<HTMLDivElement, DropdownContainerProps>(
|
|
|
33
34
|
className,
|
|
34
35
|
size = "medium",
|
|
35
36
|
width = "match",
|
|
37
|
+
minWidth,
|
|
36
38
|
portalContainer,
|
|
37
39
|
align = "start",
|
|
38
40
|
side = "bottom",
|
|
@@ -47,29 +49,46 @@ const DropdownContainer = forwardRef<HTMLDivElement, DropdownContainerProps>(
|
|
|
47
49
|
const [panelWidth, setPanelWidth] = useState<number>();
|
|
48
50
|
const shouldMatchTriggerWidth = width === "match";
|
|
49
51
|
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
+
const resolvePanelSizeValue = (
|
|
53
|
+
value?: string | number,
|
|
54
|
+
fallbackToMatch?: boolean,
|
|
55
|
+
): string | undefined => {
|
|
56
|
+
if (value === undefined) {
|
|
52
57
|
return undefined;
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
if (typeof
|
|
56
|
-
return `${
|
|
60
|
+
if (typeof value === "number") {
|
|
61
|
+
return `${value}px`;
|
|
57
62
|
}
|
|
58
63
|
|
|
59
|
-
if (typeof
|
|
60
|
-
if (
|
|
64
|
+
if (typeof value === "string") {
|
|
65
|
+
if (value === "fit-content") {
|
|
61
66
|
return "fit-content";
|
|
62
67
|
}
|
|
63
|
-
if (
|
|
68
|
+
if (value === "max-content") {
|
|
64
69
|
return "max-content";
|
|
65
70
|
}
|
|
66
|
-
if (
|
|
67
|
-
return
|
|
71
|
+
if (fallbackToMatch && value === "match" && panelWidth) {
|
|
72
|
+
return `${panelWidth}px`;
|
|
73
|
+
}
|
|
74
|
+
if (value.trim().length > 0 && value !== "match") {
|
|
75
|
+
return value;
|
|
68
76
|
}
|
|
69
77
|
}
|
|
70
78
|
|
|
71
79
|
return undefined;
|
|
72
|
-
}
|
|
80
|
+
};
|
|
81
|
+
const resolvedWidth = useMemo(() => {
|
|
82
|
+
if (shouldMatchTriggerWidth) {
|
|
83
|
+
return panelWidth ? `${panelWidth}px` : undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return resolvePanelSizeValue(width);
|
|
87
|
+
}, [panelWidth, shouldMatchTriggerWidth, width]);
|
|
88
|
+
const resolvedMinWidth = useMemo(() => {
|
|
89
|
+
// 변경 설명: width 계약은 기준 폭, minWidth 계약은 최소 보장 폭으로 분리한다.
|
|
90
|
+
return resolvePanelSizeValue(minWidth, true);
|
|
91
|
+
}, [minWidth, panelWidth]);
|
|
73
92
|
|
|
74
93
|
useEffect(() => {
|
|
75
94
|
if (!shouldMatchTriggerWidth) {
|
|
@@ -110,8 +129,7 @@ const DropdownContainer = forwardRef<HTMLDivElement, DropdownContainerProps>(
|
|
|
110
129
|
className={clsx("dropdown-panel", `dropdown-panel-${size}`, className)}
|
|
111
130
|
style={{
|
|
112
131
|
...style,
|
|
113
|
-
width:
|
|
114
|
-
shouldMatchTriggerWidth && panelWidth ? panelWidth : style?.width,
|
|
132
|
+
width: resolvedWidth ?? style?.width,
|
|
115
133
|
minWidth:
|
|
116
134
|
resolvedMinWidth !== undefined ? resolvedMinWidth : style?.minWidth,
|
|
117
135
|
}}
|
|
@@ -2,16 +2,15 @@ import { DropdownFoundation } from "./foundation";
|
|
|
2
2
|
import DropdownTemplate from "./Template";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Dropdown
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* -
|
|
13
|
-
* -
|
|
14
|
-
* - Template
|
|
5
|
+
* Dropdown; 컴포넌트 모듈
|
|
6
|
+
* @namespace Dropdown
|
|
7
|
+
* - `Dropdown.Provider`
|
|
8
|
+
* - `Dropdown.Root`
|
|
9
|
+
* - `Dropdown.Trigger`
|
|
10
|
+
* - `Dropdown.Container`
|
|
11
|
+
* - `Dropdown.Menu.Item`
|
|
12
|
+
* - `Dropdown.Menu.List`
|
|
13
|
+
* - `Dropdown.Template`
|
|
15
14
|
*/
|
|
16
15
|
export const Dropdown = {
|
|
17
16
|
...DropdownFoundation,
|
|
@@ -16,3 +16,16 @@ export type DropdownPanelWidth =
|
|
|
16
16
|
| "max-content"
|
|
17
17
|
| string
|
|
18
18
|
| number;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Dropdown panel min-width 옵션
|
|
22
|
+
* - "match": trigger width를 최소 폭으로 보장
|
|
23
|
+
* - "fit-content" | "max-content": 콘텐츠 기준 최소 폭
|
|
24
|
+
* - string/number: 커스텀 최소 폭
|
|
25
|
+
*/
|
|
26
|
+
export type DropdownPanelMinWidth =
|
|
27
|
+
| "match"
|
|
28
|
+
| "fit-content"
|
|
29
|
+
| "max-content"
|
|
30
|
+
| string
|
|
31
|
+
| number;
|
|
@@ -6,7 +6,11 @@ import type {
|
|
|
6
6
|
import type { HTMLAttributes, ReactNode, RefObject } from "react";
|
|
7
7
|
|
|
8
8
|
import type { CheckboxProps } from "../../checkbox/types";
|
|
9
|
-
import type {
|
|
9
|
+
import type {
|
|
10
|
+
DropdownPanelMinWidth,
|
|
11
|
+
DropdownPanelWidth,
|
|
12
|
+
DropdownSize,
|
|
13
|
+
} from "./base";
|
|
10
14
|
|
|
11
15
|
/**
|
|
12
16
|
* Dropdown template value 타입
|
|
@@ -17,6 +21,7 @@ export type DropdownTemplateValue = string | number;
|
|
|
17
21
|
* Dropdown Container props
|
|
18
22
|
* @property {DropdownSize} [size="medium"] option 높이 스케일
|
|
19
23
|
* @property {DropdownPanelWidth} [width="match"] dropdown panel width 옵션
|
|
24
|
+
* @property {DropdownPanelMinWidth} [minWidth] dropdown panel 최소 너비 옵션
|
|
20
25
|
* @property {HTMLElement | null} [portalContainer] portal을 렌더링할 DOM 컨테이너
|
|
21
26
|
*/
|
|
22
27
|
export interface DropdownContainerProps extends DropdownMenuContentProps {
|
|
@@ -28,6 +33,10 @@ export interface DropdownContainerProps extends DropdownMenuContentProps {
|
|
|
28
33
|
* trigger 너비에 맞춰 dropdown 너비를 맞출지 여부
|
|
29
34
|
*/
|
|
30
35
|
width?: DropdownPanelWidth;
|
|
36
|
+
/**
|
|
37
|
+
* dropdown 최소 너비 제약
|
|
38
|
+
*/
|
|
39
|
+
minWidth?: DropdownPanelMinWidth;
|
|
31
40
|
/**
|
|
32
41
|
* portal을 렌더링할 DOM 컨테이너
|
|
33
42
|
*/
|
|
@@ -191,6 +200,7 @@ export interface DropdownTemplateChangePayload {
|
|
|
191
200
|
* @property {(payload: DropdownTemplateChangePayload) => void} [onChange] 선택 결과 변경 콜백
|
|
192
201
|
* @property {DropdownSize} [size="medium"] surface height scale
|
|
193
202
|
* @property {DropdownPanelWidth} [width="match"] panel width 옵션
|
|
203
|
+
* @property {DropdownPanelMinWidth} [minWidth] panel 최소 너비 옵션
|
|
194
204
|
* @property {DropdownMenuProps} [rootProps] Root 에 전달할 props
|
|
195
205
|
* @property {DropdownContainerProps} [containerProps] Container 에 전달할 props
|
|
196
206
|
* @property {DropdownMenuListProps} [menuListProps] MenuList 에 전달할 props
|
|
@@ -205,6 +215,10 @@ export interface DropdownTemplateProps {
|
|
|
205
215
|
onChange?: (payload: DropdownTemplateChangePayload) => void;
|
|
206
216
|
size?: DropdownSize;
|
|
207
217
|
width?: DropdownPanelWidth;
|
|
218
|
+
/**
|
|
219
|
+
* panel 최소 너비 옵션
|
|
220
|
+
*/
|
|
221
|
+
minWidth?: DropdownPanelMinWidth;
|
|
208
222
|
/**
|
|
209
223
|
* Root 에 전달할 props
|
|
210
224
|
* - 타입 출처를 명확히 하기 위해 Radix 원본 타입을 직접 사용한다.
|
|
@@ -213,7 +227,10 @@ export interface DropdownTemplateProps {
|
|
|
213
227
|
/**
|
|
214
228
|
* Container 에 전달할 props
|
|
215
229
|
*/
|
|
216
|
-
containerProps?: Omit<
|
|
230
|
+
containerProps?: Omit<
|
|
231
|
+
DropdownContainerProps,
|
|
232
|
+
"children" | "size" | "width" | "minWidth"
|
|
233
|
+
>;
|
|
217
234
|
/**
|
|
218
235
|
* MenuList 에 전달할 props
|
|
219
236
|
*/
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form; provider + field layout 카테고리 배럴
|
|
3
|
+
* @desc
|
|
4
|
+
* - `Form.Provider`: react-hook-form provider 래퍼다.
|
|
5
|
+
* - `Form.Field.*`: Container/Header/Body/Footer/Template 레이아웃 도구다.
|
|
6
|
+
* - `getFormFieldWidthAttr`, `getFormFieldWidthValue`: width 계산 util이다.
|
|
7
|
+
*/
|
|
1
8
|
import "./index.scss";
|
|
2
9
|
|
|
3
10
|
export { Form } from "./markup";
|
|
@@ -2,8 +2,12 @@ import FormProvider from "./Provider";
|
|
|
2
2
|
import { FormField } from "./form-field";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Form
|
|
6
|
-
*
|
|
5
|
+
* Form; provider + field layout namespace
|
|
6
|
+
* @desc
|
|
7
|
+
* - `Form.Provider`: react-hook-form provider 래퍼다.
|
|
8
|
+
* - `Form.Field.Container`: field 루트 wrapper다.
|
|
9
|
+
* - `Form.Field.Header`, `Form.Field.Body`, `Form.Field.Footer`: depth 고정 섹션이다.
|
|
10
|
+
* - `Form.Field.Template`: 반복 조합용 필드 템플릿이다.
|
|
7
11
|
*/
|
|
8
12
|
export const Form = {
|
|
9
13
|
Provider: FormProvider,
|
|
@@ -7,7 +7,7 @@ import { InfoBoxIcon } from "./Icon";
|
|
|
7
7
|
* InfoBox Component; 안내 메시지 전용 정보 박스
|
|
8
8
|
* @component
|
|
9
9
|
* @param {InfoBoxProps} props
|
|
10
|
-
* @param {"info"} [props.state="info"]
|
|
10
|
+
* @param {"info" | "caution" | "success" | "error"} [props.state="info"] 안내/상태 메시지 시각 축이다.
|
|
11
11
|
* @param {React.ReactNode} [props.heading] 상단 제목 영역.
|
|
12
12
|
* @param {React.ReactNode} [props.children] 본문 콘텐츠.
|
|
13
13
|
* @param {string} [props.className] 루트 section className.
|
|
@@ -7,7 +7,7 @@ type NativeSectionProps = Omit<ComponentPropsWithoutRef<"section">, "title">;
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* InfoBox Props; info-box 루트 속성
|
|
10
|
-
* @property {"info" | "caution" | "success" | "error"} [state]
|
|
10
|
+
* @property {"info" | "caution" | "success" | "error"} [state] info/caution/success/error 상태 축이다.
|
|
11
11
|
* @property {ReactNode} [heading] 상단 제목 콘텐츠
|
|
12
12
|
* @property {ReactNode} [children] 본문 콘텐츠
|
|
13
13
|
* @property {string} [className] 루트 section className
|
|
@@ -15,7 +15,7 @@ type NativeSectionProps = Omit<ComponentPropsWithoutRef<"section">, "title">;
|
|
|
15
15
|
*/
|
|
16
16
|
export interface InfoBoxProps extends Omit<NativeSectionProps, "children"> {
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* info/caution/success/error 상태 축이다.
|
|
19
19
|
* - info, caution, success, error
|
|
20
20
|
*/
|
|
21
21
|
state?: InfoBoxState;
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Input; namespace 배럴 export
|
|
3
|
+
* @desc
|
|
4
|
+
* - `Input.Base`, `Input.TextArea`: foundation control
|
|
5
|
+
* - `Input.Text.*`: text scenario wrappers
|
|
6
|
+
* - `Input.Date`, `Input.Address`, `Input.File`: category presets
|
|
7
|
+
* - hooks/utils/types는 별도 배럴로 함께 export한다
|
|
3
8
|
*/
|
|
4
9
|
import "./index.scss";
|
|
5
10
|
|
|
@@ -34,7 +34,7 @@ import InputBaseUtil from "./Utility";
|
|
|
34
34
|
* @param {"default" | "active" | "focused" | "success" | "error" | "disabled" | "loading"} [props.state="default"] 시각 상태(tertiary는 disabled 외 feedback color 미적용)
|
|
35
35
|
* @param {boolean} [props.block=false] true면 width 100% (`priority="table"`은 width 미지정 시 full 기본)
|
|
36
36
|
* @param {React.ReactNode} [props.inlineLabel] tertiary border 내부 상단 라벨
|
|
37
|
-
* @param {
|
|
37
|
+
* @param {"full" | "fit" | "fill" | "auto" | number | string} [props.width] width preset 또는 custom width
|
|
38
38
|
* @param {React.ReactNode} [props.left] 입력 왼쪽 슬롯(아이콘/텍스트)
|
|
39
39
|
* @param {React.ReactNode} [props.right] 입력 오른쪽 슬롯
|
|
40
40
|
* @param {React.ReactNode} [props.clear] 입력값 초기화 아이콘. 지정하지 않으면 기본 Reset 아이콘
|
|
@@ -54,7 +54,7 @@ import InputBaseUtil from "./Utility";
|
|
|
54
54
|
* @param {string | number | readonly string[]} [props.value] 제어형 값
|
|
55
55
|
* @param {string | number | readonly string[]} [props.defaultValue] 비제어 초기값
|
|
56
56
|
* @param {string} [props.type="text"] native input type
|
|
57
|
-
* @param {boolean} [props.readOnly] native readOnly
|
|
57
|
+
* @param {boolean} [props.readOnly] native readOnly. value가 없으면 placeholder는 alternative 토큰으로 그대로 노출된다.
|
|
58
58
|
*/
|
|
59
59
|
const InputBase = forwardRef<HTMLInputElement, InputProps>(
|
|
60
60
|
(
|