@fpkit/acss 5.0.0 → 6.1.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 (172) hide show
  1. package/libs/{chunk-DIJBIOFE.js → chunk-2ZJV6KQ3.js} +3 -3
  2. package/libs/{chunk-LXODKKA3.cjs → chunk-3D6WUYSL.cjs} +4 -4
  3. package/libs/{chunk-2JCDEC32.js → chunk-3ENBUQIB.js} +3 -3
  4. package/libs/{chunk-NCGVF2QS.cjs → chunk-3RVZZZWX.cjs} +4 -4
  5. package/libs/{chunk-M7JLT62Q.js → chunk-4F6SI5V5.js} +2 -2
  6. package/libs/chunk-4KJP3L35.js +7 -0
  7. package/libs/chunk-4KJP3L35.js.map +1 -0
  8. package/libs/chunk-66C2J4IX.cjs +13 -0
  9. package/libs/chunk-66C2J4IX.cjs.map +1 -0
  10. package/libs/{chunk-3XJC4XUG.js → chunk-6ADHES7B.js} +2 -2
  11. package/libs/{chunk-AOFQDQVS.cjs → chunk-6WMLG4O5.cjs} +3 -3
  12. package/libs/{chunk-Q7OAQLUT.js → chunk-AQAI6COH.js} +2 -2
  13. package/libs/{chunk-6BUJZ4DJ.cjs → chunk-BVPUT2PP.cjs} +3 -3
  14. package/libs/{chunk-F64GE6RG.cjs → chunk-GVVCXXKI.cjs} +4 -4
  15. package/libs/{chunk-75YQDONV.cjs → chunk-H4JRUNKU.cjs} +6 -6
  16. package/libs/{chunk-G3TFKMWB.js → chunk-H6A2CUWA.js} +5 -5
  17. package/libs/{chunk-2GJHKWEK.cjs → chunk-LQPWXSCK.cjs} +3 -3
  18. package/libs/{chunk-IBUTNPTQ.js → chunk-M5ES7OWP.js} +2 -2
  19. package/libs/{chunk-AWZLSWDO.js → chunk-MAG46S3P.js} +2 -2
  20. package/libs/{chunk-KAR3HDXK.js → chunk-MJJKNHVH.js} +2 -2
  21. package/libs/{chunk-5CJPTDK3.cjs → chunk-OZM455LO.cjs} +3 -3
  22. package/libs/{chunk-NPWHQVYB.cjs → chunk-QU5AQQ4S.cjs} +3 -3
  23. package/libs/{chunk-U5VA34SU.js → chunk-RQSMWB3J.js} +2 -2
  24. package/libs/{chunk-5QSNJQVH.cjs → chunk-S7NIA6PI.cjs} +3 -3
  25. package/libs/{chunk-MBWI67UT.js → chunk-SPESKPUA.js} +2 -2
  26. package/libs/{chunk-PMWL5XZ4.js → chunk-SQ44OCJ2.js} +3 -3
  27. package/libs/{chunk-EKJYOCLY.cjs → chunk-VISQ434C.cjs} +3 -3
  28. package/libs/{chunk-AFINOD2L.cjs → chunk-VN2CVD4H.cjs} +3 -3
  29. package/libs/{chunk-M5JARVJD.cjs → chunk-WTWGTWVI.cjs} +3 -3
  30. package/libs/{chunk-TF3GQKOY.js → chunk-X2RDXWH5.js} +2 -2
  31. package/libs/components/breadcrumbs/breadcrumb.cjs +6 -6
  32. package/libs/components/breadcrumbs/breadcrumb.d.cts +1 -1
  33. package/libs/components/breadcrumbs/breadcrumb.d.ts +1 -1
  34. package/libs/components/breadcrumbs/breadcrumb.js +3 -3
  35. package/libs/components/button.cjs +4 -4
  36. package/libs/components/button.d.cts +1 -1
  37. package/libs/components/button.d.ts +1 -1
  38. package/libs/components/button.js +2 -2
  39. package/libs/components/card.cjs +7 -7
  40. package/libs/components/card.d.cts +1 -1
  41. package/libs/components/card.d.ts +1 -1
  42. package/libs/components/card.js +2 -2
  43. package/libs/components/dialog/dialog.cjs +7 -7
  44. package/libs/components/dialog/dialog.js +5 -5
  45. package/libs/components/form/checkbox.css +1 -1
  46. package/libs/components/form/checkbox.css.map +1 -1
  47. package/libs/components/form/checkbox.min.css +2 -2
  48. package/libs/components/form/fields.cjs +4 -4
  49. package/libs/components/form/fields.d.cts +1 -1
  50. package/libs/components/form/fields.d.ts +1 -1
  51. package/libs/components/form/fields.js +2 -2
  52. package/libs/components/form/form.css +1 -1
  53. package/libs/components/form/form.css.map +1 -1
  54. package/libs/components/form/form.min.css +2 -2
  55. package/libs/components/form/select.css +1 -0
  56. package/libs/components/form/select.css.map +1 -0
  57. package/libs/components/form/select.min.css +3 -0
  58. package/libs/components/form/textarea.cjs +4 -4
  59. package/libs/components/form/textarea.js +2 -2
  60. package/libs/components/heading/heading.cjs +3 -3
  61. package/libs/components/heading/heading.d.cts +2 -2
  62. package/libs/components/heading/heading.d.ts +2 -2
  63. package/libs/components/heading/heading.js +2 -2
  64. package/libs/components/icons/icon.cjs +4 -4
  65. package/libs/components/icons/icon.d.cts +2 -2
  66. package/libs/components/icons/icon.d.ts +2 -2
  67. package/libs/components/icons/icon.js +2 -2
  68. package/libs/components/link/link.cjs +6 -6
  69. package/libs/components/link/link.js +2 -2
  70. package/libs/components/list/list.cjs +5 -5
  71. package/libs/components/list/list.d.cts +2 -2
  72. package/libs/components/list/list.d.ts +2 -2
  73. package/libs/components/list/list.js +2 -2
  74. package/libs/components/modal.cjs +4 -4
  75. package/libs/components/modal.js +3 -3
  76. package/libs/components/nav/nav.cjs +7 -7
  77. package/libs/components/nav/nav.d.cts +2 -2
  78. package/libs/components/nav/nav.d.ts +2 -2
  79. package/libs/components/nav/nav.js +3 -3
  80. package/libs/components/text/text.cjs +5 -5
  81. package/libs/components/text/text.d.cts +1 -1
  82. package/libs/components/text/text.d.ts +1 -1
  83. package/libs/components/text/text.js +2 -2
  84. package/libs/{heading-81eef89a.d.ts → heading-064675b6.d.ts} +1 -1
  85. package/libs/hooks.cjs +4 -4
  86. package/libs/hooks.d.cts +1 -1
  87. package/libs/hooks.d.ts +1 -1
  88. package/libs/hooks.js +3 -3
  89. package/libs/{icons-df8e744f.d.ts → icons-48788561.d.ts} +1 -1
  90. package/libs/icons.cjs +3 -3
  91. package/libs/icons.d.cts +2 -2
  92. package/libs/icons.d.ts +2 -2
  93. package/libs/icons.js +2 -2
  94. package/libs/index.cjs +49 -49
  95. package/libs/index.cjs.map +1 -1
  96. package/libs/index.css +1 -1
  97. package/libs/index.css.map +1 -1
  98. package/libs/index.d.cts +74 -25
  99. package/libs/index.d.ts +74 -25
  100. package/libs/index.js +21 -21
  101. package/libs/index.js.map +1 -1
  102. package/libs/{list.types-d26de310.d.ts → list.types-bf2c44c1.d.ts} +1 -1
  103. package/libs/{ui-d01b50d4.d.ts → ui-993fc2e2.d.ts} +5 -2
  104. package/package.json +4 -7
  105. package/src/components/alert/alert.stories.tsx +1 -1
  106. package/src/components/alert/elements/dismiss-button.stories.tsx +1 -2
  107. package/src/components/badge/badge.stories.tsx +1 -1
  108. package/src/components/breadcrumbs/breadcrumb.stories.tsx +1 -2
  109. package/src/components/buttons/button.stories.tsx +1 -3
  110. package/src/components/cards/card.stories.tsx +1 -1
  111. package/src/components/cards/card.test.tsx +1 -1
  112. package/src/components/details/details.stories.tsx +1 -2
  113. package/src/components/dialog/dialog-modal.stories.tsx +1 -2
  114. package/src/components/dialog/dialog.stories.tsx +1 -1
  115. package/src/components/dialog/views/dialog-header.stories.tsx +1 -2
  116. package/src/components/form/CHECKBOX-STYLES.mdx +766 -0
  117. package/src/components/form/CHECKBOX.mdx +665 -0
  118. package/src/components/form/checkbox.scss +28 -0
  119. package/src/components/form/checkbox.tsx +72 -22
  120. package/src/components/form/form.scss +11 -14
  121. package/src/components/form/form.stories.tsx +1 -1
  122. package/src/components/form/input.stories.tsx +72 -23
  123. package/src/components/form/select.scss +97 -0
  124. package/src/components/form/select.stories.tsx +225 -9
  125. package/src/components/form/select.test.tsx +541 -0
  126. package/src/components/form/select.tsx +133 -16
  127. package/src/components/heading/heading.stories.tsx +1 -2
  128. package/src/components/images/figure.stories.tsx +1 -2
  129. package/src/components/images/img.stories.tsx +1 -1
  130. package/src/components/nav/nav.stories.tsx +1 -2
  131. package/src/components/text/text.stories.tsx +1 -1
  132. package/src/components/text-to-speech/TextToSpeech.stories.tsx +1 -1
  133. package/src/components/title/title.stories.tsx +1 -2
  134. package/src/components/ui.tsx +11 -4
  135. package/src/styles/form/checkbox.css +19 -0
  136. package/src/styles/form/checkbox.css.map +1 -1
  137. package/src/styles/form/form.css +100 -14
  138. package/src/styles/form/form.css.map +1 -1
  139. package/src/styles/form/select.css +75 -0
  140. package/src/styles/form/select.css.map +1 -0
  141. package/src/styles/index.css +100 -14
  142. package/src/styles/index.css.map +1 -1
  143. package/libs/chunk-DDSXKOUB.js +0 -7
  144. package/libs/chunk-DDSXKOUB.js.map +0 -1
  145. package/libs/chunk-EJ6KYBFE.cjs +0 -13
  146. package/libs/chunk-EJ6KYBFE.cjs.map +0 -1
  147. /package/libs/{chunk-DIJBIOFE.js.map → chunk-2ZJV6KQ3.js.map} +0 -0
  148. /package/libs/{chunk-LXODKKA3.cjs.map → chunk-3D6WUYSL.cjs.map} +0 -0
  149. /package/libs/{chunk-2JCDEC32.js.map → chunk-3ENBUQIB.js.map} +0 -0
  150. /package/libs/{chunk-NCGVF2QS.cjs.map → chunk-3RVZZZWX.cjs.map} +0 -0
  151. /package/libs/{chunk-M7JLT62Q.js.map → chunk-4F6SI5V5.js.map} +0 -0
  152. /package/libs/{chunk-3XJC4XUG.js.map → chunk-6ADHES7B.js.map} +0 -0
  153. /package/libs/{chunk-AOFQDQVS.cjs.map → chunk-6WMLG4O5.cjs.map} +0 -0
  154. /package/libs/{chunk-Q7OAQLUT.js.map → chunk-AQAI6COH.js.map} +0 -0
  155. /package/libs/{chunk-6BUJZ4DJ.cjs.map → chunk-BVPUT2PP.cjs.map} +0 -0
  156. /package/libs/{chunk-F64GE6RG.cjs.map → chunk-GVVCXXKI.cjs.map} +0 -0
  157. /package/libs/{chunk-75YQDONV.cjs.map → chunk-H4JRUNKU.cjs.map} +0 -0
  158. /package/libs/{chunk-G3TFKMWB.js.map → chunk-H6A2CUWA.js.map} +0 -0
  159. /package/libs/{chunk-2GJHKWEK.cjs.map → chunk-LQPWXSCK.cjs.map} +0 -0
  160. /package/libs/{chunk-IBUTNPTQ.js.map → chunk-M5ES7OWP.js.map} +0 -0
  161. /package/libs/{chunk-AWZLSWDO.js.map → chunk-MAG46S3P.js.map} +0 -0
  162. /package/libs/{chunk-KAR3HDXK.js.map → chunk-MJJKNHVH.js.map} +0 -0
  163. /package/libs/{chunk-5CJPTDK3.cjs.map → chunk-OZM455LO.cjs.map} +0 -0
  164. /package/libs/{chunk-NPWHQVYB.cjs.map → chunk-QU5AQQ4S.cjs.map} +0 -0
  165. /package/libs/{chunk-U5VA34SU.js.map → chunk-RQSMWB3J.js.map} +0 -0
  166. /package/libs/{chunk-5QSNJQVH.cjs.map → chunk-S7NIA6PI.cjs.map} +0 -0
  167. /package/libs/{chunk-MBWI67UT.js.map → chunk-SPESKPUA.js.map} +0 -0
  168. /package/libs/{chunk-PMWL5XZ4.js.map → chunk-SQ44OCJ2.js.map} +0 -0
  169. /package/libs/{chunk-EKJYOCLY.cjs.map → chunk-VISQ434C.cjs.map} +0 -0
  170. /package/libs/{chunk-AFINOD2L.cjs.map → chunk-VN2CVD4H.cjs.map} +0 -0
  171. /package/libs/{chunk-M5JARVJD.cjs.map → chunk-WTWGTWVI.cjs.map} +0 -0
  172. /package/libs/{chunk-TF3GQKOY.js.map → chunk-X2RDXWH5.js.map} +0 -0
@@ -31,7 +31,7 @@ import { Input, type InputProps } from "./inputs";
31
31
  */
32
32
  export interface CheckboxProps extends Omit<
33
33
  InputProps,
34
- 'type' | 'value' | 'onChange' | 'defaultValue' | 'placeholder'
34
+ 'type' | 'value' | 'onChange' | 'defaultValue' | 'placeholder' | 'size'
35
35
  > {
36
36
  /**
37
37
  * Unique identifier for the checkbox input.
@@ -51,6 +51,30 @@ export interface CheckboxProps extends Omit<
51
51
  */
52
52
  label: React.ReactNode;
53
53
 
54
+ /**
55
+ * Predefined size variant for the checkbox.
56
+ * Maps to standardized size tokens for consistent sizing across the design system.
57
+ *
58
+ * Available sizes:
59
+ * - `xs`: Extra small (0.875rem / 14px) - Compact forms, tight spaces
60
+ * - `sm`: Small (1rem / 16px) - Dense layouts
61
+ * - `md`: Medium (1.25rem / 20px) - Default, optimal for most use cases
62
+ * - `lg`: Large (1.5rem / 24px) - Touch-friendly, prominent CTAs
63
+ *
64
+ * For custom sizes beyond these presets, use the `styles` prop:
65
+ * ```tsx
66
+ * styles={{ '--checkbox-size': '2rem' }}
67
+ * ```
68
+ *
69
+ * @default 'md'
70
+ * @example
71
+ * ```tsx
72
+ * <Checkbox id="small" label="Small checkbox" size="sm" />
73
+ * <Checkbox id="large" label="Large checkbox" size="lg" />
74
+ * ```
75
+ */
76
+ size?: 'xs' | 'sm' | 'md' | 'lg';
77
+
54
78
  /**
55
79
  * Controlled mode: Current checked state.
56
80
  * When provided, component becomes controlled and requires onChange handler.
@@ -113,33 +137,46 @@ export interface CheckboxProps extends Omit<
113
137
  inputClasses?: string;
114
138
 
115
139
  /**
116
- * CSS custom properties for theming.
140
+ * CSS custom properties for theming and custom sizing.
117
141
  *
118
- * Available variables:
119
- * - --checkbox-gap: Space between checkbox and label (default: 0.5rem)
120
- * - --checkbox-disabled-opacity: Opacity for disabled state (default: 0.6)
121
- * - --checkbox-disabled-color: Label color when disabled (default: #6b7280)
122
- * - --checkbox-label-fs: Label font size (default: 1rem)
123
- * - --checkbox-label-lh: Label line height (default: 1.5)
124
- * - --color-required: Required indicator color (default: #dc2626)
125
- * - --checkbox-focus-ring-color: Focus ring color (default: #2563eb)
126
- * - --checkbox-focus-ring-width: Focus ring width (default: 0.125rem)
127
- * - --checkbox-focus-ring-offset: Focus ring offset (default: 0.125rem)
128
- * - --checkbox-hover-label-color: Label color on hover
129
- * - --checkbox-error-label-color: Label color when invalid (default: #dc2626)
130
- * - --checkbox-valid-label-color: Label color when valid (default: #16a34a)
142
+ * Common variables:
143
+ * - `--checkbox-size`: Custom checkbox dimensions (for sizes beyond xs/sm/md/lg presets)
144
+ * - `--checkbox-gap`: Space between checkbox and label (default: 0.5rem)
145
+ * - `--checkbox-border-color`: Border color (default: var(--color-neutral-600))
146
+ * - `--checkbox-checked-bg`: Background color when checked (default: var(--color-success))
147
+ * - `--checkbox-radius`: Border radius (default: 0.25rem)
148
+ * - `--checkbox-focus-ring-color`: Focus ring color (default: var(--color-focus-ring))
149
+ * - `--checkbox-disabled-opacity`: Opacity for disabled state (default: 0.6)
150
+ * - `--checkbox-label-fs`: Label font size (default: 1rem)
151
+ *
152
+ * For custom sizes beyond the preset variants (xs/sm/md/lg), use `--checkbox-size`:
131
153
  *
132
154
  * @example
133
155
  * ```tsx
156
+ * // Custom size beyond presets
134
157
  * <Checkbox
135
158
  * id="custom"
136
- * label="Custom styled"
159
+ * label="Custom sized (2rem)"
160
+ * styles={{
161
+ * '--checkbox-size': '2rem',
162
+ * '--checkbox-gap': '1rem'
163
+ * }}
164
+ * />
165
+ *
166
+ * // Brand theming
167
+ * <Checkbox
168
+ * id="branded"
169
+ * label="Brand checkbox"
170
+ * size="lg"
137
171
  * styles={{
138
- * '--checkbox-gap': '1rem',
139
- * '--checkbox-focus-ring-color': '#ff0000'
172
+ * '--checkbox-checked-bg': '#0066cc',
173
+ * '--checkbox-focus-ring-color': '#0066cc'
140
174
  * }}
141
175
  * />
142
176
  * ```
177
+ *
178
+ * @see {@link ./CHECKBOX-STYLES.mdx|CHECKBOX-STYLES.mdx} - Complete CSS variable reference
179
+ * @see {@link ./CHECKBOX.mdx|CHECKBOX.mdx} - Component documentation with examples
143
180
  */
144
181
  styles?: React.CSSProperties;
145
182
  }
@@ -152,6 +189,7 @@ export interface CheckboxProps extends Omit<
152
189
  * validation, disabled state, and ARIA logic from the base Input component.
153
190
  *
154
191
  * **Key Features:**
192
+ * - ✅ Semantic size variants (xs, sm, md, lg) via `size` prop
155
193
  * - ✅ Boolean onChange API (`onChange={(checked) => ...}`)
156
194
  * - ✅ Automatic label association via htmlFor
157
195
  * - ✅ WCAG 2.1 AA compliant (uses aria-disabled pattern)
@@ -199,11 +237,21 @@ export interface CheckboxProps extends Omit<
199
237
  *
200
238
  * @example
201
239
  * ```tsx
240
+ * // Size variants
241
+ * <Checkbox id="small" label="Small" size="sm" />
242
+ * <Checkbox id="large" label="Large" size="lg" />
243
+ * ```
244
+ *
245
+ * @example
246
+ * ```tsx
202
247
  * // Custom styling
203
248
  * <Checkbox
204
249
  * id="custom"
205
- * label="Large checkbox"
206
- * styles={{ '--checkbox-gap': '1rem' }}
250
+ * label="Custom sized"
251
+ * styles={{
252
+ * '--checkbox-size': '2rem',
253
+ * '--checkbox-gap': '1rem'
254
+ * }}
207
255
  * />
208
256
  * ```
209
257
  *
@@ -211,6 +259,8 @@ export interface CheckboxProps extends Omit<
211
259
  * @param {React.Ref<HTMLInputElement>} ref - Forwarded ref to the input element
212
260
  * @returns {JSX.Element} Checkbox wrapper with input and label
213
261
  *
262
+ * @see {@link ./CHECKBOX.mdx|CHECKBOX.mdx} - Complete component documentation
263
+ * @see {@link ./CHECKBOX-STYLES.mdx|CHECKBOX-STYLES.mdx} - CSS customization guide
214
264
  * @see {@link https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html|WCAG 4.1.2 Name, Role, Value}
215
265
  * @see {@link https://www.w3.org/WAI/WCAG21/Understanding/focus-visible.html|WCAG 2.4.7 Focus Visible}
216
266
  * @see {@link https://www.w3.org/WAI/WCAG21/Understanding/error-identification.html|WCAG 3.3.1 Error Identification}
@@ -218,7 +268,7 @@ export interface CheckboxProps extends Omit<
218
268
  export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
219
269
  ({
220
270
  id, label, checked, defaultChecked, value = "on",
221
- onChange, classes, inputClasses, styles,
271
+ onChange, classes, inputClasses, styles, size,
222
272
  name, disabled, required, validationState,
223
273
  errorMessage, hintText, onBlur, onFocus, autoFocus,
224
274
  ...props
@@ -264,7 +314,7 @@ export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
264
314
  // Note: No need to manage disabled class - CSS uses :has() selector with aria-disabled
265
315
  // The Input component handles aria-disabled automatically via useDisabledState hook
266
316
  return (
267
- <div className={classes} style={styles}>
317
+ <div className={classes} style={styles} data-checkbox-size={size}>
268
318
  <Input
269
319
  ref={ref}
270
320
  type="checkbox"
@@ -1,5 +1,7 @@
1
1
  // Import checkbox wrapper component styles
2
2
  @use "./checkbox";
3
+ // Import select component styles
4
+ @use "./select";
3
5
 
4
6
  :root {
5
7
  --input-border-color: var(--color-border);
@@ -9,9 +11,9 @@
9
11
  --input-outline: thin solid var(--input-border-color);
10
12
  --input-padding-inline: 0.6rem;
11
13
  --input-padding-block: 0.4rem;
12
- --input-radius: --var(--radius);
14
+ --input-radius: var(--radius);
13
15
  --input-fs: var(--fs);
14
- --input-width: clamp(200px, 100%, 500px);
16
+ --input-width: clamp(12.5rem, 100%, 31.25rem);
15
17
 
16
18
  // Focus state variables (NEW - for accessibility)
17
19
  --input-focus-outline: medium solid var(--input-border-color);
@@ -28,16 +30,22 @@
28
30
  --placeholder-fs: smaller;
29
31
 
30
32
  --form-direction: column;
31
- --select-arrow: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20'><polyline points='6,9 10,13 14,9' stroke='%23000000' stroke-width='1.5' fill='none' /></svg>");
32
33
 
33
34
  /* ==========================================================================
34
35
  Size Tokens
35
36
  ========================================================================== */
36
37
 
38
+ --checkbox-size-xs: 0.875rem; /* 14px - extra small */
37
39
  --checkbox-size-sm: 1rem; /* 16px */
38
40
  --checkbox-size-md: 1.25rem; /* 20px */
39
41
  --checkbox-size-lg: 1.5rem; /* 24px */
40
42
 
43
+ /* Gap tokens for each size variant */
44
+ --checkbox-gap-xs: 0.375rem; /* 6px */
45
+ --checkbox-gap-sm: 0.5rem; /* 8px */
46
+ --checkbox-gap-md: 0.5rem; /* 8px - default */
47
+ --checkbox-gap-lg: 0.625rem; /* 10px */
48
+
41
49
  /* ==========================================================================
42
50
  Base Properties
43
51
  ========================================================================== */
@@ -138,14 +146,3 @@ input[type="checkbox"] {
138
146
  no-repeat center center;
139
147
  }
140
148
  }
141
-
142
- select {
143
- border: var(--input-outline);
144
- outline: none;
145
- -webkit-appearance: none; /* Remove default arrow in Chrome and Safari */
146
- -moz-appearance: none; /* Remove default arrow in Firefox */
147
- appearance: none; /* Remove default arrow in other browsers */
148
- background: var(--select-arrow) no-repeat;
149
- background-position: right 0.5rem top 50%;
150
- padding-inline-end: 0;
151
- }
@@ -10,7 +10,7 @@ import "./form.scss";
10
10
  const FormComponent = Form as unknown as typeof Form;
11
11
 
12
12
  const meta: Meta<typeof FormComponent> = {
13
- title: "FP.REACT Forms/Form",
13
+ title: "FP.React Forms/Form",
14
14
  tags: ["stable", "autodocs"],
15
15
  component: FormComponent,
16
16
  parameters: {
@@ -7,7 +7,7 @@ import { Checkbox as CheckboxComponent } from "./checkbox";
7
7
  import "./form.scss";
8
8
 
9
9
  const meta: Meta<typeof Input> = {
10
- title: "FP.REACT Forms/Inputs",
10
+ title: "FP.React Forms/Inputs",
11
11
  component: Input,
12
12
  tags: ["stable"],
13
13
  args: {},
@@ -405,47 +405,96 @@ export const CheckboxWithHint: Story = {
405
405
  };
406
406
 
407
407
  /**
408
- * CheckboxCustomSize - Custom sized checkboxes using CSS variables
408
+ * CheckboxCustomSize - Predefined size variants using size prop
409
409
  *
410
- * Demonstrates responsive sizing by overriding --checkbox-size and --checkbox-gap variables.
411
- * Useful for contexts requiring larger touch targets or compact layouts.
410
+ * Demonstrates semantic size prop for common size variants.
411
+ * For custom sizes beyond presets, see CheckboxCustomSizeCSSOverride story.
412
412
  */
413
413
  export const CheckboxCustomSize: Story = {
414
414
  render: () => (
415
415
  <div style={{ display: "flex", gap: "1.5rem", flexDirection: "column" }}>
416
416
  <CheckboxComponent
417
- id="small"
418
- label="Small (1rem)"
419
- styles={{
420
- "--checkbox-size": "1rem",
421
- "--checkbox-gap": "0.5rem",
422
- } as React.CSSProperties}
417
+ id="xs"
418
+ label="Extra Small (0.875rem / 14px)"
419
+ size="xs"
423
420
  />
424
421
  <CheckboxComponent
425
- id="medium"
426
- label="Medium (1.25rem - default)"
427
- styles={{
428
- "--checkbox-gap": "0.5rem",
429
- } as React.CSSProperties}
422
+ id="sm"
423
+ label="Small (1rem / 16px)"
424
+ size="sm"
430
425
  />
431
426
  <CheckboxComponent
432
- id="large"
433
- label="Large (1.5rem)"
427
+ id="md"
428
+ label="Medium (1.25rem / 20px) - Default"
429
+ size="md"
430
+ />
431
+ <CheckboxComponent
432
+ id="lg"
433
+ label="Large (1.5rem / 24px)"
434
+ size="lg"
435
+ />
436
+ </div>
437
+ ),
438
+ play: async ({ canvasElement, step }) => {
439
+ const canvas = within(canvasElement);
440
+
441
+ await step("XS checkbox has correct data attribute", async () => {
442
+ const checkbox = canvas.getByRole("checkbox", { name: /Extra Small/ });
443
+ const wrapper = checkbox.closest('div');
444
+ expect(wrapper).toHaveAttribute("data-checkbox-size", "xs");
445
+ });
446
+
447
+ await step("LG checkbox has correct data attribute", async () => {
448
+ const checkbox = canvas.getByRole("checkbox", { name: /Large/ });
449
+ const wrapper = checkbox.closest('div');
450
+ expect(wrapper).toHaveAttribute("data-checkbox-size", "lg");
451
+ });
452
+
453
+ await step("All checkboxes are functional", async () => {
454
+ const xsCheckbox = canvas.getByRole("checkbox", { name: /Extra Small/ });
455
+ await userEvent.click(xsCheckbox);
456
+ expect(xsCheckbox).toBeChecked();
457
+ });
458
+ },
459
+ };
460
+
461
+ /**
462
+ * CheckboxCustomSizeCSSOverride - Custom sizes via CSS variables
463
+ *
464
+ * Demonstrates that CSS variable overrides still work for custom sizes
465
+ * beyond the predefined xs/sm/md/lg variants.
466
+ */
467
+ export const CheckboxCustomSizeCSSOverride: Story = {
468
+ render: () => (
469
+ <div style={{ display: "flex", gap: "1.5rem", flexDirection: "column" }}>
470
+ <CheckboxComponent
471
+ id="custom-tiny"
472
+ label="Custom Tiny (0.75rem)"
434
473
  styles={{
435
- "--checkbox-size": "1.5rem",
436
- "--checkbox-gap": "0.625rem",
474
+ "--checkbox-size": "0.75rem",
475
+ "--checkbox-gap": "0.375rem",
437
476
  } as React.CSSProperties}
438
477
  />
439
478
  <CheckboxComponent
440
- id="xlarge"
441
- label="Extra Large (2rem)"
479
+ id="custom-huge"
480
+ label="Custom Huge (2.5rem)"
442
481
  styles={{
443
- "--checkbox-size": "2rem",
444
- "--checkbox-gap": "0.75rem",
482
+ "--checkbox-size": "2.5rem",
483
+ "--checkbox-gap": "1rem",
445
484
  } as React.CSSProperties}
446
485
  />
447
486
  </div>
448
487
  ),
488
+ parameters: {
489
+ docs: {
490
+ description: {
491
+ story: `
492
+ For sizes outside the predefined variants, use the \`styles\` prop to override CSS variables directly.
493
+ This provides maximum flexibility while keeping the API clean for common cases.
494
+ `,
495
+ },
496
+ },
497
+ },
449
498
  };
450
499
 
451
500
  /**
@@ -0,0 +1,97 @@
1
+ // Select Component Styles
2
+
3
+ :root {
4
+ // Select arrow color (themeable)
5
+ --select-arrow-color: var(--color-text);
6
+
7
+ // Select width (responsive)
8
+ --select-width-mobile: 18.75rem; /* 300px minimum on mobile */
9
+ --select-width-desktop: 100%; /* Full width on larger screens */
10
+ }
11
+
12
+ select {
13
+ // Match input component styling
14
+ border: var(--input-outline);
15
+ border-radius: var(--input-radius);
16
+ outline: none;
17
+ background-color: var(--input-bg, var(--color-surface));
18
+
19
+ // Remove default browser select styling
20
+ -webkit-appearance: none; /* Remove default arrow in Chrome and Safari */
21
+ -moz-appearance: none; /* Remove default arrow in Firefox */
22
+ appearance: none; /* Remove default arrow in other browsers */
23
+
24
+ // Create themeable arrow using CSS gradients
25
+ background-image: linear-gradient(45deg, transparent 50%, var(--select-arrow-color, currentColor) 50%),
26
+ linear-gradient(135deg, var(--select-arrow-color, currentColor) 50%, transparent 50%);
27
+ background-position: calc(100% - 1.25rem) center,
28
+ calc(100% - 1rem) center;
29
+ background-size: 0.3125rem 0.3125rem,
30
+ 0.3125rem 0.3125rem;
31
+ background-repeat: no-repeat;
32
+
33
+ // Match input component height using shared padding variables
34
+ padding-inline-start: var(--input-padding-inline);
35
+ padding-inline-end: 2.5rem; // Extra space for arrow
36
+ padding-block: var(--input-padding-block);
37
+
38
+ // Responsive width: uses larger of 300px or 100% of container
39
+ width: max(var(--select-width-mobile), var(--select-width-desktop));
40
+ }
41
+
42
+ /* ==========================================================================
43
+ Option Styling with Data Attributes
44
+ ========================================================================== */
45
+
46
+ // Example: Variant-based option styling
47
+ // Uncomment and customize for your design system
48
+ /*
49
+ option[data-option="primary"] {
50
+ background-color: var(--color-primary-light, #dbeafe);
51
+ color: var(--color-primary, #2563eb);
52
+ font-weight: 600;
53
+ }
54
+
55
+ option[data-option="success"] {
56
+ background-color: var(--color-success-bg, #dcfce7);
57
+ color: var(--color-success, #16a34a);
58
+ }
59
+
60
+ option[data-option="error"] {
61
+ background-color: var(--color-error-bg, #fee2e2);
62
+ color: var(--color-error, #dc2626);
63
+ }
64
+
65
+ option[data-option="warning"] {
66
+ background-color: var(--color-warning-bg, #fef3c7);
67
+ color: var(--color-warning, #d97706);
68
+ }
69
+ */
70
+
71
+ // Example: Size-based option styling
72
+ /*
73
+ option[data-size="sm"] {
74
+ font-size: 0.875rem; // 14px
75
+ padding: 0.25rem 0.5rem;
76
+ }
77
+
78
+ option[data-size="lg"] {
79
+ font-size: 1.125rem; // 18px
80
+ padding: 0.75rem 1rem;
81
+ font-weight: 500;
82
+ }
83
+ */
84
+
85
+ // Example: Custom data attribute styling
86
+ /*
87
+ option[data-featured="true"] {
88
+ font-weight: 700;
89
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
90
+ color: white;
91
+ }
92
+
93
+ option[data-category="premium"] {
94
+ background-color: #fef3c7;
95
+ font-style: italic;
96
+ }
97
+ */