mado-ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -0
- package/README.md +274 -0
- package/css/index.css +5829 -0
- package/dist/components/button.d.ts +21 -0
- package/dist/components/form/index.d.ts +30 -0
- package/dist/components/form/input/index.d.ts +36 -0
- package/dist/components/form/submit-button.d.ts +20 -0
- package/dist/components/ghost.d.ts +4 -0
- package/dist/components/heading.d.ts +11 -0
- package/dist/components/index.d.ts +8 -0
- package/dist/components/link.d.ts +51 -0
- package/dist/components/mado-ui-provider.d.ts +1 -0
- package/dist/components/modal.d.ts +19 -0
- package/dist/components/time.d.ts +16 -0
- package/dist/hooks/create-fast-context.d.ts +7 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/use-anime-scope.d.ts +15 -0
- package/dist/hooks/use-form-context.d.ts +30 -0
- package/dist/hooks/use-form-status.d.ts +7 -0
- package/dist/icons/3-people.d.ts +2 -0
- package/dist/icons/3-rectangles-desktop-fill.d.ts +2 -0
- package/dist/icons/3-rectangles-desktop.d.ts +2 -0
- package/dist/icons/airplane.d.ts +2 -0
- package/dist/icons/arrow-triangle-2-circlepath-circle-fill.d.ts +2 -0
- package/dist/icons/arrow-triangle-2-circlepath-circle.d.ts +2 -0
- package/dist/icons/bag-fill.d.ts +2 -0
- package/dist/icons/banknote.d.ts +2 -0
- package/dist/icons/bell-fill.d.ts +2 -0
- package/dist/icons/bolt-car.d.ts +2 -0
- package/dist/icons/bolt-fill.d.ts +2 -0
- package/dist/icons/bolt-ring-closed.d.ts +2 -0
- package/dist/icons/bolt-trianglebadge-exclamationmark.d.ts +2 -0
- package/dist/icons/book-fill.d.ts +2 -0
- package/dist/icons/bookmark-fill.d.ts +2 -0
- package/dist/icons/briefcase-fill.d.ts +2 -0
- package/dist/icons/bubble-left-fill.d.ts +2 -0
- package/dist/icons/building-2-fill.d.ts +2 -0
- package/dist/icons/calendar.d.ts +2 -0
- package/dist/icons/camera-fill.d.ts +2 -0
- package/dist/icons/car-fill.d.ts +2 -0
- package/dist/icons/cart-fill.d.ts +2 -0
- package/dist/icons/chart-bar-doc-horizontal.d.ts +2 -0
- package/dist/icons/checkmark-seal.d.ts +2 -0
- package/dist/icons/checkmark.d.ts +2 -0
- package/dist/icons/chevron-compact-down.d.ts +2 -0
- package/dist/icons/chevron-down.d.ts +2 -0
- package/dist/icons/chevron-left-forwardslash-chevron-right.d.ts +2 -0
- package/dist/icons/chevron-left.d.ts +2 -0
- package/dist/icons/chevron-right.d.ts +2 -0
- package/dist/icons/chevron-up-chevron-down.d.ts +2 -0
- package/dist/icons/circle-fill.d.ts +2 -0
- package/dist/icons/clock-badge-checkmark.d.ts +2 -0
- package/dist/icons/clock-fill.d.ts +2 -0
- package/dist/icons/cloud-fill.d.ts +2 -0
- package/dist/icons/cube-fill.d.ts +2 -0
- package/dist/icons/curve-point-left.d.ts +2 -0
- package/dist/icons/dial-high.d.ts +2 -0
- package/dist/icons/doc-fill.d.ts +2 -0
- package/dist/icons/doc-on-clipboard.d.ts +2 -0
- package/dist/icons/doc-on-doc-fill.d.ts +2 -0
- package/dist/icons/doc-on-doc.d.ts +2 -0
- package/dist/icons/doc-text-magnifyingglass.d.ts +2 -0
- package/dist/icons/dollar-sign.d.ts +2 -0
- package/dist/icons/ellipsis-circle-fill.d.ts +2 -0
- package/dist/icons/ellipsis-circle.d.ts +2 -0
- package/dist/icons/envelope-fill.d.ts +2 -0
- package/dist/icons/envelope.d.ts +2 -0
- package/dist/icons/exclamationmark-octagon.d.ts +2 -0
- package/dist/icons/eye.d.ts +2 -0
- package/dist/icons/figure-water-fitness.d.ts +2 -0
- package/dist/icons/flag-fill.d.ts +2 -0
- package/dist/icons/flame-fill.d.ts +2 -0
- package/dist/icons/folder-fill.d.ts +2 -0
- package/dist/icons/folder.d.ts +2 -0
- package/dist/icons/gearshape-fill.d.ts +2 -0
- package/dist/icons/gearshape.d.ts +2 -0
- package/dist/icons/gift-fill.d.ts +2 -0
- package/dist/icons/globe-americas-fill.d.ts +2 -0
- package/dist/icons/hare-fill.d.ts +2 -0
- package/dist/icons/house-deskclock.d.ts +2 -0
- package/dist/icons/house-fill.d.ts +2 -0
- package/dist/icons/house.d.ts +2 -0
- package/dist/icons/index.d.ts +104 -0
- package/dist/icons/iphone-house.d.ts +2 -0
- package/dist/icons/light-ribbon.d.ts +2 -0
- package/dist/icons/lightbulb-fill.d.ts +2 -0
- package/dist/icons/lightbulb-led.d.ts +2 -0
- package/dist/icons/list-bullet-clipboard-fill.d.ts +2 -0
- package/dist/icons/magnifyingglass.d.ts +2 -0
- package/dist/icons/map-pin-ellipse.d.ts +2 -0
- package/dist/icons/minus-plus-batterblock.d.ts +2 -0
- package/dist/icons/network-shield.d.ts +2 -0
- package/dist/icons/network.d.ts +2 -0
- package/dist/icons/newspaper-fill.d.ts +2 -0
- package/dist/icons/number.d.ts +2 -0
- package/dist/icons/paperplane-fill.d.ts +2 -0
- package/dist/icons/person-crop-square.d.ts +2 -0
- package/dist/icons/person-fill-questionmark.d.ts +2 -0
- package/dist/icons/person-fill.d.ts +2 -0
- package/dist/icons/person.d.ts +2 -0
- package/dist/icons/phone-arrow-up-right.d.ts +2 -0
- package/dist/icons/phone-fill.d.ts +2 -0
- package/dist/icons/phone.d.ts +2 -0
- package/dist/icons/play-rectangle-fill.d.ts +2 -0
- package/dist/icons/plus.d.ts +2 -0
- package/dist/icons/qrcode.d.ts +2 -0
- package/dist/icons/rectangle-portrait-and-arrow-left-fill.d.ts +2 -0
- package/dist/icons/rectangle-portrait-and-arrow-left.d.ts +2 -0
- package/dist/icons/sensor.d.ts +2 -0
- package/dist/icons/signature.d.ts +2 -0
- package/dist/icons/solar-panel.d.ts +2 -0
- package/dist/icons/square-and-arrow-down-fill.d.ts +2 -0
- package/dist/icons/square-and-arrow-down.d.ts +2 -0
- package/dist/icons/square-and-arrow-up-fill.d.ts +2 -0
- package/dist/icons/square-and-arrow-up.d.ts +2 -0
- package/dist/icons/square-and-pencil-fill.d.ts +2 -0
- package/dist/icons/square-and-pencil.d.ts +2 -0
- package/dist/icons/text-bubble.d.ts +2 -0
- package/dist/icons/trash-fill.d.ts +2 -0
- package/dist/icons/trash.d.ts +2 -0
- package/dist/icons/tree.d.ts +2 -0
- package/dist/icons/umbrella-fill.d.ts +2 -0
- package/dist/icons/xmark.d.ts +2 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.esm.js +1168 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +1186 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/utils.d.ts +18 -0
- package/dist/utils/class-management.d.ts +29 -0
- package/dist/utils/custom-tailwind-merge.d.ts +4 -0
- package/dist/utils/get-date.d.ts +153 -0
- package/dist/utils/helpers.d.ts +2 -0
- package/dist/utils/index.d.ts +9 -0
- package/dist/utils/math.d.ts +1 -0
- package/dist/utils/regex.d.ts +12 -0
- package/dist/utils/string-manipulation.d.ts +17 -0
- package/dist/utils/tw-sort.d.ts +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,1168 @@
|
|
|
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, 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
|
+
/**
|
|
278
|
+
* # To Lower Case
|
|
279
|
+
* Converts a string to lowercase, and offers easy string replacements for creating snake case, kebab case, or your own.
|
|
280
|
+
* @param str - The string to convert to lowercase.
|
|
281
|
+
* @param options - Configuration options.
|
|
282
|
+
* @param options[0] - The delimiter to split the string. Defaults to space.
|
|
283
|
+
* @param options[1] - The string to join the parts back together. Defaults to space.
|
|
284
|
+
* @returns The lowercase version of the input string, with the replacements, if provided.
|
|
285
|
+
*/
|
|
286
|
+
function toLowerCase(str, [delimiter, joiner]) {
|
|
287
|
+
return str.toLowerCase().replaceAll(delimiter || ' ', joiner || ' ');
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function twSort(className) {
|
|
291
|
+
return className;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function Anchor({ className, disabled, href, onClick, ref, target, rel, ...props }) {
|
|
295
|
+
const isExternal = `${href}`.startsWith('http'), hasHash = `${href}`.includes('#');
|
|
296
|
+
const handleClick = e => {
|
|
297
|
+
if (disabled)
|
|
298
|
+
return e.preventDefault();
|
|
299
|
+
onClick?.(e);
|
|
300
|
+
setTimeout(() => history.replaceState({}, document.title, location.pathname), 100);
|
|
301
|
+
};
|
|
302
|
+
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
|
|
303
|
+
? rel === 'nofollow'
|
|
304
|
+
? `${rel} noreferrer noopener`
|
|
305
|
+
: `${rel} prefetch`
|
|
306
|
+
: isExternal
|
|
307
|
+
? 'nofollow noreferrer noopener'
|
|
308
|
+
: 'prefetch' }));
|
|
309
|
+
}
|
|
310
|
+
// * Styles
|
|
311
|
+
const baseClasses = twSort('ease-exponential isolate inline-block cursor-pointer duration-300 after:absolute after:left-1/2 after:-z-10 after:-translate-x-1/2 after:duration-500 active:scale-95 active:after:opacity-100');
|
|
312
|
+
const lineStaticClasses = twJoin(baseClasses, 'after:border-1 whitespace-nowrap after:-bottom-0.5 after:w-[calc(100%+0.15rem)] after:rounded-full after:border-current');
|
|
313
|
+
const lineClasses = twJoin(lineStaticClasses, 'after:ease-exponential whitespace-nowrap transition-transform after:transition-transform');
|
|
314
|
+
const scaleXClasses = 'after:scale-x-0 pointer-fine:hover:after:scale-x-100 active:after:scale-x-100';
|
|
315
|
+
const scaleYClasses = 'after:scale-y-0 pointer-fine:hover:after:scale-y-100 active:after:scale-y-100';
|
|
316
|
+
const lineNormalClasses = twJoin([
|
|
317
|
+
lineClasses,
|
|
318
|
+
scaleYClasses,
|
|
319
|
+
'pointer-fine:hover:after:translate-y-0 after:origin-bottom after:translate-y-0.5 active:after:translate-y-0',
|
|
320
|
+
]);
|
|
321
|
+
const lineLtrClasses = twJoin([lineClasses, scaleXClasses, 'after:origin-left']);
|
|
322
|
+
const lineRtlClasses = twJoin([lineClasses, scaleXClasses, 'after:origin-right']);
|
|
323
|
+
const lineCenterClasses = twJoin([lineClasses, scaleXClasses]);
|
|
324
|
+
const lineLiftClasses = twJoin([
|
|
325
|
+
lineClasses,
|
|
326
|
+
scaleYClasses,
|
|
327
|
+
'pointer-fine:hover:after:translate-y-0 pointer-fine:hover:after:scale-x-100 after:origin-bottom after:translate-y-1 after:scale-x-75 active:after:translate-y-0 active:after:scale-x-100',
|
|
328
|
+
]);
|
|
329
|
+
const fillClasses = twJoin(baseClasses, 'after:ease-exponential pointer-fine:hover:text-zinc-50 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 active:text-zinc-50');
|
|
330
|
+
// Define theme-specific fill color transition classes
|
|
331
|
+
const getFillColorTransitionClasses = (theme = 'blue') => {
|
|
332
|
+
switch (theme) {
|
|
333
|
+
case 'brown':
|
|
334
|
+
return twJoin(fillClasses, 'after:bg-ui-brown contrast-more:after:bg-ui-brown after:transition-transform');
|
|
335
|
+
case 'green':
|
|
336
|
+
return twJoin(fillClasses, 'after:bg-ui-green contrast-more:after:bg-ui-green after:transition-transform');
|
|
337
|
+
case 'grey':
|
|
338
|
+
return twJoin(fillClasses, 'after:bg-ui-grey contrast-more:after:bg-ui-grey after:transition-transform');
|
|
339
|
+
case 'sky-blue':
|
|
340
|
+
return twJoin(fillClasses, 'after:bg-ui-sky-blue contrast-more:after:bg-ui-sky-blue after:transition-transform');
|
|
341
|
+
case 'magenta':
|
|
342
|
+
return twJoin(fillClasses, 'after:bg-ui-magenta contrast-more:after:bg-ui-magenta after:transition-transform');
|
|
343
|
+
case 'neutral':
|
|
344
|
+
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');
|
|
345
|
+
case 'orange':
|
|
346
|
+
return twJoin(fillClasses, 'after:bg-ui-orange contrast-more:after:bg-ui-orange after:transition-transform');
|
|
347
|
+
case 'pink':
|
|
348
|
+
return twJoin(fillClasses, 'after:bg-ui-pink contrast-more:after:bg-ui-pink after:transition-transform');
|
|
349
|
+
case 'primary':
|
|
350
|
+
return twJoin(fillClasses, 'after:bg-primary-500 contrast-more:after:bg-primary-500 after:transition-transform');
|
|
351
|
+
case 'purple':
|
|
352
|
+
return twJoin(fillClasses, 'after:bg-ui-purple contrast-more:after:bg-ui-purple after:transition-transform');
|
|
353
|
+
case 'red':
|
|
354
|
+
return twJoin(fillClasses, 'after:bg-ui-red contrast-more:after:bg-ui-red after:transition-transform');
|
|
355
|
+
case 'violet':
|
|
356
|
+
return twJoin(fillClasses, 'after:bg-ui-violet contrast-more:after:bg-ui-violet after:transition-transform');
|
|
357
|
+
case 'yellow':
|
|
358
|
+
return twJoin(fillClasses, 'after:bg-ui-yellow contrast-more:after:bg-ui-yellow after:transition-transform');
|
|
359
|
+
case 'blue':
|
|
360
|
+
default:
|
|
361
|
+
return twJoin(fillClasses, 'after:bg-ui-blue contrast-more:after:bg-ui-blue after:transition-transform');
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
// Define theme-specific fill center classes
|
|
365
|
+
const getFillCenterClasses = (theme = 'blue') => {
|
|
366
|
+
switch (theme) {
|
|
367
|
+
case 'brown':
|
|
368
|
+
return twJoin(fillClasses, 'after:bg-ui-brown/0 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 after:scale-x-50 after:scale-y-[0.25] after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100');
|
|
369
|
+
case 'green':
|
|
370
|
+
return twJoin(fillClasses, 'after:bg-ui-green/0 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 after:scale-x-50 after:scale-y-[0.25] after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100');
|
|
371
|
+
case 'grey':
|
|
372
|
+
return twJoin(fillClasses, 'after:bg-ui-grey/0 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 after:scale-x-50 after:scale-y-[0.25] after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100');
|
|
373
|
+
case 'sky-blue':
|
|
374
|
+
return twJoin(fillClasses, 'after:bg-ui-sky-blue/0 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 after:scale-x-50 after:scale-y-[0.25] after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100');
|
|
375
|
+
case 'magenta':
|
|
376
|
+
return twJoin(fillClasses, 'after:bg-ui-magenta/0 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 after:scale-x-50 after:scale-y-[0.25] after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100');
|
|
377
|
+
case 'neutral':
|
|
378
|
+
return twJoin(fillClasses, '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 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');
|
|
379
|
+
case 'orange':
|
|
380
|
+
return twJoin(fillClasses, 'after:bg-ui-orange/0 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 after:scale-x-50 after:scale-y-[0.25] after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100');
|
|
381
|
+
case 'pink':
|
|
382
|
+
return twJoin(fillClasses, 'after:bg-ui-pink/0 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 after:scale-x-50 after:scale-y-[0.25] after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100');
|
|
383
|
+
case 'primary':
|
|
384
|
+
return twJoin(fillClasses, 'after:bg-primary-500/0 active:after:bg-primary-500 pointer-fine:hover:after:scale-x-100 pointer-fine:hover:after:scale-y-100 pointer-fine:hover:after:bg-primary-500 after:scale-x-50 after:scale-y-[0.25] after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100');
|
|
385
|
+
case 'purple':
|
|
386
|
+
return twJoin(fillClasses, 'after:bg-ui-purple/0 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 after:scale-x-50 after:scale-y-[0.25] after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100');
|
|
387
|
+
case 'red':
|
|
388
|
+
return twJoin(fillClasses, 'after:bg-ui-red/0 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 after:scale-x-50 after:scale-y-[0.25] after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100');
|
|
389
|
+
case 'violet':
|
|
390
|
+
return twJoin(fillClasses, 'after:bg-ui-violet/0 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 after:scale-x-50 after:scale-y-[0.25] after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100');
|
|
391
|
+
case 'yellow':
|
|
392
|
+
return twJoin(fillClasses, 'after:bg-ui-yellow/0 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 after:scale-x-50 after:scale-y-[0.25] after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100');
|
|
393
|
+
case 'blue':
|
|
394
|
+
default:
|
|
395
|
+
return twJoin(fillClasses, 'after:bg-ui-blue/0 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 after:scale-x-50 after:scale-y-[0.25] after:transition-[transform_background-color] active:after:scale-x-100 active:after:scale-y-100');
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
const multilineBaseClasses = twSort('bg-linear-to-r from-current to-current bg-no-repeat active:scale-95');
|
|
399
|
+
const multilineLineStaticClasses = 'underline';
|
|
400
|
+
const multilineNormalClasses = twSort('pointer-fine:hover:underline underline-offset-1 active:underline');
|
|
401
|
+
const multilineClasses = twJoin(multilineBaseClasses, 'ease-exponential duration-500');
|
|
402
|
+
const multilineLineClasses = twJoin(multilineClasses, 'bg-[position:0%_100%] px-px pb-px transition-[background-size]');
|
|
403
|
+
const multilineXClasses = twJoin(multilineLineClasses, 'pointer-fine:hover:bg-[size:100%_2px] bg-[size:0%_2px] focus-visible:bg-[size:100%_2px] active:bg-[size:100%_2px]');
|
|
404
|
+
const multilineLineRtlClasses = twJoin([multilineXClasses, 'bg-[position:100%_100%]']);
|
|
405
|
+
const multilineLineCenterClasses = twJoin([multilineXClasses, 'bg-[position:50%_100%]']);
|
|
406
|
+
const multilineLineLiftClasses = twJoin(multilineLineClasses, 'pointer-fine:hover:bg-[size:auto_2px] bg-[size:auto_0px] focus-visible:bg-[size:auto_2px] active:bg-[size:auto_2px]');
|
|
407
|
+
const multilineFillBaseClasses = twJoin(multilineBaseClasses, 'py-0.75 pointer-fine:hover:text-zinc-50 rounded px-0.5 focus-visible:text-zinc-50 active:text-zinc-50');
|
|
408
|
+
// Define theme-specific multiline fill color classes
|
|
409
|
+
const getMultilineFillColorClasses = (theme = 'blue') => {
|
|
410
|
+
switch (theme) {
|
|
411
|
+
case 'brown':
|
|
412
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-brown to-ui-brown contrast-more:from-ui-brown contrast-more:to-ui-brown transition-[background-size_color]');
|
|
413
|
+
case 'green':
|
|
414
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-green to-ui-green contrast-more:from-ui-green contrast-more:to-ui-green transition-[background-size_color]');
|
|
415
|
+
case 'grey':
|
|
416
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-grey to-ui-grey contrast-more:from-ui-grey contrast-more:to-ui-grey transition-[background-size_color]');
|
|
417
|
+
case 'sky-blue':
|
|
418
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-sky-blue to-ui-sky-blue contrast-more:from-ui-sky-blue contrast-more:to-ui-sky-blue transition-[background-size_color]');
|
|
419
|
+
case 'magenta':
|
|
420
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-magenta to-ui-magenta contrast-more:from-ui-magenta contrast-more:to-ui-magenta transition-[background-size_color]');
|
|
421
|
+
case 'neutral':
|
|
422
|
+
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');
|
|
423
|
+
case 'orange':
|
|
424
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-orange to-ui-orange contrast-more:from-ui-orange contrast-more:to-ui-orange transition-[background-size_color]');
|
|
425
|
+
case 'pink':
|
|
426
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-pink to-ui-pink contrast-more:from-ui-pink contrast-more:to-ui-pink transition-[background-size_color]');
|
|
427
|
+
case 'primary':
|
|
428
|
+
return twJoin(multilineFillBaseClasses, 'from-primary-500 to-primary-500 contrast-more:from-primary-500 contrast-more:to-primary-500 transition-[background-size_color]');
|
|
429
|
+
case 'purple':
|
|
430
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-purple to-ui-purple contrast-more:from-ui-purple contrast-more:to-ui-purple transition-[background-size_color]');
|
|
431
|
+
case 'red':
|
|
432
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-red to-ui-red contrast-more:from-ui-red contrast-more:to-ui-red transition-[background-size_color]');
|
|
433
|
+
case 'violet':
|
|
434
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-violet to-ui-violet contrast-more:from-ui-violet contrast-more:to-ui-violet transition-[background-size_color]');
|
|
435
|
+
case 'yellow':
|
|
436
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-yellow to-ui-yellow contrast-more:from-ui-yellow contrast-more:to-ui-yellow transition-[background-size_color]');
|
|
437
|
+
case 'blue':
|
|
438
|
+
default:
|
|
439
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-blue to-ui-blue contrast-more:from-ui-blue contrast-more:to-ui-blue transition-[background-size_color]');
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
// Define theme-specific multiline fill classes
|
|
443
|
+
const getMultilineFillClasses = (theme = 'blue') => {
|
|
444
|
+
switch (theme) {
|
|
445
|
+
case 'brown':
|
|
446
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-brown/0 to-ui-brown/0 focus-visible:from-ui-brown focus-visible:to-ui-brown active:from-ui-brown active:to-ui-brown 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 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:bg-[size:100%_100%] active:bg-[size:100%_100%]');
|
|
447
|
+
case 'green':
|
|
448
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-green/0 to-ui-green/0 focus-visible:from-ui-green focus-visible:to-ui-green active:from-ui-green active:to-ui-green 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 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:bg-[size:100%_100%] active:bg-[size:100%_100%]');
|
|
449
|
+
case 'grey':
|
|
450
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-grey/0 to-ui-grey/0 focus-visible:from-ui-grey focus-visible:to-ui-grey active:from-ui-grey active:to-ui-grey 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 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:bg-[size:100%_100%] active:bg-[size:100%_100%]');
|
|
451
|
+
case 'sky-blue':
|
|
452
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-sky-blue/0 to-ui-sky-blue/0 focus-visible:from-ui-sky-blue focus-visible:to-ui-sky-blue active:from-ui-sky-blue active:to-ui-sky-blue 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 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:bg-[size:100%_100%] active:bg-[size:100%_100%]');
|
|
453
|
+
case 'magenta':
|
|
454
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-magenta/0 to-ui-magenta/0 focus-visible:from-ui-magenta focus-visible:to-ui-magenta active:from-ui-magenta active:to-ui-magenta 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 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:bg-[size:100%_100%] active:bg-[size:100%_100%]');
|
|
455
|
+
case 'neutral':
|
|
456
|
+
return twJoin(multilineFillBaseClasses, '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 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');
|
|
457
|
+
case 'orange':
|
|
458
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-orange/0 to-ui-orange/0 focus-visible:from-ui-orange focus-visible:to-ui-orange active:from-ui-orange active:to-ui-orange 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 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:bg-[size:100%_100%] active:bg-[size:100%_100%]');
|
|
459
|
+
case 'pink':
|
|
460
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-pink/0 to-ui-pink/0 focus-visible:from-ui-pink focus-visible:to-ui-pink active:from-ui-pink active:to-ui-pink 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 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:bg-[size:100%_100%] active:bg-[size:100%_100%]');
|
|
461
|
+
case 'primary':
|
|
462
|
+
return twJoin(multilineFillBaseClasses, 'from-primary-500/0 to-primary-500/0 focus-visible:from-primary-500 focus-visible:to-primary-500 active:from-primary-500 active:to-primary-500 contrast-more:from-primary-500/0 contrast-more:to-primary-500/0 focus-visible:contrast-more:from-primary-500 focus-visible:contrast-more:to-primary-500 active:contrast-more:from-primary-500 active:contrast-more:to-primary-500 pointer-fine:hover:from-primary-500 pointer-fine:hover:to-primary-500 pointer-fine:hover:bg-[size:100%_100%] pointer-fine:hover:contrast-more:from-primary-500 pointer-fine:hover:contrast-more:to-primary-500 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:bg-[size:100%_100%] active:bg-[size:100%_100%]');
|
|
463
|
+
case 'purple':
|
|
464
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-purple/0 to-ui-purple/0 focus-visible:from-ui-purple focus-visible:to-ui-purple active:from-ui-purple active:to-ui-purple 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 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:bg-[size:100%_100%] active:bg-[size:100%_100%]');
|
|
465
|
+
case 'red':
|
|
466
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-red/0 to-ui-red/0 focus-visible:from-ui-red focus-visible:to-ui-red active:from-ui-red active:to-ui-red 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 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:bg-[size:100%_100%] active:bg-[size:100%_100%]');
|
|
467
|
+
case 'violet':
|
|
468
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-violet/0 to-ui-violet/0 focus-visible:from-ui-violet focus-visible:to-ui-violet active:from-ui-violet active:to-ui-violet 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 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:bg-[size:100%_100%] active:bg-[size:100%_100%]');
|
|
469
|
+
case 'yellow':
|
|
470
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-yellow/0 to-ui-yellow/0 focus-visible:from-ui-yellow focus-visible:to-ui-yellow active:from-ui-yellow active:to-ui-yellow 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 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:bg-[size:100%_100%] active:bg-[size:100%_100%]');
|
|
471
|
+
case 'blue':
|
|
472
|
+
default:
|
|
473
|
+
return twJoin(multilineFillBaseClasses, 'from-ui-blue/0 to-ui-blue/0 focus-visible:from-ui-blue focus-visible:to-ui-blue active:from-ui-blue active:to-ui-blue 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 bg-[size:50%_0px] bg-[position:50%_50%] transition-[background-size_background-image_color] focus-visible:bg-[size:100%_100%] active:bg-[size:100%_100%]');
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
const getMultilineFillLiftClasses = (theme = 'blue') => {
|
|
477
|
+
return twJoin(getMultilineFillColorClasses(theme), 'pointer-fine:hover:bg-[size:auto_100%] bg-[size:auto_0px] bg-[position:auto_100%] focus-visible:bg-[size:auto_100%] active:bg-[size:auto_100%]');
|
|
478
|
+
};
|
|
479
|
+
const getMultilineFillXClasses = (theme = 'blue') => {
|
|
480
|
+
return twJoin(getMultilineFillColorClasses(theme), 'pointer-fine:hover:bg-[size:100%_100%] bg-[size:0%_100%] focus-visible:bg-[size:100%_100%] active:bg-[size:100%_100%]');
|
|
481
|
+
};
|
|
482
|
+
const getMultilineFillRtlClasses = (theme = 'blue') => {
|
|
483
|
+
return twJoin(getMultilineFillXClasses(theme), 'bg-[position:100%_auto]');
|
|
484
|
+
};
|
|
485
|
+
const getMultilineFillCenterClasses = (theme = 'blue') => {
|
|
486
|
+
return twJoin(getMultilineFillXClasses(theme), 'bg-[position:50%_auto]');
|
|
487
|
+
};
|
|
488
|
+
/**
|
|
489
|
+
* # Link
|
|
490
|
+
*
|
|
491
|
+
* - A component for rendering links with various styles and options.
|
|
492
|
+
* - Utilizes the Next.js `Link` component and provides additional functionality.
|
|
493
|
+
*
|
|
494
|
+
* ---
|
|
495
|
+
*
|
|
496
|
+
* ## Styles
|
|
497
|
+
*
|
|
498
|
+
* This component includes various classes to style the link. The styles are divided into two types:
|
|
499
|
+
*
|
|
500
|
+
* - Line styles: These styles add a line underneath the link, and include variations for different positions and orientations.
|
|
501
|
+
* - Fill styles: These styles add a background color behind the link, and include variations for different positions and orientations.
|
|
502
|
+
* - Multiline styles: These styles seek to accomplish the same as the line and fill styles, while offering multiline support.
|
|
503
|
+
*
|
|
504
|
+
* ---
|
|
505
|
+
*
|
|
506
|
+
* ## Examples
|
|
507
|
+
*
|
|
508
|
+
* @example
|
|
509
|
+
* <Link href='/about' type='ltr' title='About Us'>Learn more about our company</Link>
|
|
510
|
+
*
|
|
511
|
+
* @example
|
|
512
|
+
* <Link href='/about' type='fill-ltr' title='About Us'>Learn more about our company</Link>
|
|
513
|
+
*
|
|
514
|
+
* @example
|
|
515
|
+
* <Link href='/about' type='fill-ltr' theme='red' title='About Us'>Learn more about our company</Link>
|
|
516
|
+
*/
|
|
517
|
+
function Link({ type, theme = 'blue', className, ref, ...props }) {
|
|
518
|
+
const getLinkClasses = () => {
|
|
519
|
+
switch (type) {
|
|
520
|
+
case 'static':
|
|
521
|
+
return lineStaticClasses;
|
|
522
|
+
case 'ltr':
|
|
523
|
+
return lineLtrClasses;
|
|
524
|
+
case 'rtl':
|
|
525
|
+
return lineRtlClasses;
|
|
526
|
+
case 'center':
|
|
527
|
+
return lineCenterClasses;
|
|
528
|
+
case 'lift':
|
|
529
|
+
return lineLiftClasses;
|
|
530
|
+
case 'fill':
|
|
531
|
+
return getFillCenterClasses(theme);
|
|
532
|
+
case 'fill-ltr':
|
|
533
|
+
return twJoin([getFillColorTransitionClasses(theme), scaleXClasses, 'after:origin-left']);
|
|
534
|
+
case 'fill-rtl':
|
|
535
|
+
return twJoin([getFillColorTransitionClasses(theme), scaleXClasses, 'after:origin-right']);
|
|
536
|
+
case 'fill-lift':
|
|
537
|
+
return twJoin([getFillColorTransitionClasses(theme), scaleYClasses, 'after:origin-bottom']);
|
|
538
|
+
case 'multiline':
|
|
539
|
+
return multilineNormalClasses;
|
|
540
|
+
case 'multiline-static':
|
|
541
|
+
return multilineLineStaticClasses;
|
|
542
|
+
case 'multiline-ltr':
|
|
543
|
+
return multilineXClasses;
|
|
544
|
+
case 'multiline-rtl':
|
|
545
|
+
return multilineLineRtlClasses;
|
|
546
|
+
case 'multiline-center':
|
|
547
|
+
return multilineLineCenterClasses;
|
|
548
|
+
case 'multiline-lift':
|
|
549
|
+
return multilineLineLiftClasses;
|
|
550
|
+
case 'multiline-fill':
|
|
551
|
+
return getMultilineFillClasses(theme);
|
|
552
|
+
case 'multiline-fill-ltr':
|
|
553
|
+
return getMultilineFillXClasses(theme);
|
|
554
|
+
case 'multiline-fill-rtl':
|
|
555
|
+
return getMultilineFillRtlClasses(theme);
|
|
556
|
+
case 'multiline-fill-center':
|
|
557
|
+
return getMultilineFillCenterClasses(theme);
|
|
558
|
+
case 'multiline-fill-lift':
|
|
559
|
+
return getMultilineFillLiftClasses(theme);
|
|
560
|
+
default:
|
|
561
|
+
return lineNormalClasses;
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
const linkClasses = getLinkClasses();
|
|
565
|
+
return jsx(Anchor, { ref: ref, ...props, className: twMerge(linkClasses, className) });
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* # Button
|
|
570
|
+
* - A pre-styled button with utility props for easy customization depending on use case.
|
|
571
|
+
*/
|
|
572
|
+
function Button({ className, padding = 'md', rounded = 'lg', theme = 'primary', ref, ...props }) {
|
|
573
|
+
const getPaddingClasses = () => {
|
|
574
|
+
switch (padding) {
|
|
575
|
+
case 'xs':
|
|
576
|
+
return 'px-2 py-0.5';
|
|
577
|
+
case 'sm':
|
|
578
|
+
return 'px-4 py-1';
|
|
579
|
+
case 'md':
|
|
580
|
+
return 'px-6 py-1.5';
|
|
581
|
+
case 'lg':
|
|
582
|
+
return 'px-8 py-2';
|
|
583
|
+
case 'xl':
|
|
584
|
+
return 'px-12 py-3';
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
const getRoundedClasses = () => {
|
|
588
|
+
switch (rounded) {
|
|
589
|
+
case 'xs':
|
|
590
|
+
return 'rounded-sm';
|
|
591
|
+
case 'sm':
|
|
592
|
+
return 'rounded-md';
|
|
593
|
+
case 'md':
|
|
594
|
+
return 'rounded-lg';
|
|
595
|
+
case 'lg':
|
|
596
|
+
return 'rounded-xl';
|
|
597
|
+
case 'xl':
|
|
598
|
+
return 'rounded-3xl';
|
|
599
|
+
case 'full':
|
|
600
|
+
return 'rounded-full';
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
const getThemeClasses = () => {
|
|
604
|
+
switch (theme) {
|
|
605
|
+
case 'blue':
|
|
606
|
+
return twSort('before:bg-ui-blue shadow-ui-blue/25 before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:transition-[filter] before:duration-300 active:before:brightness-90');
|
|
607
|
+
case 'blue-gradient':
|
|
608
|
+
return twSort('bg-ui-blue shadow-ui-blue/25 before:bg-linear-to-t before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:rounded-[inherit] 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 active:before:brightness-90');
|
|
609
|
+
case 'brown':
|
|
610
|
+
return twSort('before:bg-ui-brown shadow-ui-brown/25 before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:transition-[filter] before:duration-300 active:before:brightness-90');
|
|
611
|
+
case 'brown-gradient':
|
|
612
|
+
return twSort('bg-ui-brown shadow-ui-brown/25 before:bg-linear-to-t before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:rounded-[inherit] 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 active:before:brightness-90');
|
|
613
|
+
case 'green':
|
|
614
|
+
return twSort('before:bg-ui-green shadow-ui-green/25 before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:transition-[filter] before:duration-300 active:before:brightness-90');
|
|
615
|
+
case 'green-gradient':
|
|
616
|
+
return twSort('bg-ui-green shadow-ui-green/25 before:bg-linear-to-t before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:rounded-[inherit] 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 active:before:brightness-90');
|
|
617
|
+
case 'grey':
|
|
618
|
+
return twSort('before:bg-ui-grey shadow-ui-grey/25 before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:transition-[filter] before:duration-300 active:before:brightness-90');
|
|
619
|
+
case 'grey-gradient':
|
|
620
|
+
return twSort('bg-ui-grey shadow-ui-grey/25 before:bg-linear-to-t before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:rounded-[inherit] 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 active:before:brightness-90');
|
|
621
|
+
case 'sky-blue':
|
|
622
|
+
return twSort('before:bg-ui-sky-blue shadow-ui-sky-blue/25 before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:transition-[filter] before:duration-300 active:before:brightness-90');
|
|
623
|
+
case 'sky-blue-gradient':
|
|
624
|
+
return twSort('bg-ui-sky-blue shadow-text-white lg shadow-ui-sky-blue/25 before:bg-linear-to-t before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 transition-transform before:absolute before:inset-0 before:rounded-[inherit] 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 active:before:brightness-90');
|
|
625
|
+
case 'magenta':
|
|
626
|
+
return twSort('before:bg-ui-magenta shadow-ui-magenta/25 before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:transition-[filter] before:duration-300 active:before:brightness-90');
|
|
627
|
+
case 'magenta-gradient':
|
|
628
|
+
return twSort('bg-ui-magenta shadow-ui-magenta/25 before:bg-linear-to-t active:before transition-transform:brightness-90 pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white mix-blend-soft-light shadow-lg transition-transform before:absolute before:inset-0 before:rounded-[inherit] before:from-black/75 before:via-transparent before:to-white/75 before:text-white before:opacity-75');
|
|
629
|
+
case 'neutral':
|
|
630
|
+
return twSort('before:ease-exponential pointer-fine:hover:before:brightness-110 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 active:before:brightness-90 dark:bg-zinc-800');
|
|
631
|
+
case 'neutral-gradient':
|
|
632
|
+
return twSort('bg-linear-to-t before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 dark from-zinc-300 via-zinc-200 to-zinc-100 text-black before:transition-[filter] before:duration-300 active:before:brightness-90 dark:from-zinc-900 dark:via-zinc-800 dark:to-zinc-700');
|
|
633
|
+
case 'orange':
|
|
634
|
+
return twSort('before:bg-ui-orange shadow-ui-orange/25 before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:transition-[filter] before:duration-300 active:before:brightness-90');
|
|
635
|
+
case 'orange-gradient':
|
|
636
|
+
return twSort('bg-ui-orange shadow-ui-orange/25 before:bg-linear-to-t before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:rounded-[inherit] 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 active:before:brightness-90');
|
|
637
|
+
case 'pink':
|
|
638
|
+
return twSort('before:bg-ui-pink shadow-ui-pink/25 before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:transition-[filter] before:duration-300 active:before:brightness-90');
|
|
639
|
+
case 'pink-gradient':
|
|
640
|
+
return twSort('bg-ui-pink shadow-ui-pink/25 before:bg-linear-to-t before:to-white/75/75 before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:rounded-[inherit] before:from-black/75 before:via-transparent before:opacity-75 before:mix-blend-soft-light before:transition-[filter] before:duration-300 active:before:brightness-90');
|
|
641
|
+
case 'primary-light':
|
|
642
|
+
return twSort('bg-primary-50 text-primary-600 active:bg-primary-600 active:text-primary-50 pointer-fine:hover:bg-primary-600 pointer-fine:hover:text-primary-50 pointer-fine:active:bg-primary-700 transition-[transform_background-color_color_box-shadow]');
|
|
643
|
+
case 'primary-gradient':
|
|
644
|
+
return twSort('bg-linear-to-t from-primary-700 via-primary-500 to-primary-300 bg-size-y-[200%] shadow-primary-600/25 pointer-fine:hover:[background-position:50%_0%] transition-[transform_background-position] [background-position:50%_50%] active:[background-position:50%_75%]');
|
|
645
|
+
case 'purple':
|
|
646
|
+
return twSort('before:bg-ui-purple shadow-ui-purple/25 before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:transition-[filter] before:duration-300 active:before:brightness-90');
|
|
647
|
+
case 'purple-gradient':
|
|
648
|
+
return twSort('bg-ui-purple shadow-ui-purple/25 before:bg-linear-to-t before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:rounded-[inherit] 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 active:before:brightness-90');
|
|
649
|
+
case 'red':
|
|
650
|
+
return twSort('before:bg-ui-red shadow-ui-red/25 before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:transition-[filter] before:duration-300 active:before:brightness-90');
|
|
651
|
+
case 'red-gradient':
|
|
652
|
+
return twSort('bg-ui-red shadow-ui-red/25 before:bg-linear-to-t before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:rounded-[inherit] 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 active:before:brightness-90');
|
|
653
|
+
case 'violet':
|
|
654
|
+
return twSort('before:bg-ui-violet shadow-ui-violet/25 before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:transition-[filter] before:duration-300 active:before:brightness-90');
|
|
655
|
+
case 'violet-gradient':
|
|
656
|
+
return twSort('bg-ui-violet shadow-ui-violet/25 before:bg-linear-to-t before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-white shadow-lg transition-transform before:absolute before:inset-0 before:rounded-[inherit] 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 active:before:brightness-90');
|
|
657
|
+
case 'yellow':
|
|
658
|
+
return twSort('before:bg-ui-yellow shadow-ui-yellow/25 before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-black shadow-lg transition-transform before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:transition-[filter] before:duration-300 active:before:brightness-90');
|
|
659
|
+
case 'yellow-gradient':
|
|
660
|
+
return twSort('bg-ui-yellow shadow-ui-yellow/25 before:bg-linear-to-t before:ease-exponential pointer-fine:hover:before:brightness-110 pointer-fine:active:before:brightness-90 text-black shadow-lg transition-transform before:absolute before:inset-0 before:rounded-[inherit] 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 active:before:brightness-90');
|
|
661
|
+
case 'primary':
|
|
662
|
+
default:
|
|
663
|
+
return twSort('bg-primary-500 shadow-primary-700/25 active:bg-primary-600 pointer-fine:hover:bg-primary-400 pointer-fine:active:bg-primary-600 text-white shadow-lg transition-[transform_background-color_box-shadow]');
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
const paddingClasses = getPaddingClasses(), roundedClasses = getRoundedClasses(), themeClasses = getThemeClasses();
|
|
667
|
+
const buttonClasses = twMerge([
|
|
668
|
+
'ease-exponential focus-visible:scale-101 pointer-fine:hover:scale-101 pointer-fine:active:scale-99 block w-fit min-w-fit text-center font-semibold duration-300 active:scale-95',
|
|
669
|
+
paddingClasses,
|
|
670
|
+
roundedClasses,
|
|
671
|
+
themeClasses,
|
|
672
|
+
className,
|
|
673
|
+
]);
|
|
674
|
+
return 'href' in props && typeof props.href === 'string' ? (jsx(Anchor, { ref: ref, ...props, className: buttonClasses })) : (jsx(Button$1, { ref: ref, ...props, className: buttonClasses }));
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
function createFastContext(defaultInitialState) {
|
|
678
|
+
function useStoreData(initialState = defaultInitialState) {
|
|
679
|
+
const store = useRef(initialState), get = () => store.current, subscribers = useRef(new Set());
|
|
680
|
+
const set = (value) => {
|
|
681
|
+
if (typeof value === 'function') {
|
|
682
|
+
store.current = value(store.current);
|
|
683
|
+
}
|
|
684
|
+
else {
|
|
685
|
+
store.current = value;
|
|
686
|
+
}
|
|
687
|
+
subscribers.current.forEach(callback => callback());
|
|
688
|
+
};
|
|
689
|
+
const subscribe = (callback) => {
|
|
690
|
+
subscribers.current.add(callback);
|
|
691
|
+
return () => subscribers.current.delete(callback);
|
|
692
|
+
};
|
|
693
|
+
return {
|
|
694
|
+
get,
|
|
695
|
+
set,
|
|
696
|
+
subscribe,
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
const StoreContext = createContext(null);
|
|
700
|
+
function Provider({ initialValue = defaultInitialState, ...props }) {
|
|
701
|
+
return jsx(StoreContext.Provider, { value: useStoreData(initialValue), ...props });
|
|
702
|
+
}
|
|
703
|
+
function useStore(selector, initialValue) {
|
|
704
|
+
const store = useContext(StoreContext);
|
|
705
|
+
if (!store) {
|
|
706
|
+
const localStoreValue = initialValue !== undefined ? initialValue : defaultInitialState;
|
|
707
|
+
const selectedValue = selector(localStoreValue);
|
|
708
|
+
const noOpSet = () => console.warn('Attempting to set store value outside of Provider');
|
|
709
|
+
return [selectedValue, noOpSet];
|
|
710
|
+
}
|
|
711
|
+
const state = useSyncExternalStore(store.subscribe, () => selector(store.get()), () => selector(initialValue !== undefined ? initialValue : defaultInitialState));
|
|
712
|
+
return [state, store.set];
|
|
713
|
+
}
|
|
714
|
+
return {
|
|
715
|
+
Provider,
|
|
716
|
+
useStore,
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* # Define Field
|
|
722
|
+
*
|
|
723
|
+
* This is a helper function to define a field in a form context with type safety.
|
|
724
|
+
*/
|
|
725
|
+
function defineField(fieldDefinition) {
|
|
726
|
+
return fieldDefinition;
|
|
727
|
+
}
|
|
728
|
+
const { Provider: Provider$1, useStore: useStore$1 } = createFastContext([]);
|
|
729
|
+
function FormContextProvider({ children }) {
|
|
730
|
+
return jsx(Provider$1, { children: children });
|
|
731
|
+
}
|
|
732
|
+
function useFormContext() {
|
|
733
|
+
return useStore$1(store => store);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
const DEFAULT_STATUS = 'incomplete';
|
|
737
|
+
const { Provider, useStore } = createFastContext(DEFAULT_STATUS);
|
|
738
|
+
function FormStatusProvider({ children, initialStatus = DEFAULT_STATUS, }) {
|
|
739
|
+
return (jsx(Suspense, { children: jsx(Provider, { initialValue: initialStatus, children: children }) }));
|
|
740
|
+
}
|
|
741
|
+
function useFormStatus() {
|
|
742
|
+
return useStore(store => store);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
function validateField(value, { required, type }) {
|
|
746
|
+
const noValue = !value || value === '';
|
|
747
|
+
if (!required && noValue)
|
|
748
|
+
return true;
|
|
749
|
+
if (noValue)
|
|
750
|
+
return false;
|
|
751
|
+
switch (type) {
|
|
752
|
+
case 'email':
|
|
753
|
+
return isEmail(value);
|
|
754
|
+
case 'number':
|
|
755
|
+
return !isNaN(Number(value));
|
|
756
|
+
case 'tel':
|
|
757
|
+
return isPhoneNumber(value);
|
|
758
|
+
default:
|
|
759
|
+
return true;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
function Input({ checked, className, defaultValue, description, descriptionProps, disabled, fieldProps, invalid = true, label, labelProps, name, onChange, placeholder, ref, required = true, type, value, ...props }) {
|
|
763
|
+
const [formContext, setFormContext] = useFormContext(), [, setFormStatus] = useFormStatus();
|
|
764
|
+
if (placeholder === '*')
|
|
765
|
+
placeholder = name + (required && !label ? '*' : '');
|
|
766
|
+
if (label === '*')
|
|
767
|
+
label = name;
|
|
768
|
+
const uniqueID = useId(), fieldContextID = toLowerCase(name, [, '_']) + '§' + uniqueID;
|
|
769
|
+
if (Boolean(formContext?.find(field => field.id === fieldContextID)?.invalid))
|
|
770
|
+
invalid = true;
|
|
771
|
+
const getFieldContextType = () => {
|
|
772
|
+
switch (type) {
|
|
773
|
+
case 'email':
|
|
774
|
+
return 'email';
|
|
775
|
+
case 'file':
|
|
776
|
+
return 'file';
|
|
777
|
+
case 'number':
|
|
778
|
+
return 'number';
|
|
779
|
+
case 'tel':
|
|
780
|
+
return 'tel';
|
|
781
|
+
case 'url':
|
|
782
|
+
return 'url';
|
|
783
|
+
default:
|
|
784
|
+
return 'string';
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
const fieldContextType = getFieldContextType();
|
|
788
|
+
const fieldContext = defineField({
|
|
789
|
+
type: fieldContextType,
|
|
790
|
+
id: fieldContextID,
|
|
791
|
+
invalid,
|
|
792
|
+
name,
|
|
793
|
+
required,
|
|
794
|
+
value: value ? `${value}` : defaultValue ? `${defaultValue}` : '',
|
|
795
|
+
});
|
|
796
|
+
useEffect(() => {
|
|
797
|
+
if (!setFormContext)
|
|
798
|
+
return;
|
|
799
|
+
setFormContext(prevContext => {
|
|
800
|
+
const otherFields = (prevContext || []).filter(field => field.id !== fieldContext.id);
|
|
801
|
+
return [...otherFields, fieldContext];
|
|
802
|
+
});
|
|
803
|
+
return () => {
|
|
804
|
+
setFormContext(prevContext => (prevContext || []).filter(field => field.id !== fieldContext.id));
|
|
805
|
+
};
|
|
806
|
+
}, [setFormContext]);
|
|
807
|
+
const debounceTimerRef = useRef(undefined);
|
|
808
|
+
const handleChange = e => {
|
|
809
|
+
if (disabled) {
|
|
810
|
+
e.preventDefault();
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
clearTimeout(debounceTimerRef.current);
|
|
814
|
+
const { currentTarget } = e, { value: newValue } = currentTarget;
|
|
815
|
+
setFormContext?.(prevContext => {
|
|
816
|
+
if (!prevContext)
|
|
817
|
+
return [];
|
|
818
|
+
const field = prevContext.find(({ id: fieldID }) => fieldID === fieldContext.id);
|
|
819
|
+
if (!field)
|
|
820
|
+
throw new Error(`Field with id "${fieldContext.id}" not found in form context.`);
|
|
821
|
+
const otherFields = prevContext.filter(({ id: fieldID }) => fieldID !== fieldContext.id);
|
|
822
|
+
const updatedField = { ...field, value: newValue };
|
|
823
|
+
return [...otherFields, updatedField];
|
|
824
|
+
});
|
|
825
|
+
debounceTimerRef.current = setTimeout(() => {
|
|
826
|
+
const field = formContext?.find(({ id: fieldID }) => fieldID === fieldContext.id);
|
|
827
|
+
if (!field)
|
|
828
|
+
return;
|
|
829
|
+
const invalid = validateField(newValue, field) === false;
|
|
830
|
+
if (invalid !== field.invalid)
|
|
831
|
+
setFormContext?.(prevContext => {
|
|
832
|
+
if (!prevContext)
|
|
833
|
+
return [];
|
|
834
|
+
const field = prevContext.find(({ id: fieldID }) => fieldID === fieldContext.id);
|
|
835
|
+
if (!field)
|
|
836
|
+
throw new Error(`Field with id "${fieldContext.id}" not found in form context.`);
|
|
837
|
+
const otherFields = prevContext.filter(({ id: fieldID }) => fieldID !== fieldContext.id);
|
|
838
|
+
const updatedField = { ...field, invalid };
|
|
839
|
+
return [...otherFields, updatedField];
|
|
840
|
+
});
|
|
841
|
+
}, 500);
|
|
842
|
+
onChange?.(e);
|
|
843
|
+
};
|
|
844
|
+
const restFieldProps = fieldProps
|
|
845
|
+
? Object.fromEntries(Object.entries(fieldProps).filter(([key]) => key !== 'className'))
|
|
846
|
+
: {};
|
|
847
|
+
const restLabelProps = labelProps
|
|
848
|
+
? Object.fromEntries(Object.entries(labelProps).filter(([key]) => key !== 'className'))
|
|
849
|
+
: {};
|
|
850
|
+
const restDescriptionProps = descriptionProps
|
|
851
|
+
? Object.fromEntries(Object.entries(descriptionProps).filter(([key]) => key !== 'className'))
|
|
852
|
+
: {};
|
|
853
|
+
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('pointer-fine:hover:bg-neutral-50 dark:pointer-fine:hover:bg-neutral-600 pointer-fine:active:bg-neutral-200 dark:pointer-fine:active:bg-neutral-800 border-1 outline-ui-sky-blue/95 focus-visible:outline-3 ease-exponential rounded-xl border-neutral-500/50 bg-neutral-100 py-1 pl-2 text-neutral-950 outline-offset-1 transition-[background-color] duration-300 focus-visible:bg-neutral-50 active:bg-neutral-200 dark:bg-neutral-700 dark:text-neutral-50 dark:focus-visible:bg-neutral-600 dark:active:bg-neutral-800', typeof className === 'function' ? className(bag) : className), invalid: invalid, onChange: handleChange, placeholder: placeholder, ref: ref, type: type }), description && (jsx(Description, { ...restDescriptionProps, className: bag => twMerge('text-xs', typeof descriptionProps?.className === 'function'
|
|
854
|
+
? descriptionProps?.className(bag)
|
|
855
|
+
: descriptionProps?.className), children: description }))] }));
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
function SubmitButton({ children, className, 'aria-disabled': ariaDisabled, error, incomplete, loading, success, theme, type = 'submit', ref, ...props }) {
|
|
859
|
+
const [formStatus] = useFormStatus();
|
|
860
|
+
const getDisabledStatus = () => {
|
|
861
|
+
if (ariaDisabled !== undefined)
|
|
862
|
+
return ariaDisabled;
|
|
863
|
+
if (formStatus !== 'ready')
|
|
864
|
+
return 'true';
|
|
865
|
+
return 'false';
|
|
866
|
+
};
|
|
867
|
+
const disabled = getDisabledStatus();
|
|
868
|
+
const getFormStatusButtonClasses = () => {
|
|
869
|
+
switch (formStatus) {
|
|
870
|
+
case 'loading':
|
|
871
|
+
return twSort('animate-pulse cursor-wait text-lg font-black leading-6 tracking-widest');
|
|
872
|
+
case 'error':
|
|
873
|
+
case 'success':
|
|
874
|
+
return 'cursor-not-allowed';
|
|
875
|
+
default:
|
|
876
|
+
return undefined;
|
|
877
|
+
}
|
|
878
|
+
};
|
|
879
|
+
const formStatusButtonClasses = getFormStatusButtonClasses();
|
|
880
|
+
const getFormStatusButtonTheme = () => {
|
|
881
|
+
switch (formStatus) {
|
|
882
|
+
case 'incomplete':
|
|
883
|
+
return 'grey';
|
|
884
|
+
case 'loading':
|
|
885
|
+
return 'blue';
|
|
886
|
+
case 'error':
|
|
887
|
+
return 'red';
|
|
888
|
+
case 'success':
|
|
889
|
+
return 'green';
|
|
890
|
+
default:
|
|
891
|
+
return theme;
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
const formStatusButtonTheme = getFormStatusButtonTheme();
|
|
895
|
+
const getButtonText = () => {
|
|
896
|
+
switch (formStatus) {
|
|
897
|
+
case 'incomplete':
|
|
898
|
+
return incomplete || 'Complete Form';
|
|
899
|
+
case 'loading':
|
|
900
|
+
return (loading || (jsxs(Fragment$1, { children: [jsx("span", { className: 'animate-wave animation-delay-300 inline-block', children: "\u2022" }), jsx("span", { className: 'animate-wave animation-delay-150 inline-block', children: "\u2022" }), jsx("span", { className: 'animate-wave inline-block', children: "\u2022" })] })));
|
|
901
|
+
case 'error':
|
|
902
|
+
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" })] }));
|
|
903
|
+
case 'success':
|
|
904
|
+
return success || 'Successfully Submitted';
|
|
905
|
+
default:
|
|
906
|
+
return children || 'Submit';
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
const buttonText = getButtonText();
|
|
910
|
+
return (jsx(Button, { ...props, ...(disabled === 'true' ? { 'aria-disabled': 'true', disabled: true } : {}), className: twMerge([formStatusButtonClasses, 'w-full', className]), ref: ref, theme: formStatusButtonTheme, type: type, children: buttonText }));
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// import { findComponentByType } from '../../utils'
|
|
914
|
+
function FormComponent({ as, children, className, handleSubmit, onError, onSubmit, onSuccess, ...props }) {
|
|
915
|
+
const [formContext] = useFormContext(), [formStatus, setFormStatus] = useFormStatus();
|
|
916
|
+
// const submitButton = findComponentByType(children, SubmitButton)
|
|
917
|
+
useEffect(() => {
|
|
918
|
+
if (!formContext)
|
|
919
|
+
return;
|
|
920
|
+
if (formStatus !== 'incomplete' && formContext.find(({ invalid }) => invalid))
|
|
921
|
+
setFormStatus?.('incomplete');
|
|
922
|
+
if (formStatus !== 'ready' && formContext.every(({ invalid }) => !invalid))
|
|
923
|
+
setFormStatus?.('ready');
|
|
924
|
+
}, [formContext]);
|
|
925
|
+
const processSubmit = handleSubmit ||
|
|
926
|
+
(async (e) => {
|
|
927
|
+
e.preventDefault();
|
|
928
|
+
e.stopPropagation();
|
|
929
|
+
setFormStatus?.('loading');
|
|
930
|
+
const response = await onSubmit?.({ event: e, formContext });
|
|
931
|
+
if (response && ('error' in response || response.status === 'error')) {
|
|
932
|
+
setFormStatus?.('error');
|
|
933
|
+
onError?.({ event: e, error: response.error || 'An error occurred when submitting the form.' });
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
if ((response && response.status === 'success') || !response) {
|
|
937
|
+
setFormStatus?.('success');
|
|
938
|
+
onSuccess?.({ event: e });
|
|
939
|
+
}
|
|
940
|
+
});
|
|
941
|
+
const FormElement = as || 'form';
|
|
942
|
+
return (jsxs(FormElement, { ...props, className: twMerge(className, 'grid gap-3'), onSubmit: processSubmit, children: [jsx("span", { className: 'block text-xl font-black', children: formStatus }), children] }));
|
|
943
|
+
}
|
|
944
|
+
function Form({ controlled = 'auto', initialStatus = 'incomplete', ...props }) {
|
|
945
|
+
const FormContextOrNotProvider = controlled === 'auto' ? FormContextProvider : Fragment;
|
|
946
|
+
return (jsx(FormStatusProvider, { initialStatus: initialStatus, children: jsx(FormContextOrNotProvider, { children: jsx(FormComponent, { ...props }) }) }));
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
function Ghost({ children, className, ...props }) {
|
|
950
|
+
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" }) }));
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
function getTextFromChildren(children) {
|
|
954
|
+
let text = '';
|
|
955
|
+
Children.forEach(children, child => {
|
|
956
|
+
if (typeof child === 'string' || typeof child === 'number') {
|
|
957
|
+
text += child;
|
|
958
|
+
}
|
|
959
|
+
else if (isValidElement(child)) {
|
|
960
|
+
text += getTextFromChildren(child.props.children);
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
return text;
|
|
964
|
+
}
|
|
965
|
+
/**
|
|
966
|
+
* # Heading
|
|
967
|
+
* A heading component that renders HTML heading elements (h1-h6) with appropriate styling.
|
|
968
|
+
* Automatically generates an ID for the heading based on its content if none is provided.
|
|
969
|
+
*/
|
|
970
|
+
function Heading({ as = 'h2', children, className, id, ref, ...props }) {
|
|
971
|
+
const H = as;
|
|
972
|
+
const targetableID = id || getTextFromChildren(children).replace(/\s+/g, '-').toLowerCase();
|
|
973
|
+
const getBaseClasses = () => {
|
|
974
|
+
switch (as) {
|
|
975
|
+
case 'h1':
|
|
976
|
+
return twSort('pb-2.5 text-6xl font-black last:pb-0');
|
|
977
|
+
case 'h3':
|
|
978
|
+
return twSort('pb-2 text-4xl font-extralight last:pb-0');
|
|
979
|
+
case 'h4':
|
|
980
|
+
return twSort('pb-2 text-3xl font-extrabold last:pb-0');
|
|
981
|
+
case 'h5':
|
|
982
|
+
return twSort('pb-1.5 text-2xl font-semibold last:pb-0');
|
|
983
|
+
case 'h6':
|
|
984
|
+
return twSort('pb-1 text-xl font-bold last:pb-0');
|
|
985
|
+
default:
|
|
986
|
+
return twSort('pb-2.5 text-5xl font-medium last:pb-0');
|
|
987
|
+
}
|
|
988
|
+
};
|
|
989
|
+
const baseClasses = getBaseClasses();
|
|
990
|
+
return (jsx(H, { ref: ref, id: targetableID, ...props, className: twMerge(baseClasses, className), children: children }));
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
function xmark(props) {
|
|
994
|
+
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' }) }));
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
function ModalTrigger({ as, ...props }) {
|
|
998
|
+
const Element = as || Button$1;
|
|
999
|
+
return jsx(Element, { ...props });
|
|
1000
|
+
}
|
|
1001
|
+
function ModalDialog(props) {
|
|
1002
|
+
return jsx("div", { ...props });
|
|
1003
|
+
}
|
|
1004
|
+
function Modal({ children, className, onClose, onOpen, place = 'bottom' }) {
|
|
1005
|
+
const [bodyElement, setBodyElement] = useState(null);
|
|
1006
|
+
useEffect(() => {
|
|
1007
|
+
if (!bodyElement && typeof window !== 'undefined')
|
|
1008
|
+
setBodyElement(document.body);
|
|
1009
|
+
}, [bodyElement]);
|
|
1010
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1011
|
+
const dialogPanelRef = useRef(null), dragMoveBoxRef = useRef(null),
|
|
1012
|
+
// lastTouchYRef = useRef(0),
|
|
1013
|
+
startDragCoords = useRef({ x: 0, y: 0 });
|
|
1014
|
+
const [allowDragClose, setAllowDragClose] = useState(false), [readyToClose, setReadyToClose] = useState(false);
|
|
1015
|
+
const openModal = () => {
|
|
1016
|
+
console.log('open');
|
|
1017
|
+
setIsOpen(true);
|
|
1018
|
+
onOpen?.();
|
|
1019
|
+
};
|
|
1020
|
+
const closeModal = () => {
|
|
1021
|
+
console.log('close');
|
|
1022
|
+
setIsOpen(false);
|
|
1023
|
+
onClose?.();
|
|
1024
|
+
};
|
|
1025
|
+
const enableClose = (clientX, clientY) => {
|
|
1026
|
+
startDragCoords.current.x = clientX;
|
|
1027
|
+
startDragCoords.current.y = clientY;
|
|
1028
|
+
dialogPanelRef.current.style.transitionDuration = '0s';
|
|
1029
|
+
setAllowDragClose(true);
|
|
1030
|
+
};
|
|
1031
|
+
const enableTouchClose = e => {
|
|
1032
|
+
const { touches } = e, touch = touches[0], { clientY } = touch;
|
|
1033
|
+
enableClose(0, clientY);
|
|
1034
|
+
};
|
|
1035
|
+
const enableMouseClose = e => {
|
|
1036
|
+
const { clientX, clientY } = e;
|
|
1037
|
+
enableClose(clientX, clientY);
|
|
1038
|
+
};
|
|
1039
|
+
const handleMove = (clientX, clientY) => {
|
|
1040
|
+
if (!dialogPanelRef.current)
|
|
1041
|
+
return;
|
|
1042
|
+
let deltaX = clientX - startDragCoords.current.x, deltaY = clientY - startDragCoords.current.y;
|
|
1043
|
+
if (deltaX > 0)
|
|
1044
|
+
deltaX = easeOutExpo(Math.abs(deltaX), 0, 25, 5000);
|
|
1045
|
+
if (deltaX < 0)
|
|
1046
|
+
deltaX = -easeOutExpo(Math.abs(deltaX), 0, 25, 5000);
|
|
1047
|
+
if (deltaY < 0)
|
|
1048
|
+
deltaY = -easeOutExpo(Math.abs(deltaY), 0, 25, 2000);
|
|
1049
|
+
if (deltaY >= 100 && !readyToClose) {
|
|
1050
|
+
setReadyToClose(true);
|
|
1051
|
+
}
|
|
1052
|
+
else if (deltaY < 100 && readyToClose) {
|
|
1053
|
+
setReadyToClose(false);
|
|
1054
|
+
}
|
|
1055
|
+
const greaterThanMediaSmall = innerWidth > 640;
|
|
1056
|
+
dialogPanelRef.current.style.translate = `calc(-50% + ${deltaX}px) ${greaterThanMediaSmall ? `calc(-50% + ${deltaY}px)` : `${deltaY}px`}`;
|
|
1057
|
+
};
|
|
1058
|
+
const handleMouseMove = e => {
|
|
1059
|
+
if (!allowDragClose)
|
|
1060
|
+
return;
|
|
1061
|
+
const { clientX, clientY } = e;
|
|
1062
|
+
handleMove(clientX, clientY);
|
|
1063
|
+
};
|
|
1064
|
+
const disableDragClose = (clientY) => {
|
|
1065
|
+
const deltaY = clientY - startDragCoords.current.y;
|
|
1066
|
+
dialogPanelRef.current.style.transitionDuration = '';
|
|
1067
|
+
if (deltaY >= 100) {
|
|
1068
|
+
closeModal();
|
|
1069
|
+
setReadyToClose(false);
|
|
1070
|
+
}
|
|
1071
|
+
else {
|
|
1072
|
+
setTimeout(() => (dialogPanelRef.current.style.removeProperty('translate'), 50));
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
const disableMouseDragClose = e => {
|
|
1076
|
+
if (allowDragClose)
|
|
1077
|
+
setAllowDragClose(false);
|
|
1078
|
+
const { clientY } = e;
|
|
1079
|
+
disableDragClose(clientY);
|
|
1080
|
+
};
|
|
1081
|
+
const content = typeof children === 'function' ? children({ openModal, closeModal }) : children;
|
|
1082
|
+
const dialogElement = findComponentByType(content, ModalDialog);
|
|
1083
|
+
if (!dialogElement)
|
|
1084
|
+
throw new Error('ModalDialog must be defined in Modal children');
|
|
1085
|
+
let triggerElement = null;
|
|
1086
|
+
if (typeof children !== 'function') {
|
|
1087
|
+
triggerElement = findComponentByType(content, ModalTrigger);
|
|
1088
|
+
if (!triggerElement)
|
|
1089
|
+
throw new Error('ModalTrigger must be provided when not using render prop pattern');
|
|
1090
|
+
}
|
|
1091
|
+
else {
|
|
1092
|
+
triggerElement = findComponentByType(content, ModalTrigger);
|
|
1093
|
+
}
|
|
1094
|
+
return (jsxs(Fragment$1, { children: [allowDragClose &&
|
|
1095
|
+
bodyElement &&
|
|
1096
|
+
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 &&
|
|
1097
|
+
cloneElement(triggerElement, { onClick: openModal }), jsxs(Dialog, { open: isOpen, onClose: closeModal, className: [
|
|
1098
|
+
'isolate z-50',
|
|
1099
|
+
place === 'bottom' &&
|
|
1100
|
+
'after:fixed after:inset-x-0 after:bottom-0 after:-z-10 after:h-16 after:bg-neutral-50 sm:after:hidden',
|
|
1101
|
+
].join(' '), children: [jsx(DialogBackdrop, { transition: true, className: [
|
|
1102
|
+
'duration-750 ease-exponential data-closed:opacity-0 fixed inset-0 cursor-pointer transition-[opacity_background-color_backdrop-filter_-webkit-backdrop-filter] delay-100',
|
|
1103
|
+
readyToClose
|
|
1104
|
+
? 'bg-neutral-50/5 backdrop-blur-[1px] dark:bg-neutral-950/5'
|
|
1105
|
+
: 'bg-neutral-50/25 backdrop-blur-sm dark:bg-neutral-950/25',
|
|
1106
|
+
].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'
|
|
1107
|
+
? 'data-enter:translate-y-[calc(-50%+12rem)] data-leave:translate-y-[calc(-50%-8rem)] top-1/2 -translate-y-1/2 rounded-2xl'
|
|
1108
|
+
: '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: [
|
|
1109
|
+
'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',
|
|
1110
|
+
readyToClose
|
|
1111
|
+
? 'after:scale-x-200 after:scale-y-200 after:bg-ui-blue'
|
|
1112
|
+
: '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',
|
|
1113
|
+
].join(' '), children: jsx("span", { className: 'sr-only', children: "Drag down to close" }) }), dialogElement] })] })] }));
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
function Time({ children, dateObject, dateTime, day, hours, milliseconds, minutes, month, seconds, year, ref, ...props }) {
|
|
1117
|
+
const [date, setDate] = useState(dateObject || undefined);
|
|
1118
|
+
const getDateAndTime = () => {
|
|
1119
|
+
if (dateTime)
|
|
1120
|
+
return dateTime;
|
|
1121
|
+
if (!date)
|
|
1122
|
+
return '';
|
|
1123
|
+
const currentYear = date.getFullYear(), currentMonth = getMonth(date), currentDay = getDate(date), currentHour = getHours(date), currentMinute = getMinutes(date), currentSecond = getSeconds(date), currentMillisecond = getMilliseconds(date);
|
|
1124
|
+
return [currentYear, currentMonth, currentDay, currentHour, currentMinute, currentSecond, currentMillisecond].join('-');
|
|
1125
|
+
};
|
|
1126
|
+
const dateAndTime = getDateAndTime();
|
|
1127
|
+
const getDateDisplay = () => {
|
|
1128
|
+
if (children)
|
|
1129
|
+
return children;
|
|
1130
|
+
if (dateAndTime === '')
|
|
1131
|
+
return '';
|
|
1132
|
+
const [dtYear, dtMonth, dtDay, dtHour, dtMinute, dtSecond, dtMillisecond] = dateAndTime.split('-').map(Number);
|
|
1133
|
+
return [
|
|
1134
|
+
day && dtDay,
|
|
1135
|
+
month && [getMonthName(Number(dtMonth) - 1), month && year && ','].filter(Boolean).join(''),
|
|
1136
|
+
year && dtYear,
|
|
1137
|
+
hours &&
|
|
1138
|
+
minutes &&
|
|
1139
|
+
[
|
|
1140
|
+
'at',
|
|
1141
|
+
hours && dtHour,
|
|
1142
|
+
hours && minutes && ':',
|
|
1143
|
+
minutes && dtMinute,
|
|
1144
|
+
minutes && seconds && ':',
|
|
1145
|
+
seconds && dtSecond,
|
|
1146
|
+
seconds && milliseconds && '.',
|
|
1147
|
+
milliseconds && dtMillisecond,
|
|
1148
|
+
]
|
|
1149
|
+
.filter(Boolean)
|
|
1150
|
+
.join(''),
|
|
1151
|
+
]
|
|
1152
|
+
.filter(Boolean)
|
|
1153
|
+
.join(' ');
|
|
1154
|
+
};
|
|
1155
|
+
const dateDisplay = getDateDisplay();
|
|
1156
|
+
useEffect(() => {
|
|
1157
|
+
if (date === undefined &&
|
|
1158
|
+
dateObject === undefined &&
|
|
1159
|
+
dateTime === undefined &&
|
|
1160
|
+
typeof window !== 'undefined' &&
|
|
1161
|
+
(dateAndTime === '' || dateDisplay === ''))
|
|
1162
|
+
setDate(new Date());
|
|
1163
|
+
}, [date, setDate, dateAndTime, dateDisplay, dateObject, dateTime]);
|
|
1164
|
+
return (jsx("time", { dateTime: dateAndTime, ref: ref, ...props, children: dateDisplay }));
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
export { Anchor, Button, Form, FormContextProvider, FormStatusProvider, Ghost, Heading, Input, Link, Modal, ModalDialog, ModalTrigger, SubmitButton, Time, defineField, useFormContext, useFormStatus };
|
|
1168
|
+
//# sourceMappingURL=index.esm.js.map
|