mado-ui 0.2.0 → 0.2.2

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.
@@ -0,0 +1,1329 @@
1
+ import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
2
+ import { extendTailwindMerge, twJoin } from 'tailwind-merge';
3
+ import { Children, isValidElement, Fragment, createContext, useContext, useSyncExternalStore, useRef, Suspense, useId, useEffect, useState, cloneElement } from 'react';
4
+ import { Button as Button$1, Field, Label, Input as Input$1, Description, Textarea as Textarea$1, Dialog, DialogBackdrop, DialogPanel } from '@headlessui/react';
5
+ import { createPortal } from 'react-dom';
6
+
7
+ const integerList = Array.from({ length: 100 }, (_, i) => `${i + 1}`);
8
+ const twMerge = extendTailwindMerge({
9
+ extend: {
10
+ theme: {
11
+ color: [
12
+ {
13
+ ui: [
14
+ 'red',
15
+ 'orange',
16
+ 'yellow',
17
+ 'green',
18
+ 'sky-blue',
19
+ 'blue',
20
+ 'violet',
21
+ 'magenta',
22
+ 'purple',
23
+ 'brown',
24
+ 'grey',
25
+ 'pink',
26
+ ],
27
+ },
28
+ ],
29
+ },
30
+ classGroups: {
31
+ animate: [
32
+ {
33
+ animate: [
34
+ 'bounce',
35
+ 'double-spin',
36
+ 'drop-in',
37
+ 'flip',
38
+ 'flip-again',
39
+ 'grid-rows',
40
+ 'heartbeat',
41
+ 'ping',
42
+ 'pulse',
43
+ 'slide-up',
44
+ 'spin',
45
+ 'wave',
46
+ ],
47
+ },
48
+ ],
49
+ 'animation-direction': [
50
+ {
51
+ 'animation-direction': ['normal', 'reverse', 'alternate', 'alternate-reverse'],
52
+ },
53
+ ],
54
+ 'animation-fill': [
55
+ {
56
+ 'animation-fill': ['none', 'forwards', 'backwards', 'both'],
57
+ },
58
+ ],
59
+ 'animation-iteration': [
60
+ {
61
+ 'animation-iteration': [...integerList, 'infinite'],
62
+ },
63
+ ],
64
+ 'animation-state': [
65
+ {
66
+ 'animation-state': ['running', 'paused'],
67
+ },
68
+ ],
69
+ 'grid-cols': [
70
+ {
71
+ 'grid-cols': ['0fr', '1fr'],
72
+ },
73
+ ],
74
+ 'grid-rows': [
75
+ {
76
+ 'grid-rows': ['0fr', '1fr'],
77
+ },
78
+ ],
79
+ transition: ['transition-rows'],
80
+ },
81
+ },
82
+ });
83
+
84
+ /** The current date as a Date object */
85
+ const d = new Date();
86
+ /** The current minute of the current hour */
87
+ const minutes = d.getMinutes();
88
+ /** The current year */
89
+ d.getFullYear();
90
+ /** An array of the names of month in order */
91
+ const monthNamesList = [
92
+ 'January',
93
+ 'February',
94
+ 'March',
95
+ 'April',
96
+ 'May',
97
+ 'June',
98
+ 'July',
99
+ 'August',
100
+ 'September',
101
+ 'October',
102
+ 'November',
103
+ 'December',
104
+ ];
105
+ /** An array of the names of the days of the week in order */
106
+ const weekdayNamesList = [
107
+ 'Sunday',
108
+ 'Monday',
109
+ 'Tuesday',
110
+ 'Wednesday',
111
+ 'Thursday',
112
+ 'Friday',
113
+ 'Saturday',
114
+ ];
115
+ /** The name of the current month */
116
+ getMonthName();
117
+ /** The name of the current day of the week */
118
+ getWeekdayName();
119
+ /**
120
+ * ### Get Date
121
+ * - Returns the date with two digits
122
+ * @param {number|Date} date The date to get date
123
+ * @returns {string} The date with two digits
124
+ */
125
+ function getDate(date = d) {
126
+ if (typeof date !== 'number')
127
+ date = date.getDate();
128
+ let formattedDate = date.toString();
129
+ if (formattedDate.length === 1)
130
+ formattedDate = `0${formattedDate}`;
131
+ return formattedDate;
132
+ }
133
+ /**
134
+ * ### Get Hours
135
+ * - Returns the hours with two digits
136
+ * @param {number|Date} hours The date to get hours
137
+ * @returns {string} The hours with two digits
138
+ */
139
+ function getHours(hours = d) {
140
+ if (typeof hours !== 'number')
141
+ hours = hours.getHours();
142
+ let formattedHours = hours.toString();
143
+ if (formattedHours.length === 1)
144
+ formattedHours = `0${formattedHours}`;
145
+ return formattedHours;
146
+ }
147
+ /**
148
+ * ### Get Milliseconds
149
+ * - Returns the milliseconds with two digits
150
+ * @param {number|Date} milliseconds The date to get milliseconds
151
+ * @returns {string} The milliseconds with two digits
152
+ */
153
+ function getMilliseconds(milliseconds = d) {
154
+ if (typeof milliseconds !== 'number')
155
+ milliseconds = milliseconds.getMilliseconds();
156
+ let formattedMilliseconds = minutes.toString();
157
+ if (formattedMilliseconds.length === 1)
158
+ formattedMilliseconds = `0${formattedMilliseconds}`;
159
+ return formattedMilliseconds;
160
+ }
161
+ /**
162
+ * ### Get Minutes
163
+ * - Returns the minutes with two digits
164
+ * @param {number|Date} minutes The date to get minutes
165
+ * @returns {string} The minutes with two digits
166
+ */
167
+ function getMinutes(minutes = d) {
168
+ if (typeof minutes !== 'number')
169
+ minutes = minutes.getMinutes();
170
+ let formattedMinutes = minutes.toString();
171
+ if (formattedMinutes.length === 1)
172
+ formattedMinutes = `0${formattedMinutes}`;
173
+ return formattedMinutes;
174
+ }
175
+ /**
176
+ * ### Get Month
177
+ * - Returns the month with two digits
178
+ * @param {number|Date} month The date to get month
179
+ * @returns {string} The month with two digits
180
+ */
181
+ function getMonth(month = d) {
182
+ if (typeof month !== 'number')
183
+ month = month.getMonth() + 1;
184
+ let formattedMonth = month.toString();
185
+ if (formattedMonth.length === 1)
186
+ formattedMonth = `0${formattedMonth}`;
187
+ return formattedMonth;
188
+ }
189
+ /**
190
+ * ### Get Month Name
191
+ * - Returns the name of the specified month
192
+ * @param {Date} date A Date object representing the month to get the name of the month from. (Preset to the current date)
193
+ * @returns {MonthName} The name of the specified month
194
+ */
195
+ function getMonthName(date = d) {
196
+ if (typeof date === 'number')
197
+ return monthNamesList[date];
198
+ return monthNamesList[date.getMonth()];
199
+ }
200
+ /**
201
+ * ### Get Seconds
202
+ * - Returns the seconds with two digits
203
+ * @param {number|Date} seconds The date to get seconds
204
+ * @returns {string} The seconds with two digits
205
+ */
206
+ function getSeconds(seconds = d) {
207
+ if (typeof seconds !== 'number')
208
+ seconds = seconds.getSeconds();
209
+ let formattedSeconds = seconds.toString();
210
+ if (formattedSeconds.length === 1)
211
+ formattedSeconds = `0${formattedSeconds}`;
212
+ return formattedSeconds;
213
+ }
214
+ /**
215
+ * ### Get Weekday Name
216
+ * - Returns the weekday name of the specified day
217
+ * @param {number | Date} weekday A Date object or number representing the day to get the weekday name from. (Preset to the current date)
218
+ * @returns {WeekdayName} The name of the specified weekday
219
+ */
220
+ function getWeekdayName(weekday = d) {
221
+ if (typeof weekday === 'number')
222
+ return weekdayNamesList[weekday];
223
+ // Return the name of the day of the week
224
+ return weekdayNamesList[weekday.getDay()];
225
+ }
226
+
227
+ function findComponentByType(children, componentType) {
228
+ const childrenArray = Children.toArray(children);
229
+ for (const child of childrenArray) {
230
+ if (isValidElement(child) && child.type === componentType)
231
+ return child;
232
+ }
233
+ for (const child of childrenArray) {
234
+ if (isValidElement(child)) {
235
+ if (child.type === Fragment && child.props.children) {
236
+ const found = findComponentByType(child.props.children, componentType);
237
+ if (found)
238
+ return found;
239
+ }
240
+ else if (child.props.children) {
241
+ const found = findComponentByType(child.props.children, componentType);
242
+ if (found)
243
+ return found;
244
+ }
245
+ }
246
+ }
247
+ return null;
248
+ }
249
+
250
+ function easeOutExpo(time, start, end, duration) {
251
+ return time == duration ? start + end : end * (-Math.pow(2, (-10 * time) / duration) + 1) + start;
252
+ }
253
+
254
+ const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
255
+ /**
256
+ * # Is Email
257
+ * Checks whether the specified string is in email format
258
+ */
259
+ function isEmail(email) {
260
+ return emailRegex.test(email);
261
+ }
262
+ const telRegex = /(?:\+1\s|1\s|)?\d{3}\.\d{3}\.\d{4}|(?:\+1\s|1\s|)?\d{3}-\d{3}-\d{4}|(?:\+1\s|1\s|)?\(\d{3}\) \d{3}-\d{4}|(?:\+1\s|1\s|\+1|1|)?\d{10}/;
263
+ /**
264
+ * # Is Phone Number
265
+ * Checks whether the specified string is in phone number format
266
+ */
267
+ function isPhoneNumber(tel) {
268
+ return telRegex.test(tel);
269
+ }
270
+
271
+ /**
272
+ * # Format Phone Number
273
+ * Converts any string containing at least 10 numbers to a formatted phone number
274
+ * @param {string} string
275
+ * @returns {string} string formatted (000) 000-0000
276
+ */
277
+ function formatPhoneNumber(string, countryCode) {
278
+ return (`${`+${countryCode} ` }` +
279
+ string
280
+ .replace(/\D/g, '')
281
+ .slice(-10)
282
+ .split('')
283
+ .map((char, index) => {
284
+ if (index === 0)
285
+ return `(${char}`;
286
+ if (index === 2)
287
+ return `${char}) `;
288
+ if (index === 5)
289
+ return `${char}-`;
290
+ return char;
291
+ })
292
+ .join(''));
293
+ }
294
+ /**
295
+ * # To Lower Case
296
+ * Converts a string to lowercase, and offers easy string replacements for creating snake case, kebab case, or your own.
297
+ * @param str - The string to convert to lowercase.
298
+ * @param options - Configuration options.
299
+ * @param options[0] - The delimiter to split the string. Defaults to space.
300
+ * @param options[1] - The string to join the parts back together. Defaults to space.
301
+ * @returns The lowercase version of the input string, with the replacements, if provided.
302
+ */
303
+ function toLowerCase(str, [delimiter, joiner]) {
304
+ return str.toLowerCase().replaceAll(delimiter || ' ', joiner || ' ');
305
+ }
306
+
307
+ function twSort(className) {
308
+ return className;
309
+ }
310
+
311
+ function Anchor({ className, disabled, href, onClick, ref, target, rel, ...props }) {
312
+ const isExternal = `${href}`.startsWith('http'), hasHash = `${href}`.includes('#');
313
+ const handleClick = e => {
314
+ if (disabled)
315
+ return e.preventDefault();
316
+ onClick?.(e);
317
+ setTimeout(() => history.replaceState({}, document.title, location.pathname), 100);
318
+ };
319
+ return (jsx("a", { ref: ref, ...props, "aria-disabled": disabled, className: twMerge(className, disabled && 'pointer-events-none'), href: href, target: target || (isExternal ? '_blank' : '_self'), onClick: hasHash ? handleClick : onClick, rel: rel !== undefined
320
+ ? rel === 'nofollow'
321
+ ? `${rel} noreferrer noopener`
322
+ : `${rel} prefetch`
323
+ : isExternal
324
+ ? 'nofollow noreferrer noopener'
325
+ : 'prefetch' }));
326
+ }
327
+ // * Styles
328
+ const baseClasses = twSort('isolate inline-block cursor-pointer duration-300 ease-exponential after:absolute after:left-1/2 after:-z-10 after:-translate-x-1/2 after:duration-500 active:scale-95 active:after:opacity-100');
329
+ const lineStaticClasses = twJoin(baseClasses, 'whitespace-nowrap after:-bottom-0.5 after:w-[calc(100%+0.15rem)] after:rounded-full after:border-1 after:border-current');
330
+ const lineClasses = twJoin(lineStaticClasses, 'whitespace-nowrap transition-transform after:transition-transform after:ease-exponential');
331
+ const scaleXClasses = 'after:scale-x-0 pointer-fine:hover:after:scale-x-100 active:after:scale-x-100';
332
+ const scaleYClasses = 'after:scale-y-0 pointer-fine:hover:after:scale-y-100 active:after:scale-y-100';
333
+ const lineNormalClasses = twJoin([
334
+ lineClasses,
335
+ scaleYClasses,
336
+ 'after:origin-bottom after:translate-y-0.5 active:after:translate-y-0 pointer-fine:hover:after:translate-y-0',
337
+ ]);
338
+ const lineLtrClasses = twJoin([lineClasses, scaleXClasses, 'after:origin-left']);
339
+ const lineRtlClasses = twJoin([lineClasses, scaleXClasses, 'after:origin-right']);
340
+ const lineCenterClasses = twJoin([lineClasses, scaleXClasses]);
341
+ const lineLiftClasses = twJoin([
342
+ lineClasses,
343
+ scaleYClasses,
344
+ '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',
345
+ ]);
346
+ const fillClasses = 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');
347
+ // Define theme-specific fill color transition classes
348
+ const getFillColorTransitionClasses = (theme = 'blue') => {
349
+ switch (theme) {
350
+ case 'brown':
351
+ return twJoin(fillClasses, 'after:bg-ui-brown after:transition-transform contrast-more:after:bg-ui-brown');
352
+ case 'green':
353
+ return twJoin(fillClasses, 'after:bg-ui-green after:transition-transform contrast-more:after:bg-ui-green');
354
+ case 'grey':
355
+ return twJoin(fillClasses, 'after:bg-ui-grey after:transition-transform contrast-more:after:bg-ui-grey');
356
+ case 'sky-blue':
357
+ return twJoin(fillClasses, 'after:bg-ui-sky-blue after:transition-transform contrast-more:after:bg-ui-sky-blue');
358
+ case 'magenta':
359
+ return twJoin(fillClasses, 'after:bg-ui-magenta after:transition-transform contrast-more:after:bg-ui-magenta');
360
+ case 'neutral':
361
+ return twJoin(fillClasses, 'after:bg-zinc-700 after:transition-transform contrast-more:after:bg-zinc-700 dark:after:bg-zinc-300 dark:contrast-more:after:bg-zinc-300');
362
+ case 'orange':
363
+ return twJoin(fillClasses, 'after:bg-ui-orange after:transition-transform contrast-more:after:bg-ui-orange');
364
+ case 'pink':
365
+ return twJoin(fillClasses, 'after:bg-ui-pink after:transition-transform contrast-more:after:bg-ui-pink');
366
+ case 'purple':
367
+ return twJoin(fillClasses, 'after:bg-ui-purple after:transition-transform contrast-more:after:bg-ui-purple');
368
+ case 'red':
369
+ return twJoin(fillClasses, 'after:bg-ui-red after:transition-transform contrast-more:after:bg-ui-red');
370
+ case 'violet':
371
+ return twJoin(fillClasses, 'after:bg-ui-violet after:transition-transform contrast-more:after:bg-ui-violet');
372
+ case 'yellow':
373
+ return twJoin(fillClasses, 'after:bg-ui-yellow after:transition-transform contrast-more:after:bg-ui-yellow');
374
+ case 'blue':
375
+ default:
376
+ return twJoin(fillClasses, 'after:bg-ui-blue after:transition-transform contrast-more:after:bg-ui-blue');
377
+ }
378
+ };
379
+ // Define theme-specific fill center classes
380
+ const getFillCenterClasses = (theme = 'blue') => {
381
+ switch (theme) {
382
+ case 'brown':
383
+ return twJoin(fillClasses, 'after:scale-x-50 after:scale-y-[0.25] after:bg-ui-brown/0 after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100 active:after:bg-ui-brown pointer-fine:hover:after:scale-x-100 pointer-fine:hover:after:scale-y-100 pointer-fine:hover:after:bg-ui-brown');
384
+ case 'green':
385
+ return twJoin(fillClasses, 'after:scale-x-50 after:scale-y-[0.25] after:bg-ui-green/0 after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100 active:after:bg-ui-green pointer-fine:hover:after:scale-x-100 pointer-fine:hover:after:scale-y-100 pointer-fine:hover:after:bg-ui-green');
386
+ case 'grey':
387
+ return twJoin(fillClasses, 'after:scale-x-50 after:scale-y-[0.25] after:bg-ui-grey/0 after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100 active:after:bg-ui-grey pointer-fine:hover:after:scale-x-100 pointer-fine:hover:after:scale-y-100 pointer-fine:hover:after:bg-ui-grey');
388
+ case 'sky-blue':
389
+ return twJoin(fillClasses, 'after:scale-x-50 after:scale-y-[0.25] after:bg-ui-sky-blue/0 after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100 active:after:bg-ui-sky-blue pointer-fine:hover:after:scale-x-100 pointer-fine:hover:after:scale-y-100 pointer-fine:hover:after:bg-ui-sky-blue');
390
+ case 'magenta':
391
+ return twJoin(fillClasses, 'after:scale-x-50 after:scale-y-[0.25] after:bg-ui-magenta/0 after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100 active:after:bg-ui-magenta pointer-fine:hover:after:scale-x-100 pointer-fine:hover:after:scale-y-100 pointer-fine:hover:after:bg-ui-magenta');
392
+ case 'neutral':
393
+ return twJoin(fillClasses, 'after:scale-x-50 after:scale-y-[0.25] after:bg-zinc-700/0 after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100 active:after:bg-zinc-700 dark:after:bg-zinc-300/0 dark:active:after:bg-zinc-300 pointer-fine:hover:after:scale-x-100 pointer-fine:hover:after:scale-y-100 pointer-fine:hover:after:bg-zinc-700 dark:pointer-fine:hover:after:bg-zinc-300');
394
+ case 'orange':
395
+ return twJoin(fillClasses, 'after:scale-x-50 after:scale-y-[0.25] after:bg-ui-orange/0 after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100 active:after:bg-ui-orange pointer-fine:hover:after:scale-x-100 pointer-fine:hover:after:scale-y-100 pointer-fine:hover:after:bg-ui-orange');
396
+ case 'pink':
397
+ return twJoin(fillClasses, 'after:scale-x-50 after:scale-y-[0.25] after:bg-ui-pink/0 after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100 active:after:bg-ui-pink pointer-fine:hover:after:scale-x-100 pointer-fine:hover:after:scale-y-100 pointer-fine:hover:after:bg-ui-pink');
398
+ case 'purple':
399
+ return twJoin(fillClasses, 'after:scale-x-50 after:scale-y-[0.25] after:bg-ui-purple/0 after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100 active:after:bg-ui-purple pointer-fine:hover:after:scale-x-100 pointer-fine:hover:after:scale-y-100 pointer-fine:hover:after:bg-ui-purple');
400
+ case 'red':
401
+ return twJoin(fillClasses, 'after:scale-x-50 after:scale-y-[0.25] after:bg-ui-red/0 after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100 active:after:bg-ui-red pointer-fine:hover:after:scale-x-100 pointer-fine:hover:after:scale-y-100 pointer-fine:hover:after:bg-ui-red');
402
+ case 'violet':
403
+ return twJoin(fillClasses, 'after:scale-x-50 after:scale-y-[0.25] after:bg-ui-violet/0 after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100 active:after:bg-ui-violet pointer-fine:hover:after:scale-x-100 pointer-fine:hover:after:scale-y-100 pointer-fine:hover:after:bg-ui-violet');
404
+ case 'yellow':
405
+ return twJoin(fillClasses, 'after:scale-x-50 after:scale-y-[0.25] after:bg-ui-yellow/0 after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100 active:after:bg-ui-yellow pointer-fine:hover:after:scale-x-100 pointer-fine:hover:after:scale-y-100 pointer-fine:hover:after:bg-ui-yellow');
406
+ case 'blue':
407
+ default:
408
+ return twJoin(fillClasses, 'after:scale-x-50 after:scale-y-[0.25] after:bg-ui-blue/0 after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100 active:after:bg-ui-blue pointer-fine:hover:after:scale-x-100 pointer-fine:hover:after:scale-y-100 pointer-fine:hover:after:bg-ui-blue');
409
+ }
410
+ };
411
+ const multilineBaseClasses = twSort('bg-linear-to-r from-current to-current bg-no-repeat active:scale-95');
412
+ const multilineLineStaticClasses = 'underline';
413
+ const multilineNormalClasses = twSort('underline-offset-1 active:underline pointer-fine:hover:underline');
414
+ const multilineClasses = twJoin(multilineBaseClasses, 'duration-500 ease-exponential');
415
+ const multilineLineClasses = twJoin(multilineClasses, 'bg-[position:0%_100%] px-px pb-px transition-[background-size]');
416
+ const multilineXClasses = twJoin(multilineLineClasses, 'bg-[size:0%_2px] focus-visible:bg-[size:100%_2px] active:bg-[size:100%_2px] pointer-fine:hover:bg-[size:100%_2px]');
417
+ const multilineLineRtlClasses = twJoin([multilineXClasses, 'bg-[position:100%_100%]']);
418
+ const multilineLineCenterClasses = twJoin([multilineXClasses, 'bg-[position:50%_100%]']);
419
+ const multilineLineLiftClasses = twJoin(multilineLineClasses, 'bg-[size:auto_0px] focus-visible:bg-[size:auto_2px] active:bg-[size:auto_2px] pointer-fine:hover:bg-[size:auto_2px]');
420
+ const multilineFillBaseClasses = twJoin(multilineBaseClasses, 'rounded px-0.5 py-0.75 focus-visible:text-zinc-50 active:text-zinc-50 pointer-fine:hover:text-zinc-50');
421
+ const getMultilineFillColorClasses = (theme = 'blue') => {
422
+ switch (theme) {
423
+ case 'brown':
424
+ return twJoin(multilineFillBaseClasses, 'from-ui-brown to-ui-brown transition-[background-size_color] contrast-more:from-ui-brown contrast-more:to-ui-brown');
425
+ case 'green':
426
+ return twJoin(multilineFillBaseClasses, 'from-ui-green to-ui-green transition-[background-size_color] contrast-more:from-ui-green contrast-more:to-ui-green');
427
+ case 'grey':
428
+ return twJoin(multilineFillBaseClasses, 'from-ui-grey to-ui-grey transition-[background-size_color] contrast-more:from-ui-grey contrast-more:to-ui-grey');
429
+ case 'sky-blue':
430
+ return twJoin(multilineFillBaseClasses, 'from-ui-sky-blue to-ui-sky-blue transition-[background-size_color] contrast-more:from-ui-sky-blue contrast-more:to-ui-sky-blue');
431
+ case 'magenta':
432
+ return twJoin(multilineFillBaseClasses, 'from-ui-magenta to-ui-magenta transition-[background-size_color] contrast-more:from-ui-magenta contrast-more:to-ui-magenta');
433
+ case 'neutral':
434
+ return twJoin(multilineFillBaseClasses, 'from-zinc-700 to-zinc-700 transition-[background-size_color] contrast-more:from-zinc-700 contrast-more:to-zinc-700 dark:from-zinc-300 dark:to-zinc-300 dark:contrast-more:from-zinc-300 dark:contrast-more:to-zinc-300');
435
+ case 'orange':
436
+ return twJoin(multilineFillBaseClasses, 'from-ui-orange to-ui-orange transition-[background-size_color] contrast-more:from-ui-orange contrast-more:to-ui-orange');
437
+ case 'pink':
438
+ return twJoin(multilineFillBaseClasses, 'from-ui-pink to-ui-pink transition-[background-size_color] contrast-more:from-ui-pink contrast-more:to-ui-pink');
439
+ case 'purple':
440
+ return twJoin(multilineFillBaseClasses, 'from-ui-purple to-ui-purple transition-[background-size_color] contrast-more:from-ui-purple contrast-more:to-ui-purple');
441
+ case 'red':
442
+ return twJoin(multilineFillBaseClasses, 'from-ui-red to-ui-red transition-[background-size_color] contrast-more:from-ui-red contrast-more:to-ui-red');
443
+ case 'violet':
444
+ return twJoin(multilineFillBaseClasses, 'from-ui-violet to-ui-violet transition-[background-size_color] contrast-more:from-ui-violet contrast-more:to-ui-violet');
445
+ case 'yellow':
446
+ return twJoin(multilineFillBaseClasses, 'from-ui-yellow to-ui-yellow transition-[background-size_color] contrast-more:from-ui-yellow contrast-more:to-ui-yellow');
447
+ case 'blue':
448
+ default:
449
+ return twJoin(multilineFillBaseClasses, 'from-ui-blue to-ui-blue transition-[background-size_color] contrast-more:from-ui-blue contrast-more:to-ui-blue');
450
+ }
451
+ };
452
+ // Define theme-specific multiline fill classes
453
+ const getMultilineFillClasses = (theme = 'blue') => {
454
+ switch (theme) {
455
+ case 'brown':
456
+ return twJoin(multilineFillBaseClasses, 'from-ui-brown/0 to-ui-brown/0 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:from-ui-brown focus-visible:to-ui-brown focus-visible:bg-[size:100%_100%] active:from-ui-brown active:to-ui-brown active:bg-[size:100%_100%] contrast-more:from-ui-brown/0 contrast-more:to-ui-brown/0 focus-visible:contrast-more:from-ui-brown focus-visible:contrast-more:to-ui-brown active:contrast-more:from-ui-brown active:contrast-more:to-ui-brown pointer-fine:hover:from-ui-brown pointer-fine:hover:to-ui-brown pointer-fine:hover:bg-[size:100%_100%] pointer-fine:hover:contrast-more:from-ui-brown pointer-fine:hover:contrast-more:to-ui-brown');
457
+ case 'green':
458
+ return twJoin(multilineFillBaseClasses, 'from-ui-green/0 to-ui-green/0 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:from-ui-green focus-visible:to-ui-green focus-visible:bg-[size:100%_100%] active:from-ui-green active:to-ui-green active:bg-[size:100%_100%] contrast-more:from-ui-green/0 contrast-more:to-ui-green/0 focus-visible:contrast-more:from-ui-green focus-visible:contrast-more:to-ui-green active:contrast-more:from-ui-green active:contrast-more:to-ui-green pointer-fine:hover:from-ui-green pointer-fine:hover:to-ui-green pointer-fine:hover:bg-[size:100%_100%] pointer-fine:hover:contrast-more:from-ui-green pointer-fine:hover:contrast-more:to-ui-green');
459
+ case 'grey':
460
+ return twJoin(multilineFillBaseClasses, 'from-ui-grey/0 to-ui-grey/0 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:from-ui-grey focus-visible:to-ui-grey focus-visible:bg-[size:100%_100%] active:from-ui-grey active:to-ui-grey active:bg-[size:100%_100%] contrast-more:from-ui-grey/0 contrast-more:to-ui-grey/0 focus-visible:contrast-more:from-ui-grey focus-visible:contrast-more:to-ui-grey active:contrast-more:from-ui-grey active:contrast-more:to-ui-grey pointer-fine:hover:from-ui-grey pointer-fine:hover:to-ui-grey pointer-fine:hover:bg-[size:100%_100%] pointer-fine:hover:contrast-more:from-ui-grey pointer-fine:hover:contrast-more:to-ui-grey');
461
+ case 'sky-blue':
462
+ return twJoin(multilineFillBaseClasses, 'from-ui-sky-blue/0 to-ui-sky-blue/0 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:from-ui-sky-blue focus-visible:to-ui-sky-blue focus-visible:bg-[size:100%_100%] active:from-ui-sky-blue active:to-ui-sky-blue active:bg-[size:100%_100%] contrast-more:from-ui-sky-blue/0 contrast-more:to-ui-sky-blue/0 focus-visible:contrast-more:from-ui-sky-blue focus-visible:contrast-more:to-ui-sky-blue active:contrast-more:from-ui-sky-blue active:contrast-more:to-ui-sky-blue pointer-fine:hover:from-ui-sky-blue pointer-fine:hover:to-ui-sky-blue pointer-fine:hover:bg-[size:100%_100%] pointer-fine:hover:contrast-more:from-ui-sky-blue pointer-fine:hover:contrast-more:to-ui-sky-blue');
463
+ case 'magenta':
464
+ return twJoin(multilineFillBaseClasses, 'from-ui-magenta/0 to-ui-magenta/0 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:from-ui-magenta focus-visible:to-ui-magenta focus-visible:bg-[size:100%_100%] active:from-ui-magenta active:to-ui-magenta active:bg-[size:100%_100%] contrast-more:from-ui-magenta/0 contrast-more:to-ui-magenta/0 focus-visible:contrast-more:from-ui-magenta focus-visible:contrast-more:to-ui-magenta active:contrast-more:from-ui-magenta active:contrast-more:to-ui-magenta pointer-fine:hover:from-ui-magenta pointer-fine:hover:to-ui-magenta pointer-fine:hover:bg-[size:100%_100%] pointer-fine:hover:contrast-more:from-ui-magenta pointer-fine:hover:contrast-more:to-ui-magenta');
465
+ case 'neutral':
466
+ return twJoin(multilineFillBaseClasses, 'from-zinc-700/0 to-zinc-700/0 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:from-zinc-700 focus-visible:to-zinc-700 focus-visible:bg-[size:100%_100%] active:from-zinc-700 active:to-zinc-700 active:bg-[size:100%_100%] contrast-more:from-zinc-700/0 contrast-more:to-zinc-700/0 focus-visible:contrast-more:from-zinc-700 focus-visible:contrast-more:to-zinc-700 active:contrast-more:from-zinc-700 active:contrast-more:to-zinc-700 dark:from-zinc-300/0 dark:to-zinc-300/0 dark:focus-visible:from-zinc-300 dark:focus-visible:to-zinc-300 dark:active:from-zinc-300 dark:active:to-zinc-300 dark:contrast-more:from-zinc-300/0 dark:contrast-more:to-zinc-300/0 dark:focus-visible:contrast-more:from-zinc-300 dark:focus-visible:contrast-more:to-zinc-300 dark:active:contrast-more:from-zinc-300 dark:active:contrast-more:to-zinc-300 pointer-fine:hover:from-zinc-700 pointer-fine:hover:to-zinc-700 pointer-fine:hover:bg-[size:100%_100%] pointer-fine:hover:contrast-more:from-zinc-700 pointer-fine:hover:contrast-more:to-zinc-700 dark:pointer-fine:hover:from-zinc-300 dark:pointer-fine:hover:to-zinc-300 dark:pointer-fine:hover:contrast-more:from-zinc-300 dark:pointer-fine:hover:contrast-more:to-zinc-300');
467
+ case 'orange':
468
+ return twJoin(multilineFillBaseClasses, 'from-ui-orange/0 to-ui-orange/0 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:from-ui-orange focus-visible:to-ui-orange focus-visible:bg-[size:100%_100%] active:from-ui-orange active:to-ui-orange active:bg-[size:100%_100%] contrast-more:from-ui-orange/0 contrast-more:to-ui-orange/0 focus-visible:contrast-more:from-ui-orange focus-visible:contrast-more:to-ui-orange active:contrast-more:from-ui-orange active:contrast-more:to-ui-orange pointer-fine:hover:from-ui-orange pointer-fine:hover:to-ui-orange pointer-fine:hover:bg-[size:100%_100%] pointer-fine:hover:contrast-more:from-ui-orange pointer-fine:hover:contrast-more:to-ui-orange');
469
+ case 'pink':
470
+ return twJoin(multilineFillBaseClasses, 'from-ui-pink/0 to-ui-pink/0 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:from-ui-pink focus-visible:to-ui-pink focus-visible:bg-[size:100%_100%] active:from-ui-pink active:to-ui-pink active:bg-[size:100%_100%] contrast-more:from-ui-pink/0 contrast-more:to-ui-pink/0 focus-visible:contrast-more:from-ui-pink focus-visible:contrast-more:to-ui-pink active:contrast-more:from-ui-pink active:contrast-more:to-ui-pink pointer-fine:hover:from-ui-pink pointer-fine:hover:to-ui-pink pointer-fine:hover:bg-[size:100%_100%] pointer-fine:hover:contrast-more:from-ui-pink pointer-fine:hover:contrast-more:to-ui-pink');
471
+ case 'purple':
472
+ return twJoin(multilineFillBaseClasses, 'from-ui-purple/0 to-ui-purple/0 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:from-ui-purple focus-visible:to-ui-purple focus-visible:bg-[size:100%_100%] active:from-ui-purple active:to-ui-purple active:bg-[size:100%_100%] contrast-more:from-ui-purple/0 contrast-more:to-ui-purple/0 focus-visible:contrast-more:from-ui-purple focus-visible:contrast-more:to-ui-purple active:contrast-more:from-ui-purple active:contrast-more:to-ui-purple pointer-fine:hover:from-ui-purple pointer-fine:hover:to-ui-purple pointer-fine:hover:bg-[size:100%_100%] pointer-fine:hover:contrast-more:from-ui-purple pointer-fine:hover:contrast-more:to-ui-purple');
473
+ case 'red':
474
+ return twJoin(multilineFillBaseClasses, 'from-ui-red/0 to-ui-red/0 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:from-ui-red focus-visible:to-ui-red focus-visible:bg-[size:100%_100%] active:from-ui-red active:to-ui-red active:bg-[size:100%_100%] contrast-more:from-ui-red/0 contrast-more:to-ui-red/0 focus-visible:contrast-more:from-ui-red focus-visible:contrast-more:to-ui-red active:contrast-more:from-ui-red active:contrast-more:to-ui-red pointer-fine:hover:from-ui-red pointer-fine:hover:to-ui-red pointer-fine:hover:bg-[size:100%_100%] pointer-fine:hover:contrast-more:from-ui-red pointer-fine:hover:contrast-more:to-ui-red');
475
+ case 'violet':
476
+ return twJoin(multilineFillBaseClasses, 'from-ui-violet/0 to-ui-violet/0 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:from-ui-violet focus-visible:to-ui-violet focus-visible:bg-[size:100%_100%] active:from-ui-violet active:to-ui-violet active:bg-[size:100%_100%] contrast-more:from-ui-violet/0 contrast-more:to-ui-violet/0 focus-visible:contrast-more:from-ui-violet focus-visible:contrast-more:to-ui-violet active:contrast-more:from-ui-violet active:contrast-more:to-ui-violet pointer-fine:hover:from-ui-violet pointer-fine:hover:to-ui-violet pointer-fine:hover:bg-[size:100%_100%] pointer-fine:hover:contrast-more:from-ui-violet pointer-fine:hover:contrast-more:to-ui-violet');
477
+ case 'yellow':
478
+ return twJoin(multilineFillBaseClasses, 'from-ui-yellow/0 to-ui-yellow/0 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:from-ui-yellow focus-visible:to-ui-yellow focus-visible:bg-[size:100%_100%] active:from-ui-yellow active:to-ui-yellow active:bg-[size:100%_100%] contrast-more:from-ui-yellow/0 contrast-more:to-ui-yellow/0 focus-visible:contrast-more:from-ui-yellow focus-visible:contrast-more:to-ui-yellow active:contrast-more:from-ui-yellow active:contrast-more:to-ui-yellow pointer-fine:hover:from-ui-yellow pointer-fine:hover:to-ui-yellow pointer-fine:hover:bg-[size:100%_100%] pointer-fine:hover:contrast-more:from-ui-yellow pointer-fine:hover:contrast-more:to-ui-yellow');
479
+ case 'blue':
480
+ default:
481
+ return twJoin(multilineFillBaseClasses, 'from-ui-blue/0 to-ui-blue/0 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:from-ui-blue focus-visible:to-ui-blue focus-visible:bg-[size:100%_100%] active:from-ui-blue active:to-ui-blue active:bg-[size:100%_100%] contrast-more:from-ui-blue/0 contrast-more:to-ui-blue/0 focus-visible:contrast-more:from-ui-blue focus-visible:contrast-more:to-ui-blue active:contrast-more:from-ui-blue active:contrast-more:to-ui-blue pointer-fine:hover:from-ui-blue pointer-fine:hover:to-ui-blue pointer-fine:hover:bg-[size:100%_100%] pointer-fine:hover:contrast-more:from-ui-blue pointer-fine:hover:contrast-more:to-ui-blue');
482
+ }
483
+ };
484
+ const getMultilineFillLiftClasses = (theme = 'blue') => {
485
+ return twJoin(getMultilineFillColorClasses(theme), 'bg-[size:auto_0px] bg-[position:50%_100%] focus-visible:bg-[size:auto_100%] active:bg-[size:auto_100%] pointer-fine:hover:bg-[size:auto_100%]');
486
+ };
487
+ const getMultilineFillXClasses = (theme = 'blue') => {
488
+ return twJoin(getMultilineFillColorClasses(theme), 'bg-[size:0%_100%] focus-visible:bg-[size:100%_100%] active:bg-[size:100%_100%] pointer-fine:hover:bg-[size:100%_100%]');
489
+ };
490
+ const getMultilineFillRtlClasses = (theme = 'blue') => {
491
+ return twJoin(getMultilineFillXClasses(theme), 'bg-[position:100%_auto]');
492
+ };
493
+ const getMultilineFillCenterClasses = (theme = 'blue') => {
494
+ return twJoin(getMultilineFillXClasses(theme), 'bg-[position:50%_auto]');
495
+ };
496
+ /**
497
+ * # Link
498
+ *
499
+ * - A component for rendering links with various styles and options.
500
+ * - Utilizes the Next.js `Link` component and provides additional functionality.
501
+ *
502
+ * ---
503
+ *
504
+ * ## Styles
505
+ *
506
+ * This component includes various classes to style the link. The styles are divided into two types:
507
+ *
508
+ * - Line styles: These styles add a line underneath the link, and include variations for different positions and orientations.
509
+ * - Fill styles: These styles add a background color behind the link, and include variations for different positions and orientations.
510
+ * - Multiline styles: These styles seek to accomplish the same as the line and fill styles, while offering multiline support.
511
+ *
512
+ * ---
513
+ *
514
+ * ## Examples
515
+ *
516
+ * @example
517
+ * <Link href='/about' type='ltr' title='About Us'>Learn more about our company</Link>
518
+ *
519
+ * @example
520
+ * <Link href='/about' type='fill-ltr' title='About Us'>Learn more about our company</Link>
521
+ *
522
+ * @example
523
+ * <Link href='/about' type='fill-ltr' theme='red' title='About Us'>Learn more about our company</Link>
524
+ */
525
+ function Link({ as, className, ref, theme = 'blue', type, ...props }) {
526
+ const getLinkClasses = () => {
527
+ switch (type) {
528
+ case 'static':
529
+ return lineStaticClasses;
530
+ case 'ltr':
531
+ return lineLtrClasses;
532
+ case 'rtl':
533
+ return lineRtlClasses;
534
+ case 'center':
535
+ return lineCenterClasses;
536
+ case 'lift':
537
+ return lineLiftClasses;
538
+ case 'fill':
539
+ return getFillCenterClasses(theme);
540
+ case 'fill-ltr':
541
+ return twJoin([getFillColorTransitionClasses(theme), scaleXClasses, 'after:origin-left']);
542
+ case 'fill-rtl':
543
+ return twJoin([getFillColorTransitionClasses(theme), scaleXClasses, 'after:origin-right']);
544
+ case 'fill-lift':
545
+ return twJoin([getFillColorTransitionClasses(theme), scaleYClasses, 'after:origin-bottom']);
546
+ case 'multiline':
547
+ return multilineNormalClasses;
548
+ case 'multiline-static':
549
+ return multilineLineStaticClasses;
550
+ case 'multiline-ltr':
551
+ return multilineXClasses;
552
+ case 'multiline-rtl':
553
+ return multilineLineRtlClasses;
554
+ case 'multiline-center':
555
+ return multilineLineCenterClasses;
556
+ case 'multiline-lift':
557
+ return multilineLineLiftClasses;
558
+ case 'multiline-fill':
559
+ return getMultilineFillClasses(theme);
560
+ case 'multiline-fill-ltr':
561
+ return getMultilineFillXClasses(theme);
562
+ case 'multiline-fill-rtl':
563
+ return getMultilineFillRtlClasses(theme);
564
+ case 'multiline-fill-center':
565
+ return getMultilineFillCenterClasses(theme);
566
+ case 'multiline-fill-lift':
567
+ return getMultilineFillLiftClasses(theme);
568
+ default:
569
+ return lineNormalClasses;
570
+ }
571
+ };
572
+ const linkClasses = getLinkClasses();
573
+ const LinkElement = as || Anchor;
574
+ return jsx(LinkElement, { ...props, className: twMerge(linkClasses, className), ref: ref });
575
+ }
576
+
577
+ /**
578
+ * # Button
579
+ * - A pre-styled button with utility props for easy customization depending on use case.
580
+ */
581
+ function Button({ className, padding = 'md', rounded = 'lg', theme = 'blue', ref, ...props }) {
582
+ const getPaddingClasses = () => {
583
+ switch (padding) {
584
+ case 'xs':
585
+ return 'px-2 py-0.5';
586
+ case 'sm':
587
+ return 'px-4 py-1';
588
+ case 'md':
589
+ return 'px-6 py-1.5';
590
+ case 'lg':
591
+ return 'px-8 py-2';
592
+ case 'xl':
593
+ return 'px-12 py-3';
594
+ }
595
+ };
596
+ const getRoundedClasses = () => {
597
+ switch (rounded) {
598
+ case 'xs':
599
+ return 'rounded-sm';
600
+ case 'sm':
601
+ return 'rounded-md';
602
+ case 'md':
603
+ return 'rounded-lg';
604
+ case 'lg':
605
+ return 'rounded-xl';
606
+ case 'xl':
607
+ return 'rounded-3xl';
608
+ case 'full':
609
+ return 'rounded-full';
610
+ }
611
+ };
612
+ const getThemeClasses = () => {
613
+ const classList = [];
614
+ switch (theme) {
615
+ case 'blue':
616
+ classList.push(twSort('text-white shadow-lg shadow-ui-blue/25 transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:bg-ui-blue before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
617
+ break;
618
+ case 'blue-gradient':
619
+ classList.push(twSort('bg-ui-blue text-white shadow-lg shadow-ui-blue/25 transition-transform before:absolute before:inset-0 before:rounded-[inherit] before:bg-linear-to-t before:from-black/75 before:via-transparent before:to-white/75 before:opacity-75 before:mix-blend-soft-light before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
620
+ break;
621
+ case 'brown':
622
+ classList.push(twSort('text-white shadow-lg shadow-ui-brown/25 transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:bg-ui-brown before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
623
+ break;
624
+ case 'brown-gradient':
625
+ classList.push(twSort('bg-ui-brown text-white shadow-lg shadow-ui-brown/25 transition-transform before:absolute before:inset-0 before:rounded-[inherit] before:bg-linear-to-t before:from-black/75 before:via-transparent before:to-white/75 before:opacity-75 before:mix-blend-soft-light before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
626
+ break;
627
+ case 'green':
628
+ classList.push(twSort('text-white shadow-lg shadow-ui-green/25 transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:bg-ui-green before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
629
+ break;
630
+ case 'green-gradient':
631
+ classList.push(twSort('bg-ui-green text-white shadow-lg shadow-ui-green/25 transition-transform before:absolute before:inset-0 before:rounded-[inherit] before:bg-linear-to-t before:from-black/75 before:via-transparent before:to-white/75 before:opacity-75 before:mix-blend-soft-light before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
632
+ break;
633
+ case 'grey':
634
+ classList.push(twSort('text-white shadow-lg shadow-ui-grey/25 transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:bg-ui-grey before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
635
+ break;
636
+ case 'grey-gradient':
637
+ classList.push(twSort('bg-ui-grey text-white shadow-lg shadow-ui-grey/25 transition-transform before:absolute before:inset-0 before:rounded-[inherit] before:bg-linear-to-t before:from-black/75 before:via-transparent before:to-white/75 before:opacity-75 before:mix-blend-soft-light before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
638
+ break;
639
+ case 'sky-blue':
640
+ classList.push(twSort('text-white shadow-lg shadow-ui-sky-blue/25 transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:bg-ui-sky-blue before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
641
+ break;
642
+ case 'sky-blue-gradient':
643
+ classList.push(twSort('bg-ui-sky-blue text-white shadow-lg shadow-ui-sky-blue/25 transition-transform before:absolute before:inset-0 before:rounded-[inherit] before:bg-linear-to-t before:from-black/75 before:via-transparent before:to-white/75 before:opacity-75 before:mix-blend-soft-light before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
644
+ break;
645
+ case 'magenta':
646
+ classList.push(twSort('text-white shadow-lg shadow-ui-magenta/25 transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:bg-ui-magenta before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
647
+ break;
648
+ case 'magenta-gradient':
649
+ classList.push(twSort('bg-ui-magenta text-white shadow-lg shadow-ui-magenta/25 transition-transform before:absolute before:inset-0 before:rounded-[inherit] before:bg-linear-to-t before:from-black/75 before:via-transparent before:to-white/75 before:opacity-75 before:mix-blend-soft-light before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
650
+ break;
651
+ case 'neutral':
652
+ classList.push(twSort('pointer-fine:active:before:brightness-90text-white dark bg-zinc-200 text-black before:absolute before:inset-0 before:rounded-[inherit] before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 dark:bg-zinc-800 pointer-fine:hover:before:brightness-110'));
653
+ break;
654
+ case 'neutral-gradient':
655
+ classList.push(twSort('dark bg-linear-to-t from-zinc-300 via-zinc-200 to-zinc-100 text-black before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 dark:from-zinc-900 dark:via-zinc-800 dark:to-zinc-700 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
656
+ break;
657
+ case 'orange':
658
+ classList.push(twSort('text-white shadow-lg shadow-ui-orange/25 transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:bg-ui-orange before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
659
+ break;
660
+ case 'orange-gradient':
661
+ classList.push(twSort('bg-ui-orange text-white shadow-lg shadow-ui-orange/25 transition-transform before:absolute before:inset-0 before:rounded-[inherit] before:bg-linear-to-t before:from-black/75 before:via-transparent before:to-white/75 before:opacity-75 before:mix-blend-soft-light before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
662
+ break;
663
+ case 'pink':
664
+ classList.push(twSort('text-white shadow-lg shadow-ui-pink/25 transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:bg-ui-pink before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
665
+ break;
666
+ case 'pink-gradient':
667
+ classList.push(twSort('before:to-white/75/75 bg-ui-pink text-white shadow-lg shadow-ui-pink/25 transition-transform before:absolute before:inset-0 before:rounded-[inherit] before:bg-linear-to-t before:from-black/75 before:via-transparent before:opacity-75 before:mix-blend-soft-light before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
668
+ break;
669
+ case 'purple':
670
+ classList.push(twSort('text-white shadow-lg shadow-ui-purple/25 transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:bg-ui-purple before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
671
+ break;
672
+ case 'purple-gradient':
673
+ classList.push(twSort('bg-ui-purple text-white shadow-lg shadow-ui-purple/25 transition-transform before:absolute before:inset-0 before:rounded-[inherit] before:bg-linear-to-t before:from-black/75 before:via-transparent before:to-white/75 before:opacity-75 before:mix-blend-soft-light before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
674
+ break;
675
+ case 'red':
676
+ classList.push(twSort('text-white shadow-lg shadow-ui-red/25 transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:bg-ui-red before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
677
+ break;
678
+ case 'red-gradient':
679
+ classList.push(twSort('bg-ui-red text-white shadow-lg shadow-ui-red/25 transition-transform before:absolute before:inset-0 before:rounded-[inherit] before:bg-linear-to-t before:from-black/75 before:via-transparent before:to-white/75 before:opacity-75 before:mix-blend-soft-light before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
680
+ break;
681
+ case 'violet':
682
+ classList.push(twSort('text-white shadow-lg shadow-ui-violet/25 transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:bg-ui-violet before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
683
+ break;
684
+ case 'violet-gradient':
685
+ classList.push(twSort('bg-ui-violet text-white shadow-lg shadow-ui-violet/25 transition-transform before:absolute before:inset-0 before:rounded-[inherit] before:bg-linear-to-t before:from-black/75 before:via-transparent before:to-white/75 before:opacity-75 before:mix-blend-soft-light before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
686
+ break;
687
+ case 'yellow':
688
+ classList.push(twSort('text-black shadow-lg shadow-ui-yellow/25 transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:bg-ui-yellow before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
689
+ break;
690
+ case 'yellow-gradient':
691
+ classList.push(twSort('bg-ui-yellow text-black shadow-lg shadow-ui-yellow/25 transition-transform before:absolute before:inset-0 before:rounded-[inherit] before:bg-linear-to-t before:from-black before:via-black/50 before:to-white/50 before:opacity-75 before:mix-blend-soft-light before:transition-[filter] before:duration-300 before:ease-exponential active:before:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90'));
692
+ break;
693
+ }
694
+ return classList.join(' ');
695
+ };
696
+ const paddingClasses = getPaddingClasses(), roundedClasses = getRoundedClasses(), themeClasses = getThemeClasses();
697
+ const buttonClasses = twMerge([
698
+ 'block w-fit min-w-fit text-center font-semibold duration-300 ease-exponential focus-visible:scale-101 active:scale-95 pointer-fine:hover:scale-101 pointer-fine:active:scale-99',
699
+ paddingClasses,
700
+ roundedClasses,
701
+ themeClasses,
702
+ className,
703
+ ]);
704
+ return 'href' in props && typeof props.href === 'string' ? (jsx(Anchor, { ref: ref, ...props, className: buttonClasses })) : (jsx(Button$1, { ref: ref, ...props, className: buttonClasses }));
705
+ }
706
+
707
+ function createFastContext(defaultInitialState) {
708
+ function useStoreData(initialState = defaultInitialState) {
709
+ const store = useRef(initialState), get = () => store.current, subscribers = useRef(new Set());
710
+ const set = (value) => {
711
+ if (typeof value === 'function') {
712
+ store.current = value(store.current);
713
+ }
714
+ else {
715
+ store.current = value;
716
+ }
717
+ subscribers.current.forEach(callback => callback());
718
+ };
719
+ const subscribe = (callback) => {
720
+ subscribers.current.add(callback);
721
+ return () => subscribers.current.delete(callback);
722
+ };
723
+ return {
724
+ get,
725
+ set,
726
+ subscribe,
727
+ };
728
+ }
729
+ const StoreContext = createContext(null);
730
+ function Provider({ initialValue = defaultInitialState, ...props }) {
731
+ return jsx(StoreContext.Provider, { value: useStoreData(initialValue), ...props });
732
+ }
733
+ function useStore(selector, initialValue) {
734
+ const store = useContext(StoreContext);
735
+ if (!store) {
736
+ const localStoreValue = initialValue !== undefined ? initialValue : defaultInitialState;
737
+ const selectedValue = selector(localStoreValue);
738
+ const noOpSet = () => console.warn('Attempting to set store value outside of Provider');
739
+ return [selectedValue, noOpSet];
740
+ }
741
+ const state = useSyncExternalStore(store.subscribe, () => selector(store.get()), () => selector(initialValue !== undefined ? initialValue : defaultInitialState));
742
+ return [state, store.set];
743
+ }
744
+ return {
745
+ Provider,
746
+ useStore,
747
+ };
748
+ }
749
+
750
+ /**
751
+ * # Define Field
752
+ *
753
+ * This is a helper function to define a field in a form context with type safety.
754
+ */
755
+ function defineField(fieldDefinition) {
756
+ return fieldDefinition;
757
+ }
758
+ const { Provider: Provider$1, useStore: useStore$1 } = createFastContext([]);
759
+ function FormContextProvider({ children }) {
760
+ return jsx(Provider$1, { children: children });
761
+ }
762
+ function useFormContext() {
763
+ return useStore$1(store => store);
764
+ }
765
+
766
+ const DEFAULT_STATUS = 'incomplete';
767
+ const { Provider, useStore } = createFastContext(DEFAULT_STATUS);
768
+ function FormStatusProvider({ children, initialStatus = DEFAULT_STATUS, }) {
769
+ return (jsx(Suspense, { children: jsx(Provider, { initialValue: initialStatus, children: children }) }));
770
+ }
771
+ function useFormStatus() {
772
+ return useStore(store => store);
773
+ }
774
+
775
+ function validateField$1(value, { required, type }) {
776
+ const noValue = !value || value === '';
777
+ if (!required && noValue)
778
+ return true;
779
+ if (noValue)
780
+ return false;
781
+ switch (type) {
782
+ case 'email':
783
+ return isEmail(value);
784
+ case 'number':
785
+ return !isNaN(Number(value));
786
+ case 'tel':
787
+ return isPhoneNumber(value);
788
+ default:
789
+ return true;
790
+ }
791
+ }
792
+ function Input({ checked, className, defaultValue, description, descriptionProps, disabled, fieldProps, invalid = true, label, labelProps, name, onBlur, onChange, placeholder, ref, required = true, type, value, ...props }) {
793
+ const [formContext, setFormContext] = useFormContext();
794
+ if (placeholder === '*')
795
+ placeholder = name + (required && !label ? '*' : '');
796
+ if (label === '*')
797
+ label = name;
798
+ const uniqueID = useId(), fieldContextID = toLowerCase(name, [, '_']) + '§' + uniqueID;
799
+ if (Boolean(formContext?.find(field => field.id === fieldContextID)?.invalid))
800
+ invalid = true;
801
+ const getFieldContextType = () => {
802
+ switch (type) {
803
+ case 'email':
804
+ return 'email';
805
+ case 'file':
806
+ return 'file';
807
+ case 'number':
808
+ return 'number';
809
+ case 'tel':
810
+ return 'tel';
811
+ case 'url':
812
+ return 'url';
813
+ default:
814
+ return 'string';
815
+ }
816
+ };
817
+ const fieldContextType = getFieldContextType();
818
+ const initialFieldContext = defineField({
819
+ type: fieldContextType,
820
+ id: fieldContextID,
821
+ invalid,
822
+ name,
823
+ required,
824
+ value: value ? `${value}` : defaultValue ? `${defaultValue}` : '',
825
+ });
826
+ useEffect(() => {
827
+ if (!setFormContext)
828
+ return;
829
+ setFormContext(prevContext => {
830
+ const otherFields = (prevContext || []).filter(field => field.id !== initialFieldContext.id);
831
+ return [...otherFields, initialFieldContext];
832
+ });
833
+ return () => {
834
+ setFormContext(prevContext => (prevContext || []).filter(field => field.id !== initialFieldContext.id));
835
+ };
836
+ }, [setFormContext]);
837
+ const fieldContext = formContext?.find(({ id: fieldID }) => fieldID === initialFieldContext.id) || initialFieldContext;
838
+ const debounceTimerRef = useRef(undefined);
839
+ const handleChange = e => {
840
+ if (disabled) {
841
+ e.preventDefault();
842
+ return;
843
+ }
844
+ clearTimeout(debounceTimerRef.current);
845
+ const { currentTarget } = e, { value: newValue } = currentTarget;
846
+ setFormContext?.(prevContext => {
847
+ if (!prevContext)
848
+ return [];
849
+ const field = prevContext.find(({ id: fieldID }) => fieldID === initialFieldContext.id);
850
+ if (!field)
851
+ throw new Error(`Field with id "${initialFieldContext.id}" not found in form context.`);
852
+ const otherFields = prevContext.filter(({ id: fieldID }) => fieldID !== initialFieldContext.id);
853
+ const updatedField = { ...field, value: newValue };
854
+ return [...otherFields, updatedField];
855
+ });
856
+ debounceTimerRef.current = setTimeout(() => {
857
+ const field = formContext?.find(({ id: fieldID }) => fieldID === initialFieldContext.id);
858
+ if (!field)
859
+ return;
860
+ const invalid = validateField$1(newValue, field) === false;
861
+ if (invalid !== field.invalid)
862
+ setFormContext?.(prevContext => {
863
+ if (!prevContext)
864
+ return [];
865
+ const field = prevContext.find(({ id: fieldID }) => fieldID === initialFieldContext.id);
866
+ if (!field)
867
+ throw new Error(`Field with id "${initialFieldContext.id}" not found in form context.`);
868
+ const otherFields = prevContext.filter(({ id: fieldID }) => fieldID !== initialFieldContext.id);
869
+ const updatedField = { ...field, invalid };
870
+ return [...otherFields, updatedField];
871
+ });
872
+ }, 500);
873
+ onChange?.(e);
874
+ };
875
+ const handleBlur = e => {
876
+ if (disabled) {
877
+ e.preventDefault();
878
+ return;
879
+ }
880
+ const { currentTarget } = e, { value: newValue } = currentTarget;
881
+ switch (type) {
882
+ case 'email':
883
+ setFormContext?.(prevContext => {
884
+ if (!prevContext)
885
+ return [];
886
+ const field = prevContext.find(({ id: fieldID }) => fieldID === initialFieldContext.id);
887
+ if (!field)
888
+ throw new Error(`Field with id "${initialFieldContext.id}" not found in form context.`);
889
+ const otherFields = prevContext.filter(({ id: fieldID }) => fieldID !== initialFieldContext.id);
890
+ const updatedField = { ...field, value: newValue.toLowerCase() };
891
+ return [...otherFields, updatedField];
892
+ });
893
+ break;
894
+ case 'tel':
895
+ setFormContext?.(prevContext => {
896
+ if (!prevContext)
897
+ return [];
898
+ const field = prevContext.find(({ id: fieldID }) => fieldID === initialFieldContext.id);
899
+ if (!field)
900
+ throw new Error(`Field with id "${initialFieldContext.id}" not found in form context.`);
901
+ const otherFields = prevContext.filter(({ id: fieldID }) => fieldID !== initialFieldContext.id);
902
+ const updatedField = { ...field, value: formatPhoneNumber(newValue, '1') };
903
+ return [...otherFields, updatedField];
904
+ });
905
+ break;
906
+ }
907
+ onBlur?.(e);
908
+ };
909
+ const restFieldProps = fieldProps
910
+ ? Object.fromEntries(Object.entries(fieldProps).filter(([key]) => key !== 'className'))
911
+ : {};
912
+ const restLabelProps = labelProps
913
+ ? Object.fromEntries(Object.entries(labelProps).filter(([key]) => key !== 'className'))
914
+ : {};
915
+ const restDescriptionProps = descriptionProps
916
+ ? Object.fromEntries(Object.entries(descriptionProps).filter(([key]) => key !== 'className'))
917
+ : {};
918
+ return (jsxs(Field, { ...restFieldProps, className: bag => twMerge('grid gap-1', typeof fieldProps?.className === 'function' ? fieldProps?.className(bag) : fieldProps?.className), disabled: disabled, children: [label && (jsx(Label, { ...restLabelProps, className: bag => twMerge('text-sm font-medium', required ? 'after:text-ui-red after:content-["_*"]' : '', typeof labelProps?.className === 'function' ? labelProps?.className(bag) : labelProps?.className), children: label })), jsx(Input$1, { ...props, className: bag => twMerge(
919
+ // Base styles
920
+ 'rounded-xl border-1 border-neutral-500/50 bg-neutral-100 py-1 pl-2 text-neutral-950 outline-offset-1 outline-ui-sky-blue/95 transition-[background-color] duration-300 ease-exponential dark:bg-neutral-700 dark:text-neutral-50',
921
+ // Pseudo styles
922
+ 'focus-visible:bg-neutral-50 focus-visible:outline-3 active:bg-neutral-200 dark:focus-visible:bg-neutral-600 dark:active:bg-neutral-800 pointer-fine:hover:bg-neutral-50 pointer-fine:active:bg-neutral-200 dark:pointer-fine:hover:bg-neutral-600 dark:pointer-fine:active:bg-neutral-800',
923
+ // user-invalid styles
924
+ '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))]',
925
+ // Custom styles
926
+ typeof className === 'function' ? className(bag) : className), id: fieldContext?.id, invalid: invalid, onBlur: handleBlur, onChange: handleChange, placeholder: placeholder, ref: ref, required: required, type: type, value: fieldContext?.value }), description && (jsx(Description, { ...restDescriptionProps, className: bag => twMerge('text-xs', typeof descriptionProps?.className === 'function'
927
+ ? descriptionProps?.className(bag)
928
+ : descriptionProps?.className), children: description }))] }));
929
+ }
930
+
931
+ function SubmitButton({ children, className, error, incomplete, loading, success, theme, type = 'submit', ref, ...props }) {
932
+ const [formStatus] = useFormStatus();
933
+ const getFormStatusButtonClasses = () => {
934
+ switch (formStatus) {
935
+ case 'loading':
936
+ return twSort('animate-pulse cursor-wait text-lg leading-6 font-black tracking-widest');
937
+ case 'error':
938
+ case 'success':
939
+ return 'cursor-not-allowed';
940
+ default:
941
+ return undefined;
942
+ }
943
+ };
944
+ const formStatusButtonClasses = getFormStatusButtonClasses();
945
+ const getFormStatusButtonTheme = () => {
946
+ switch (formStatus) {
947
+ case 'incomplete':
948
+ return 'grey';
949
+ case 'loading':
950
+ return 'blue';
951
+ case 'error':
952
+ return 'red';
953
+ case 'success':
954
+ return 'green';
955
+ default:
956
+ return theme;
957
+ }
958
+ };
959
+ const formStatusButtonTheme = getFormStatusButtonTheme();
960
+ const getButtonText = () => {
961
+ switch (formStatus) {
962
+ case 'incomplete':
963
+ return incomplete || 'Complete Form';
964
+ case 'loading':
965
+ return (loading || (jsxs(Fragment$1, { children: [jsx("span", { className: 'inline-block animate-wave animation-delay-300', children: "\u2022" }), jsx("span", { className: 'inline-block animate-wave animation-delay-150', children: "\u2022" }), jsx("span", { className: 'inline-block animate-wave', children: "\u2022" })] })));
966
+ case 'error':
967
+ return (jsxs(Fragment$1, { children: [error || 'Error', ' ', jsx("span", { className: 'absolute top-1/2 ml-1.5 translate-y-[calc(-50%-1.5px)] text-2xl', children: "\u00D7" })] }));
968
+ case 'success':
969
+ return success || 'Successfully Submitted';
970
+ default:
971
+ return children || 'Submit';
972
+ }
973
+ };
974
+ const buttonText = getButtonText();
975
+ return (jsx(Button, { ...props, className: twMerge([formStatusButtonClasses, 'w-full', className]), ref: ref, theme: formStatusButtonTheme, type: type, children: buttonText }));
976
+ }
977
+
978
+ function validateField(value, { required }) {
979
+ const noValue = !value || value === '';
980
+ if (!required && noValue)
981
+ return true;
982
+ if (noValue)
983
+ return false;
984
+ return true;
985
+ }
986
+ function Textarea({ className, defaultValue, description, descriptionProps, disabled, fieldProps, invalid = true, label, labelProps, name, onBlur, onChange, placeholder, ref, required = true, value, ...props }) {
987
+ const [formContext, setFormContext] = useFormContext();
988
+ if (placeholder === '*')
989
+ placeholder = name + (required && !label ? '*' : '');
990
+ if (label === '*')
991
+ label = name;
992
+ const uniqueID = useId(), fieldContextID = toLowerCase(name, [, '_']) + '§' + uniqueID;
993
+ if (Boolean(formContext?.find(field => field.id === fieldContextID)?.invalid))
994
+ invalid = true;
995
+ const initialFieldContext = defineField({
996
+ type: 'textarea',
997
+ id: fieldContextID,
998
+ invalid,
999
+ name,
1000
+ required,
1001
+ value: value ? `${value}` : defaultValue ? `${defaultValue}` : '',
1002
+ });
1003
+ useEffect(() => {
1004
+ if (!setFormContext)
1005
+ return;
1006
+ setFormContext(prevContext => {
1007
+ const otherFields = (prevContext || []).filter(field => field.id !== initialFieldContext.id);
1008
+ return [...otherFields, initialFieldContext];
1009
+ });
1010
+ return () => {
1011
+ setFormContext(prevContext => (prevContext || []).filter(field => field.id !== initialFieldContext.id));
1012
+ };
1013
+ }, [setFormContext]);
1014
+ const fieldContext = formContext?.find(({ id: fieldID }) => fieldID === initialFieldContext.id) || initialFieldContext;
1015
+ const debounceTimerRef = useRef(undefined);
1016
+ const handleChange = e => {
1017
+ if (disabled) {
1018
+ e.preventDefault();
1019
+ return;
1020
+ }
1021
+ clearTimeout(debounceTimerRef.current);
1022
+ const { currentTarget } = e, { value: newValue } = currentTarget;
1023
+ setFormContext?.(prevContext => {
1024
+ if (!prevContext)
1025
+ return [];
1026
+ const field = prevContext.find(({ id: fieldID }) => fieldID === initialFieldContext.id);
1027
+ if (!field)
1028
+ throw new Error(`Field with id "${initialFieldContext.id}" not found in form context.`);
1029
+ const otherFields = prevContext.filter(({ id: fieldID }) => fieldID !== initialFieldContext.id);
1030
+ const updatedField = { ...field, value: newValue };
1031
+ return [...otherFields, updatedField];
1032
+ });
1033
+ debounceTimerRef.current = setTimeout(() => {
1034
+ const field = formContext?.find(({ id: fieldID }) => fieldID === initialFieldContext.id);
1035
+ if (!field)
1036
+ return;
1037
+ const invalid = validateField(newValue, field) === false;
1038
+ if (invalid !== field.invalid)
1039
+ setFormContext?.(prevContext => {
1040
+ if (!prevContext)
1041
+ return [];
1042
+ const field = prevContext.find(({ id: fieldID }) => fieldID === initialFieldContext.id);
1043
+ if (!field)
1044
+ throw new Error(`Field with id "${initialFieldContext.id}" not found in form context.`);
1045
+ const otherFields = prevContext.filter(({ id: fieldID }) => fieldID !== initialFieldContext.id);
1046
+ const updatedField = { ...field, invalid };
1047
+ return [...otherFields, updatedField];
1048
+ });
1049
+ }, 500);
1050
+ onChange?.(e);
1051
+ };
1052
+ const restFieldProps = fieldProps
1053
+ ? Object.fromEntries(Object.entries(fieldProps).filter(([key]) => key !== 'className'))
1054
+ : {};
1055
+ const restLabelProps = labelProps
1056
+ ? Object.fromEntries(Object.entries(labelProps).filter(([key]) => key !== 'className'))
1057
+ : {};
1058
+ const restDescriptionProps = descriptionProps
1059
+ ? Object.fromEntries(Object.entries(descriptionProps).filter(([key]) => key !== 'className'))
1060
+ : {};
1061
+ return (jsxs(Field, { ...restFieldProps, className: bag => twMerge('grid gap-1', typeof fieldProps?.className === 'function' ? fieldProps?.className(bag) : fieldProps?.className), disabled: disabled, children: [label && (jsx(Label, { ...restLabelProps, className: bag => twMerge('text-sm font-medium', required ? 'after:text-ui-red after:content-["_*"]' : '', typeof labelProps?.className === 'function' ? labelProps?.className(bag) : labelProps?.className), children: label })), jsx(Textarea$1, { ...props, className: bag => twMerge(
1062
+ // Base styles
1063
+ 'field-sizing-content resize-none rounded-xl border-1 border-neutral-500/50 bg-neutral-100 py-1 pl-2 text-neutral-950 outline-offset-1 outline-ui-sky-blue/95 transition-[background-color] duration-300 ease-exponential dark:bg-neutral-700 dark:text-neutral-50',
1064
+ // Pseudo styles
1065
+ 'focus-visible:bg-neutral-50 focus-visible:outline-3 active:bg-neutral-200 dark:focus-visible:bg-neutral-600 dark:active:bg-neutral-800 pointer-fine:hover:bg-neutral-50 pointer-fine:active:bg-neutral-200 dark:pointer-fine:hover:bg-neutral-600 dark:pointer-fine:active:bg-neutral-800',
1066
+ // user-invalid styles
1067
+ '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))]',
1068
+ // Custom styles
1069
+ typeof className === 'function' ? className(bag) : className), id: fieldContext?.id, invalid: invalid, onChange: handleChange, placeholder: placeholder, ref: ref, required: required, value: fieldContext?.value }), description && (jsx(Description, { ...restDescriptionProps, className: bag => twMerge('text-xs', typeof descriptionProps?.className === 'function'
1070
+ ? descriptionProps?.className(bag)
1071
+ : descriptionProps?.className), children: description }))] }));
1072
+ }
1073
+
1074
+ // import { findComponentByType } from '../../utils'
1075
+ function FormComponent({ as, children, className, handleSubmit, onError, onSubmit, onSuccess, ...props }) {
1076
+ const [formContext] = useFormContext(), [formStatus, setFormStatus] = useFormStatus();
1077
+ // const submitButton = findComponentByType(children, SubmitButton)
1078
+ useEffect(() => {
1079
+ if (!formContext)
1080
+ return;
1081
+ if (formStatus !== 'incomplete' && formContext.find(({ invalid }) => invalid))
1082
+ setFormStatus?.('incomplete');
1083
+ if (formStatus !== 'ready' && formContext.every(({ invalid }) => !invalid))
1084
+ setFormStatus?.('ready');
1085
+ }, [formContext]);
1086
+ const processSubmit = handleSubmit ||
1087
+ (async (e) => {
1088
+ e.preventDefault();
1089
+ e.stopPropagation();
1090
+ setFormStatus?.('loading');
1091
+ const response = await onSubmit?.({ event: e, formContext });
1092
+ if (response && ('error' in response || response.status === 'error')) {
1093
+ setFormStatus?.('error');
1094
+ onError?.({ event: e, error: response.error || 'An error occurred when submitting the form.' });
1095
+ return;
1096
+ }
1097
+ if ((response && response.status === 'success') || !response) {
1098
+ setFormStatus?.('success');
1099
+ onSuccess?.({ event: e });
1100
+ }
1101
+ });
1102
+ const FormElement = as || 'form';
1103
+ return (jsx(FormElement, { ...props, className: twMerge(className, 'grid gap-3'), onSubmit: processSubmit, children: children }));
1104
+ }
1105
+ function Form({ controlled = 'auto', initialStatus = 'incomplete', ...props }) {
1106
+ const FormContextOrNotProvider = controlled === 'auto' ? FormContextProvider : Fragment;
1107
+ return (jsx(FormStatusProvider, { initialStatus: initialStatus, children: jsx(FormContextOrNotProvider, { children: jsx(FormComponent, { ...props }) }) }));
1108
+ }
1109
+
1110
+ function Ghost({ children, className, ...props }) {
1111
+ return (jsx("div", { ...props, className: twMerge('block w-24 max-w-full animate-pulse rounded bg-white/50', className), children: children || jsx(Fragment$1, { children: "\u00A0" }) }));
1112
+ }
1113
+
1114
+ function getTextFromChildren(children) {
1115
+ let text = '';
1116
+ Children.forEach(children, child => {
1117
+ if (typeof child === 'string' || typeof child === 'number') {
1118
+ text += child;
1119
+ }
1120
+ else if (isValidElement(child)) {
1121
+ text += getTextFromChildren(child.props.children);
1122
+ }
1123
+ });
1124
+ return text;
1125
+ }
1126
+ /**
1127
+ * # Heading
1128
+ * A heading component that renders HTML heading elements (h1-h6) with appropriate styling.
1129
+ * Automatically generates an ID for the heading based on its content if none is provided.
1130
+ */
1131
+ function Heading({ as = 'h2', children, customize, className, id, ref, ...props }) {
1132
+ const H = as;
1133
+ const targetableID = id || getTextFromChildren(children).replace(/\s+/g, '-').toLowerCase();
1134
+ const getBaseClasses = () => {
1135
+ switch (as) {
1136
+ case 'h1':
1137
+ return customize?.h1 || twSort('pb-2.5 text-6xl font-black last:pb-0');
1138
+ case 'h3':
1139
+ return customize?.h3 || twSort('pb-2 text-4xl font-extralight last:pb-0');
1140
+ case 'h4':
1141
+ return customize?.h4 || twSort('pb-2 text-3xl font-extrabold last:pb-0');
1142
+ case 'h5':
1143
+ return customize?.h5 || twSort('pb-1.5 text-2xl font-semibold last:pb-0');
1144
+ case 'h6':
1145
+ return customize?.h6 || twSort('pb-1 text-xl font-bold last:pb-0');
1146
+ default:
1147
+ return customize?.h2 || twSort('pb-2.5 text-5xl font-medium last:pb-0');
1148
+ }
1149
+ };
1150
+ const baseClasses = getBaseClasses();
1151
+ return (jsx(H, { ref: ref, id: targetableID, ...props, className: twMerge(baseClasses, className), children: children }));
1152
+ }
1153
+
1154
+ function xmark(props) {
1155
+ return (jsx("svg", { viewBox: '0 0 64 64', ...props, children: 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' }) }));
1156
+ }
1157
+
1158
+ function ModalTrigger({ as, ...props }) {
1159
+ const Element = as || Button$1;
1160
+ return jsx(Element, { ...props });
1161
+ }
1162
+ function ModalDialog(props) {
1163
+ return jsx("div", { ...props });
1164
+ }
1165
+ function Modal({ children, className, onClose, onOpen, place = 'bottom' }) {
1166
+ const [bodyElement, setBodyElement] = useState(null);
1167
+ useEffect(() => {
1168
+ if (!bodyElement && typeof window !== 'undefined')
1169
+ setBodyElement(document.body);
1170
+ }, [bodyElement]);
1171
+ const [isOpen, setIsOpen] = useState(false);
1172
+ const dialogPanelRef = useRef(null), dragMoveBoxRef = useRef(null),
1173
+ // lastTouchYRef = useRef(0),
1174
+ startDragCoords = useRef({ x: 0, y: 0 });
1175
+ const [allowDragClose, setAllowDragClose] = useState(false), [readyToClose, setReadyToClose] = useState(false);
1176
+ const openModal = () => {
1177
+ console.log('open');
1178
+ setIsOpen(true);
1179
+ onOpen?.();
1180
+ };
1181
+ const closeModal = () => {
1182
+ console.log('close');
1183
+ setIsOpen(false);
1184
+ onClose?.();
1185
+ };
1186
+ const enableClose = (clientX, clientY) => {
1187
+ startDragCoords.current.x = clientX;
1188
+ startDragCoords.current.y = clientY;
1189
+ dialogPanelRef.current.style.transitionDuration = '0s';
1190
+ setAllowDragClose(true);
1191
+ };
1192
+ const enableTouchClose = e => {
1193
+ const { touches } = e, touch = touches[0], { clientY } = touch;
1194
+ enableClose(0, clientY);
1195
+ };
1196
+ const enableMouseClose = e => {
1197
+ const { clientX, clientY } = e;
1198
+ enableClose(clientX, clientY);
1199
+ };
1200
+ const handleMove = (clientX, clientY) => {
1201
+ if (!dialogPanelRef.current)
1202
+ return;
1203
+ let deltaX = clientX - startDragCoords.current.x, deltaY = clientY - startDragCoords.current.y;
1204
+ if (deltaX > 0)
1205
+ deltaX = easeOutExpo(Math.abs(deltaX), 0, 25, 5000);
1206
+ if (deltaX < 0)
1207
+ deltaX = -easeOutExpo(Math.abs(deltaX), 0, 25, 5000);
1208
+ if (deltaY < 0)
1209
+ deltaY = -easeOutExpo(Math.abs(deltaY), 0, 25, 2000);
1210
+ if (deltaY >= 100 && !readyToClose) {
1211
+ setReadyToClose(true);
1212
+ }
1213
+ else if (deltaY < 100 && readyToClose) {
1214
+ setReadyToClose(false);
1215
+ }
1216
+ const greaterThanMediaSmall = innerWidth > 640;
1217
+ dialogPanelRef.current.style.translate = `calc(-50% + ${deltaX}px) ${greaterThanMediaSmall ? `calc(-50% + ${deltaY}px)` : `${deltaY}px`}`;
1218
+ };
1219
+ const handleMouseMove = e => {
1220
+ if (!allowDragClose)
1221
+ return;
1222
+ const { clientX, clientY } = e;
1223
+ handleMove(clientX, clientY);
1224
+ };
1225
+ const disableDragClose = (clientY) => {
1226
+ const deltaY = clientY - startDragCoords.current.y;
1227
+ dialogPanelRef.current.style.transitionDuration = '';
1228
+ if (deltaY >= 100) {
1229
+ closeModal();
1230
+ setReadyToClose(false);
1231
+ }
1232
+ else {
1233
+ setTimeout(() => (dialogPanelRef.current.style.removeProperty('translate'), 50));
1234
+ }
1235
+ };
1236
+ const disableMouseDragClose = e => {
1237
+ if (allowDragClose)
1238
+ setAllowDragClose(false);
1239
+ const { clientY } = e;
1240
+ disableDragClose(clientY);
1241
+ };
1242
+ const content = typeof children === 'function' ? children({ openModal, closeModal }) : children;
1243
+ const dialogElement = findComponentByType(content, ModalDialog);
1244
+ if (!dialogElement)
1245
+ throw new Error('ModalDialog must be defined in Modal children');
1246
+ let triggerElement = null;
1247
+ if (typeof children !== 'function') {
1248
+ triggerElement = findComponentByType(content, ModalTrigger);
1249
+ if (!triggerElement)
1250
+ throw new Error('ModalTrigger must be provided when not using render prop pattern');
1251
+ }
1252
+ else {
1253
+ triggerElement = findComponentByType(content, ModalTrigger);
1254
+ }
1255
+ return (jsxs(Fragment$1, { children: [allowDragClose &&
1256
+ bodyElement &&
1257
+ createPortal(jsx("div", { ref: dragMoveBoxRef, className: 'z-99 pointer-coarse:hidden fixed inset-0 h-dvh w-screen bg-transparent active:cursor-grabbing', onMouseMove: handleMouseMove, onMouseUp: disableMouseDragClose }), bodyElement), triggerElement &&
1258
+ cloneElement(triggerElement, { onClick: openModal }), jsxs(Dialog, { open: isOpen, onClose: closeModal, className: [
1259
+ 'isolate z-50',
1260
+ place === 'bottom' &&
1261
+ 'after:fixed after:inset-x-0 after:bottom-0 after:-z-10 after:h-16 after:bg-neutral-50 sm:after:hidden',
1262
+ ].join(' '), children: [jsx(DialogBackdrop, { transition: true, className: [
1263
+ 'duration-750 ease-exponential data-closed:opacity-0 fixed inset-0 cursor-pointer transition-[opacity_background-color_backdrop-filter_-webkit-backdrop-filter] delay-100',
1264
+ readyToClose
1265
+ ? 'bg-neutral-50/5 backdrop-blur-[1px] dark:bg-neutral-950/5'
1266
+ : 'bg-neutral-50/25 backdrop-blur-sm dark:bg-neutral-950/25',
1267
+ ].join(' '), children: jsx(Button, { theme: 'blue', padding: 'none', rounded: 'full', className: 'group/button pointer-fine:hover:w-20 fixed right-4 top-4 h-7 w-7 overflow-x-hidden transition-[scale_width_filter]', children: jsxs("div", { className: 'pointer-fine:group-hover/button:-translate-x-0.5 ease-exponential absolute right-1 top-1 flex items-center gap-1 pt-px transition-transform duration-300', children: [jsxs("span", { className: 'block text-xs font-medium uppercase leading-none text-neutral-50', children: ["Close", jsx("span", { className: 'sr-only', children: " Modal" })] }), jsx(xmark, { className: '-top-px block size-5 rotate-90 scale-75 fill-white stroke-white stroke-1 transition-transform duration-300 ease-in-out group-hover/button:rotate-0' })] }) }) }), jsxs(DialogPanel, { ref: dialogPanelRef, transition: true, className: twMerge('duration-750 ease-exponential data-closed:opacity-0 data-closed:scale-50 fixed left-1/2 -translate-x-1/2 overflow-y-scroll bg-neutral-50 p-4 shadow-[0_-15px_50px_-12px] shadow-neutral-950/25 transition-[transform_translate_opacity] sm:w-[calc(100vw-2rem)] sm:max-w-fit sm:p-6 sm:shadow-2xl lg:p-8 dark:bg-neutral-900', place === 'center'
1268
+ ? 'data-enter:translate-y-[calc(-50%+12rem)] data-leave:translate-y-[calc(-50%-8rem)] top-1/2 -translate-y-1/2 rounded-2xl'
1269
+ : 'rounded-t-4xl pointer-fine:top-1/2 pointer-fine:bottom-auto pointer-fine:-translate-y-1/2 pointer-fine:rounded-2xl data-enter:translate-y-full sm:data-enter:translate-y-[calc(-50%+12rem)] data-leave:translate-y-full sm:data-leave:translate-y-[calc(-50%-8rem)] sm:data-open:-translate-y-1/2 bottom-0 h-fit max-h-[calc(100dvh-4rem)] translate-y-0 sm:bottom-auto sm:top-1/2 sm:rounded-b-2xl sm:rounded-t-2xl', className), children: [jsx("button", { onTouchStart: enableTouchClose, onMouseDown: enableMouseClose, className: [
1270
+ 'after:ease-exponential absolute inset-x-0 top-0 z-10 flex h-6 cursor-grab items-center justify-center after:h-1 after:w-8 after:rounded-full after:transition-[transform_background-color] after:duration-500 active:cursor-grabbing',
1271
+ readyToClose
1272
+ ? 'after:scale-x-200 after:scale-y-200 after:bg-ui-blue'
1273
+ : 'after:bg-ui-grey/50 active:after:bg-ui-grey pointer-fine:hover:after:scale-x-125 pointer-fine:hover:after:bg-neutral-500/75 pointer-fine:active:after:scale-x-150 pointer-fine:active:after:bg-ui-grey active:after:scale-x-150 active:after:scale-y-125',
1274
+ ].join(' '), children: jsx("span", { className: 'sr-only', children: "Drag down to close" }) }), dialogElement] })] })] }));
1275
+ }
1276
+
1277
+ function Time({ children, dateObject, dateTime, day, hours, milliseconds, minutes, month, seconds, year, ref, ...props }) {
1278
+ const [date, setDate] = useState(dateObject || undefined);
1279
+ const getDateAndTime = () => {
1280
+ if (dateTime)
1281
+ return dateTime;
1282
+ if (!date)
1283
+ return '';
1284
+ const currentYear = date.getFullYear(), currentMonth = getMonth(date), currentDay = getDate(date), currentHour = getHours(date), currentMinute = getMinutes(date), currentSecond = getSeconds(date), currentMillisecond = getMilliseconds(date);
1285
+ return [currentYear, currentMonth, currentDay, currentHour, currentMinute, currentSecond, currentMillisecond].join('-');
1286
+ };
1287
+ const dateAndTime = getDateAndTime();
1288
+ const getDateDisplay = () => {
1289
+ if (children)
1290
+ return children;
1291
+ if (dateAndTime === '')
1292
+ return '';
1293
+ const [dtYear, dtMonth, dtDay, dtHour, dtMinute, dtSecond, dtMillisecond] = dateAndTime.split('-').map(Number);
1294
+ return [
1295
+ day && dtDay,
1296
+ month && [getMonthName(Number(dtMonth) - 1), month && year && ','].filter(Boolean).join(''),
1297
+ year && dtYear,
1298
+ hours &&
1299
+ minutes &&
1300
+ [
1301
+ 'at',
1302
+ hours && dtHour,
1303
+ hours && minutes && ':',
1304
+ minutes && dtMinute,
1305
+ minutes && seconds && ':',
1306
+ seconds && dtSecond,
1307
+ seconds && milliseconds && '.',
1308
+ milliseconds && dtMillisecond,
1309
+ ]
1310
+ .filter(Boolean)
1311
+ .join(''),
1312
+ ]
1313
+ .filter(Boolean)
1314
+ .join(' ');
1315
+ };
1316
+ const dateDisplay = getDateDisplay();
1317
+ useEffect(() => {
1318
+ if (date === undefined &&
1319
+ dateObject === undefined &&
1320
+ dateTime === undefined &&
1321
+ typeof window !== 'undefined' &&
1322
+ (dateAndTime === '' || dateDisplay === ''))
1323
+ setDate(new Date());
1324
+ }, [date, setDate, dateAndTime, dateDisplay, dateObject, dateTime]);
1325
+ return (jsx("time", { dateTime: dateAndTime, ref: ref, ...props, children: dateDisplay }));
1326
+ }
1327
+
1328
+ export { Anchor, Button, Form, Ghost, Heading, Input, Link, Modal, ModalDialog, ModalTrigger, SubmitButton, Textarea, Time };
1329
+ //# sourceMappingURL=components.esm.js.map