mado-ui 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/index.css +69 -14
- package/dist/components/button.d.ts +74 -29
- package/dist/components/details.d.ts +5 -7
- package/dist/components/drop-down.d.ts +4 -3
- package/dist/components/form/fieldset.d.ts +35 -7
- package/dist/components/form/index.d.ts +5 -6
- package/dist/components/form/input/date/index.d.ts +36 -0
- package/dist/components/form/input/index.d.ts +78 -12
- package/dist/components/form/submit-button.d.ts +3 -4
- package/dist/components/form/textarea.d.ts +1 -1
- package/dist/components/ghost.d.ts +1 -1
- package/dist/components/heading.d.ts +1 -1
- package/dist/components/iframe.d.ts +15 -0
- package/dist/components/index.d.ts +10 -11
- package/dist/components/link.d.ts +62 -16
- package/dist/components/modal.d.ts +1 -1
- package/dist/components/time.d.ts +1 -1
- package/dist/components/tooltip.d.ts +1 -1
- package/dist/components.esm.js +612 -138
- package/dist/components.esm.js.map +1 -1
- package/dist/components.js +613 -135
- package/dist/components.js.map +1 -1
- package/dist/hooks/index.d.ts +4 -3
- package/dist/hooks/use-fieldset-context.d.ts +22 -0
- package/dist/hooks/use-form-context.d.ts +18 -10
- package/dist/hooks.esm.js +99 -5
- package/dist/hooks.esm.js.map +1 -1
- package/dist/hooks.js +100 -3
- package/dist/hooks.js.map +1 -1
- package/dist/icons/3-people.d.ts +2 -2
- package/dist/icons/3-rectangles-desktop-fill.d.ts +2 -2
- package/dist/icons/3-rectangles-desktop.d.ts +2 -2
- package/dist/icons/airplane.d.ts +2 -2
- package/dist/icons/arrow-triangle-2-circlepath-circle-fill.d.ts +2 -2
- package/dist/icons/arrow-triangle-2-circlepath-circle.d.ts +2 -2
- package/dist/icons/bag-fill.d.ts +2 -2
- package/dist/icons/banknote.d.ts +2 -2
- package/dist/icons/bell-fill.d.ts +2 -2
- package/dist/icons/bolt-car.d.ts +2 -2
- package/dist/icons/bolt-fill.d.ts +2 -2
- package/dist/icons/bolt-ring-closed.d.ts +2 -2
- package/dist/icons/bolt-trianglebadge-exclamationmark.d.ts +2 -2
- package/dist/icons/book-fill.d.ts +2 -2
- package/dist/icons/bookmark-fill.d.ts +2 -2
- package/dist/icons/briefcase-fill.d.ts +2 -2
- package/dist/icons/bubble-left-fill.d.ts +2 -2
- package/dist/icons/building-2-fill.d.ts +2 -2
- package/dist/icons/calendar.d.ts +2 -2
- package/dist/icons/camera-fill.d.ts +2 -2
- package/dist/icons/car-fill.d.ts +2 -2
- package/dist/icons/cart-fill.d.ts +2 -2
- package/dist/icons/chart-bar-doc-horizontal.d.ts +2 -2
- package/dist/icons/checkmark-seal.d.ts +2 -2
- package/dist/icons/checkmark.d.ts +2 -2
- package/dist/icons/chevron-down.d.ts +2 -2
- package/dist/icons/chevron-left-forwardslash-chevron-right.d.ts +2 -2
- package/dist/icons/chevron-left.d.ts +2 -2
- package/dist/icons/chevron-right.d.ts +2 -2
- package/dist/icons/chevron-up-chevron-down.d.ts +2 -2
- package/dist/icons/circle-fill.d.ts +2 -2
- package/dist/icons/clock-badge-checkmark.d.ts +2 -2
- package/dist/icons/clock-fill.d.ts +2 -2
- package/dist/icons/cloud-fill.d.ts +2 -2
- package/dist/icons/cube-fill.d.ts +2 -2
- package/dist/icons/curve-point-left.d.ts +2 -2
- package/dist/icons/dial-high.d.ts +2 -2
- package/dist/icons/doc-fill.d.ts +2 -2
- package/dist/icons/doc-on-clipboard.d.ts +2 -2
- package/dist/icons/doc-on-doc-fill.d.ts +2 -2
- package/dist/icons/doc-on-doc.d.ts +2 -2
- package/dist/icons/doc-text-magnifyingglass.d.ts +2 -2
- package/dist/icons/dollar-sign.d.ts +2 -2
- package/dist/icons/ellipsis-circle-fill.d.ts +2 -2
- package/dist/icons/ellipsis-circle.d.ts +2 -2
- package/dist/icons/envelope-fill.d.ts +2 -2
- package/dist/icons/envelope.d.ts +2 -2
- package/dist/icons/exclamationmark-octagon.d.ts +2 -2
- package/dist/icons/eye.d.ts +2 -2
- package/dist/icons/figure-water-fitness.d.ts +2 -2
- package/dist/icons/flag-fill.d.ts +2 -2
- package/dist/icons/flame-fill.d.ts +2 -2
- package/dist/icons/folder-fill.d.ts +2 -2
- package/dist/icons/folder.d.ts +2 -2
- package/dist/icons/gearshape-fill.d.ts +2 -2
- package/dist/icons/gearshape.d.ts +2 -2
- package/dist/icons/gift-fill.d.ts +2 -2
- package/dist/icons/globe-americas-fill.d.ts +2 -2
- package/dist/icons/hare-fill.d.ts +2 -2
- package/dist/icons/house-deskclock.d.ts +2 -2
- package/dist/icons/house-fill.d.ts +2 -2
- package/dist/icons/house.d.ts +2 -2
- package/dist/icons/iphone-house.d.ts +2 -2
- package/dist/icons/light-ribbon.d.ts +2 -2
- package/dist/icons/lightbulb-fill.d.ts +2 -2
- package/dist/icons/lightbulb-led.d.ts +2 -2
- package/dist/icons/list-bullet-clipboard-fill.d.ts +2 -2
- package/dist/icons/magnifyingglass.d.ts +2 -2
- package/dist/icons/map-pin-ellipse.d.ts +2 -2
- package/dist/icons/minus-plus-batterblock.d.ts +2 -2
- package/dist/icons/network-shield.d.ts +2 -2
- package/dist/icons/network.d.ts +2 -2
- package/dist/icons/newspaper-fill.d.ts +2 -2
- package/dist/icons/number.d.ts +2 -2
- package/dist/icons/paperplane-fill.d.ts +2 -2
- package/dist/icons/person-crop-square.d.ts +2 -2
- package/dist/icons/person-fill-questionmark.d.ts +2 -2
- package/dist/icons/person-fill.d.ts +2 -2
- package/dist/icons/person.d.ts +2 -2
- package/dist/icons/phone-arrow-up-right.d.ts +2 -2
- package/dist/icons/phone-fill.d.ts +2 -2
- package/dist/icons/phone.d.ts +2 -2
- package/dist/icons/play-rectangle-fill.d.ts +2 -2
- package/dist/icons/plus.d.ts +2 -2
- package/dist/icons/qrcode.d.ts +2 -2
- package/dist/icons/rectangle-portrait-and-arrow-left-fill.d.ts +2 -2
- package/dist/icons/rectangle-portrait-and-arrow-left.d.ts +2 -2
- package/dist/icons/sensor.d.ts +2 -2
- package/dist/icons/signature.d.ts +2 -2
- package/dist/icons/solar-panel.d.ts +2 -2
- package/dist/icons/square-and-arrow-down-fill.d.ts +2 -2
- package/dist/icons/square-and-arrow-down.d.ts +2 -2
- package/dist/icons/square-and-arrow-up-fill.d.ts +2 -2
- package/dist/icons/square-and-arrow-up.d.ts +2 -2
- package/dist/icons/square-and-pencil-fill.d.ts +2 -2
- package/dist/icons/square-and-pencil.d.ts +2 -2
- package/dist/icons/text-bubble.d.ts +2 -2
- package/dist/icons/trash-fill.d.ts +2 -2
- package/dist/icons/trash.d.ts +2 -2
- package/dist/icons/tree.d.ts +2 -2
- package/dist/icons/umbrella-fill.d.ts +2 -2
- package/dist/icons/xmark.d.ts +2 -2
- package/dist/icons.esm.js.map +1 -1
- package/dist/icons.js.map +1 -1
- package/dist/index.esm.js +612 -138
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +613 -135
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +1 -2
- package/dist/types/utils.d.ts +20 -0
- package/dist/utils/get-date.d.ts +17 -0
- package/dist/utils/index.d.ts +8 -9
- package/dist/utils/string-manipulation.d.ts +38 -3
- package/dist/utils/tw-sort.d.ts +1 -1
- package/dist/utils.esm.js +112 -21
- package/dist/utils.esm.js.map +1 -1
- package/dist/utils.js +113 -20
- package/dist/utils.js.map +1 -1
- package/package.json +4 -4
package/dist/components.js
CHANGED
|
@@ -208,6 +208,9 @@ function getMonth(month = d) {
|
|
|
208
208
|
formattedMonth = `0${formattedMonth}`;
|
|
209
209
|
return formattedMonth;
|
|
210
210
|
}
|
|
211
|
+
function getMonthIndexFromName(name) {
|
|
212
|
+
return monthNamesList.findIndex(monthName => monthName === name);
|
|
213
|
+
}
|
|
211
214
|
/**
|
|
212
215
|
* ### Get Month Name
|
|
213
216
|
* - Returns the name of the specified month
|
|
@@ -233,6 +236,30 @@ function getSeconds(seconds = d) {
|
|
|
233
236
|
formattedSeconds = `0${formattedSeconds}`;
|
|
234
237
|
return formattedSeconds;
|
|
235
238
|
}
|
|
239
|
+
/**
|
|
240
|
+
* ### Get User Readable Date
|
|
241
|
+
* - Returns a string of the current date in a user-friendly way
|
|
242
|
+
* - Includes `'Yesterday'`, '`Today'`, and `'Tomorrow'`
|
|
243
|
+
* @param date (default: `new Date()`)
|
|
244
|
+
* @returns {'Today'|'Tomorrow'|'Yesterday'|string} `'weekday, month day, year'` | `'Yesterday'` | `'Today'` | `'Tomorrow'`
|
|
245
|
+
*/
|
|
246
|
+
function getUserReadableDate(date = d) {
|
|
247
|
+
const dateTime = date.getTime();
|
|
248
|
+
const today = new Date(), isToday = dateTime === today.getTime();
|
|
249
|
+
if (isToday)
|
|
250
|
+
return 'Today';
|
|
251
|
+
const yesterday = new Date(today.getDate() - 1), isYesterday = dateTime === yesterday.getTime();
|
|
252
|
+
if (isYesterday)
|
|
253
|
+
return 'Yesterday';
|
|
254
|
+
const tomorrow = new Date(today.getDate() + 1), isTomorrow = dateTime === tomorrow.getTime();
|
|
255
|
+
if (isTomorrow)
|
|
256
|
+
return 'Tomorrow';
|
|
257
|
+
const thisYear = today.getFullYear(), isSameYear = date.getFullYear() === thisYear;
|
|
258
|
+
const fullDateString = toFullDateString(date, {
|
|
259
|
+
year: !isSameYear,
|
|
260
|
+
});
|
|
261
|
+
return fullDateString;
|
|
262
|
+
}
|
|
236
263
|
/**
|
|
237
264
|
* ### Get Weekday Name
|
|
238
265
|
* - Returns the weekday name of the specified day
|
|
@@ -245,6 +272,45 @@ function getWeekdayName(weekday = d) {
|
|
|
245
272
|
// Return the name of the day of the week
|
|
246
273
|
return weekdayNamesList[weekday.getDay()];
|
|
247
274
|
}
|
|
275
|
+
/**
|
|
276
|
+
* ### To Full Date String
|
|
277
|
+
* - Returns a formatted string to display the date
|
|
278
|
+
* @param {Date} date (default: `new Date()`)
|
|
279
|
+
* @param {ToFullDateStringOptionsProps} options Change how to display the weekday, month name, day of the month, and year.
|
|
280
|
+
* @returns {string} '`weekday`, `month` `day`, `year`'
|
|
281
|
+
*/
|
|
282
|
+
function toFullDateString(date = d, options) {
|
|
283
|
+
let weekdayName = getWeekdayName(date), monthName = getMonthName(date), dayOfMonth = date.getDate(), year = date.getFullYear().toString();
|
|
284
|
+
if (options) {
|
|
285
|
+
const includesDay = options.day !== false, includesMonth = options.month !== false, includesYear = options.year !== false;
|
|
286
|
+
{
|
|
287
|
+
weekdayName = weekdayName.slice(0, 3);
|
|
288
|
+
if (includesMonth || includesDay || includesYear)
|
|
289
|
+
weekdayName += ', ';
|
|
290
|
+
}
|
|
291
|
+
if (includesMonth) {
|
|
292
|
+
if (options.month === 'code')
|
|
293
|
+
monthName = monthName.slice(0, 3);
|
|
294
|
+
if (includesDay)
|
|
295
|
+
monthName += ' ';
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
monthName = '';
|
|
299
|
+
}
|
|
300
|
+
if (!includesDay)
|
|
301
|
+
dayOfMonth = '';
|
|
302
|
+
if (includesYear) {
|
|
303
|
+
if (options.year === 'code')
|
|
304
|
+
year = year.slice(-2);
|
|
305
|
+
if (includesMonth || includesDay)
|
|
306
|
+
year = ', ' + year;
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
year = '';
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return weekdayName + monthName + dayOfMonth + year;
|
|
313
|
+
}
|
|
248
314
|
|
|
249
315
|
function findComponentByType(children, componentType) {
|
|
250
316
|
const childrenArray = React.Children.toArray(children);
|
|
@@ -293,25 +359,97 @@ function isPhoneNumber(tel) {
|
|
|
293
359
|
/**
|
|
294
360
|
* # Format Phone Number
|
|
295
361
|
* Converts any string containing at least 10 numbers to a formatted phone number
|
|
296
|
-
* @param {string}
|
|
297
|
-
* @
|
|
362
|
+
* @param {string} phoneNumber
|
|
363
|
+
* @param options
|
|
364
|
+
* @property {string} `countryCode`
|
|
365
|
+
* @property {'continuous' | 'dot' | 'hyphenated' | 'none' | 'space' | 'standard'} `format`
|
|
366
|
+
*
|
|
367
|
+
* Input: a555b555c5555d
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* format: 'continuous'
|
|
371
|
+
* countryCode: '1'
|
|
372
|
+
* returns: +1 5555555555
|
|
373
|
+
*
|
|
374
|
+
* @example
|
|
375
|
+
* format: 'dot'
|
|
376
|
+
* returns: 555.555.5555
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* format: 'hyphenated'
|
|
380
|
+
* returns: 555-555-5555
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* format: 'none'
|
|
384
|
+
* countryCode: '1'
|
|
385
|
+
* returns: +1 a555b555c5555d
|
|
386
|
+
*
|
|
387
|
+
* @example
|
|
388
|
+
* format: 'space'
|
|
389
|
+
* returns: 555 555 5555
|
|
390
|
+
*
|
|
391
|
+
* @example
|
|
392
|
+
* format: 'standard' (default)
|
|
393
|
+
* returns: (555) 555-5555
|
|
394
|
+
*
|
|
395
|
+
* @returns {string} string formatted
|
|
298
396
|
*/
|
|
299
|
-
function formatPhoneNumber(
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
397
|
+
function formatPhoneNumber(phoneNumber, options) {
|
|
398
|
+
const format = options?.format || 'standard';
|
|
399
|
+
if (format !== 'none')
|
|
400
|
+
phoneNumber = phoneNumber.replace(/\D/g, '').slice(-10);
|
|
401
|
+
switch (format) {
|
|
402
|
+
case 'dot':
|
|
403
|
+
phoneNumber = phoneNumber
|
|
404
|
+
.split('')
|
|
405
|
+
.map((char, index) => {
|
|
406
|
+
if (index === 2)
|
|
407
|
+
return `${char}.`;
|
|
408
|
+
if (index === 5)
|
|
409
|
+
return `${char}.`;
|
|
410
|
+
return char;
|
|
411
|
+
})
|
|
412
|
+
.join('');
|
|
413
|
+
break;
|
|
414
|
+
case 'hyphenated':
|
|
415
|
+
phoneNumber = phoneNumber
|
|
416
|
+
.split('')
|
|
417
|
+
.map((char, index) => {
|
|
418
|
+
if (index === 2)
|
|
419
|
+
return `${char}-`;
|
|
420
|
+
if (index === 5)
|
|
421
|
+
return `${char}-`;
|
|
422
|
+
return char;
|
|
423
|
+
})
|
|
424
|
+
.join('');
|
|
425
|
+
break;
|
|
426
|
+
case 'space':
|
|
427
|
+
phoneNumber = phoneNumber
|
|
428
|
+
.split('')
|
|
429
|
+
.map((char, index) => {
|
|
430
|
+
if (index === 2)
|
|
431
|
+
return `${char} `;
|
|
432
|
+
if (index === 5)
|
|
433
|
+
return `${char} `;
|
|
434
|
+
return char;
|
|
435
|
+
})
|
|
436
|
+
.join('');
|
|
437
|
+
break;
|
|
438
|
+
case 'standard':
|
|
439
|
+
phoneNumber = phoneNumber
|
|
440
|
+
.split('')
|
|
441
|
+
.map((char, index) => {
|
|
442
|
+
if (index === 0)
|
|
443
|
+
return `(${char}`;
|
|
444
|
+
if (index === 2)
|
|
445
|
+
return `${char}) `;
|
|
446
|
+
if (index === 5)
|
|
447
|
+
return `${char}-`;
|
|
448
|
+
return char;
|
|
449
|
+
})
|
|
450
|
+
.join('');
|
|
451
|
+
}
|
|
452
|
+
return `${options?.countryCode ? `+${options?.countryCode} ` : ''}` + phoneNumber;
|
|
315
453
|
}
|
|
316
454
|
/**
|
|
317
455
|
* # To Lower Case
|
|
@@ -366,7 +504,7 @@ const lineLiftClasses = tailwindMerge.twJoin([
|
|
|
366
504
|
scaleYClasses,
|
|
367
505
|
'after:origin-bottom after:translate-y-1 after:scale-x-75 active:after:translate-y-0 active:after:scale-x-100 pointer-fine:hover:after:translate-y-0 pointer-fine:hover:after:scale-x-100',
|
|
368
506
|
]);
|
|
369
|
-
const fillClasses = tailwindMerge.twJoin(baseClasses, 'whitespace-nowrap transition-[
|
|
507
|
+
const fillClasses = tailwindMerge.twJoin(baseClasses, 'whitespace-nowrap transition-[transform,color] after:top-1/2 after:h-[calc(100%+0.05rem)] after:w-[calc(100%+0.25rem)] after:-translate-y-1/2 after:rounded after:ease-exponential active:text-zinc-50 pointer-fine:hover:text-zinc-50');
|
|
370
508
|
// Define theme-specific fill color transition classes
|
|
371
509
|
const getFillColorTransitionClasses = (theme = 'blue', customTheme) => {
|
|
372
510
|
let fillColorTransitionClasses = tailwindMerge.twJoin(fillClasses, 'transition-transform after:bg-(--theme-color)');
|
|
@@ -419,7 +557,7 @@ const getFillColorTransitionClasses = (theme = 'blue', customTheme) => {
|
|
|
419
557
|
};
|
|
420
558
|
// Define theme-specific fill center classes
|
|
421
559
|
const getFillCenterClasses = (theme = 'blue', customTheme) => {
|
|
422
|
-
let fillCenterColorClasses = tailwindMerge.twJoin(fillClasses, 'after:scale-x-50 after:scale-y-[0.25] after:bg-(--theme-color)/0 after:transition-[
|
|
560
|
+
let fillCenterColorClasses = tailwindMerge.twJoin(fillClasses, 'after:scale-x-50 after:scale-y-[0.25] after:bg-(--theme-color)/0 after:transition-[transform,background-color] active:after:scale-x-100 active:after:scale-y-100 active:after:bg-(--theme-color) pointer-fine:hover:after:scale-x-100 pointer-fine:hover:after:scale-y-100 pointer-fine:hover:after:bg-(--theme-color)');
|
|
423
561
|
switch (theme) {
|
|
424
562
|
case 'blue':
|
|
425
563
|
fillCenterColorClasses = tailwindMerge.twJoin(fillCenterColorClasses, 'after:[--theme-color:var(--color-ui-blue)]');
|
|
@@ -478,7 +616,7 @@ const multilineLineCenterClasses = tailwindMerge.twJoin([multilineXClasses, 'bg-
|
|
|
478
616
|
const multilineLineLiftClasses = tailwindMerge.twJoin(multilineLineClasses, 'bg-[size:auto_0px] focus-visible:bg-[size:auto_2px] active:bg-[size:auto_2px] pointer-fine:hover:bg-[size:auto_2px]');
|
|
479
617
|
const multilineFillBaseClasses = tailwindMerge.twJoin(multilineBaseClasses, 'rounded px-0.5 py-0.75 focus-visible:text-zinc-50 active:text-zinc-50 pointer-fine:hover:text-zinc-50');
|
|
480
618
|
const getMultilineFillColorClasses = (theme = 'blue', customTheme) => {
|
|
481
|
-
let multilineFillColorClasses = tailwindMerge.twJoin(multilineFillBaseClasses, 'from-(--theme-color) to-(--theme-color) transition-[background-
|
|
619
|
+
let multilineFillColorClasses = tailwindMerge.twJoin(multilineFillBaseClasses, 'from-(--theme-color) to-(--theme-color) transition-[background-size,color]');
|
|
482
620
|
switch (theme) {
|
|
483
621
|
case 'blue':
|
|
484
622
|
multilineFillColorClasses = tailwindMerge.twJoin(multilineFillColorClasses, '[--theme-color:var(--color-ui-blue)]');
|
|
@@ -527,7 +665,7 @@ const getMultilineFillColorClasses = (theme = 'blue', customTheme) => {
|
|
|
527
665
|
return multilineFillColorClasses;
|
|
528
666
|
};
|
|
529
667
|
const getMultilineFillClasses = (theme = 'blue', customTheme) => {
|
|
530
|
-
let multilineFillColorClasses = tailwindMerge.twJoin(multilineFillBaseClasses, 'from-(--theme-color)/0 to-(--theme-color)/0 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-
|
|
668
|
+
let multilineFillColorClasses = tailwindMerge.twJoin(multilineFillBaseClasses, 'from-(--theme-color)/0 to-(--theme-color)/0 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size,background-image,color] focus-visible:from-(--theme-color) focus-visible:to-(--theme-color) focus-visible:bg-[size:100%_100%] active:from-(--theme-color) active:to-(--theme-color) active:bg-[size:100%_100%] contrast-more:from-(--theme-color)/0 pointer-fine:hover:from-(--theme-color) pointer-fine:hover:to-(--theme-color) pointer-fine:hover:bg-[size:100%_100%]');
|
|
531
669
|
switch (theme) {
|
|
532
670
|
case 'blue':
|
|
533
671
|
multilineFillColorClasses = tailwindMerge.twJoin(multilineFillColorClasses, '[--theme-color:var(--color-ui-blue)]');
|
|
@@ -667,6 +805,71 @@ function Link({ as, className, customTheme, theme = 'blue', type, ...props }) {
|
|
|
667
805
|
const LinkElement = as || Anchor;
|
|
668
806
|
return jsxRuntime.jsx(LinkElement, { ...props, className: twMerge(linkClasses, className) });
|
|
669
807
|
}
|
|
808
|
+
/**
|
|
809
|
+
* # createLink
|
|
810
|
+
* Creates an extended Link component with additional theme options.
|
|
811
|
+
*
|
|
812
|
+
* @param config - Configuration object defining new themes and defaults
|
|
813
|
+
* @returns A new Link component with extended theme support
|
|
814
|
+
*
|
|
815
|
+
* @example
|
|
816
|
+
* ```tsx
|
|
817
|
+
* const MyLink = createLink({
|
|
818
|
+
* as: NextLink,
|
|
819
|
+
* className: 'font-bold',
|
|
820
|
+
* type: 'fill',
|
|
821
|
+
* theme: {
|
|
822
|
+
* primary: {
|
|
823
|
+
* customTheme: {
|
|
824
|
+
* fill: 'after:[--theme-color:var(--color-primary-500)]',
|
|
825
|
+
* multilineFill: '[--theme-color:var(--color-primary-500)]'
|
|
826
|
+
* },
|
|
827
|
+
* className: 'text-white'
|
|
828
|
+
* }
|
|
829
|
+
* }
|
|
830
|
+
* })
|
|
831
|
+
* ```
|
|
832
|
+
*/
|
|
833
|
+
function createLink(config) {
|
|
834
|
+
return function ExtendedLink({ theme, className, customTheme, type, as, ...props }) {
|
|
835
|
+
const finalType = type !== undefined ? type : config.type, finalTheme = theme !== undefined ? theme : config.defaultTheme;
|
|
836
|
+
const configClassName = config.className;
|
|
837
|
+
const shouldOverrideElement = !Boolean(as) && Boolean(config.as);
|
|
838
|
+
const linkProps = {
|
|
839
|
+
...props,
|
|
840
|
+
className: undefined,
|
|
841
|
+
customTheme: undefined,
|
|
842
|
+
type: finalType,
|
|
843
|
+
};
|
|
844
|
+
if (shouldOverrideElement) {
|
|
845
|
+
linkProps.as = config.as;
|
|
846
|
+
}
|
|
847
|
+
else if (as) {
|
|
848
|
+
linkProps.as = as;
|
|
849
|
+
}
|
|
850
|
+
if (finalTheme && typeof finalTheme === 'string' && config.theme && finalTheme in config.theme) {
|
|
851
|
+
const extendedTheme = config.theme[finalTheme];
|
|
852
|
+
if (customTheme)
|
|
853
|
+
return (jsxRuntime.jsx(Link, { ...linkProps, theme: 'custom', customTheme: customTheme, className: twMerge(configClassName, extendedTheme.className, className) }));
|
|
854
|
+
let resolvedCustomTheme;
|
|
855
|
+
if (extendedTheme.customTheme.themeColor) {
|
|
856
|
+
const isMultilineType = finalType ? finalType.includes('multiline') : false;
|
|
857
|
+
resolvedCustomTheme = {
|
|
858
|
+
themeColor: isMultilineType
|
|
859
|
+
? extendedTheme.customTheme.themeColor.multilineFill
|
|
860
|
+
: extendedTheme.customTheme.themeColor.fill,
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
else {
|
|
864
|
+
resolvedCustomTheme = {
|
|
865
|
+
classes: extendedTheme.customTheme.classes,
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
return (jsxRuntime.jsx(Link, { ...linkProps, theme: 'custom', customTheme: resolvedCustomTheme, className: twMerge(configClassName, extendedTheme.className, className) }));
|
|
869
|
+
}
|
|
870
|
+
return (jsxRuntime.jsx(Link, { ...linkProps, theme: finalTheme, className: twMerge(configClassName, className), customTheme: customTheme }));
|
|
871
|
+
};
|
|
872
|
+
}
|
|
670
873
|
|
|
671
874
|
/**
|
|
672
875
|
* # Button
|
|
@@ -752,9 +955,76 @@ function Button({ className, customTheme, gradient = false, padding = 'md', roun
|
|
|
752
955
|
themeClasses,
|
|
753
956
|
className,
|
|
754
957
|
]);
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
return jsxRuntime.jsx(
|
|
958
|
+
if ('href' in props && !props.as && props.href)
|
|
959
|
+
return jsxRuntime.jsx(react.Button, { ...props, as: Anchor, className: buttonClasses });
|
|
960
|
+
return jsxRuntime.jsx(react.Button, { ...props, className: buttonClasses });
|
|
961
|
+
}
|
|
962
|
+
/**
|
|
963
|
+
* # createButton
|
|
964
|
+
* Creates an extended Button component with additional theme options.
|
|
965
|
+
*
|
|
966
|
+
* @param extendedThemes - Configuration object defining new themes
|
|
967
|
+
* @returns A new Button component with extended theme support
|
|
968
|
+
*
|
|
969
|
+
* @example
|
|
970
|
+
* ```tsx
|
|
971
|
+
* const MyButton = createButton({
|
|
972
|
+
* as: {
|
|
973
|
+
* default: 'div',
|
|
974
|
+
* link: NextLink
|
|
975
|
+
* },
|
|
976
|
+
* className: 'min-w-64',
|
|
977
|
+
* padding: 'sm',
|
|
978
|
+
* rounded: 'full',
|
|
979
|
+
* theme: {
|
|
980
|
+
* primary: {
|
|
981
|
+
* customTheme: { themeColor: '[--theme-color:var(--color-primary-500)]' },
|
|
982
|
+
* className: 'text-white'
|
|
983
|
+
* }
|
|
984
|
+
* }
|
|
985
|
+
* })
|
|
986
|
+
* ```
|
|
987
|
+
*/
|
|
988
|
+
function createButton(config) {
|
|
989
|
+
return function ExtendedButton({ theme, className, customTheme, gradient, padding, rounded, as, ...props }) {
|
|
990
|
+
const finalGradient = gradient !== undefined ? gradient : config.gradient, finalPadding = padding !== undefined ? padding : config.padding, finalRounded = rounded !== undefined ? rounded : config.rounded, finalTheme = theme !== undefined ? theme : config.defaultTheme;
|
|
991
|
+
const configClassName = config.className;
|
|
992
|
+
const shouldOverrideElement = !Boolean(as) && Boolean(config.as);
|
|
993
|
+
const getOverrideElement = () => {
|
|
994
|
+
if (!config.as)
|
|
995
|
+
return undefined;
|
|
996
|
+
if (typeof config.as === 'function' || typeof config.as === 'string')
|
|
997
|
+
return config.as;
|
|
998
|
+
const hasHref = 'href' in props && props.href;
|
|
999
|
+
if (hasHref && config.as.link) {
|
|
1000
|
+
return config.as.link;
|
|
1001
|
+
}
|
|
1002
|
+
else if (!hasHref && config.as.default) {
|
|
1003
|
+
return config.as.default;
|
|
1004
|
+
}
|
|
1005
|
+
return undefined;
|
|
1006
|
+
};
|
|
1007
|
+
const buttonProps = {
|
|
1008
|
+
...props,
|
|
1009
|
+
className: undefined,
|
|
1010
|
+
customTheme: undefined,
|
|
1011
|
+
gradient: finalGradient,
|
|
1012
|
+
padding: finalPadding,
|
|
1013
|
+
rounded: finalRounded,
|
|
1014
|
+
};
|
|
1015
|
+
if (shouldOverrideElement) {
|
|
1016
|
+
const overrideElement = getOverrideElement();
|
|
1017
|
+
if (overrideElement)
|
|
1018
|
+
buttonProps.as = overrideElement;
|
|
1019
|
+
}
|
|
1020
|
+
else if (as)
|
|
1021
|
+
buttonProps.as = as;
|
|
1022
|
+
if (finalTheme && typeof finalTheme === 'string' && config.theme && finalTheme in config.theme) {
|
|
1023
|
+
const extendedTheme = config.theme[finalTheme];
|
|
1024
|
+
return (jsxRuntime.jsx(Button, { ...buttonProps, theme: 'custom', customTheme: customTheme || extendedTheme.customTheme, className: twMerge(configClassName, extendedTheme.className, className) }));
|
|
1025
|
+
}
|
|
1026
|
+
return (jsxRuntime.jsx(Button, { ...buttonProps, theme: finalTheme, className: twMerge(configClassName, className), customTheme: customTheme }));
|
|
1027
|
+
};
|
|
758
1028
|
}
|
|
759
1029
|
|
|
760
1030
|
function ChevronDown(props) {
|
|
@@ -769,10 +1039,8 @@ function xmark(props) {
|
|
|
769
1039
|
return (jsxRuntime.jsx("svg", { viewBox: '0 0 64 64', ...props, children: jsxRuntime.jsx("path", { d: 'M1,63c0.7,0.7,1.6,1,2.6,1s1.9-0.3,2.6-1L32,37.1L57.8,63c0.7,0.7,1.5,1,2.5,1c1,0,1.9-0.3,2.6-1c0.7-0.7,1-1.6,1-2.6 c0-1-0.3-1.8-1-2.5L37.1,32L63,6.2c0.7-0.7,1-1.6,1-2.6S63.7,1.7,63,1c-0.7-0.7-1.6-1-2.6-1c-1,0-1.8,0.3-2.5,1L32,26.9L6.2,1 C5.5,0.3,4.6,0,3.6,0C2.6,0,1.7,0.3,1,1C0.3,1.7,0,2.6,0,3.6c0,1,0.3,1.9,1,2.6L26.9,32L1,57.8c-0.7,0.7-1,1.5-1,2.6 C0,61.4,0.3,62.3,1,63z' }) }));
|
|
770
1040
|
}
|
|
771
1041
|
|
|
772
|
-
function DetailsSummary({ arrow = true,
|
|
773
|
-
return (
|
|
774
|
-
// @ts-expect-error Button has some extra props
|
|
775
|
-
jsxRuntime.jsx(react.DisclosureButton, { ...props, as: as || (Button), className: twMerge('w-full', className, Boolean(arrow) && 'grid grid-cols-[1fr_1rem] gap-2'), role: 'summary', children: bag => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [typeof children === 'function' ? children(bag) : children, arrow &&
|
|
1042
|
+
function DetailsSummary({ arrow = true, children, className, ...props }) {
|
|
1043
|
+
return (jsxRuntime.jsx(react.DisclosureButton, { ...props, as: (Button), className: twMerge('w-full', className, Boolean(arrow) && 'grid grid-cols-[1fr_1rem] gap-2'), role: 'summary', children: bag => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [typeof children === 'function' ? children(bag) : children, arrow &&
|
|
776
1044
|
(typeof arrow === 'boolean' ? (jsxRuntime.jsx(ChevronDown, { className: 'absolute top-1/2 right-3 block w-4 -translate-y-1/2' })) : (arrow))] })) }));
|
|
777
1045
|
}
|
|
778
1046
|
function DetailsBody({ children, className, ...props }) {
|
|
@@ -789,7 +1057,7 @@ function DropDownButton({ arrow = true, as, children, className, ...props }) {
|
|
|
789
1057
|
function DropDownItem({ as, ...props }) {
|
|
790
1058
|
return jsxRuntime.jsx(react.MenuItem, { as: as || 'div', ...props });
|
|
791
1059
|
}
|
|
792
|
-
function DropDownItems({ anchor, children, className, style, ...props }) {
|
|
1060
|
+
function DropDownItems({ anchor, children, className, containerClassName, style, ...props }) {
|
|
793
1061
|
const getAnchorProps = () => {
|
|
794
1062
|
let initialAnchor = { gap: '1rem', padding: '1rem', to: 'bottom start' };
|
|
795
1063
|
if (anchor) {
|
|
@@ -801,11 +1069,11 @@ function DropDownItems({ anchor, children, className, style, ...props }) {
|
|
|
801
1069
|
return initialAnchor;
|
|
802
1070
|
};
|
|
803
1071
|
const anchorProps = getAnchorProps();
|
|
804
|
-
return (jsxRuntime.jsx(react.MenuItems, { ...props, anchor: anchorProps, className: 'grid grid-rows-1fr rounded-xl shadow-xl transition-rows duration-500 ease-exponential data-closed:grid-rows-0fr', transition: true, style: { ...style, minWidth: 'var(--button-width)' }, children: bag => (jsxRuntime.jsx("div", { className: 'overflow-y-
|
|
1072
|
+
return (jsxRuntime.jsx(react.MenuItems, { ...props, anchor: anchorProps, className: twMerge('grid grid-rows-1fr rounded-xl shadow-xl transition-rows duration-500 ease-exponential data-closed:grid-rows-0fr', containerClassName), transition: true, style: { ...style, minWidth: 'var(--button-width)' }, children: bag => (jsxRuntime.jsx("div", { className: 'overflow-y-scroll', children: jsxRuntime.jsx("div", { className: twMerge('rounded-xl bg-neutral-50/20 px-6 py-5 backdrop-blur-md backdrop-brightness-150', className), children: typeof children === 'function' ? children(bag) : children }) })) }));
|
|
805
1073
|
}
|
|
806
1074
|
function DropDownSection({ children, label, labelProps, separatorAbove, separatorBelow, ...props }) {
|
|
807
1075
|
const { labelClassName, ...restLabelProps } = { labelClassName: labelProps?.className || '', ...labelProps };
|
|
808
|
-
return (jsxRuntime.jsx(react.MenuSection, { ...props, children: sectionBag => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [separatorAbove && jsxRuntime.jsx(DropDownSeparator, {}), jsxRuntime.jsx(react.MenuHeading, { ...restLabelProps, className: headingBag => twMerge('text-[size:larger] font-bold', typeof labelClassName === 'function' ? labelClassName(headingBag) : labelClassName), children: label }), typeof children === 'function' ? children(sectionBag) : children, separatorBelow && jsxRuntime.jsx(DropDownSeparator, {})] })) }));
|
|
1076
|
+
return (jsxRuntime.jsx(react.MenuSection, { ...props, children: sectionBag => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [separatorAbove && jsxRuntime.jsx(DropDownSeparator, {}), label && (jsxRuntime.jsx(react.MenuHeading, { ...restLabelProps, className: headingBag => twMerge('text-[size:larger] font-bold text-current/80', typeof labelClassName === 'function' ? labelClassName(headingBag) : labelClassName), children: label })), typeof children === 'function' ? children(sectionBag) : children, separatorBelow && jsxRuntime.jsx(DropDownSeparator, {})] })) }));
|
|
809
1077
|
}
|
|
810
1078
|
function DropDownSeparator({ className, ...props }) {
|
|
811
1079
|
return (jsxRuntime.jsx(react.MenuSeparator, { ...props, className: bag => twMerge('my-4 block h-px rounded-full bg-neutral-950/20', typeof className === 'function' ? className(bag) : className) }));
|
|
@@ -865,12 +1133,106 @@ function createFastContext(defaultInitialState) {
|
|
|
865
1133
|
function defineField(fieldDefinition) {
|
|
866
1134
|
return fieldDefinition;
|
|
867
1135
|
}
|
|
868
|
-
|
|
1136
|
+
function isStringField(field) {
|
|
1137
|
+
return Boolean(field.type !== 'object' && field.type !== 'array');
|
|
1138
|
+
}
|
|
1139
|
+
const { Provider: Provider$2, useStore: useStore$2 } = createFastContext([]);
|
|
869
1140
|
function FormContextProvider({ children }) {
|
|
870
|
-
return jsxRuntime.jsx(Provider$
|
|
1141
|
+
return jsxRuntime.jsx(Provider$2, { children: children });
|
|
871
1142
|
}
|
|
872
1143
|
function useFormContext() {
|
|
873
|
-
|
|
1144
|
+
const [formContext, setFormContext] = useStore$2(store => store);
|
|
1145
|
+
const registerField = React.useCallback((field) => {
|
|
1146
|
+
setFormContext?.(prevContext => {
|
|
1147
|
+
const otherFields = (prevContext || []).filter(otherField => otherField.id !== field.id);
|
|
1148
|
+
return [...otherFields, field];
|
|
1149
|
+
});
|
|
1150
|
+
}, []);
|
|
1151
|
+
const removeField = React.useCallback((fieldID) => {
|
|
1152
|
+
setFormContext?.(prevContext => (prevContext || []).filter(field => field.id !== fieldID));
|
|
1153
|
+
}, []);
|
|
1154
|
+
const updateField = React.useCallback((fieldID, updates) => {
|
|
1155
|
+
setFormContext?.(prevContext => {
|
|
1156
|
+
const field = prevContext.find(({ id }) => id === fieldID);
|
|
1157
|
+
if (!field)
|
|
1158
|
+
throw new Error(`Field with id "${fieldID}" not found in form context.`);
|
|
1159
|
+
const otherFields = prevContext.filter(({ id }) => id !== fieldID);
|
|
1160
|
+
const updatedField = { ...field, ...updates };
|
|
1161
|
+
return [...otherFields, updatedField];
|
|
1162
|
+
});
|
|
1163
|
+
}, []);
|
|
1164
|
+
return [formContext, { registerField, removeField, updateField }];
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
const { Provider: Provider$1, useStore: useStore$1 } = createFastContext(undefined);
|
|
1168
|
+
function FieldsetContextProvider({ children, initialValue, }) {
|
|
1169
|
+
return jsxRuntime.jsx(Provider$1, { initialValue: initialValue, children: children });
|
|
1170
|
+
}
|
|
1171
|
+
function useFieldsetContext() {
|
|
1172
|
+
const [fieldsetContext, setFieldsetContext] = useStore$1(store => store), [, formContextFunctions] = useFormContext();
|
|
1173
|
+
const registerField = React.useCallback((field) => {
|
|
1174
|
+
setFieldsetContext?.(prev => {
|
|
1175
|
+
if (!prev)
|
|
1176
|
+
return prev;
|
|
1177
|
+
const existingFieldIndex = prev.fieldList.findIndex(existingField => existingField.id === field.id);
|
|
1178
|
+
const newFieldList = existingFieldIndex >= 0
|
|
1179
|
+
? prev.fieldList.map((existingField, index) => (index === existingFieldIndex ? field : existingField))
|
|
1180
|
+
: [...prev.fieldList, field];
|
|
1181
|
+
return { ...prev, fieldList: newFieldList };
|
|
1182
|
+
});
|
|
1183
|
+
}, []);
|
|
1184
|
+
const removeField = React.useCallback((fieldID) => {
|
|
1185
|
+
setFieldsetContext?.(prev => {
|
|
1186
|
+
if (!prev)
|
|
1187
|
+
return prev;
|
|
1188
|
+
return {
|
|
1189
|
+
...prev,
|
|
1190
|
+
fieldList: prev.fieldList.filter(field => field.id !== fieldID),
|
|
1191
|
+
};
|
|
1192
|
+
});
|
|
1193
|
+
}, []);
|
|
1194
|
+
const updateField = React.useCallback((fieldID, updates) => {
|
|
1195
|
+
setFieldsetContext?.(prev => {
|
|
1196
|
+
if (!prev)
|
|
1197
|
+
return prev;
|
|
1198
|
+
return {
|
|
1199
|
+
...prev,
|
|
1200
|
+
fieldList: prev.fieldList.map(field => (field.id === fieldID ? { ...field, ...updates } : field)),
|
|
1201
|
+
};
|
|
1202
|
+
});
|
|
1203
|
+
}, []);
|
|
1204
|
+
const createFormContextEntry = React.useCallback((fieldsetEntry) => {
|
|
1205
|
+
if (fieldsetEntry.join) {
|
|
1206
|
+
const joinedValue = fieldsetEntry.fieldList
|
|
1207
|
+
.filter(field => isStringField(field) && field.value !== '')
|
|
1208
|
+
.map(field => field.value)
|
|
1209
|
+
.join(fieldsetEntry.join);
|
|
1210
|
+
return defineField({
|
|
1211
|
+
type: 'string',
|
|
1212
|
+
id: fieldsetEntry.id,
|
|
1213
|
+
name: fieldsetEntry.name,
|
|
1214
|
+
value: joinedValue,
|
|
1215
|
+
required: fieldsetEntry.fieldList.some(field => field.required),
|
|
1216
|
+
invalid: fieldsetEntry.fieldList.some(field => field.invalid),
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
return defineField({
|
|
1220
|
+
type: 'object',
|
|
1221
|
+
id: fieldsetEntry.id,
|
|
1222
|
+
name: fieldsetEntry.name,
|
|
1223
|
+
fields: fieldsetEntry.fieldList,
|
|
1224
|
+
});
|
|
1225
|
+
}, []);
|
|
1226
|
+
React.useEffect(() => {
|
|
1227
|
+
if (!fieldsetContext || fieldsetContext.decorative)
|
|
1228
|
+
return;
|
|
1229
|
+
const formContextEntry = createFormContextEntry(fieldsetContext);
|
|
1230
|
+
formContextFunctions.registerField(formContextEntry);
|
|
1231
|
+
return () => {
|
|
1232
|
+
formContextFunctions.removeField(fieldsetContext.id);
|
|
1233
|
+
};
|
|
1234
|
+
}, [fieldsetContext, formContextFunctions.registerField, formContextFunctions.removeField, createFormContextEntry]);
|
|
1235
|
+
return [fieldsetContext, { registerField, removeField, updateField }];
|
|
874
1236
|
}
|
|
875
1237
|
|
|
876
1238
|
const DEFAULT_STATUS = 'incomplete';
|
|
@@ -882,9 +1244,18 @@ function useFormStatus() {
|
|
|
882
1244
|
return useStore(store => store);
|
|
883
1245
|
}
|
|
884
1246
|
|
|
885
|
-
function Fieldset({ children, className, legend, legendProps, ...props }) {
|
|
1247
|
+
function Fieldset({ children, className, decorative = false, join, legend, legendProps, name, ...props }) {
|
|
1248
|
+
const uniqueID = React.useId();
|
|
1249
|
+
const fieldsetId = toLowerCase(legend || name, [' ', '_']) + '§' + uniqueID;
|
|
886
1250
|
const { className: legendClassName, ...restLegendProps } = legendProps || {};
|
|
887
|
-
|
|
1251
|
+
name = legend || name;
|
|
1252
|
+
return (jsxRuntime.jsx(FieldsetContextProvider, { initialValue: {
|
|
1253
|
+
decorative,
|
|
1254
|
+
fieldList: [],
|
|
1255
|
+
id: fieldsetId,
|
|
1256
|
+
join,
|
|
1257
|
+
name,
|
|
1258
|
+
}, children: jsxRuntime.jsx(react.Fieldset, { ...props, name: name, className: bag => twMerge('contents', typeof className === 'function' ? className(bag) : className), children: bag => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [legend && (jsxRuntime.jsx(react.Legend, { ...restLegendProps, className: twMerge('text-xl font-bold text-current/80', typeof legendClassName === 'function' ? legendClassName(bag) : legendClassName), children: legend })), typeof children === 'function' ? children(bag) : children] })) }) }));
|
|
888
1259
|
}
|
|
889
1260
|
|
|
890
1261
|
/**
|
|
@@ -3076,15 +3447,17 @@ function ArrowSvg({ className, ...props }) {
|
|
|
3076
3447
|
return (jsxRuntime.jsxs("svg", { viewBox: '0 0 20 10', className: twMerge('h-2.5 w-5 fill-none', className), ...props, children: [jsxRuntime.jsx("path", { d: 'M9.66437 2.60207L4.80758 6.97318C4.07308 7.63423 3.11989 8 2.13172 8H0V10H20V8H18.5349C17.5468 8 16.5936 7.63423 15.8591 6.97318L11.0023 2.60207C10.622 2.2598 10.0447 2.25979 9.66437 2.60207Z', className: 'fill-neutral-50 dark:fill-neutral-800' }), jsxRuntime.jsx("path", { d: 'M8.99542 1.85876C9.75604 1.17425 10.9106 1.17422 11.6713 1.85878L16.5281 6.22989C17.0789 6.72568 17.7938 7.00001 18.5349 7.00001L15.89 7L11.0023 2.60207C10.622 2.2598 10.0447 2.2598 9.66436 2.60207L4.77734 7L2.13171 7.00001C2.87284 7.00001 3.58774 6.72568 4.13861 6.22989L8.99542 1.85876Z', className: 'fill-neutral-400 dark:fill-none' }), jsxRuntime.jsx("path", { d: 'M10.3333 3.34539L5.47654 7.71648C4.55842 8.54279 3.36693 9 2.13172 9H0V8H2.13172C3.11989 8 4.07308 7.63423 4.80758 6.97318L9.66437 2.60207C10.0447 2.25979 10.622 2.2598 11.0023 2.60207L15.8591 6.97318C16.5936 7.63423 17.5468 8 18.5349 8H20V9H18.5349C17.2998 9 16.1083 8.54278 15.1901 7.71648L10.3333 3.34539Z', className: 'dark:fill-neutral-600' })] }));
|
|
3077
3448
|
}
|
|
3078
3449
|
|
|
3079
|
-
|
|
3080
|
-
|
|
3450
|
+
const specialCharacterRegex = new RegExp(/[!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~€‚ƒ„…†‡‰‹‘’“”•–—™›¡¢£¥§©«¬®°±¶º»¿×÷]/);
|
|
3451
|
+
function Input({ checked, className, defaultValue, description, descriptionProps, disabled, fieldProps, invalid = true, label, labelProps, max, min, name, onBlur, onChange, options, placeholder, ref, required = true, type, value, ...props }) {
|
|
3452
|
+
const [formContext, formContextFunctions] = useFormContext(), [fieldsetContext, fieldsetContextFunctions] = useFieldsetContext(), [errorMessage, setErrorMessage] = React.useState(undefined);
|
|
3453
|
+
if (type === 'password' && !placeholder)
|
|
3454
|
+
placeholder = '••••••••' + (required && !label ? '*' : '');
|
|
3081
3455
|
if (placeholder === '*')
|
|
3082
3456
|
placeholder = name + (required && !label ? '*' : '');
|
|
3083
3457
|
if (label === '*')
|
|
3084
3458
|
label = name;
|
|
3085
3459
|
const uniqueID = React.useId(), fieldContextID = toLowerCase(name, [, '_']) + '§' + uniqueID;
|
|
3086
|
-
|
|
3087
|
-
invalid = true;
|
|
3460
|
+
const isInFieldset = fieldsetContext && !fieldsetContext.decorative;
|
|
3088
3461
|
const getFieldContextType = () => {
|
|
3089
3462
|
switch (type) {
|
|
3090
3463
|
case 'email':
|
|
@@ -3102,26 +3475,27 @@ function Input({ checked, className, defaultValue, description, descriptionProps
|
|
|
3102
3475
|
}
|
|
3103
3476
|
};
|
|
3104
3477
|
const fieldContextType = getFieldContextType();
|
|
3105
|
-
const
|
|
3106
|
-
type: fieldContextType,
|
|
3107
|
-
id: fieldContextID,
|
|
3108
|
-
invalid,
|
|
3109
|
-
name,
|
|
3110
|
-
required,
|
|
3111
|
-
value: value ? `${value}` : defaultValue ? `${defaultValue}` : '',
|
|
3112
|
-
});
|
|
3478
|
+
const fieldContext = (isInFieldset ? fieldsetContext.fieldList : formContext)?.find(({ id: fieldID }) => fieldID === fieldContextID);
|
|
3113
3479
|
React.useEffect(() => {
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3480
|
+
const initialFieldContext = defineField({
|
|
3481
|
+
type: fieldContextType,
|
|
3482
|
+
id: fieldContextID,
|
|
3483
|
+
invalid,
|
|
3484
|
+
name,
|
|
3485
|
+
required,
|
|
3486
|
+
value: value ? `${value}` : defaultValue ? `${defaultValue}` : '',
|
|
3119
3487
|
});
|
|
3488
|
+
if (isInFieldset) {
|
|
3489
|
+
fieldsetContextFunctions.registerField(initialFieldContext);
|
|
3490
|
+
return () => {
|
|
3491
|
+
fieldsetContextFunctions.removeField(initialFieldContext.id);
|
|
3492
|
+
};
|
|
3493
|
+
}
|
|
3494
|
+
formContextFunctions.registerField(initialFieldContext);
|
|
3120
3495
|
return () => {
|
|
3121
|
-
|
|
3496
|
+
formContextFunctions.removeField(initialFieldContext.id);
|
|
3122
3497
|
};
|
|
3123
|
-
}, [
|
|
3124
|
-
const fieldContext = formContext?.find(({ id: fieldID }) => fieldID === initialFieldContext.id) || initialFieldContext;
|
|
3498
|
+
}, [isInFieldset]);
|
|
3125
3499
|
const validateField = (validValue) => {
|
|
3126
3500
|
const noValue = !validValue || validValue === '';
|
|
3127
3501
|
if (!required && noValue)
|
|
@@ -3137,15 +3511,86 @@ function Input({ checked, className, defaultValue, description, descriptionProps
|
|
|
3137
3511
|
if (!isEmail(validValue))
|
|
3138
3512
|
errorMessageList.push('This is not a valid email.');
|
|
3139
3513
|
break;
|
|
3514
|
+
case 'date':
|
|
3515
|
+
const valueAsTime = new Date().getTime();
|
|
3516
|
+
if (min && !(min instanceof Date) && typeof min !== 'number') {
|
|
3517
|
+
if (Array.isArray(min)) {
|
|
3518
|
+
const monthIndex = typeof min[1] === 'number' ? min[1] - 1 : getMonthIndexFromName(min[1]);
|
|
3519
|
+
min = new Date(min[0], monthIndex, min[2]);
|
|
3520
|
+
}
|
|
3521
|
+
else if ('year' in min && 'month' in min && 'day' in min) {
|
|
3522
|
+
const monthIndex = typeof min.month === 'number' ? min.month - 1 : getMonthIndexFromName(min.month);
|
|
3523
|
+
min = new Date(min.year, monthIndex, min.day);
|
|
3524
|
+
}
|
|
3525
|
+
if (valueAsTime < min.getTime())
|
|
3526
|
+
errorMessageList.push(`Value cannot be lower than ${getUserReadableDate(min)}.`);
|
|
3527
|
+
}
|
|
3528
|
+
if (max && !(max instanceof Date) && typeof max !== 'number') {
|
|
3529
|
+
if (Array.isArray(max)) {
|
|
3530
|
+
const monthIndex = typeof max[1] === 'number' ? max[1] - 1 : getMonthIndexFromName(max[1]);
|
|
3531
|
+
max = new Date(max[0], monthIndex, max[2]);
|
|
3532
|
+
}
|
|
3533
|
+
else if ('year' in max && 'month' in max && 'day' in max) {
|
|
3534
|
+
const monthIndex = typeof max.month === 'number' ? max.month - 1 : getMonthIndexFromName(max.month);
|
|
3535
|
+
max = new Date(max.year, monthIndex, max.day);
|
|
3536
|
+
}
|
|
3537
|
+
if (valueAsTime > max.getTime())
|
|
3538
|
+
errorMessageList.push(`Value cannot be higher than ${getUserReadableDate(max)}.`);
|
|
3539
|
+
}
|
|
3540
|
+
break;
|
|
3140
3541
|
case 'number':
|
|
3141
|
-
|
|
3542
|
+
const valueAsNumber = Number(validValue);
|
|
3543
|
+
if (isNaN(valueAsNumber))
|
|
3142
3544
|
errorMessageList.push('This is not a valid number.');
|
|
3545
|
+
if (typeof max === 'number' && valueAsNumber > max)
|
|
3546
|
+
errorMessageList.push(`Value cannot be higher than ${max}.`);
|
|
3547
|
+
if (typeof min === 'number' && valueAsNumber < min)
|
|
3548
|
+
errorMessageList.push(`Value cannot be lower than ${min}.`);
|
|
3549
|
+
break;
|
|
3550
|
+
case 'password':
|
|
3551
|
+
if (options) {
|
|
3552
|
+
const { matchPreviousInput, requireLowercaseCharacter, requireNumber, requireSpecialCharacter, requireUppercaseCharacter, } = options;
|
|
3553
|
+
if (matchPreviousInput && formContext && formContext.length >= 2) {
|
|
3554
|
+
if (isInFieldset && fieldsetContext.fieldList.length > 1) {
|
|
3555
|
+
const currentInputIndex = fieldsetContext.fieldList.findIndex(({ id: fieldID }) => fieldID === fieldContext?.id);
|
|
3556
|
+
if (currentInputIndex > 0) {
|
|
3557
|
+
const previousInput = fieldsetContext.fieldList.find((_, index) => index === currentInputIndex - 1);
|
|
3558
|
+
if (previousInput &&
|
|
3559
|
+
isStringField(previousInput) &&
|
|
3560
|
+
previousInput.value !== validValue)
|
|
3561
|
+
errorMessageList.push('Passwords must match.');
|
|
3562
|
+
}
|
|
3563
|
+
}
|
|
3564
|
+
else {
|
|
3565
|
+
const currentInputIndex = formContext.findIndex(({ id: fieldID }) => fieldID === fieldContext?.id);
|
|
3566
|
+
if (currentInputIndex > 0) {
|
|
3567
|
+
const previousInput = formContext.find((_, index) => index === currentInputIndex - 1);
|
|
3568
|
+
if (previousInput &&
|
|
3569
|
+
isStringField(previousInput) &&
|
|
3570
|
+
previousInput.value !== validValue)
|
|
3571
|
+
errorMessageList.push('Passwords must match.');
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3574
|
+
}
|
|
3575
|
+
if (requireLowercaseCharacter && !/[a-z]/g.test(validValue))
|
|
3576
|
+
errorMessageList.push('You must include a lowercase character.');
|
|
3577
|
+
if (requireNumber && !/[0-9]/g.test(validValue))
|
|
3578
|
+
errorMessageList.push('You must include a number.');
|
|
3579
|
+
if (requireSpecialCharacter && !specialCharacterRegex.test(validValue))
|
|
3580
|
+
errorMessageList.push('You must include a special character.');
|
|
3581
|
+
if (requireUppercaseCharacter && !/[A-Z]/g.test(validValue))
|
|
3582
|
+
errorMessageList.push('You must include an uppercase character.');
|
|
3583
|
+
}
|
|
3143
3584
|
break;
|
|
3144
3585
|
case 'tel':
|
|
3145
3586
|
if (!isPhoneNumber(validValue))
|
|
3146
3587
|
errorMessageList.push('This is not a valid phone number.');
|
|
3147
3588
|
break;
|
|
3148
3589
|
}
|
|
3590
|
+
if (props.maxLength && validValue.length > Number(props.maxLength))
|
|
3591
|
+
errorMessageList.push(`This may not have more than ${props.maxLength} characters.`);
|
|
3592
|
+
if (props.minLength && validValue.length < Number(props.minLength))
|
|
3593
|
+
errorMessageList.push(`This must have at least ${props.minLength} characters.`);
|
|
3149
3594
|
if (errorMessageList.length === 0)
|
|
3150
3595
|
return true;
|
|
3151
3596
|
setErrorMessage(errorMessageList.join(' '));
|
|
@@ -3157,19 +3602,15 @@ function Input({ checked, className, defaultValue, description, descriptionProps
|
|
|
3157
3602
|
return;
|
|
3158
3603
|
}
|
|
3159
3604
|
const { currentTarget } = e, { value: newValue } = currentTarget;
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
if (invalidField !== field.invalid)
|
|
3170
|
-
updatedField.invalid = invalidField;
|
|
3171
|
-
return [...otherFields, updatedField];
|
|
3172
|
-
});
|
|
3605
|
+
if (isInFieldset) {
|
|
3606
|
+
fieldsetContextFunctions.updateField(fieldContextID, {
|
|
3607
|
+
value: newValue,
|
|
3608
|
+
invalid: validateField(newValue) === false,
|
|
3609
|
+
});
|
|
3610
|
+
}
|
|
3611
|
+
else {
|
|
3612
|
+
formContextFunctions.updateField(fieldContextID, { value: newValue, invalid: validateField(newValue) === false });
|
|
3613
|
+
}
|
|
3173
3614
|
onChange?.(e);
|
|
3174
3615
|
};
|
|
3175
3616
|
const handleBlur = e => {
|
|
@@ -3180,32 +3621,21 @@ function Input({ checked, className, defaultValue, description, descriptionProps
|
|
|
3180
3621
|
const { currentTarget } = e, { value: newValue } = currentTarget;
|
|
3181
3622
|
if (required)
|
|
3182
3623
|
validateField(newValue);
|
|
3624
|
+
let processedValue = newValue;
|
|
3183
3625
|
switch (type) {
|
|
3184
3626
|
case 'email':
|
|
3185
|
-
|
|
3186
|
-
if (!prevContext)
|
|
3187
|
-
return [];
|
|
3188
|
-
const field = prevContext.find(({ id: fieldID }) => fieldID === initialFieldContext.id);
|
|
3189
|
-
if (!field)
|
|
3190
|
-
throw new Error(`Field with id "${initialFieldContext.id}" not found in form context.`);
|
|
3191
|
-
const otherFields = prevContext.filter(({ id: fieldID }) => fieldID !== initialFieldContext.id);
|
|
3192
|
-
const updatedField = { ...field, value: newValue.toLowerCase() };
|
|
3193
|
-
return [...otherFields, updatedField];
|
|
3194
|
-
});
|
|
3627
|
+
processedValue = newValue.toLowerCase();
|
|
3195
3628
|
break;
|
|
3196
3629
|
case 'tel':
|
|
3197
|
-
|
|
3198
|
-
if (!prevContext)
|
|
3199
|
-
return [];
|
|
3200
|
-
const field = prevContext.find(({ id: fieldID }) => fieldID === initialFieldContext.id);
|
|
3201
|
-
if (!field)
|
|
3202
|
-
throw new Error(`Field with id "${initialFieldContext.id}" not found in form context.`);
|
|
3203
|
-
const otherFields = prevContext.filter(({ id: fieldID }) => fieldID !== initialFieldContext.id);
|
|
3204
|
-
const updatedField = { ...field, value: formatPhoneNumber(newValue, '1') };
|
|
3205
|
-
return [...otherFields, updatedField];
|
|
3206
|
-
});
|
|
3630
|
+
processedValue = formatPhoneNumber(newValue, options);
|
|
3207
3631
|
break;
|
|
3208
3632
|
}
|
|
3633
|
+
if (isInFieldset) {
|
|
3634
|
+
fieldsetContextFunctions.updateField(fieldContextID, { value: processedValue });
|
|
3635
|
+
}
|
|
3636
|
+
else {
|
|
3637
|
+
formContextFunctions.updateField(fieldContextID, { value: processedValue });
|
|
3638
|
+
}
|
|
3209
3639
|
onBlur?.(e);
|
|
3210
3640
|
};
|
|
3211
3641
|
const restFieldProps = fieldProps
|
|
@@ -3225,12 +3655,12 @@ function Input({ checked, className, defaultValue, description, descriptionProps
|
|
|
3225
3655
|
// user-invalid styles
|
|
3226
3656
|
'user-invalid:border-ui-red user-invalid:bg-[color-mix(in_oklab,var(--color-ui-red)_20%,var(--color-neutral-100))] user-invalid:focus-visible:bg-[color-mix(in_oklab,var(--color-ui-red)_1%,var(--color-neutral-100))] user-invalid:active:bg-[color-mix(in_oklab,var(--color-ui-red)_25%,var(--color-neutral-100))] dark:user-invalid:bg-[color-mix(in_oklab,var(--color-ui-red)_20%,var(--color-neutral-800))] dark:user-invalid:focus-visible:bg-[color-mix(in_oklab,var(--color-ui-red)_1%,var(--color-neutral-800))] dark:user-invalid:active:bg-[color-mix(in_oklab,var(--color-ui-red)_25%,var(--color-neutral-800))] user-invalid:pointer-fine:hover:bg-[color-mix(in_oklab,var(--color-ui-red)_10%,var(--color-neutral-100))] user-invalid:pointer-fine:focus-visible:bg-[color-mix(in_oklab,var(--color-ui-red)_1%,var(--color-neutral-100))] user-invalid:pointer-fine:active:bg-[color-mix(in_oklab,var(--color-ui-red)_25%,var(--color-neutral-100))] dark:user-invalid:pointer-fine:hover:bg-[color-mix(in_oklab,var(--color-ui-red)_10%,var(--color-neutral-800))] dark:user-invalid:pointer-fine:focus-visible:bg-[color-mix(in_oklab,var(--color-ui-red)_1%,var(--color-neutral-800))] dark:user-invalid:pointer-fine:active:bg-[color-mix(in_oklab,var(--color-ui-red)_25%,var(--color-neutral-800))]',
|
|
3227
3657
|
// Custom styles
|
|
3228
|
-
typeof className === 'function' ? className(bag) : className), invalid: invalid, onBlur: handleBlur, onChange: handleChange, placeholder: placeholder, ref: ref, required: required, type: type, value: fieldContext?.value }), fieldContext
|
|
3658
|
+
typeof className === 'function' ? className(bag) : className), invalid: invalid, onBlur: handleBlur, onChange: handleChange, placeholder: placeholder, ref: ref, required: required, type: type, value: fieldContext?.value || '' }), fieldContext?.invalid && errorMessage && (jsxRuntime.jsxs(Tooltip, { anchor: 'top-end', arrow: true, portal: true, children: [jsxRuntime.jsx(TooltipTrigger, { as: Button, className: 'absolute top-1.25 right-1.25 z-10 size-6 min-w-0', padding: 'none', rounded: 'md', theme: 'red', children: jsxRuntime.jsx(ExclamationmarkOctagon, { className: 'absolute top-1/2 left-1/2 size-full -translate-x-1/2 -translate-y-1/2 scale-70' }) }), jsxRuntime.jsx(TooltipPanel, { children: errorMessage })] }))] }), description && (jsxRuntime.jsx(react.Description, { ...restDescriptionProps, className: bag => twMerge('text-xs', typeof descriptionProps?.className === 'function'
|
|
3229
3659
|
? descriptionProps?.className(bag)
|
|
3230
3660
|
: descriptionProps?.className), children: description }))] }));
|
|
3231
3661
|
}
|
|
3232
3662
|
|
|
3233
|
-
function SubmitButton({ children, className, customTheme, error, incomplete, loading, success, type
|
|
3663
|
+
function SubmitButton({ children, className, customTheme, error, incomplete, loading, success, type, ...props }) {
|
|
3234
3664
|
const [formStatus] = useFormStatus();
|
|
3235
3665
|
const getFormStatusButtonClasses = () => {
|
|
3236
3666
|
switch (formStatus) {
|
|
@@ -3278,40 +3708,43 @@ function SubmitButton({ children, className, customTheme, error, incomplete, loa
|
|
|
3278
3708
|
}
|
|
3279
3709
|
};
|
|
3280
3710
|
const dataFormState = getDataFormState();
|
|
3281
|
-
return (jsxRuntime.jsx(Button, { ...props, ...dataFormState,
|
|
3711
|
+
return (jsxRuntime.jsx(Button, { ...props, ...dataFormState, className: twMerge([formStatusButtonClasses, 'w-full text-white data-loading:text-black', className]), customTheme: {
|
|
3282
3712
|
themeColor: twMerge('data-error:[--theme-color:var(--color-ui-red)] data-incomplete:[--theme-color:var(--color-ui-grey)] data-loading:[--theme-color:var(--color-ui-yellow)] data-readonly:[--theme-color:var(--color-ui-grey)] data-ready:[--theme-color:var(--color-ui-blue)] data-success:[--theme-color:var(--color-ui-green)]', customTheme?.themeColor),
|
|
3283
|
-
}, theme: 'custom', type: type, children: buttonText }));
|
|
3713
|
+
}, theme: 'custom', type: type || 'submit', children: buttonText }));
|
|
3284
3714
|
}
|
|
3285
3715
|
|
|
3286
3716
|
function Textarea({ className, defaultValue, description, descriptionProps, disabled, fieldProps, invalid = true, label, labelProps, name, onBlur, onChange, placeholder, ref, required = true, value, ...props }) {
|
|
3287
|
-
const [formContext,
|
|
3717
|
+
const [formContext, formContextFunctions] = useFormContext();
|
|
3718
|
+
const [fieldsetContext, fieldsetContextFunctions] = useFieldsetContext();
|
|
3719
|
+
const [errorMessage, setErrorMessage] = React.useState(undefined);
|
|
3288
3720
|
if (placeholder === '*')
|
|
3289
3721
|
placeholder = name + (required && !label ? '*' : '');
|
|
3290
3722
|
if (label === '*')
|
|
3291
3723
|
label = name;
|
|
3292
|
-
const uniqueID = React.useId()
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
const initialFieldContext = defineField({
|
|
3296
|
-
type: 'textarea',
|
|
3297
|
-
id: fieldContextID,
|
|
3298
|
-
invalid,
|
|
3299
|
-
name,
|
|
3300
|
-
required,
|
|
3301
|
-
value: value ? `${value}` : defaultValue ? `${defaultValue}` : '',
|
|
3302
|
-
});
|
|
3724
|
+
const uniqueID = React.useId();
|
|
3725
|
+
const fieldContextID = toLowerCase(name, [' ', '_']) + '§' + uniqueID;
|
|
3726
|
+
const isInFieldset = fieldsetContext && !fieldsetContext.decorative;
|
|
3303
3727
|
React.useEffect(() => {
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3728
|
+
const initialFieldContext = defineField({
|
|
3729
|
+
type: 'textarea',
|
|
3730
|
+
id: fieldContextID,
|
|
3731
|
+
invalid,
|
|
3732
|
+
name,
|
|
3733
|
+
required,
|
|
3734
|
+
value: value ? `${value}` : defaultValue ? `${defaultValue}` : '',
|
|
3309
3735
|
});
|
|
3736
|
+
if (isInFieldset) {
|
|
3737
|
+
fieldsetContextFunctions.registerField(initialFieldContext);
|
|
3738
|
+
return () => {
|
|
3739
|
+
fieldsetContextFunctions.removeField(initialFieldContext.id);
|
|
3740
|
+
};
|
|
3741
|
+
}
|
|
3742
|
+
formContextFunctions.registerField(initialFieldContext);
|
|
3310
3743
|
return () => {
|
|
3311
|
-
|
|
3744
|
+
formContextFunctions.removeField(initialFieldContext.id);
|
|
3312
3745
|
};
|
|
3313
|
-
}, [
|
|
3314
|
-
const fieldContext = formContext?.find(({ id: fieldID }) => fieldID ===
|
|
3746
|
+
}, [isInFieldset]);
|
|
3747
|
+
const fieldContext = (isInFieldset ? fieldsetContext.fieldList : formContext)?.find(({ id: fieldID }) => fieldID === fieldContextID);
|
|
3315
3748
|
const validateField = (validValue) => {
|
|
3316
3749
|
const noValue = !validValue || validValue === '';
|
|
3317
3750
|
if (!required && noValue)
|
|
@@ -3322,6 +3755,10 @@ function Textarea({ className, defaultValue, description, descriptionProps, disa
|
|
|
3322
3755
|
setErrorMessage(errorMessageList.join(' '));
|
|
3323
3756
|
return false;
|
|
3324
3757
|
}
|
|
3758
|
+
if (props.maxLength && validValue.length > Number(props.maxLength))
|
|
3759
|
+
errorMessageList.push(`This may not have more than ${props.maxLength} characters.`);
|
|
3760
|
+
if (props.minLength && validValue.length < Number(props.minLength))
|
|
3761
|
+
errorMessageList.push(`This must have at least ${props.minLength} characters.`);
|
|
3325
3762
|
if (errorMessageList.length === 0)
|
|
3326
3763
|
return true;
|
|
3327
3764
|
setErrorMessage(errorMessageList.join(' '));
|
|
@@ -3332,22 +3769,41 @@ function Textarea({ className, defaultValue, description, descriptionProps, disa
|
|
|
3332
3769
|
e.preventDefault();
|
|
3333
3770
|
return;
|
|
3334
3771
|
}
|
|
3335
|
-
const { currentTarget } = e
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
}
|
|
3772
|
+
const { currentTarget } = e;
|
|
3773
|
+
const { value: newValue } = currentTarget;
|
|
3774
|
+
if (isInFieldset) {
|
|
3775
|
+
fieldsetContextFunctions.updateField(fieldContextID, {
|
|
3776
|
+
value: newValue,
|
|
3777
|
+
invalid: validateField(newValue) === false,
|
|
3778
|
+
});
|
|
3779
|
+
}
|
|
3780
|
+
else {
|
|
3781
|
+
formContextFunctions.updateField(fieldContextID, {
|
|
3782
|
+
value: newValue,
|
|
3783
|
+
invalid: validateField(newValue) === false,
|
|
3784
|
+
});
|
|
3785
|
+
}
|
|
3349
3786
|
onChange?.(e);
|
|
3350
3787
|
};
|
|
3788
|
+
const handleBlur = e => {
|
|
3789
|
+
if (disabled) {
|
|
3790
|
+
e.preventDefault();
|
|
3791
|
+
return;
|
|
3792
|
+
}
|
|
3793
|
+
const { currentTarget } = e;
|
|
3794
|
+
const { value: newValue } = currentTarget;
|
|
3795
|
+
if (required)
|
|
3796
|
+
validateField(newValue);
|
|
3797
|
+
// No special processing needed for textarea like email/phone formatting
|
|
3798
|
+
const processedValue = newValue;
|
|
3799
|
+
if (isInFieldset) {
|
|
3800
|
+
fieldsetContextFunctions.updateField(fieldContextID, { value: processedValue });
|
|
3801
|
+
}
|
|
3802
|
+
else {
|
|
3803
|
+
formContextFunctions.updateField(fieldContextID, { value: processedValue });
|
|
3804
|
+
}
|
|
3805
|
+
onBlur?.(e);
|
|
3806
|
+
};
|
|
3351
3807
|
const restFieldProps = fieldProps
|
|
3352
3808
|
? Object.fromEntries(Object.entries(fieldProps).filter(([key]) => key !== 'className'))
|
|
3353
3809
|
: {};
|
|
@@ -3365,23 +3821,34 @@ function Textarea({ className, defaultValue, description, descriptionProps, disa
|
|
|
3365
3821
|
// user-invalid styles
|
|
3366
3822
|
'user-invalid:border-ui-red user-invalid:bg-[color-mix(in_oklab,var(--color-ui-red)_20%,var(--color-neutral-100))] user-invalid:focus-visible:bg-[color-mix(in_oklab,var(--color-ui-red)_1%,var(--color-neutral-100))] user-invalid:active:bg-[color-mix(in_oklab,var(--color-ui-red)_25%,var(--color-neutral-100))] dark:user-invalid:bg-[color-mix(in_oklab,var(--color-ui-red)_20%,var(--color-neutral-800))] dark:user-invalid:focus-visible:bg-[color-mix(in_oklab,var(--color-ui-red)_1%,var(--color-neutral-800))] dark:user-invalid:active:bg-[color-mix(in_oklab,var(--color-ui-red)_25%,var(--color-neutral-800))] user-invalid:pointer-fine:hover:bg-[color-mix(in_oklab,var(--color-ui-red)_10%,var(--color-neutral-100))] user-invalid:pointer-fine:focus-visible:bg-[color-mix(in_oklab,var(--color-ui-red)_1%,var(--color-neutral-100))] user-invalid:pointer-fine:active:bg-[color-mix(in_oklab,var(--color-ui-red)_25%,var(--color-neutral-100))] dark:user-invalid:pointer-fine:hover:bg-[color-mix(in_oklab,var(--color-ui-red)_10%,var(--color-neutral-800))] dark:user-invalid:pointer-fine:focus-visible:bg-[color-mix(in_oklab,var(--color-ui-red)_1%,var(--color-neutral-800))] dark:user-invalid:pointer-fine:active:bg-[color-mix(in_oklab,var(--color-ui-red)_25%,var(--color-neutral-800))]',
|
|
3367
3823
|
// Custom styles
|
|
3368
|
-
typeof className === 'function' ? className(bag) : className), id: fieldContext?.id, invalid: invalid, onChange: handleChange, placeholder: placeholder, ref: ref, required: required, value: fieldContext?.value }), fieldContext
|
|
3824
|
+
typeof className === 'function' ? className(bag) : className), id: fieldContext?.id, invalid: invalid, onChange: handleChange, onBlur: handleBlur, placeholder: placeholder, ref: ref, required: required, value: fieldContext?.value || '' }), fieldContext?.invalid && errorMessage && (jsxRuntime.jsxs(Tooltip, { anchor: 'top-end', arrow: true, portal: true, children: [jsxRuntime.jsx(TooltipTrigger, { as: Button, className: 'absolute top-1.25 right-1.25 z-10 size-6 min-w-0', padding: 'none', rounded: 'md', theme: 'red', children: jsxRuntime.jsx(ExclamationmarkOctagon, { className: 'absolute top-1/2 left-1/2 size-full -translate-x-1/2 -translate-y-1/2 scale-70' }) }), jsxRuntime.jsx(TooltipPanel, { children: errorMessage })] }))] }), description && (jsxRuntime.jsx(react.Description, { ...restDescriptionProps, className: bag => twMerge('text-xs', typeof descriptionProps?.className === 'function'
|
|
3369
3825
|
? descriptionProps?.className(bag)
|
|
3370
3826
|
: descriptionProps?.className), children: description }))] }));
|
|
3371
3827
|
}
|
|
3372
3828
|
|
|
3373
|
-
// import { findComponentByType } from '../../utils'
|
|
3374
3829
|
function FormComponent({ as, children, className, handleSubmit, onError, onSubmit, onSuccess, ...props }) {
|
|
3375
3830
|
const [formContext] = useFormContext(), [formStatus, setFormStatus] = useFormStatus();
|
|
3376
|
-
|
|
3831
|
+
const checkField = React.useCallback((field) => {
|
|
3832
|
+
if (field.type !== 'array' && field.type !== 'object' && !field.invalid)
|
|
3833
|
+
return true;
|
|
3834
|
+
if (field.type === 'object')
|
|
3835
|
+
return field.fields.every(objectField => checkField(objectField));
|
|
3836
|
+
return false;
|
|
3837
|
+
}, []);
|
|
3838
|
+
const everyFieldIsValid = React.useCallback(() => {
|
|
3839
|
+
if (!formContext)
|
|
3840
|
+
return false;
|
|
3841
|
+
return formContext.every(field => checkField(field));
|
|
3842
|
+
}, [formContext, checkField]);
|
|
3377
3843
|
React.useEffect(() => {
|
|
3378
3844
|
if (!formContext)
|
|
3379
3845
|
return;
|
|
3380
|
-
if (formStatus !== 'incomplete' &&
|
|
3846
|
+
if (formStatus !== 'incomplete' &&
|
|
3847
|
+
formContext.find(context => context.type !== 'array' && context.type !== 'object' && context.invalid))
|
|
3381
3848
|
setFormStatus?.('incomplete');
|
|
3382
|
-
if (formStatus !== 'ready' &&
|
|
3849
|
+
if (formStatus !== 'ready' && everyFieldIsValid())
|
|
3383
3850
|
setFormStatus?.('ready');
|
|
3384
|
-
}, [formContext]);
|
|
3851
|
+
}, [formContext, everyFieldIsValid]);
|
|
3385
3852
|
const processSubmit = handleSubmit ||
|
|
3386
3853
|
(async (e) => {
|
|
3387
3854
|
e.preventDefault();
|
|
@@ -3454,9 +3921,16 @@ function ModalTrigger({ as, ...props }) {
|
|
|
3454
3921
|
const Element = as || react.Button;
|
|
3455
3922
|
return jsxRuntime.jsx(Element, { ...props });
|
|
3456
3923
|
}
|
|
3924
|
+
function ModalTitle(props) {
|
|
3925
|
+
return jsxRuntime.jsx(react.DialogTitle, { ...props });
|
|
3926
|
+
}
|
|
3457
3927
|
function ModalDialog(props) {
|
|
3458
3928
|
return jsxRuntime.jsx("div", { ...props });
|
|
3459
3929
|
}
|
|
3930
|
+
function ModalClose({ as, ...props }) {
|
|
3931
|
+
const Element = as || react.Button;
|
|
3932
|
+
return jsxRuntime.jsx(Element, { ...props });
|
|
3933
|
+
}
|
|
3460
3934
|
function Modal({ children, className, onClose, onOpen, place = 'bottom' }) {
|
|
3461
3935
|
const [bodyElement, setBodyElement] = React.useState(null);
|
|
3462
3936
|
React.useEffect(() => {
|
|
@@ -3640,7 +4114,9 @@ exports.Heading = Heading;
|
|
|
3640
4114
|
exports.Input = Input;
|
|
3641
4115
|
exports.Link = Link;
|
|
3642
4116
|
exports.Modal = Modal;
|
|
4117
|
+
exports.ModalClose = ModalClose;
|
|
3643
4118
|
exports.ModalDialog = ModalDialog;
|
|
4119
|
+
exports.ModalTitle = ModalTitle;
|
|
3644
4120
|
exports.ModalTrigger = ModalTrigger;
|
|
3645
4121
|
exports.SubmitButton = SubmitButton;
|
|
3646
4122
|
exports.Textarea = Textarea;
|
|
@@ -3648,4 +4124,6 @@ exports.Time = Time;
|
|
|
3648
4124
|
exports.Tooltip = Tooltip;
|
|
3649
4125
|
exports.TooltipPanel = TooltipPanel;
|
|
3650
4126
|
exports.TooltipTrigger = TooltipTrigger;
|
|
4127
|
+
exports.createButton = createButton;
|
|
4128
|
+
exports.createLink = createLink;
|
|
3651
4129
|
//# sourceMappingURL=components.js.map
|