infinity-ui-elements 1.3.1 → 1.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 +62 -1
- package/dist/components/Button/Button.d.ts.map +1 -1
- package/dist/components/Checkbox/Checkbox.d.ts +49 -0
- package/dist/components/Checkbox/Checkbox.d.ts.map +1 -0
- package/dist/components/Checkbox/Checkbox.stories.d.ts +23 -0
- package/dist/components/Checkbox/Checkbox.stories.d.ts.map +1 -0
- package/dist/components/Checkbox/index.d.ts +3 -0
- package/dist/components/Checkbox/index.d.ts.map +1 -0
- package/dist/components/FormFooter/FormFooter.d.ts +38 -0
- package/dist/components/FormFooter/FormFooter.d.ts.map +1 -0
- package/dist/components/FormFooter/FormFooter.stories.d.ts +50 -0
- package/dist/components/FormFooter/FormFooter.stories.d.ts.map +1 -0
- package/dist/components/FormFooter/index.d.ts +3 -0
- package/dist/components/FormFooter/index.d.ts.map +1 -0
- package/dist/components/FormHeader/FormHeader.d.ts +58 -0
- package/dist/components/FormHeader/FormHeader.d.ts.map +1 -0
- package/dist/components/FormHeader/FormHeader.stories.d.ts +65 -0
- package/dist/components/FormHeader/FormHeader.stories.d.ts.map +1 -0
- package/dist/components/FormHeader/index.d.ts +3 -0
- package/dist/components/FormHeader/index.d.ts.map +1 -0
- package/dist/components/Text/Text.d.ts +2 -9
- package/dist/components/Text/Text.d.ts.map +1 -1
- package/dist/components/Text/index.d.ts +1 -1
- package/dist/components/Text/index.d.ts.map +1 -1
- package/dist/components/TextArea/TextArea.d.ts +31 -0
- package/dist/components/TextArea/TextArea.d.ts.map +1 -0
- package/dist/components/TextArea/TextArea.stories.d.ts +27 -0
- package/dist/components/TextArea/TextArea.stories.d.ts.map +1 -0
- package/dist/components/TextArea/index.d.ts +3 -0
- package/dist/components/TextArea/index.d.ts.map +1 -0
- package/dist/components/TextField/TextField.d.ts +4 -0
- package/dist/components/TextField/TextField.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +501 -171
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +510 -171
- package/dist/index.js.map +1 -1
- package/dist/lib/icons.d.ts +96 -0
- package/dist/lib/icons.d.ts.map +1 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -11,6 +11,18 @@ import { twMerge } from 'tailwind-merge';
|
|
|
11
11
|
const CUSTOM_CLASS_PATTERNS = [
|
|
12
12
|
// Custom font classes
|
|
13
13
|
/^font-(functional|display)$/,
|
|
14
|
+
// Custom font-size classes
|
|
15
|
+
/^font-size-/,
|
|
16
|
+
// Custom leading (line-height) classes
|
|
17
|
+
/^leading-(00|25|50|75|100|200|300|400|500|600|700|800|900|1000|1100)$/,
|
|
18
|
+
// Custom text utility classes (text-display, text-heading, text-body, text-caption variants)
|
|
19
|
+
/^text-(display|heading|body|caption)(-\w+)?(-\w+)?$/,
|
|
20
|
+
// Text weight classes
|
|
21
|
+
/^text-weight-/,
|
|
22
|
+
// Text color classes
|
|
23
|
+
/^text-color-/,
|
|
24
|
+
/^outline-width-/,
|
|
25
|
+
/^border-width-/,
|
|
14
26
|
// Custom spacing classes (example)
|
|
15
27
|
// /^spacing-(xs|sm|md|lg|xl)$/,
|
|
16
28
|
// Custom color classes (example)
|
|
@@ -33,7 +45,7 @@ function cn(...inputs) {
|
|
|
33
45
|
return clsx(mergedStandard, customClasses);
|
|
34
46
|
}
|
|
35
47
|
|
|
36
|
-
const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap
|
|
48
|
+
const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none", {
|
|
37
49
|
variants: {
|
|
38
50
|
variant: {
|
|
39
51
|
primary: "bg-action-fill-primary-default text-action-ink-on-primary-normal hover:bg-action-fill-primary-hover",
|
|
@@ -49,10 +61,10 @@ const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap
|
|
|
49
61
|
neutral: "",
|
|
50
62
|
},
|
|
51
63
|
size: {
|
|
52
|
-
xsmall: "md:h-[28px] px-3
|
|
53
|
-
small: "md:h-[32px] px-4
|
|
54
|
-
medium: "md:h-[36px] px-6 py-2 rounded-medium",
|
|
55
|
-
large: "md:h-[44px] px-6
|
|
64
|
+
xsmall: "md:h-[28px] px-3 rounded-medium text-body-small-medium",
|
|
65
|
+
small: "md:h-[32px] px-4 rounded-medium text-body-small-medium",
|
|
66
|
+
medium: "md:h-[36px] px-6 py-2 rounded-medium text-body-medium-medium",
|
|
67
|
+
large: "md:h-[44px] px-6 rounded-xlarge text-body-large-medium",
|
|
56
68
|
},
|
|
57
69
|
isIconOnly: {
|
|
58
70
|
true: "aspect-square p-0",
|
|
@@ -79,7 +91,8 @@ const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap
|
|
|
79
91
|
class: `bg-action-fill-primary-default text-action-ink-on-primary-normal
|
|
80
92
|
hover:bg-action-fill-primary-hover
|
|
81
93
|
disabled:bg-action-fill-primary-disabled
|
|
82
|
-
disabled:text-action-ink-primary-disabled
|
|
94
|
+
disabled:text-action-ink-primary-disabled,
|
|
95
|
+
active:bg-action-fill-primary-activated
|
|
83
96
|
`,
|
|
84
97
|
},
|
|
85
98
|
{
|
|
@@ -89,6 +102,7 @@ const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap
|
|
|
89
102
|
hover:bg-action-fill-positive-hover
|
|
90
103
|
disabled:bg-action-fill-primary-disabled
|
|
91
104
|
disabled:text-action-ink-primary-disabled
|
|
105
|
+
active:bg-action-fill-positive-activated
|
|
92
106
|
`,
|
|
93
107
|
},
|
|
94
108
|
{
|
|
@@ -98,6 +112,7 @@ const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap
|
|
|
98
112
|
hover:bg-action-fill-negative-hover
|
|
99
113
|
disabled:bg-action-fill-negative-disabled
|
|
100
114
|
disabled:text-action-ink-negative-disabled
|
|
115
|
+
active:bg-action-fill-negative-activated
|
|
101
116
|
`,
|
|
102
117
|
},
|
|
103
118
|
{
|
|
@@ -107,6 +122,7 @@ const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap
|
|
|
107
122
|
hover:bg-action-fill-notice-hover
|
|
108
123
|
disabled:bg-action-fill-notice-disabled
|
|
109
124
|
disabled:text-action-ink-notice-disabled
|
|
125
|
+
active:bg-action-fill-notice-activated
|
|
110
126
|
`,
|
|
111
127
|
},
|
|
112
128
|
{
|
|
@@ -116,6 +132,7 @@ const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap
|
|
|
116
132
|
hover:bg-action-fill-info-hover
|
|
117
133
|
disabled:bg-action-fill-info-disabled
|
|
118
134
|
disabled:text-action-ink-info-disabled
|
|
135
|
+
active:bg-action-fill-info-activated
|
|
119
136
|
`,
|
|
120
137
|
},
|
|
121
138
|
{
|
|
@@ -125,42 +142,96 @@ const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap
|
|
|
125
142
|
hover:bg-action-fill-neutral-hover
|
|
126
143
|
disabled:bg-action-fill-neutral-disabled
|
|
127
144
|
disabled:text-action-ink-neutral-disabled
|
|
145
|
+
active:bg-action-fill-neutral-activated
|
|
128
146
|
`,
|
|
129
147
|
},
|
|
130
148
|
// Secondary variant colors
|
|
131
149
|
{
|
|
132
150
|
variant: "secondary",
|
|
133
151
|
color: "primary",
|
|
134
|
-
class: `
|
|
152
|
+
class: `
|
|
153
|
+
border-action-outline-info-faded
|
|
154
|
+
text-action-ink-primary-normal
|
|
155
|
+
hover:border-action-outline-primary-faded-hover
|
|
156
|
+
hover:bg-action-fill-primary-faded-hover
|
|
135
157
|
disabled:bg-action-outline-info-disabled
|
|
136
158
|
disabled:text-action-ink-primary-disabled
|
|
137
159
|
disabled:border-action-outline-primary-disabled
|
|
160
|
+
active:border-action-outline-primary-faded-activated
|
|
161
|
+
active:bg-action-fill-primary-faded-activated
|
|
138
162
|
`,
|
|
139
163
|
},
|
|
140
164
|
{
|
|
141
165
|
variant: "secondary",
|
|
142
166
|
color: "positive",
|
|
143
|
-
class:
|
|
167
|
+
class: `
|
|
168
|
+
border-action-outline-positive-faded
|
|
169
|
+
text-action-ink-positive-normal
|
|
170
|
+
hover:border-action-outline-positive-faded-hover
|
|
171
|
+
hover:bg-action-fill-positive-faded-hover
|
|
172
|
+
disabled:bg-action-outline-positive-disabled
|
|
173
|
+
disabled:text-action-ink-positive-disabled
|
|
174
|
+
disabled:border-action-outline-positive-disabled
|
|
175
|
+
active:border-action-outline-positive-faded-activated
|
|
176
|
+
active:bg-action-fill-positive-faded-activated
|
|
177
|
+
`,
|
|
144
178
|
},
|
|
145
179
|
{
|
|
146
180
|
variant: "secondary",
|
|
147
181
|
color: "negative",
|
|
148
|
-
class:
|
|
182
|
+
class: `
|
|
183
|
+
border-action-outline-negative-faded
|
|
184
|
+
text-action-ink-negative-normal
|
|
185
|
+
hover:border-action-outline-negative-faded-hover
|
|
186
|
+
hover:bg-action-fill-negative-faded-hover
|
|
187
|
+
disabled:bg-action-outline-negative-disabled
|
|
188
|
+
disabled:text-action-ink-negative-disabled
|
|
189
|
+
disabled:border-action-outline-negative-disabled
|
|
190
|
+
active:border-action-outline-negative-faded-activated
|
|
191
|
+
active:bg-action-fill-negative-faded-activated
|
|
192
|
+
`,
|
|
149
193
|
},
|
|
150
194
|
{
|
|
151
195
|
variant: "secondary",
|
|
152
196
|
color: "notice",
|
|
153
|
-
class:
|
|
197
|
+
class: `
|
|
198
|
+
border-action-outline-notice-faded
|
|
199
|
+
text-action-ink-notice-normal
|
|
200
|
+
hover:border-action-outline-notice-faded-hover
|
|
201
|
+
hover:bg-action-fill-notice-faded-hover
|
|
202
|
+
disabled:bg-action-outline-notice-disabled
|
|
203
|
+
disabled:text-action-ink-notice-disabled
|
|
204
|
+
disabled:border-action-outline-notice-disabled
|
|
205
|
+
active:border-action-outline-notice-faded-activated
|
|
206
|
+
active:bg-action-fill-notice-faded-activated
|
|
207
|
+
`,
|
|
154
208
|
},
|
|
155
209
|
{
|
|
156
210
|
variant: "secondary",
|
|
157
211
|
color: "info",
|
|
158
|
-
class:
|
|
212
|
+
class: `border-action-outline-info-faded
|
|
213
|
+
text-action-ink-info-normal
|
|
214
|
+
hover:border-action-outline-info-faded-hover
|
|
215
|
+
hover:bg-action-fill-info-faded-hover
|
|
216
|
+
disabled:bg-action-outline-info-disabled
|
|
217
|
+
disabled:text-action-ink-info-disabled
|
|
218
|
+
disabled:border-action-outline-info-disabled
|
|
219
|
+
active:border-action-outline-info-faded-activated
|
|
220
|
+
active:bg-action-fill-info-faded-activated
|
|
221
|
+
`,
|
|
159
222
|
},
|
|
160
223
|
{
|
|
161
224
|
variant: "secondary",
|
|
162
225
|
color: "neutral",
|
|
163
|
-
class:
|
|
226
|
+
class: `border-action-outline-neutral-faded
|
|
227
|
+
text-action-ink-neutral-normal
|
|
228
|
+
hover:bg-action-outline-neutral-faded-hover
|
|
229
|
+
hover:bg-action-fill-neutral-faded-hover
|
|
230
|
+
disabled:text-action-ink-neutral-disabled
|
|
231
|
+
disabled:border-action-outline-neutral-disabled
|
|
232
|
+
active:border-action-outline-neutral-faded-activated
|
|
233
|
+
active:bg-action-fill-neutral-faded-activated
|
|
234
|
+
`,
|
|
164
235
|
},
|
|
165
236
|
// Tertiary variant colors
|
|
166
237
|
{
|
|
@@ -169,6 +240,7 @@ const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap
|
|
|
169
240
|
class: `text-action-ink-primary-normal
|
|
170
241
|
hover:bg-action-fill-primary-faded
|
|
171
242
|
disabled:text-action-ink-on-primary-muted
|
|
243
|
+
active:bg-action-fill-primary-faded-activated
|
|
172
244
|
`,
|
|
173
245
|
},
|
|
174
246
|
{
|
|
@@ -177,6 +249,7 @@ const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap
|
|
|
177
249
|
class: `text-action-ink-positive-normal
|
|
178
250
|
hover:bg-action-fill-positive-faded
|
|
179
251
|
disabled:text-action-ink-on-positive-muted
|
|
252
|
+
active:bg-action-fill-positive-faded-activated
|
|
180
253
|
`,
|
|
181
254
|
},
|
|
182
255
|
{
|
|
@@ -185,6 +258,7 @@ const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap
|
|
|
185
258
|
class: `text-action-ink-negative-normal
|
|
186
259
|
hover:bg-action-fill-negative-faded
|
|
187
260
|
disabled:text-action-ink-on-negative-muted
|
|
261
|
+
active:bg-action-fill-negative-faded-activated
|
|
188
262
|
`,
|
|
189
263
|
},
|
|
190
264
|
{
|
|
@@ -193,6 +267,7 @@ const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap
|
|
|
193
267
|
class: `text-action-ink-notice-normal
|
|
194
268
|
hover:bg-action-fill-notice-faded
|
|
195
269
|
disabled:text-action-ink-on-notice-muted
|
|
270
|
+
active:bg-action-fill-notice-faded-activated
|
|
196
271
|
`,
|
|
197
272
|
},
|
|
198
273
|
{
|
|
@@ -201,6 +276,7 @@ const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap
|
|
|
201
276
|
class: `text-action-ink-info-normal
|
|
202
277
|
hover:bg-action-fill-info-faded
|
|
203
278
|
disabled:text-action-ink-on-notice-muted
|
|
279
|
+
active:bg-action-fill-info-faded-activated
|
|
204
280
|
`,
|
|
205
281
|
},
|
|
206
282
|
{
|
|
@@ -209,6 +285,7 @@ const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap
|
|
|
209
285
|
class: `text-action-ink-neutral-normal
|
|
210
286
|
hover:bg-action-fill-neutral-faded
|
|
211
287
|
disabled:text-action-ink-on-notice-muted
|
|
288
|
+
active:bg-action-fill-neutral-faded-activated
|
|
212
289
|
`,
|
|
213
290
|
},
|
|
214
291
|
// Icon only sizing
|
|
@@ -258,174 +335,318 @@ const Button = React.forwardRef(({ className, variant = "primary", color = "prim
|
|
|
258
335
|
});
|
|
259
336
|
Button.displayName = "Button";
|
|
260
337
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
h5: "",
|
|
296
|
-
h6: "",
|
|
297
|
-
p: "",
|
|
298
|
-
span: "",
|
|
299
|
-
div: "",
|
|
300
|
-
label: "",
|
|
301
|
-
},
|
|
302
|
-
},
|
|
303
|
-
compoundVariants: [
|
|
304
|
-
// Display variants use Clash Grotesk with medium weight
|
|
305
|
-
{
|
|
306
|
-
variant: "display",
|
|
307
|
-
weight: "regular",
|
|
308
|
-
class: "font-medium",
|
|
309
|
-
},
|
|
310
|
-
{
|
|
311
|
-
variant: "display",
|
|
312
|
-
weight: "medium",
|
|
313
|
-
class: "font-medium",
|
|
314
|
-
},
|
|
315
|
-
{
|
|
316
|
-
variant: "display",
|
|
317
|
-
weight: "semibold",
|
|
318
|
-
class: "font-medium",
|
|
319
|
-
},
|
|
320
|
-
// Caption is always semibold
|
|
321
|
-
{
|
|
322
|
-
variant: "caption",
|
|
323
|
-
weight: "regular",
|
|
324
|
-
class: "font-semibold",
|
|
325
|
-
},
|
|
326
|
-
{
|
|
327
|
-
variant: "caption",
|
|
328
|
-
weight: "medium",
|
|
329
|
-
class: "font-semibold",
|
|
330
|
-
},
|
|
331
|
-
{
|
|
332
|
-
variant: "caption",
|
|
333
|
-
weight: "semibold",
|
|
334
|
-
class: "font-semibold",
|
|
335
|
-
},
|
|
336
|
-
// Size-specific styling based on variant
|
|
337
|
-
// Display sizes
|
|
338
|
-
{
|
|
339
|
-
variant: "display",
|
|
340
|
-
size: "xlarge",
|
|
341
|
-
class: "font-size-1100 leading-1100 tracking-[0%] mb-0",
|
|
338
|
+
// Helper function to get the text utility class name
|
|
339
|
+
function getTextClassName(variant = "body", size = "medium", weight = "regular", color = "default") {
|
|
340
|
+
// Build the base class name
|
|
341
|
+
let baseClass = `text-${variant}`;
|
|
342
|
+
// Add size
|
|
343
|
+
if (size) {
|
|
344
|
+
baseClass += `-${size}`;
|
|
345
|
+
}
|
|
346
|
+
// Add weight
|
|
347
|
+
if (weight) {
|
|
348
|
+
baseClass += `-${weight}`;
|
|
349
|
+
}
|
|
350
|
+
// Add color class separately
|
|
351
|
+
const colorClass = `text-color-${color}`;
|
|
352
|
+
return `${baseClass} ${colorClass}`;
|
|
353
|
+
}
|
|
354
|
+
const Text = React.forwardRef(({ className, variant = "body", size = "medium", weight = "regular", color = "default", as = "p", children, ...props }, ref) => {
|
|
355
|
+
const Component = as;
|
|
356
|
+
const textClass = getTextClassName(variant, size, weight, color);
|
|
357
|
+
return React.createElement(Component, {
|
|
358
|
+
className: cn(textClass, className),
|
|
359
|
+
ref,
|
|
360
|
+
...props,
|
|
361
|
+
}, children);
|
|
362
|
+
});
|
|
363
|
+
Text.displayName = "Text";
|
|
364
|
+
|
|
365
|
+
const FormFooter = React.forwardRef(({ helperText, trailingText, validationState = "default", size = "medium", isDisabled = false, className, helperTextClassName, trailingTextClassName, }, ref) => {
|
|
366
|
+
// Size-based configurations
|
|
367
|
+
const sizeConfig = {
|
|
368
|
+
small: {
|
|
369
|
+
textSize: "xsmall",
|
|
370
|
+
iconSize: 12,
|
|
371
|
+
gap: "gap-1",
|
|
342
372
|
},
|
|
343
|
-
{
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
373
|
+
medium: {
|
|
374
|
+
textSize: "small",
|
|
375
|
+
iconSize: 14,
|
|
376
|
+
gap: "gap-1",
|
|
347
377
|
},
|
|
348
|
-
{
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
378
|
+
large: {
|
|
379
|
+
textSize: "medium",
|
|
380
|
+
iconSize: 16,
|
|
381
|
+
gap: "gap-1.5",
|
|
352
382
|
},
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
383
|
+
};
|
|
384
|
+
const config = sizeConfig[size];
|
|
385
|
+
// Determine text color based on validation state and disabled state
|
|
386
|
+
const getTextColor = () => {
|
|
387
|
+
if (isDisabled)
|
|
388
|
+
return "disabled";
|
|
389
|
+
if (validationState === "positive")
|
|
390
|
+
return "positive";
|
|
391
|
+
if (validationState === "negative")
|
|
392
|
+
return "negative";
|
|
393
|
+
if (validationState === "default")
|
|
394
|
+
return "default";
|
|
395
|
+
return "default";
|
|
396
|
+
};
|
|
397
|
+
// Don't render anything if there's no content
|
|
398
|
+
if (!helperText && !trailingText) {
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
return (jsxs("div", { ref: ref, className: cn("flex items-center justify-between px-1", config.gap, className), children: [helperText && (jsxs("div", { className: cn("flex items-center", config.gap), children: [validationState === "positive" && (jsx("svg", { width: config.iconSize, height: config.iconSize, viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: "text-feedback-ink-positive-intense shrink-0", children: jsx("path", { d: "M3 7L6 10L11 4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })), validationState === "negative" && (jsxs("svg", { width: config.iconSize, height: config.iconSize, viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: "text-feedback-ink-negative-subtle shrink-0", children: [jsx("circle", { cx: "7", cy: "7", r: "6", stroke: "currentColor", strokeWidth: "1" }), jsx("path", { d: "M7 4V7.5M7 10V9.5", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round" })] })), jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "regular", color: getTextColor(), className: cn("italic font-size-100 leading-100", helperTextClassName), children: helperText })] })), trailingText && (jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "regular", color: isDisabled ? "disabled" : "muted", className: cn("font-size-100 leading-100 shrink-0", trailingTextClassName), children: trailingText }))] }));
|
|
402
|
+
});
|
|
403
|
+
FormFooter.displayName = "FormFooter";
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* ==============================================
|
|
407
|
+
* HOW TO ADD A NEW ICON:
|
|
408
|
+
* ==============================================
|
|
409
|
+
*
|
|
410
|
+
* 1. Add your SVG file to: src/assets/icons/{iconName}.svg
|
|
411
|
+
*
|
|
412
|
+
* 2. Copy the SVG content from the file
|
|
413
|
+
*
|
|
414
|
+
* 3. Add it to the iconRegistry below:
|
|
415
|
+
* iconName: `<svg>...</svg>`,
|
|
416
|
+
*
|
|
417
|
+
* 4. Use it anywhere in your app:
|
|
418
|
+
* <Icon name="iconName" size={24} />
|
|
419
|
+
*
|
|
420
|
+
* The Icon component will automatically:
|
|
421
|
+
* - Replace hardcoded colors with currentColor
|
|
422
|
+
* - Allow you to control color via className or style
|
|
423
|
+
* - Resize based on the size prop
|
|
424
|
+
* ==============================================
|
|
425
|
+
*/
|
|
426
|
+
/**
|
|
427
|
+
* Icon registry - maps icon names to their SVG content
|
|
428
|
+
* Add your icons here by copying the SVG content from your icon files
|
|
429
|
+
*/
|
|
430
|
+
const iconRegistry = {
|
|
431
|
+
// Tick/Check icon
|
|
432
|
+
tick: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
433
|
+
<path d="M10.364 15.1924L19.5564 6L20.9706 7.41421L10.364 18.0208L4 11.6569L5.41422 10.2427L10.364 15.1924Z" fill="#081416"/>
|
|
434
|
+
</svg>`,
|
|
435
|
+
// Alias: check points to the same icon as tick
|
|
436
|
+
check: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
437
|
+
<path d="M10.364 15.1924L19.5564 6L20.9706 7.41421L10.364 18.0208L4 11.6569L5.41422 10.2427L10.364 15.1924Z" fill="#081416"/>
|
|
438
|
+
</svg>`,
|
|
439
|
+
};
|
|
440
|
+
const Icon = ({ name, size = 24, className = "", style = {}, ...props }) => {
|
|
441
|
+
const svgContent = iconRegistry[name];
|
|
442
|
+
if (!svgContent) {
|
|
443
|
+
console.warn(`Icon "${String(name)}" not found in registry.\n` +
|
|
444
|
+
`Available icons: ${Object.keys(iconRegistry).join(", ")}`);
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
// Parse the SVG content
|
|
448
|
+
const parser = new DOMParser();
|
|
449
|
+
const svgDoc = parser.parseFromString(svgContent, "image/svg+xml");
|
|
450
|
+
const svgElement = svgDoc.querySelector("svg");
|
|
451
|
+
if (!svgElement) {
|
|
452
|
+
console.error(`Invalid SVG content for icon "${String(name)}"`);
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
// Extract viewBox attribute
|
|
456
|
+
const viewBox = svgElement.getAttribute("viewBox") || "0 0 24 24";
|
|
457
|
+
let innerHTML = svgElement.innerHTML;
|
|
458
|
+
// Replace hardcoded fill and stroke colors with currentColor
|
|
459
|
+
// This allows the icon color to be controlled via CSS color property
|
|
460
|
+
innerHTML = innerHTML
|
|
461
|
+
.replace(/fill="[^"]*"/g, 'fill="currentColor"')
|
|
462
|
+
.replace(/stroke="[^"]*"/g, 'stroke="currentColor"');
|
|
463
|
+
return (jsx("svg", { width: size, height: size, viewBox: viewBox, fill: "none", xmlns: "http://www.w3.org/2000/svg", className: className, style: style, ...props, dangerouslySetInnerHTML: { __html: innerHTML } }));
|
|
464
|
+
};
|
|
465
|
+
Icon.displayName = "Icon";
|
|
466
|
+
/**
|
|
467
|
+
* Get all available icon names from the registry
|
|
468
|
+
* @returns Array of registered icon names
|
|
469
|
+
*
|
|
470
|
+
* @example
|
|
471
|
+
* ```tsx
|
|
472
|
+
* const icons = getAvailableIcons();
|
|
473
|
+
* console.log(icons); // ['tick', 'check', ...]
|
|
474
|
+
* ```
|
|
475
|
+
*/
|
|
476
|
+
function getAvailableIcons() {
|
|
477
|
+
return Object.keys(iconRegistry);
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Check if an icon exists in the registry
|
|
481
|
+
* @param name - Icon name to check
|
|
482
|
+
* @returns true if the icon exists
|
|
483
|
+
*
|
|
484
|
+
* @example
|
|
485
|
+
* ```tsx
|
|
486
|
+
* if (hasIcon('tick')) {
|
|
487
|
+
* // Icon exists
|
|
488
|
+
* }
|
|
489
|
+
* ```
|
|
490
|
+
*/
|
|
491
|
+
function hasIcon(name) {
|
|
492
|
+
return name in iconRegistry;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
const checkboxVariants = cva("relative inline-flex items-center justify-center shrink-0 border transition-all cursor-pointer", {
|
|
496
|
+
variants: {
|
|
497
|
+
size: {
|
|
498
|
+
small: "w-[14px] h-[14px] rounded-small border-[1.5px]",
|
|
499
|
+
medium: "w-[16px] h-[16px] rounded-small border-[1.5px]",
|
|
500
|
+
large: "w-[20px] h-[20px] rounded-medium border-[2px]",
|
|
363
501
|
},
|
|
364
|
-
{
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
class: "font-size-600 leading-600 tracking-[0%] mb-0",
|
|
502
|
+
validationState: {
|
|
503
|
+
none: "",
|
|
504
|
+
error: "border-action-outline-negative-default hover:border-action-outline-negative-hover focus:ring-2 ring-action-outline-negative-faded-hover",
|
|
368
505
|
},
|
|
369
|
-
{
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
class: "font-size-500 leading-500 tracking-[0%] mb-0",
|
|
506
|
+
isChecked: {
|
|
507
|
+
true: "",
|
|
508
|
+
false: "",
|
|
373
509
|
},
|
|
374
|
-
{
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
class: "font-size-400 leading-400 tracking-[0%] mb-0",
|
|
510
|
+
isIndeterminate: {
|
|
511
|
+
true: "",
|
|
512
|
+
false: "",
|
|
378
513
|
},
|
|
379
|
-
{
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
class: "font-size-300 leading-300 tracking-[0%] mb-0",
|
|
514
|
+
isDisabled: {
|
|
515
|
+
true: "cursor-not-allowed opacity-60 border-action-outline-neutral-disabled bg-surface-fill-neutral-subtle",
|
|
516
|
+
false: "",
|
|
383
517
|
},
|
|
384
|
-
|
|
518
|
+
},
|
|
519
|
+
compoundVariants: [
|
|
520
|
+
// Unchecked state - none validation
|
|
385
521
|
{
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
522
|
+
isChecked: false,
|
|
523
|
+
validationState: "none",
|
|
524
|
+
isDisabled: false,
|
|
525
|
+
class: "border-action-outline-neutral-faded hover:bg-action-fill-neutral-faded hover:border-action-outline-neutral-faded",
|
|
389
526
|
},
|
|
527
|
+
// Checked state - none validation
|
|
390
528
|
{
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
529
|
+
isChecked: true,
|
|
530
|
+
validationState: "none",
|
|
531
|
+
isDisabled: false,
|
|
532
|
+
class: "bg-action-fill-primary-hover border-surface-outline-neutral-muted",
|
|
394
533
|
},
|
|
534
|
+
// Checked or Indeterminate state - error validation
|
|
395
535
|
{
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
536
|
+
isChecked: true,
|
|
537
|
+
validationState: "error",
|
|
538
|
+
isDisabled: false,
|
|
539
|
+
class: "bg-action-fill-negative-default border-action-fill-negative-default hover:bg-action-fill-negative-hover hover:border-action-fill-negative-hover",
|
|
399
540
|
},
|
|
541
|
+
// Indeterminate state - none validation
|
|
400
542
|
{
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
543
|
+
isIndeterminate: true,
|
|
544
|
+
validationState: "none",
|
|
545
|
+
isDisabled: false,
|
|
546
|
+
class: "bg-action-fill-primary-default border-action-fill-primary-default hover:bg-action-fill-primary-hover hover:border-action-fill-primary-hover",
|
|
404
547
|
},
|
|
405
|
-
//
|
|
548
|
+
// Indeterminate state - error validation (same as checked error)
|
|
406
549
|
{
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
550
|
+
isIndeterminate: true,
|
|
551
|
+
validationState: "error",
|
|
552
|
+
isDisabled: false,
|
|
553
|
+
class: "bg-action-fill-negative-default border-action-fill-negative-default hover:bg-action-fill-negative-hover hover:border-action-fill-negative-hover",
|
|
410
554
|
},
|
|
411
555
|
],
|
|
412
556
|
defaultVariants: {
|
|
413
|
-
variant: "body",
|
|
414
557
|
size: "medium",
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
558
|
+
validationState: "none",
|
|
559
|
+
isChecked: false,
|
|
560
|
+
isIndeterminate: false,
|
|
561
|
+
isDisabled: false,
|
|
418
562
|
},
|
|
419
563
|
});
|
|
420
|
-
const
|
|
421
|
-
const
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
564
|
+
const Checkbox = React.forwardRef(({ label, errorText, size = "medium", validationState = "none", isDisabled = false, isIndeterminate = false, showErrorText = true, containerClassName, labelClassName, className, checked, onChange, ...props }, ref) => {
|
|
565
|
+
const [internalChecked, setInternalChecked] = React.useState(false);
|
|
566
|
+
const [showRipple, setShowRipple] = React.useState(false);
|
|
567
|
+
const inputRef = React.useRef(null);
|
|
568
|
+
// Use forwarded ref or internal ref
|
|
569
|
+
React.useImperativeHandle(ref, () => inputRef.current);
|
|
570
|
+
const isChecked = checked !== undefined ? checked : internalChecked;
|
|
571
|
+
// Set indeterminate property on the input element
|
|
572
|
+
React.useEffect(() => {
|
|
573
|
+
if (inputRef.current) {
|
|
574
|
+
inputRef.current.indeterminate = isIndeterminate;
|
|
575
|
+
}
|
|
576
|
+
}, [isIndeterminate]);
|
|
577
|
+
const handleChange = (e) => {
|
|
578
|
+
if (onChange) {
|
|
579
|
+
onChange(e);
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
setInternalChecked(e.target.checked);
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
const triggerRipple = () => {
|
|
586
|
+
if (!isDisabled) {
|
|
587
|
+
setShowRipple(true);
|
|
588
|
+
setTimeout(() => {
|
|
589
|
+
setShowRipple(false);
|
|
590
|
+
}, 360); // Match animation duration (0.36s)
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
const handleContainerClick = () => {
|
|
594
|
+
if (!isDisabled && inputRef.current) {
|
|
595
|
+
// Only show ripple when checking (not unchecking)
|
|
596
|
+
const willBeChecked = !isChecked && !isIndeterminate;
|
|
597
|
+
if (willBeChecked) {
|
|
598
|
+
triggerRipple();
|
|
599
|
+
}
|
|
600
|
+
inputRef.current.click();
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
const handleKeyDown = (e) => {
|
|
604
|
+
if ((e.key === " " || e.key === "Enter") && !isDisabled) {
|
|
605
|
+
e.preventDefault();
|
|
606
|
+
// Only show ripple when checking (not unchecking)
|
|
607
|
+
const willBeChecked = !isChecked && !isIndeterminate;
|
|
608
|
+
if (willBeChecked) {
|
|
609
|
+
triggerRipple();
|
|
610
|
+
}
|
|
611
|
+
inputRef.current?.click();
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
// Size-based configurations
|
|
615
|
+
const sizeConfig = {
|
|
616
|
+
small: {
|
|
617
|
+
gap: "gap-2",
|
|
618
|
+
labelSize: "text-body-small-regular",
|
|
619
|
+
iconSize: 10,
|
|
620
|
+
},
|
|
621
|
+
medium: {
|
|
622
|
+
gap: "gap-2.5",
|
|
623
|
+
labelSize: "text-body-medium-regular",
|
|
624
|
+
iconSize: 12,
|
|
625
|
+
},
|
|
626
|
+
large: {
|
|
627
|
+
gap: "gap-3",
|
|
628
|
+
labelSize: "text-body-large-regular",
|
|
629
|
+
iconSize: 14,
|
|
630
|
+
},
|
|
631
|
+
};
|
|
632
|
+
const config = sizeConfig[size];
|
|
633
|
+
// Determine if we should show the error text
|
|
634
|
+
const shouldShowError = errorText && showErrorText;
|
|
635
|
+
return (jsxs("div", { className: cn("inline-flex flex-col", containerClassName), children: [jsxs("div", { className: cn("inline-flex items-center", config.gap, isDisabled ? "cursor-not-allowed" : "cursor-pointer"), onClick: handleContainerClick, onKeyDown: handleKeyDown, role: "checkbox", "aria-checked": isIndeterminate ? "mixed" : isChecked, "aria-disabled": isDisabled, tabIndex: isDisabled ? -1 : 0, children: [jsx("input", { ref: inputRef, type: "checkbox", className: "sr-only", checked: isChecked, onChange: handleChange, disabled: isDisabled, ...props }), jsxs("div", { className: "relative inline-flex shrink-0", children: [showRipple && (jsx("div", { className: cn("absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full pointer-events-none w-full h-full", validationState === "error"
|
|
636
|
+
? "bg-action-outline-negative-faded"
|
|
637
|
+
: "bg-action-outline-primary-faded"), style: {
|
|
638
|
+
animation: "var(--animate-checkbox-ripple)",
|
|
639
|
+
} })), jsxs("div", { className: cn(checkboxVariants({
|
|
640
|
+
size,
|
|
641
|
+
validationState,
|
|
642
|
+
isChecked: isChecked && !isIndeterminate,
|
|
643
|
+
isIndeterminate,
|
|
644
|
+
isDisabled,
|
|
645
|
+
}), className), children: [isChecked && !isIndeterminate && (jsx(Icon, { name: "tick", size: config.iconSize, className: "text-action-ink-on-primary-normal" })), isIndeterminate && (jsx("svg", { width: config.iconSize, height: config.iconSize, viewBox: "0 0 12 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: "text-action-ink-on-primary-normal", children: jsx("path", { d: "M3 6H9", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }))] })] }), label && (jsx("label", { className: cn(config.labelSize, "select-none inline-flex items-center", isDisabled
|
|
646
|
+
? "text-surface-ink-neutral-disabled"
|
|
647
|
+
: "text-surface-ink-neutral-normal", labelClassName), children: label }))] }), shouldShowError && (jsx(FormFooter, { helperText: errorText, validationState: "negative", size: size, isDisabled: isDisabled }))] }));
|
|
427
648
|
});
|
|
428
|
-
|
|
649
|
+
Checkbox.displayName = "Checkbox";
|
|
429
650
|
|
|
430
651
|
const tooltipVariants = cva("fixed z-50 bg-popup-fill-intense text-action-ink-on-primary-normal rounded-medium border border-popup-outline-subtle flex flex-col p-4 rounded-xlarge min-w-[200px] max-w-[300px] transition-opacity duration-200", {
|
|
431
652
|
variants: {
|
|
@@ -657,6 +878,112 @@ const Tooltip = React.forwardRef(({ children, heading, description, placement =
|
|
|
657
878
|
});
|
|
658
879
|
Tooltip.displayName = "Tooltip";
|
|
659
880
|
|
|
881
|
+
const FormHeader = React.forwardRef(({ label, size = "medium", isOptional = false, isRequired = false, infoHeading, infoDescription, linkText, linkHref, onLinkClick, htmlFor, className, labelClassName, linkClassName, }, ref) => {
|
|
882
|
+
// Size-based configurations
|
|
883
|
+
const sizeConfig = {
|
|
884
|
+
small: {
|
|
885
|
+
textSize: "xsmall",
|
|
886
|
+
iconSize: 12,
|
|
887
|
+
gap: "gap-1.5",
|
|
888
|
+
},
|
|
889
|
+
medium: {
|
|
890
|
+
textSize: "small",
|
|
891
|
+
iconSize: 14,
|
|
892
|
+
gap: "gap-2",
|
|
893
|
+
},
|
|
894
|
+
large: {
|
|
895
|
+
textSize: "medium",
|
|
896
|
+
iconSize: 16,
|
|
897
|
+
gap: "gap-2.5",
|
|
898
|
+
},
|
|
899
|
+
};
|
|
900
|
+
const config = sizeConfig[size];
|
|
901
|
+
return (jsxs("div", { ref: ref, className: cn("flex items-center justify-between px-1", config.gap, className), children: [jsxs("div", { className: cn("flex items-center", config.gap), children: [jsxs("label", { htmlFor: htmlFor, className: cn("flex items-center", labelClassName), children: [jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "semibold", color: "subtle", children: label }), isRequired && (jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "semibold", className: "text-feedback-ink-negative-subtle ml-0.5", children: "*" })), isOptional && (jsx(Text, { as: "span", variant: "body", size: config.textSize, weight: "regular", className: "text-surface-ink-neutral-muted ml-1", children: "(optional)" }))] }), infoDescription && (jsx(Tooltip, { description: infoDescription, heading: infoHeading, children: jsxs("svg", { width: config.iconSize, height: config.iconSize, viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: "text-surface-ink-neutral-muted cursor-help", children: [jsx("circle", { cx: "7", cy: "7", r: "6", stroke: "currentColor", strokeWidth: "1" }), jsx("path", { d: "M7 6V10M7 4.5V4", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round" })] }) }))] }), linkText && (jsx("a", { href: linkHref, onClick: onLinkClick, className: cn("text-surface-ink-primary-normal hover:text-surface-ink-primary-hover transition-colors cursor-pointer font-display font-semibold leading-tight shrink-0", size === "small" && "text-xs", size === "medium" && "text-xs", size === "large" && "text-sm", linkClassName), children: linkText }))] }));
|
|
902
|
+
});
|
|
903
|
+
FormHeader.displayName = "FormHeader";
|
|
904
|
+
|
|
905
|
+
const textAreaVariants = cva("relative flex flex-col border rounded-medium transition-all font-display font-size-100 leading-100", {
|
|
906
|
+
variants: {
|
|
907
|
+
size: {
|
|
908
|
+
small: "p-3 min-h-[56px] text-xs gap-2",
|
|
909
|
+
medium: "p-4 min-h-[56px] text-sm gap-2",
|
|
910
|
+
large: "p-5 min-h-[64px]text-base gap-3",
|
|
911
|
+
},
|
|
912
|
+
validationState: {
|
|
913
|
+
none: `
|
|
914
|
+
border-action-outline-neutral-default
|
|
915
|
+
hover:border-action-outline-primary-hover
|
|
916
|
+
focus-within:border-action-outline-primary-hover
|
|
917
|
+
focus-within:ring-2
|
|
918
|
+
ring-action-outline-primary-faded-hover`,
|
|
919
|
+
positive: `
|
|
920
|
+
border-action-outline-positive-default
|
|
921
|
+
hover:border-action-outline-positive-hover
|
|
922
|
+
focus-within:border-action-outline-positive-hover
|
|
923
|
+
focus-within:ring-2
|
|
924
|
+
ring-action-outline-positive-faded-hover`,
|
|
925
|
+
negative: `border-action-outline-negative-default
|
|
926
|
+
hover:border-action-outline-negative-hover
|
|
927
|
+
focus-within:border-action-outline-negative-hover
|
|
928
|
+
focus-within:ring-2
|
|
929
|
+
ring-action-outline-negative-faded-hover`,
|
|
930
|
+
},
|
|
931
|
+
isDisabled: {
|
|
932
|
+
true: `
|
|
933
|
+
border-[var(--border-width-thinner)]
|
|
934
|
+
hover:border-action-outline-neutral-disabled
|
|
935
|
+
border-action-outline-neutral-disabled
|
|
936
|
+
bg-surface-fill-neutral-intense cursor-not-allowed opacity-60`,
|
|
937
|
+
false: "bg-surface-fill-neutral-intense",
|
|
938
|
+
},
|
|
939
|
+
},
|
|
940
|
+
defaultVariants: {
|
|
941
|
+
size: "medium",
|
|
942
|
+
validationState: "none",
|
|
943
|
+
isDisabled: false,
|
|
944
|
+
},
|
|
945
|
+
});
|
|
946
|
+
const TextArea = React.forwardRef(({ label, helperText, errorText, successText, size = "medium", validationState = "none", isDisabled = false, isRequired = false, isOptional = false, maxChar, showCharCount = true, infoDescription, infoHeading, linkText, linkHref, onLinkClick, containerClassName, labelClassName, textAreaClassName, className, value, onChange, rows = 4, ...props }, ref) => {
|
|
947
|
+
const [internalValue, setInternalValue] = React.useState("");
|
|
948
|
+
const textAreaValue = value !== undefined ? value : internalValue;
|
|
949
|
+
const currentLength = String(textAreaValue).length;
|
|
950
|
+
const handleChange = (e) => {
|
|
951
|
+
const newValue = e.target.value;
|
|
952
|
+
// Prevent exceeding maxChar if specified
|
|
953
|
+
if (maxChar && newValue.length > maxChar) {
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
if (onChange) {
|
|
957
|
+
onChange(e);
|
|
958
|
+
}
|
|
959
|
+
else {
|
|
960
|
+
setInternalValue(newValue);
|
|
961
|
+
}
|
|
962
|
+
};
|
|
963
|
+
// Determine which helper text to show
|
|
964
|
+
const displayHelperText = errorText || successText || helperText;
|
|
965
|
+
const currentValidationState = errorText
|
|
966
|
+
? "negative"
|
|
967
|
+
: successText
|
|
968
|
+
? "positive"
|
|
969
|
+
: validationState;
|
|
970
|
+
// Check if we're approaching or at the limit
|
|
971
|
+
const isNearLimit = maxChar && currentLength >= maxChar * 0.9;
|
|
972
|
+
const isAtLimit = maxChar && currentLength >= maxChar;
|
|
973
|
+
return (jsxs("div", { className: cn("w-full flex flex-col gap-3", containerClassName), children: [label && (jsx(FormHeader, { label: label, size: size, isRequired: isRequired, isOptional: isOptional, infoHeading: infoHeading, infoDescription: infoDescription, linkText: linkText, linkHref: linkHref, onLinkClick: onLinkClick, htmlFor: props.id, className: "mb-2", labelClassName: labelClassName })), jsx("div", { className: cn(textAreaVariants({
|
|
974
|
+
size,
|
|
975
|
+
validationState: currentValidationState,
|
|
976
|
+
isDisabled,
|
|
977
|
+
}), className), children: jsx("textarea", { ref: ref, value: textAreaValue, onChange: handleChange, disabled: isDisabled, required: isRequired, rows: rows, className: cn("flex-1 bg-transparent border-none outline-none text-surface-ink-neutral-normal placeholder:text-surface-ink-neutral-muted disabled:cursor-not-allowed disabled:text-surface-ink-neutral-disabled font-display resize-none", size === "small" && "text-xs", size === "medium" && "text-sm", size === "large" && "text-base", textAreaClassName), ...props }) }), jsx(FormFooter, { helperText: displayHelperText, trailingText: maxChar && showCharCount ? `${currentLength}/${maxChar}` : undefined, validationState: currentValidationState === "none"
|
|
978
|
+
? "default"
|
|
979
|
+
: currentValidationState, size: size, isDisabled: isDisabled, className: "mt-1", trailingTextClassName: cn("transition-colors", isAtLimit
|
|
980
|
+
? "text-feedback-ink-negative-subtle"
|
|
981
|
+
: isNearLimit
|
|
982
|
+
? "text-feedback-ink-warning-subtle"
|
|
983
|
+
: "") })] }));
|
|
984
|
+
});
|
|
985
|
+
TextArea.displayName = "TextArea";
|
|
986
|
+
|
|
660
987
|
const textFieldVariants = cva("relative flex items-center gap-2 border rounded-medium transition-all font-display font-size-100 leading-100", {
|
|
661
988
|
variants: {
|
|
662
989
|
size: {
|
|
@@ -666,19 +993,17 @@ const textFieldVariants = cva("relative flex items-center gap-2 border rounded-m
|
|
|
666
993
|
},
|
|
667
994
|
validationState: {
|
|
668
995
|
none: `
|
|
669
|
-
border-action-outline-neutral-
|
|
996
|
+
border-action-outline-neutral-faded
|
|
670
997
|
hover:border-action-outline-primary-hover
|
|
671
998
|
focus-within:border-action-outline-primary-hover
|
|
672
999
|
focus-within:ring-2
|
|
673
1000
|
ring-action-outline-primary-faded-hover`,
|
|
674
1001
|
positive: `
|
|
675
1002
|
border-action-outline-positive-default
|
|
676
|
-
hover:border-action-outline-positive-hover
|
|
677
1003
|
focus-within:border-action-outline-positive-hover
|
|
678
1004
|
focus-within:ring-2
|
|
679
1005
|
ring-action-outline-positive-faded-hover`,
|
|
680
1006
|
negative: `border-action-outline-negative-default
|
|
681
|
-
hover:border-action-outline-negative-hover
|
|
682
1007
|
focus-within:border-action-outline-negative-hover
|
|
683
1008
|
focus-within:ring-2
|
|
684
1009
|
ring-action-outline-negative-faded-hover`,
|
|
@@ -698,7 +1023,7 @@ const textFieldVariants = cva("relative flex items-center gap-2 border rounded-m
|
|
|
698
1023
|
isDisabled: false,
|
|
699
1024
|
},
|
|
700
1025
|
});
|
|
701
|
-
const TextField = React.forwardRef(({ label, helperText, errorText, successText, size = "medium", validationState = "none", isDisabled = false, isRequired = false, prefix, suffix, showClearButton = false, infoDescription, infoHeading, onClear, containerClassName, labelClassName, inputClassName, className, value, onChange, ...props }, ref) => {
|
|
1026
|
+
const TextField = React.forwardRef(({ label, helperText, errorText, successText, size = "medium", validationState = "none", isDisabled = false, isRequired = false, isOptional = false, prefix, suffix, showClearButton = false, infoDescription, infoHeading, linkText, linkHref, onLinkClick, onClear, containerClassName, labelClassName, inputClassName, className, value, onChange, ...props }, ref) => {
|
|
702
1027
|
const [internalValue, setInternalValue] = React.useState("");
|
|
703
1028
|
const inputValue = value !== undefined ? value : internalValue;
|
|
704
1029
|
const hasValue = inputValue && String(inputValue).length > 0;
|
|
@@ -730,7 +1055,18 @@ const TextField = React.forwardRef(({ label, helperText, errorText, successText,
|
|
|
730
1055
|
: successText
|
|
731
1056
|
? "positive"
|
|
732
1057
|
: validationState;
|
|
733
|
-
|
|
1058
|
+
const sizeConfig = {
|
|
1059
|
+
small: {
|
|
1060
|
+
gap: "gap-2",
|
|
1061
|
+
},
|
|
1062
|
+
medium: {
|
|
1063
|
+
gap: "gap-2",
|
|
1064
|
+
},
|
|
1065
|
+
large: {
|
|
1066
|
+
gap: "gap-3",
|
|
1067
|
+
},
|
|
1068
|
+
};
|
|
1069
|
+
return (jsxs("div", { className: cn("w-full flex flex-col", sizeConfig[size].gap, containerClassName), children: [label && (jsx(FormHeader, { label: label, size: size, isRequired: isRequired, isOptional: isOptional, infoHeading: infoHeading, infoDescription: infoDescription, linkText: linkText, linkHref: linkHref, onLinkClick: onLinkClick, htmlFor: props.id, className: "mb-2", labelClassName: labelClassName })), jsxs("div", { className: cn(textFieldVariants({
|
|
734
1070
|
size,
|
|
735
1071
|
validationState: currentValidationState,
|
|
736
1072
|
isDisabled,
|
|
@@ -746,17 +1082,11 @@ const TextField = React.forwardRef(({ label, helperText, errorText, successText,
|
|
|
746
1082
|
? "text-feedback-ink-positive-intense"
|
|
747
1083
|
: currentValidationState === "negative"
|
|
748
1084
|
? "text-feedback-ink-negative-subtle"
|
|
749
|
-
: "text-surface-ink-neutral-muted"), children: suffix }))] }),
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
? "default"
|
|
753
|
-
: isDisabled
|
|
754
|
-
? "disabled"
|
|
755
|
-
: "subtle", className: cn("italic font-size-100 leading-100", currentValidationState === "positive" &&
|
|
756
|
-
"text-feedback-ink-positive-intense", currentValidationState === "negative" &&
|
|
757
|
-
"text-feedback-ink-negative-subtle"), children: displayHelperText })] }))] }));
|
|
1085
|
+
: "text-surface-ink-neutral-muted"), children: suffix }))] }), jsx(FormFooter, { helperText: displayHelperText, validationState: currentValidationState === "none"
|
|
1086
|
+
? "default"
|
|
1087
|
+
: currentValidationState, size: size, isDisabled: isDisabled, className: "mt-1" })] }));
|
|
758
1088
|
});
|
|
759
1089
|
TextField.displayName = "TextField";
|
|
760
1090
|
|
|
761
|
-
export { Button, Text, TextField, Tooltip, buttonVariants, cn,
|
|
1091
|
+
export { Button, Checkbox, FormFooter, FormHeader, Icon, Text, TextArea, TextField, Tooltip, buttonVariants, checkboxVariants, cn, getAvailableIcons, hasIcon, iconRegistry, textAreaVariants, textFieldVariants, tooltipVariants };
|
|
762
1092
|
//# sourceMappingURL=index.esm.js.map
|