@uniai-fe/uds-primitives 0.12.5 → 0.12.7

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 (51) hide show
  1. package/README.md +17 -0
  2. package/dist/styles.css +253 -840
  3. package/package.json +9 -9
  4. package/src/components/button/markup/Base.tsx +3 -2
  5. package/src/components/button/styles/button.scss +99 -326
  6. package/src/components/button/styles/round-button.scss +12 -39
  7. package/src/components/button/styles/text-button.scss +16 -52
  8. package/src/components/button/styles/variables.scss +33 -55
  9. package/src/components/button/types/options.ts +7 -4
  10. package/src/components/button/types/props.ts +11 -14
  11. package/src/components/button/utils/index.ts +14 -3
  12. package/src/components/form/markup/Provider.tsx +7 -3
  13. package/src/components/form/markup/form-field/Body.tsx +1 -0
  14. package/src/components/form/markup/form-field/Container.tsx +3 -1
  15. package/src/components/form/markup/form-field/Footer.tsx +1 -0
  16. package/src/components/form/markup/form-field/Header.tsx +2 -0
  17. package/src/components/form/markup/form-field/Template.tsx +3 -2
  18. package/src/components/form/markup/form-field/index.tsx +1 -1
  19. package/src/components/form/markup/index.tsx +1 -0
  20. package/src/components/form/styles/form-field/variables.scss +2 -2
  21. package/src/components/form/types/props.ts +21 -19
  22. package/src/components/form/utils/form-field.ts +6 -4
  23. package/src/components/input/styles/date.scss +1 -1
  24. package/src/components/input/styles/text.scss +1 -1
  25. package/src/components/slot/index.tsx +3 -6
  26. package/src/components/slot/markup/Base.tsx +146 -9
  27. package/src/components/slot/markup/index.tsx +2 -4
  28. package/src/components/slot/types/props.ts +119 -23
  29. package/src/components/table/types/foundation.ts +9 -7
  30. package/src/index.scss +0 -2
  31. package/src/index.tsx +8 -2
  32. package/src/types/index.ts +1 -4
  33. package/src/utils/index.ts +8 -4
  34. package/src/utils/selected-values.ts +20 -14
  35. package/src/components/scrollbar/hooks/index.ts +0 -4
  36. package/src/components/scrollbar/img/.gitkeep +0 -0
  37. package/src/components/scrollbar/index.scss +0 -1
  38. package/src/components/scrollbar/index.tsx +0 -4
  39. package/src/components/scrollbar/markup/index.tsx +0 -4
  40. package/src/components/scrollbar/styles/index.scss +0 -0
  41. package/src/components/scrollbar/types/index.ts +0 -4
  42. package/src/components/scrollbar/utils/index.ts +0 -4
  43. package/src/components/spinner/hooks/index.ts +0 -4
  44. package/src/components/spinner/img/.gitkeep +0 -0
  45. package/src/components/spinner/index.scss +0 -1
  46. package/src/components/spinner/index.tsx +0 -4
  47. package/src/components/spinner/markup/index.tsx +0 -4
  48. package/src/components/spinner/styles/index.scss +0 -0
  49. package/src/components/spinner/types/index.ts +0 -4
  50. package/src/components/spinner/utils/index.ts +0 -4
  51. package/src/hooks/index.ts +0 -4
@@ -3,55 +3,28 @@
3
3
  // 라운드 버튼 사이즈 토큰을 맵으로 정의해 중복 제거
4
4
  $round-size-map: (
5
5
  small: (
6
- min-height: var(
7
- --button-round-height-small,
8
- var(--theme-size-small-2, 24px)
9
- ),
10
- padding-inline: var(
11
- --button-round-padding-inline-small,
12
- var(--spacing-padding-5, 12px)
13
- ),
14
- radius: var(--button-round-radius-small, var(--theme-radius-xlarge-2, 16px)),
6
+ min-height: var(--button-round-height-small),
7
+ padding-inline: var(--button-round-padding-inline-small),
8
+ radius: var(--button-round-radius-small),
15
9
  ),
16
10
  medium: (
17
- min-height: var(
18
- --button-round-height-medium,
19
- var(--theme-size-small-3, 32px)
20
- ),
21
- padding-inline: var(
22
- --button-round-padding-inline-medium,
23
- var(--spacing-padding-6, 16px)
24
- ),
25
- radius: var(
26
- --button-round-radius-medium,
27
- var(--theme-radius-xlarge-2, 16px)
28
- ),
11
+ min-height: var(--button-round-height-medium),
12
+ padding-inline: var(--button-round-padding-inline-medium),
13
+ radius: var(--button-round-radius-medium),
29
14
  ),
30
15
  large: (
31
- min-height: var(
32
- --button-round-height-large,
33
- var(--theme-size-medium-1, 40px)
34
- ),
35
- padding-inline: var(
36
- --button-round-padding-inline-large,
37
- var(--spacing-padding-7, 20px)
38
- ),
39
- radius: var(--button-round-radius-large, 30px),
16
+ min-height: var(--button-round-height-large),
17
+ padding-inline: var(--button-round-padding-inline-large),
18
+ radius: var(--button-round-radius-large),
40
19
  ),
41
20
  );
42
21
 
43
22
  .button {
44
23
  &:where(.button-template-round) {
45
24
  min-width: auto;
46
- padding-block: var(
47
- --button-round-padding-block-base,
48
- var(--spacing-padding-2, 4px)
49
- );
50
- padding-inline: var(
51
- --button-round-padding-inline-medium,
52
- var(--spacing-padding-6, 16px)
53
- );
54
- gap: var(--spacing-gap-2, 8px);
25
+ padding-block: var(--button-round-padding-block-base);
26
+ padding-inline: var(--button-round-padding-inline-medium);
27
+ gap: var(--spacing-gap-2);
55
28
  }
56
29
 
57
30
  @each $size, $tokens in $round-size-map {
@@ -3,28 +3,16 @@
3
3
  // 텍스트 버튼 사이즈 토큰을 맵으로 정의해 가독성을 높인다
4
4
  $text-size-map: (
5
5
  small: (
6
- min-height: var(--button-text-height-small, var(--theme-size-small-1, 20px)),
7
- padding-inline: var(
8
- --button-text-padding-inline-small,
9
- var(--spacing-padding-4, 8px)
10
- ),
6
+ min-height: var(--button-text-height-small),
7
+ padding-inline: var(--button-text-padding-inline-small),
11
8
  ),
12
9
  medium: (
13
- min-height: var(
14
- --button-text-height-medium,
15
- var(--theme-size-small-2, 24px)
16
- ),
17
- padding-inline: var(
18
- --button-text-padding-inline-medium,
19
- var(--spacing-padding-5, 12px)
20
- ),
10
+ min-height: var(--button-text-height-medium),
11
+ padding-inline: var(--button-text-padding-inline-medium),
21
12
  ),
22
13
  large: (
23
- min-height: var(--button-text-height-large, var(--theme-size-small-3, 32px)),
24
- padding-inline: var(
25
- --button-text-padding-inline-large,
26
- var(--spacing-padding-5, 12px)
27
- ),
14
+ min-height: var(--button-text-height-large),
15
+ padding-inline: var(--button-text-padding-inline-large),
28
16
  ),
29
17
  );
30
18
 
@@ -33,20 +21,11 @@ $text-size-map: (
33
21
  min-width: auto;
34
22
  border-color: transparent;
35
23
  background-color: transparent;
36
- padding-block: var(
37
- --button-text-padding-block-base,
38
- var(--spacing-padding-4, 8px)
39
- );
40
- padding-inline: var(
41
- --button-text-padding-inline-small,
42
- var(--spacing-padding-4, 8px)
43
- );
24
+ padding-block: var(--button-text-padding-block-base);
25
+ padding-inline: var(--button-text-padding-inline-small);
44
26
  border-width: 0;
45
- gap: var(--spacing-gap-1, 4px);
46
- border-radius: var(
47
- --button-text-radius-base,
48
- var(--theme-radius-small, 4px)
49
- );
27
+ gap: var(--spacing-gap-1);
28
+ border-radius: var(--button-text-radius-base);
50
29
  }
51
30
 
52
31
  @each $size, $tokens in $text-size-map {
@@ -62,45 +41,30 @@ $text-size-map: (
62
41
  }
63
42
 
64
43
  &:where(.button-template-text.button-priority-secondary) {
65
- color: var(
66
- --button-text-secondary-foreground,
67
- var(--color-primary-default)
68
- );
44
+ color: var(--button-text-secondary-foreground);
69
45
 
70
46
  &:hover:not(:disabled),
71
47
  &[data-user-action="hover"]:not(:disabled) {
72
- background-color: var(
73
- --button-text-secondary-hover-bg,
74
- var(--color-bg-alternative-cool-gray, var(--color-cool-gray-95))
75
- );
48
+ background-color: var(--button-text-secondary-hover-bg);
76
49
  }
77
50
 
78
51
  &:active:not(:disabled),
79
52
  &[data-user-action="pressed"]:not(:disabled) {
80
- background-color: var(
81
- --button-text-secondary-pressed-bg,
82
- var(--color-secondary-strong, var(--color-blue-90))
83
- );
53
+ background-color: var(--button-text-secondary-pressed-bg);
84
54
  }
85
55
  }
86
56
 
87
57
  &:where(.button-template-text.button-priority-tertiary) {
88
- color: var(--button-text-tertiary-foreground, var(--color-cool-gray-10));
58
+ color: var(--button-text-tertiary-foreground);
89
59
 
90
60
  &:hover:not(:disabled),
91
61
  &[data-user-action="hover"]:not(:disabled) {
92
- background-color: var(
93
- --button-text-tertiary-hover-bg,
94
- var(--color-bg-alternative-cool-gray, var(--color-cool-gray-95))
95
- );
62
+ background-color: var(--button-text-tertiary-hover-bg);
96
63
  }
97
64
 
98
65
  &:active:not(:disabled),
99
66
  &[data-user-action="pressed"]:not(:disabled) {
100
- background-color: var(
101
- --button-text-tertiary-pressed-bg,
102
- var(--color-surface-strong, var(--color-cool-gray-20))
103
- );
67
+ background-color: var(--button-text-tertiary-pressed-bg);
104
68
  }
105
69
  }
106
70
  }
@@ -25,11 +25,11 @@
25
25
  /* default button sizing */
26
26
  --button-default-width-min-base: var(--theme-size-small-2);
27
27
 
28
- --button-default-height-small: var(--theme-size-small-3, 32px);
29
- --button-default-height-medium: var(--theme-size-medium-1, 40px);
30
- --button-default-height-large: var(--theme-size-medium-2, 48px);
31
- --button-default-height-xlarge: var(--theme-size-medium-3, 56px);
32
- --button-default-height-table: var(--theme-size-small-2, 24px);
28
+ --button-default-height-small: var(--theme-size-small-3);
29
+ --button-default-height-medium: var(--theme-size-medium-1);
30
+ --button-default-height-large: var(--theme-size-medium-2);
31
+ --button-default-height-xlarge: var(--theme-size-medium-3);
32
+ --button-default-height-table: var(--theme-size-small-2);
33
33
 
34
34
  --button-default-radius-small: var(--theme-radius-medium-3);
35
35
  --button-default-radius-medium: var(--theme-radius-medium-3);
@@ -38,68 +38,57 @@
38
38
  --button-default-radius-table: var(--theme-radius-medium-2);
39
39
 
40
40
  /* text buttons */
41
- --button-text-padding-block-base: var(--spacing-padding-4, 8px);
42
- --button-text-padding-inline-small: var(--spacing-padding-4, 8px);
43
- --button-text-padding-inline-medium: var(--spacing-padding-5, 12px);
44
- --button-text-padding-inline-large: var(--spacing-padding-5, 12px);
45
- --button-text-height-small: var(--theme-size-small-1, 20px);
46
- --button-text-height-medium: var(--theme-size-small-2, 24px);
47
- --button-text-height-large: var(--theme-size-small-3, 32px);
48
- --button-text-radius-base: var(--theme-radius-small, 4px);
41
+ --button-text-padding-block-base: var(--spacing-padding-4);
42
+ --button-text-padding-inline-small: var(--spacing-padding-4);
43
+ --button-text-padding-inline-medium: var(--spacing-padding-5);
44
+ --button-text-padding-inline-large: var(--spacing-padding-5);
45
+ --button-text-height-small: var(--theme-size-small-1);
46
+ --button-text-height-medium: var(--theme-size-small-2);
47
+ --button-text-height-large: var(--theme-size-small-3);
48
+ --button-text-radius-base: var(--theme-radius-small);
49
49
 
50
50
  /* round buttons */
51
- --button-round-padding-inline-small: var(--spacing-padding-5, 12px);
52
- --button-round-padding-inline-medium: var(--spacing-padding-6, 16px);
53
- --button-round-padding-inline-large: var(--spacing-padding-7, 20px);
54
- --button-round-padding-block-base: var(--spacing-padding-2, 4px);
55
- --button-round-height-small: var(--theme-size-small-2, 24px);
56
- --button-round-height-medium: var(--theme-size-small-3, 32px);
57
- --button-round-height-large: var(--theme-size-medium-1, 40px);
58
- --button-round-radius-small: var(--theme-radius-xlarge-2, 16px);
59
- --button-round-radius-medium: var(--theme-radius-xlarge-2, 16px);
51
+ --button-round-padding-inline-small: var(--spacing-padding-5);
52
+ --button-round-padding-inline-medium: var(--spacing-padding-6);
53
+ --button-round-padding-inline-large: var(--spacing-padding-7);
54
+ --button-round-padding-block-base: var(--spacing-padding-2);
55
+ --button-round-height-small: var(--theme-size-small-2);
56
+ --button-round-height-medium: var(--theme-size-small-3);
57
+ --button-round-height-large: var(--theme-size-medium-1);
58
+ --button-round-radius-small: var(--theme-radius-xlarge);
59
+ --button-round-radius-medium: var(--theme-radius-xlarge);
60
60
  --button-round-radius-large: 30px;
61
61
 
62
62
  /* typography */
63
63
  --button-default-font-weight: 400;
64
- --button-default-font-body-medium-family: var(--font-body-medium-family);
65
64
  --button-default-font-body-medium-size: var(--font-body-medium-size);
66
65
  --button-default-font-body-medium-weight: var(--button-default-font-weight);
67
- --button-default-font-body-medium-line-height: var(
68
- --font-body-medium-line-height
69
- );
66
+ --button-default-font-body-medium-line-height: 1em;
70
67
  --button-default-font-body-medium-letter-spacing: var(
71
68
  --font-body-medium-letter-spacing
72
69
  );
73
70
  --button-default-font-label-medium-size: var(--font-body-xxsmall-size);
74
71
  --button-default-font-label-medium-weight: var(--button-default-font-weight);
75
- --button-default-font-label-medium-line-height: var(
76
- --font-body-xxsmall-line-height
77
- );
72
+ --button-default-font-label-medium-line-height: 1em;
78
73
  --button-default-font-label-medium-letter-spacing: var(
79
74
  --font-body-xxsmall-letter-spacing
80
75
  );
81
76
  --button-default-font-label-large-size: var(--font-body-xsmall-size);
82
77
  --button-default-font-label-large-weight: var(--button-default-font-weight);
83
- --button-default-font-label-large-line-height: var(
84
- --font-body-xsmall-line-height
85
- );
78
+ --button-default-font-label-large-line-height: 1em;
86
79
  --button-default-font-label-large-letter-spacing: var(
87
80
  --font-body-xsmall-letter-spacing
88
81
  );
89
82
  --button-default-font-body-large-size: var(--font-body-large-size);
90
83
  --button-default-font-body-large-weight: var(--button-default-font-weight);
91
- --button-default-font-body-large-line-height: var(
92
- --font-body-large-line-height
93
- );
84
+ --button-default-font-body-large-line-height: 1em;
94
85
  --button-default-font-body-large-letter-spacing: var(
95
86
  --font-body-large-letter-spacing
96
87
  );
97
88
  /* 변경: table 버튼은 caption-large 스케일(12px)을 사용한다. */
98
89
  --button-default-font-caption-large-size: var(--font-caption-large-size);
99
90
  --button-default-font-caption-large-weight: var(--button-default-font-weight);
100
- --button-default-font-caption-large-line-height: var(
101
- --font-caption-large-line-height
102
- );
91
+ --button-default-font-caption-large-line-height: 1em;
103
92
  --button-default-font-caption-large-letter-spacing: var(
104
93
  --font-caption-large-letter-spacing
105
94
  );
@@ -107,6 +96,7 @@
107
96
  --button-default-neutral-foreground: var(--color-neutral-20);
108
97
  --button-default-neutral-disabled-bg: var(--color-surface-standard);
109
98
  --button-default-neutral-disabled-foreground: var(--color-label-disabled);
99
+ --button-default-outline-bg: var(--color-surface-static-white);
110
100
 
111
101
  --button-default-primary-solid-bg: var(--color-primary-default);
112
102
  --button-default-primary-solid-hover-bg: var(--color-blue-50);
@@ -118,7 +108,7 @@
118
108
  --button-default-primary-outline-hover-foreground: var(--color-common-100);
119
109
  --button-default-primary-overlay-outlined-bg: var(--color-blue-90);
120
110
 
121
- --button-default-secondary-solid-bg: var(--color-blue-95, #e5eeff);
111
+ --button-default-secondary-solid-bg: var(--color-blue-95);
122
112
  --button-default-secondary-solid-hover-bg: #dbe9ff;
123
113
  --button-default-secondary-solid-active-bg: #ccdeff;
124
114
  --button-default-secondary-solid-foreground: var(--color-primary-default);
@@ -216,21 +206,9 @@
216
206
 
217
207
  /* text button colors */
218
208
  --button-text-secondary-foreground: var(--color-primary-default);
219
- --button-text-secondary-hover-bg: var(
220
- --color-bg-alternative-cool-gray,
221
- var(--color-cool-gray-95)
222
- );
223
- --button-text-secondary-pressed-bg: var(
224
- --color-secondary-strong,
225
- var(--color-blue-90)
226
- );
209
+ --button-text-secondary-hover-bg: var(--color-bg-alternative-cool-gray);
210
+ --button-text-secondary-pressed-bg: var(--color-secondary-strong);
227
211
  --button-text-tertiary-foreground: var(--color-cool-gray-10);
228
- --button-text-tertiary-hover-bg: var(
229
- --color-bg-alternative-cool-gray,
230
- var(--color-cool-gray-95)
231
- );
232
- --button-text-tertiary-pressed-bg: var(
233
- --color-surface-strong,
234
- var(--color-cool-gray-20)
235
- );
212
+ --button-text-tertiary-hover-bg: var(--color-bg-alternative-cool-gray);
213
+ --button-text-tertiary-pressed-bg: var(--color-surface-strong);
236
214
  }
@@ -10,22 +10,25 @@ import type {
10
10
 
11
11
  /**
12
12
  * Button Types; scale 구성 객체 타입
13
- * @property {ButtonFill} fill fill 옵션.
14
- * @property {ButtonScaleGroup} group scale group 옵션.
15
- * @property {ButtonSize} size size 옵션.
13
+ * @property {"solid" | "outlined"} fill fill 옵션.
14
+ * @property {"solid" | "outlined"} group scale group 옵션.
15
+ * @property {"xlarge" | "large" | "medium" | "small" | "table"} size size 옵션.
16
16
  * @deprecated
17
17
  */
18
- type ButtonScaleConfig = {
18
+ export type ButtonScaleConfig = {
19
19
  /**
20
20
  * fill 옵션.
21
+ * "solid" | "outlined"
21
22
  */
22
23
  fill: ButtonFill;
23
24
  /**
24
25
  * scale group 옵션.
26
+ * "solid" | "outlined"
25
27
  */
26
28
  group: ButtonScaleGroup;
27
29
  /**
28
30
  * size 옵션.
31
+ * "xlarge" | "large" | "medium" | "small" | "table"
29
32
  */
30
33
  size: ButtonSize;
31
34
  };
@@ -28,7 +28,7 @@ export type ButtonPriority =
28
28
  * @typedef {"solid" | "outlined"} ButtonFill
29
29
  * @desc
30
30
  * - solid: 배경을 채우는 스타일.
31
- * - outlined: 배경을 비우고 선만 두르는 스타일.
31
+ * - outlined: 흰색 기본 면에 테두리를 두르는 스타일.
32
32
  */
33
33
  export type ButtonFill = "solid" | "outlined";
34
34
 
@@ -52,6 +52,7 @@ export type ButtonSize = "xlarge" | "large" | "medium" | "small" | "table";
52
52
  * } ButtonScale
53
53
  * @deprecated
54
54
  * @desc
55
+ * Base는 전달된 값을 완전히 무시하며 fill/size fallback으로 사용하지 않는다.
55
56
  * - solid-xlarge~solid-small: Solid fill + size 조합.
56
57
  * - outlined-xlarge~outlined-small: Outline fill + size 조합.
57
58
  */
@@ -92,27 +93,27 @@ export type ButtonScaleGroup = ButtonFill;
92
93
  /**
93
94
  * Button; <button /> native props 타입
94
95
  */
95
- type NativeButtonProps = ComponentPropsWithoutRef<"button">;
96
+ export type NativeButtonProps = ComponentPropsWithoutRef<"button">;
96
97
  /**
97
98
  * Button; <a /> native props 타입
98
99
  */
99
- type AnchorProps = ComponentPropsWithoutRef<"a">;
100
+ export type AnchorProps = ComponentPropsWithoutRef<"a">;
100
101
 
101
102
  /**
102
103
  * Button; 컴포넌트 공통 props 타입
103
104
  */
104
- type SharedElementProps = Omit<NativeButtonProps, "children"> &
105
+ export type SharedElementProps = Omit<NativeButtonProps, "children"> &
105
106
  Omit<AnchorProps, "children">;
106
107
 
107
108
  /**
108
109
  * Button 컴포넌트의 공통 props.
109
110
  * @property {ElementType} [as] 렌더링할 요소. 기본값은 button.
110
111
  * @property {ReactNode} [children] 주 내용. 문자열이면 자동으로 .button-label로 감싼다.
111
- * @property {"solid-xlarge" | "solid-large" | "solid-medium" | "solid-small" | "outlined-xlarge" | "outlined-large" | "outlined-medium" | "outlined-small"} [scale] 레이아웃/spacing 집합. 추후 fill/size 조합으로 대체 예정이다.
112
- * @property {"solid" | "outlined"} fill 채움 스타일. scale 조합보다 우선한다.
113
- * @property {"xlarge" | "large" | "medium" | "small" | "table"} size 높이/타이포 스케일. scale 조합보다 우선한다.
112
+ * @property {"solid-xlarge" | "solid-large" | "solid-medium" | "solid-small" | "outlined-xlarge" | "outlined-large" | "outlined-medium" | "outlined-small"} [scale] deprecated 호환 입력. Base는 값을 완전히 무시하며 fill/size fallback이 아니다.
113
+ * @property {"solid" | "outlined"} fill 필수 채움 스타일.
114
+ * @property {"xlarge" | "large" | "medium" | "small" | "table"} size 필수 높이/타이포 스케일.
114
115
  * @property {"primary" | "secondary" | "tertiary" | "green" | "yellow" | "orange" | "teal" | "pink" | "red" | "darkGray" | "lightGray"} priority semantic color priority.
115
- * @property {"default" | "readonly" | "disabled"} [state] UI 상태. disabled prop과 조합된다.
116
+ * @property {"default" | "readonly" | "disabled"} [state] UI 상태. 최종 값은 loading → disabled state 순서로 계산된다.
116
117
  * @property {boolean} [block] width:100% 확장 여부.
117
118
  * @property {FormFieldWidth} [width] width preset. block보다 우선 적용된다.
118
119
  * @property {boolean} [loading] true면 readonly 처리 + aria-busy.
@@ -135,7 +136,7 @@ export interface ButtonProps extends SharedElementProps {
135
136
  * @deprecated
136
137
  * "solid-xlarge" | "solid-large" | "solid-medium" | "solid-small" |
137
138
  * "outlined-xlarge" | "outlined-large" | "outlined-medium" | "outlined-small"
138
- * fill/size 제공하지 않을 때만 fallback으로 사용한다.
139
+ * Base는 값을 완전히 무시하며 fill/size fallback이 아니다. 필수 fill과 size를 사용한다.
139
140
  */
140
141
  scale?: ButtonScale;
141
142
  /**
@@ -156,7 +157,7 @@ export interface ButtonProps extends SharedElementProps {
156
157
  size: ButtonSize;
157
158
  /**
158
159
  * 컴포넌트 내부 state.
159
- * disabled prop과 병합되어 최종 상태를 결정한다.
160
+ * loading → disabled state 우선순위로 최종 상태를 결정한다.
160
161
  * "default" | "readonly" | "disabled"
161
162
  */
162
163
  state?: ButtonState;
@@ -188,10 +189,6 @@ export interface ButtonProps extends SharedElementProps {
188
189
  "data-user-action"?: ButtonUserAction;
189
190
  }
190
191
 
191
- /**
192
- * 변경 사항: preset 타입 파일을 제거하고 props.ts로 통합한다.
193
- */
194
-
195
192
  /**
196
193
  * Button Types; Text preset size 옵션
197
194
  * @typedef {"small" | "medium" | "large"} TextButtonSize
@@ -1,15 +1,26 @@
1
1
  import clsx from "clsx";
2
- type ButtonClassNameOptions = {
2
+
3
+ /**
4
+ * Button utility; className 조합 입력
5
+ * @property {string} [className] 기본 `button` class와 병합할 추가 className.
6
+ */
7
+ export type ButtonClassNameOptions = {
8
+ /**
9
+ * 기본 `button` class와 병합할 추가 className.
10
+ */
3
11
  className?: string;
4
12
  };
5
13
 
6
14
  const BUTTON_CLASSNAME = "button";
7
15
 
8
16
  /**
9
- * 버튼 클래스 조합 helper: scale/fill/priority/size 별 modifier를 한 곳에서 관리한다.
17
+ * Button utility; 기본 className 조합
18
+ * @utility
19
+ * @property {string} [className] 기본 `button` class와 병합할 추가 className.
20
+ * @desc 기본 `button` class와 전달된 className만 clsx로 병합하며 modifier는 생성하지 않는다.
21
+ * @return {string} 병합된 className.
10
22
  */
11
23
  const composeButtonClassName = ({ className }: ButtonClassNameOptions) =>
12
24
  clsx(BUTTON_CLASSNAME, className);
13
25
 
14
26
  export { BUTTON_CLASSNAME, composeButtonClassName };
15
- export type { ButtonClassNameOptions };
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
 
3
3
  import { useEffect } from "react";
4
- // import { useEffect } from "react";
5
4
  import {
6
5
  FormProvider as ReactHookFormProvider,
7
6
  useForm,
@@ -11,7 +10,13 @@ import {
11
10
  } from "react-hook-form";
12
11
 
13
12
  /**
14
- * react-hook-form; context provider
13
+ * Form Component; react-hook-form context provider
14
+ * @component
15
+ * @param {object} props Form provider props
16
+ * @property {React.ReactNode} props.children provider 하위 콘텐츠
17
+ * @property {UseFormProps<FormDataType>} [props.options] useForm 초기 옵션
18
+ * @property {(params: UseFormReturn<FormDataType>) => void | undefined} [props.callback] 생성된 form methods 전달 callback
19
+ * @desc useForm methods를 생성하고 React Hook Form context로 제공하며 callback이 있으면 effect에서 methods를 전달한다.
15
20
  */
16
21
  export default function FormProvider<FormDataType extends FieldValues>({
17
22
  children,
@@ -27,7 +32,6 @@ export default function FormProvider<FormDataType extends FieldValues>({
27
32
 
28
33
  useEffect(() => {
29
34
  if (typeof callback === "undefined") return;
30
- // if (typeof callback !== "undefined")
31
35
  callback(formMethods);
32
36
  }, [callback, formMethods]);
33
37
 
@@ -6,6 +6,7 @@ import clsx from "clsx";
6
6
  * @param {object} props
7
7
  * @property {string} [className]
8
8
  * @property {React.ReactNode} [children]
9
+ * @desc field control과 주요 콘텐츠를 body 영역에 렌더링한다.
9
10
  */
10
11
  export default function FormFieldBody({
11
12
  className,
@@ -13,10 +13,12 @@ import {
13
13
  * @component
14
14
  * @param {FormFieldContainerProps} props
15
15
  * @property {React.ElementType} [as] container 태그 지정 (default: <section />)
16
- * @property {FormFieldWidth} [width] form field 너비 옵션
16
+ * @property {"full" | "fit" | "fill" | "auto" | number | string} [width] form field 너비 옵션
17
+ * @property {"default" | "error"} [state] visual state
17
18
  * @property {string} [className]
18
19
  * @property {React.ReactNode} [children]
19
20
  * @property {React.HTMLAttributes<HTMLElement>} [containerProps] container 속성
21
+ * @desc width를 data attribute와 CSS variable로 변환하고 visual state를 노출하는 field wrapper다.
20
22
  */
21
23
  const FormFieldContainer = forwardRef<HTMLElement, FormFieldContainerProps>(
22
24
  (
@@ -7,6 +7,7 @@ import type { FormFieldFooterProps } from "../../types";
7
7
  * @param {FormFieldFooterProps} props
8
8
  * @property {string} [className]
9
9
  * @property {React.ReactNode} [children]
10
+ * @desc helper 또는 action 콘텐츠와 footer DOM 속성을 렌더링한다.
10
11
  */
11
12
  export default function FormFieldFooter({
12
13
  className,
@@ -10,11 +10,13 @@ import { Slot } from "../../../slot";
10
10
  * @param {FormFieldHeaderProps} props
11
11
  * @property {string} [className]
12
12
  * @property {string} [label] 필드명
13
+ * @property {React.ReactNode} [labelJsx] label보다 우선하는 커스텀 label JSX
13
14
  * @property {React.ElementType} [labelAs] 필드 태그 지정 (default: <h5 />)
14
15
  * @property {string} [labelId] 필드 아이디 지정
15
16
  * @property {boolean} [required] 필수 여부
16
17
  * @property {React.ReactNode} [children] 추가 헤더 내용
17
18
  * @property {React.HTMLAttributes<HTMLElement>} [labelProps] 추가 라벨 속성
19
+ * @desc labelJsx를 우선 렌더링하고 문자열 label은 Slot.Text로 감싸 필수 표시와 함께 구성한다.
18
20
  */
19
21
  export default function FormFieldHeader({
20
22
  className,
@@ -17,10 +17,11 @@ import FormFieldContainer from "./Container";
17
17
  * @property {React.ReactNode} [footer] 푸터 내용
18
18
  * @property {FormFieldHeaderProps} [headerProps] 헤더 속성
19
19
  * @property {FormFieldFooterProps} [footerProps] 푸터 속성
20
- * @property {FormFieldWidth} [width] form field 너비 옵션
21
- * @property {FormFieldState} [state] visual state
20
+ * @property {"full" | "fit" | "fill" | "auto" | number | string} [width] form field 너비 옵션
21
+ * @property {"default" | "error"} [state] visual state
22
22
  * @property {React.HTMLAttributes<HTMLElement>} [containerProps] container 속성
23
23
  * @property {React.ReactNode} children
24
+ * @desc Header와 Body를 렌더링하고 footer가 있으면 Footer를 추가해 field layout을 구성한다.
24
25
  */
25
26
  const FormFieldTemplate = forwardRef<HTMLElement, FormFieldTemplateProps>(
26
27
  (
@@ -6,7 +6,7 @@ import FormFieldTemplate from "./Template";
6
6
 
7
7
  /**
8
8
  * Form; form field 컴포넌트
9
- * @component
9
+ * @namespace Form.Field
10
10
  * @desc
11
11
  * - FormField.Container: Form 필드의 컨테이너 컴포넌트
12
12
  * - FormField.Header: Form 필드의 헤더 컴포넌트
@@ -3,6 +3,7 @@ import { FormField } from "./form-field";
3
3
 
4
4
  /**
5
5
  * Form; provider + field layout namespace
6
+ * @namespace Form
6
7
  * @desc
7
8
  * - `Form.Provider`: react-hook-form provider 래퍼다.
8
9
  * - `Form.Field.Container`: field 루트 wrapper다.
@@ -2,8 +2,8 @@
2
2
  --form-field-width: auto;
3
3
  --form-field-flex: 0 0 auto;
4
4
 
5
- --form-field-gap-x: var(--spacing-gap-5, 12px);
6
- --form-field-gap-y: var(--spacing-gap-3, 6px);
5
+ --form-field-gap-x: var(--spacing-gap-5);
6
+ --form-field-gap-y: var(--spacing-gap-3);
7
7
 
8
8
  --form-field-label-font-size: var(--font-label-small-size);
9
9
  --form-field-label-font-weight: 400;