@stacksjs/components 0.2.27 → 0.2.53
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/dist/Accordion-19x8q4rj.stx +88 -0
- package/dist/{Audio-vdmg1258.stx → Audio-hjywk3qc.stx} +4 -4
- package/dist/{Avatar-365cvrh4.stx → Avatar-h3jmwcq0.stx} +23 -34
- package/dist/{Badge-8m3qete4.stx → Badge-k8dy3d53.stx} +11 -19
- package/dist/{Button-3tt4vsqt.stx → Button-1vknasy3.stx} +18 -33
- package/dist/Calendar-reny0et7.stx +189 -0
- package/dist/{Card-6wdbexqr.stx → Card-c1g1fd1w.stx} +27 -33
- package/dist/{Checkbox-p3q3e3nf.stx → Checkbox-zgdmy3p5.stx} +36 -44
- package/dist/{Checkout-e4037tyy.stx → Checkout-agt0ngpw.stx} +8 -16
- package/dist/Combobox-fdkr6cdq.stx +96 -0
- package/dist/{ComboboxButton-8gxwkhdx.stx → ComboboxButton-g76stp1e.stx} +14 -2
- package/dist/{ComboboxInput-mk99z65n.stx → ComboboxInput-z1293bbh.stx} +12 -5
- package/dist/ComboboxOption-hmxt3gte.stx +49 -0
- package/dist/{ListboxOptions-8kqvfp7z.stx → ComboboxOptions-sq5360ae.stx} +2 -2
- package/dist/CommandPalette-36mxf05w.stx +81 -0
- package/dist/CommandPaletteItem-mvk6q7a2.stx +27 -0
- package/dist/Dialog-hczpexs4.stx +37 -0
- package/dist/{Drawer-p7m351bn.stx → Drawer-xhevp5cw.stx} +29 -49
- package/dist/Dropdown-vvhemtc0.stx +82 -0
- package/dist/{DropdownButton-9w8zkfwj.stx → DropdownButton-wcz67dxy.stx} +12 -6
- package/dist/DropdownItem-c7rz08e5.stx +35 -0
- package/dist/{DropdownItems-aygjpxkx.stx → DropdownItems-1sxnd5qn.stx} +2 -2
- package/dist/EmailInput-vak3kkmk.stx +30 -0
- package/dist/Form-mas630hy.stx +95 -0
- package/dist/{Image-jhkm6w1f.stx → Image-yhxcvgzs.stx} +68 -100
- package/dist/Listbox-q49tnr90.stx +101 -0
- package/dist/{ListboxButton-spwx7513.stx → ListboxButton-keb8gm0q.stx} +12 -1
- package/dist/ListboxOption-e0dtv1gc.stx +49 -0
- package/dist/{ComboboxOptions-6b5ywc5x.stx → ListboxOptions-ejkatcfg.stx} +7 -3
- package/dist/{Login-rx9gyqhx.stx → Login-gepemsth.stx} +17 -19
- package/dist/Navigator-rk2a5wvk.stx +113 -0
- package/dist/Notification-tb9b525s.stx +78 -0
- package/dist/{NumberInput-nzpkx1ry.stx → NumberInput-drnvtqej.stx} +40 -53
- package/dist/{Pagination-h61eq390.stx → Pagination-n3d31cns.stx} +73 -108
- package/dist/PasswordInput-n02x6053.stx +142 -0
- package/dist/{PaymentMethods-j42jsk5x.stx → PaymentMethods-x4vrx9yb.stx} +21 -30
- package/dist/Popover-et2q44m7.stx +60 -0
- package/dist/{PopoverButton-fnaqc77g.stx → PopoverButton-mffzc9pr.stx} +12 -6
- package/dist/{PopoverPanel-y0vtf5w9.stx → PopoverPanel-054yh38h.stx} +6 -6
- package/dist/{Portal-s2q37yp0.stx → Portal-1vf14s4x.stx} +20 -37
- package/dist/{Progress-vmdkm06p.stx → Progress-yxcntr4x.stx} +36 -48
- package/dist/{Radio-04bs3d21.stx → Radio-cgjv2hb2.stx} +29 -34
- package/dist/RadioGroup-qxmnm3xm.stx +60 -0
- package/dist/RadioGroupOption-s1d6r221.stx +58 -0
- package/dist/SearchInput-pdx7agn0.stx +44 -0
- package/dist/{Select-g4mmvfv8.stx → Select-28y0pg83.stx} +23 -31
- package/dist/Sidebar-73vc78as.stx +236 -0
- package/dist/SidebarFooter-zsfsgcxb.stx +109 -0
- package/dist/SidebarHeader-7v174a9c.stx +122 -0
- package/dist/SidebarItem-3y3e8g2t.stx +92 -0
- package/dist/SidebarSection-z5ey6awe.stx +113 -0
- package/dist/{Signup-c4dyv6f3.stx → Signup-hxm5hwkr.stx} +26 -28
- package/dist/{StepperStep-en4r00zv.stx → StepperStep-wxgembat.stx} +9 -5
- package/dist/{SubscriptionCheckout-gawjzf3q.stx → SubscriptionCheckout-zy2ycrmw.stx} +99 -129
- package/dist/Switch-r5t5w04w.stx +70 -0
- package/dist/{TableHeader-ydys9rzz.stx → TableHeader-0eyzbqpz.stx} +10 -3
- package/dist/Tabs-bzvvn4ke.stx +126 -0
- package/dist/Teleport-tsx4bt4n.stx +65 -0
- package/dist/{TextInput-k2kfkgy1.stx → TextInput-kf084763.stx} +42 -59
- package/dist/{Textarea-szad57dz.stx → Textarea-xg4rr2xz.stx} +42 -54
- package/dist/{Tooltip-em7t551n.stx → Tooltip-m0tqd72e.stx} +34 -40
- package/dist/Transition-7smenaz8.stx +102 -0
- package/dist/{TwoFactorChallenge-an9yvxvq.stx → TwoFactorChallenge-y5m3nk79.stx} +49 -63
- package/dist/{Video-crxva65p.stx → Video-84j4pv6h.stx} +4 -4
- package/dist/VirtualList-fa7v5a3h.stx +67 -0
- package/dist/VirtualTable-f9crbfjr.stx +103 -0
- package/dist/components/CodeBlock.stx +1 -6
- package/dist/index.js +13 -13
- package/dist/ui/accordion/Accordion.stx +1 -3
- package/dist/ui/auth/Login.stx +0 -1
- package/dist/ui/auth/Signup.stx +0 -1
- package/dist/ui/auth/TwoFactorChallenge.stx +1 -3
- package/dist/ui/avatar/Avatar.stx +0 -2
- package/dist/ui/badge/Badge.stx +0 -1
- package/dist/ui/button/Button.stx +1 -2
- package/dist/ui/calendar/Calendar.stx +12 -2
- package/dist/ui/card/Card.stx +0 -2
- package/dist/ui/checkbox/Checkbox.stx +2 -2
- package/dist/ui/combobox/Combobox.stx +2 -1
- package/dist/ui/combobox/ComboboxButton.stx +1 -0
- package/dist/ui/combobox/ComboboxInput.stx +1 -4
- package/dist/ui/combobox/ComboboxOption.stx +2 -9
- package/dist/ui/combobox/ComboboxOptions.stx +1 -1
- package/dist/ui/command-palette/CommandPalette.stx +3 -6
- package/dist/ui/command-palette/CommandPaletteItem.stx +2 -7
- package/dist/ui/dialog/Dialog.stx +1 -3
- package/dist/ui/drawer/Drawer.stx +1 -3
- package/dist/ui/dropdown/Dropdown.stx +2 -5
- package/dist/ui/dropdown/DropdownButton.stx +1 -3
- package/dist/ui/dropdown/DropdownItem.stx +2 -7
- package/dist/ui/dropdown/DropdownItems.stx +1 -1
- package/dist/ui/form/Form.stx +0 -5
- package/dist/ui/image/Image.stx +1 -6
- package/dist/ui/input/EmailInput.stx +1 -1
- package/dist/ui/input/NumberInput.stx +0 -1
- package/dist/ui/input/PasswordInput.stx +1 -4
- package/dist/ui/input/SearchInput.stx +2 -2
- package/dist/ui/input/TextInput.stx +1 -2
- package/dist/ui/listbox/Listbox.stx +2 -1
- package/dist/ui/listbox/ListboxButton.stx +1 -0
- package/dist/ui/listbox/ListboxOption.stx +2 -9
- package/dist/ui/listbox/ListboxOptions.stx +1 -1
- package/dist/ui/navigator/Navigator.stx +4 -4
- package/dist/ui/notification/Notification.stx +1 -5
- package/dist/ui/pagination/Pagination.stx +1 -2
- package/dist/ui/payment/Checkout.stx +0 -4
- package/dist/ui/payment/PaymentMethods.stx +15 -2
- package/dist/ui/payment/SubscriptionCheckout.stx +3 -184
- package/dist/ui/popover/Popover.stx +2 -5
- package/dist/ui/popover/PopoverButton.stx +1 -3
- package/dist/ui/popover/PopoverPanel.stx +1 -1
- package/dist/ui/portal/Portal.stx +1 -0
- package/dist/ui/progress/Progress.stx +6 -1
- package/dist/ui/radio/Radio.stx +1 -1
- package/dist/ui/radio-group/RadioGroup.stx +2 -1
- package/dist/ui/radio-group/RadioGroupOption.stx +2 -9
- package/dist/ui/select/Select.stx +1 -1
- package/dist/ui/sidebar/Sidebar.stx +9 -26
- package/dist/ui/sidebar/SidebarFooter.stx +6 -21
- package/dist/ui/sidebar/SidebarHeader.stx +7 -18
- package/dist/ui/sidebar/SidebarItem.stx +4 -20
- package/dist/ui/sidebar/SidebarSection.stx +5 -18
- package/dist/ui/sidebar/index.d.ts +13 -1
- package/dist/ui/stepper/StepperStep.stx +1 -5
- package/dist/ui/switch/Switch.stx +4 -10
- package/dist/ui/table/TableHeader.stx +1 -1
- package/dist/ui/tabs/Tabs.stx +0 -1
- package/dist/ui/teleport/Teleport.stx +1 -0
- package/dist/ui/textarea/Textarea.stx +1 -1
- package/dist/ui/tooltip/Tooltip.stx +1 -2
- package/dist/ui/transition/Transition.stx +9 -16
- package/dist/ui/virtual-list/VirtualList.stx +2 -4
- package/dist/ui/virtual-table/VirtualTable.stx +1 -1
- package/package.json +3 -3
- package/src/components/CodeBlock.stx +26 -29
- package/src/components/Footer.stx +1 -1
- package/src/components/Hero.stx +1 -1
- package/src/components/Installation.stx +5 -7
- package/src/ui/accordion/Accordion.stx +48 -68
- package/src/ui/audio/Audio.stx +4 -4
- package/src/ui/auth/Login.stx +17 -19
- package/src/ui/auth/Signup.stx +26 -28
- package/src/ui/auth/TwoFactorChallenge.stx +49 -63
- package/src/ui/avatar/Avatar.stx +23 -34
- package/src/ui/badge/Badge.stx +11 -19
- package/src/ui/button/Button.stx +18 -33
- package/src/ui/calendar/Calendar.stx +93 -136
- package/src/ui/card/Card.stx +27 -33
- package/src/ui/checkbox/Checkbox.stx +36 -44
- package/src/ui/combobox/Combobox.stx +87 -4
- package/src/ui/combobox/ComboboxButton.stx +14 -2
- package/src/ui/combobox/ComboboxInput.stx +12 -5
- package/src/ui/combobox/ComboboxOption.stx +29 -32
- package/src/ui/combobox/ComboboxOptions.stx +7 -3
- package/src/ui/command-palette/CommandPalette.stx +70 -28
- package/src/ui/command-palette/CommandPaletteItem.stx +15 -20
- package/src/ui/dialog/Dialog.stx +28 -10
- package/src/ui/drawer/Drawer.stx +29 -49
- package/src/ui/dropdown/Dropdown.stx +69 -11
- package/src/ui/dropdown/DropdownButton.stx +12 -6
- package/src/ui/dropdown/DropdownItem.stx +18 -26
- package/src/ui/dropdown/DropdownItems.stx +2 -2
- package/src/ui/form/Form.stx +50 -164
- package/src/ui/heatmap/Heatmap.stx +16 -37
- package/src/ui/image/Image.stx +68 -100
- package/src/ui/input/EmailInput.stx +16 -27
- package/src/ui/input/NumberInput.stx +40 -53
- package/src/ui/input/PasswordInput.stx +64 -77
- package/src/ui/input/SearchInput.stx +27 -46
- package/src/ui/input/TextInput.stx +42 -59
- package/src/ui/listbox/Listbox.stx +91 -4
- package/src/ui/listbox/ListboxButton.stx +12 -1
- package/src/ui/listbox/ListboxOption.stx +30 -38
- package/src/ui/listbox/ListboxOptions.stx +2 -2
- package/src/ui/navigator/Navigator.stx +52 -77
- package/src/ui/notification/Notification.stx +46 -39
- package/src/ui/pagination/Pagination.stx +73 -108
- package/src/ui/payment/Checkout.stx +8 -16
- package/src/ui/payment/PaymentMethods.stx +21 -30
- package/src/ui/payment/SubscriptionCheckout.stx +99 -129
- package/src/ui/popover/Popover.stx +50 -14
- package/src/ui/popover/PopoverButton.stx +12 -6
- package/src/ui/popover/PopoverPanel.stx +6 -6
- package/src/ui/portal/Portal.stx +20 -37
- package/src/ui/progress/Progress.stx +36 -48
- package/src/ui/radio/Radio.stx +29 -34
- package/src/ui/radio-group/RadioGroup.stx +51 -4
- package/src/ui/radio-group/RadioGroupOption.stx +37 -30
- package/src/ui/select/Select.stx +23 -31
- package/src/ui/sidebar/Sidebar.stx +136 -188
- package/src/ui/sidebar/SidebarFooter.stx +49 -35
- package/src/ui/sidebar/SidebarHeader.stx +52 -30
- package/src/ui/sidebar/SidebarItem.stx +52 -78
- package/src/ui/sidebar/SidebarSection.stx +56 -51
- package/src/ui/sidebar/index.ts +21 -1
- package/src/ui/stepper/StepperStep.stx +9 -5
- package/src/ui/switch/Switch.stx +38 -42
- package/src/ui/table/TableHeader.stx +10 -3
- package/src/ui/tabs/Tabs.stx +68 -87
- package/src/ui/teleport/Teleport.stx +23 -59
- package/src/ui/textarea/Textarea.stx +42 -54
- package/src/ui/tooltip/Tooltip.stx +34 -40
- package/src/ui/transition/Transition.stx +76 -148
- package/src/ui/video/Video.stx +4 -4
- package/src/ui/virtual-list/VirtualList.stx +45 -61
- package/src/ui/virtual-table/VirtualTable.stx +62 -72
- package/dist/Accordion-sbfra0mz.stx +0 -108
- package/dist/Calendar-58nnkdh8.stx +0 -232
- package/dist/Combobox-th5ebw62.stx +0 -13
- package/dist/ComboboxOption-an9zyan6.stx +0 -52
- package/dist/CommandPalette-kwmdf2np.stx +0 -39
- package/dist/CommandPaletteItem-zx2fbpts.stx +0 -32
- package/dist/Dialog-rgmj8q2j.stx +0 -19
- package/dist/Dropdown-jz4jy0n3.stx +0 -24
- package/dist/DropdownItem-wagdspb8.stx +0 -43
- package/dist/EmailInput-ajsp9vw6.stx +0 -41
- package/dist/Form-1mdmx9b6.stx +0 -209
- package/dist/Listbox-pqqh72g8.stx +0 -14
- package/dist/ListboxOption-7nxzaexq.stx +0 -57
- package/dist/Navigator-aay8bjab.stx +0 -138
- package/dist/Notification-gk33gv7b.stx +0 -71
- package/dist/PasswordInput-zv4hm43j.stx +0 -155
- package/dist/Popover-469gbt6r.stx +0 -24
- package/dist/RadioGroup-bvb1mrhd.stx +0 -13
- package/dist/RadioGroupOption-cpdwgnhw.stx +0 -51
- package/dist/SearchInput-2521m475.stx +0 -63
- package/dist/Sidebar-40ckbzh8.stx +0 -288
- package/dist/SidebarFooter-hnth56mg.stx +0 -95
- package/dist/SidebarHeader-3wrte2p2.stx +0 -100
- package/dist/SidebarItem-zqtvvzpc.stx +0 -118
- package/dist/SidebarSection-3etwnbjr.stx +0 -108
- package/dist/Switch-036j9vm1.stx +0 -74
- package/dist/Tabs-svh721m0.stx +0 -145
- package/dist/Teleport-qfch3w0b.stx +0 -101
- package/dist/Transition-0hmr6zxb.stx +0 -174
- package/dist/VirtualList-cndhjejh.stx +0 -83
- package/dist/VirtualTable-ng0b48yp.stx +0 -113
package/dist/Form-1mdmx9b6.stx
DELETED
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const action = $props.action || ''
|
|
3
|
-
export const method = $props.method || 'POST'
|
|
4
|
-
export const validationSchema = $props.validationSchema || {}
|
|
5
|
-
export const initialValues = $props.initialValues || {}
|
|
6
|
-
export const validateOnChange = $props.validateOnChange ?? true
|
|
7
|
-
export const validateOnBlur = $props.validateOnBlur ?? true
|
|
8
|
-
export const onSubmit = $props.onSubmit
|
|
9
|
-
export const onError = $props.onError
|
|
10
|
-
export const className = $props.className || ''
|
|
11
|
-
|
|
12
|
-
let values = { ...initialValues }
|
|
13
|
-
let errors = {}
|
|
14
|
-
let touched = {}
|
|
15
|
-
let isSubmitting = false
|
|
16
|
-
let isValidating = false
|
|
17
|
-
let submitCount = 0
|
|
18
|
-
|
|
19
|
-
// Validate a single field
|
|
20
|
-
function validateField(name, value) {
|
|
21
|
-
const fieldSchema = validationSchema[name]
|
|
22
|
-
if (!fieldSchema)
|
|
23
|
-
return null
|
|
24
|
-
|
|
25
|
-
// Required validation
|
|
26
|
-
if (fieldSchema.required && !value) {
|
|
27
|
-
return fieldSchema.requiredMessage || `${name} is required`
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Min length validation
|
|
31
|
-
if (fieldSchema.minLength && value.length < fieldSchema.minLength) {
|
|
32
|
-
return fieldSchema.minLengthMessage || `${name} must be at least ${fieldSchema.minLength} characters`
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Max length validation
|
|
36
|
-
if (fieldSchema.maxLength && value.length > fieldSchema.maxLength) {
|
|
37
|
-
return fieldSchema.maxLengthMessage || `${name} must be at most ${fieldSchema.maxLength} characters`
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Pattern validation
|
|
41
|
-
if (fieldSchema.pattern && !fieldSchema.pattern.test(value)) {
|
|
42
|
-
return fieldSchema.patternMessage || `${name} is invalid`
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Custom validation
|
|
46
|
-
if (fieldSchema.validate && typeof fieldSchema.validate === 'function') {
|
|
47
|
-
return fieldSchema.validate(value, values)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return null
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Validate all fields
|
|
54
|
-
function validateForm() {
|
|
55
|
-
const newErrors = {}
|
|
56
|
-
let isValid = true
|
|
57
|
-
|
|
58
|
-
Object.keys(validationSchema).forEach((name) => {
|
|
59
|
-
const error = validateField(name, values[name])
|
|
60
|
-
if (error) {
|
|
61
|
-
newErrors[name] = error
|
|
62
|
-
isValid = false
|
|
63
|
-
}
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
errors = newErrors
|
|
67
|
-
return isValid
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Handle field change
|
|
71
|
-
function handleChange(event) {
|
|
72
|
-
const { name, value } = event.target
|
|
73
|
-
values[name] = value
|
|
74
|
-
|
|
75
|
-
if (validateOnChange && touched[name]) {
|
|
76
|
-
const error = validateField(name, value)
|
|
77
|
-
if (error) {
|
|
78
|
-
errors[name] = error
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
delete errors[name]
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Handle field blur
|
|
87
|
-
function handleBlur(event) {
|
|
88
|
-
const { name } = event.target
|
|
89
|
-
touched[name] = true
|
|
90
|
-
|
|
91
|
-
if (validateOnBlur) {
|
|
92
|
-
const error = validateField(name, values[name])
|
|
93
|
-
if (error) {
|
|
94
|
-
errors[name] = error
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
delete errors[name]
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Handle form submission
|
|
103
|
-
async function handleSubmit(event) {
|
|
104
|
-
event.preventDefault()
|
|
105
|
-
submitCount++
|
|
106
|
-
|
|
107
|
-
// Mark all fields as touched
|
|
108
|
-
Object.keys(validationSchema).forEach((name) => {
|
|
109
|
-
touched[name] = true
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
// Validate
|
|
113
|
-
isValidating = true
|
|
114
|
-
const isValid = validateForm()
|
|
115
|
-
isValidating = false
|
|
116
|
-
|
|
117
|
-
if (!isValid) {
|
|
118
|
-
if (onError) {
|
|
119
|
-
onError(errors)
|
|
120
|
-
}
|
|
121
|
-
return
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Submit
|
|
125
|
-
isSubmitting = true
|
|
126
|
-
|
|
127
|
-
try {
|
|
128
|
-
if (onSubmit) {
|
|
129
|
-
await onSubmit(values, { setErrors, setValues, resetForm })
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
catch (error) {
|
|
133
|
-
if (onError) {
|
|
134
|
-
onError(error)
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
finally {
|
|
138
|
-
isSubmitting = false
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Helper functions
|
|
143
|
-
function setErrors(newErrors) {
|
|
144
|
-
errors = { ...errors, ...newErrors }
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function setValues(newValues) {
|
|
148
|
-
values = { ...values, ...newValues }
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function resetForm() {
|
|
152
|
-
values = { ...initialValues }
|
|
153
|
-
errors = {}
|
|
154
|
-
touched = {}
|
|
155
|
-
isSubmitting = false
|
|
156
|
-
submitCount = 0
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function getFieldProps(name) {
|
|
160
|
-
return {
|
|
161
|
-
name,
|
|
162
|
-
value: values[name] || '',
|
|
163
|
-
error: errors[name],
|
|
164
|
-
touched: touched[name],
|
|
165
|
-
onChange: handleChange,
|
|
166
|
-
onBlur: handleBlur,
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
export const formClasses = `space-y-6 ${className}`.trim()
|
|
171
|
-
export const errorClasses = `mt-1 text-sm text-red-600 dark:text-red-400`.trim()
|
|
172
|
-
</script>
|
|
173
|
-
|
|
174
|
-
<form
|
|
175
|
-
class="{{ formClasses }}"
|
|
176
|
-
@if(action)action="{{ action }}"@endif
|
|
177
|
-
method="{{ method }}"
|
|
178
|
-
onsubmit="handleSubmit(event)"
|
|
179
|
-
novalidate
|
|
180
|
-
>
|
|
181
|
-
<slot
|
|
182
|
-
values="{{ values }}"
|
|
183
|
-
errors="{{ errors }}"
|
|
184
|
-
touched="{{ touched }}"
|
|
185
|
-
isSubmitting="{{ isSubmitting }}"
|
|
186
|
-
isValidating="{{ isValidating }}"
|
|
187
|
-
submitCount="{{ submitCount }}"
|
|
188
|
-
getFieldProps="{{ getFieldProps }}"
|
|
189
|
-
setErrors="{{ setErrors }}"
|
|
190
|
-
setValues="{{ setValues }}"
|
|
191
|
-
resetForm="{{ resetForm }}"
|
|
192
|
-
/>
|
|
193
|
-
</form>
|
|
194
|
-
|
|
195
|
-
<script>
|
|
196
|
-
// Export context for child components
|
|
197
|
-
if (typeof window !== 'undefined') {
|
|
198
|
-
window.__formContext = {
|
|
199
|
-
values,
|
|
200
|
-
errors,
|
|
201
|
-
touched,
|
|
202
|
-
isSubmitting,
|
|
203
|
-
isValidating,
|
|
204
|
-
getFieldProps,
|
|
205
|
-
handleChange,
|
|
206
|
-
handleBlur,
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
</script>
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const value = $props.value
|
|
3
|
-
export const onChange = $props.onChange
|
|
4
|
-
export const multiple = $props.multiple || false
|
|
5
|
-
export const className = $props.className || ''
|
|
6
|
-
export const as = $props.as || 'div'
|
|
7
|
-
|
|
8
|
-
const baseClasses = 'relative'
|
|
9
|
-
const listboxClasses = `${baseClasses} ${className}`.trim()
|
|
10
|
-
</script>
|
|
11
|
-
|
|
12
|
-
<component :is="{{ as }}" class="{{ listboxClasses }}">
|
|
13
|
-
<slot :value="value" :onChange="onChange" :multiple="multiple" />
|
|
14
|
-
</component>
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const value = $props.value
|
|
3
|
-
export const disabled = $props.disabled || false
|
|
4
|
-
export const className = $props.className || ''
|
|
5
|
-
export const as = $props.as || 'li'
|
|
6
|
-
export const currentValue = $props.currentValue
|
|
7
|
-
export const onChange = $props.onChange
|
|
8
|
-
|
|
9
|
-
export let active = false
|
|
10
|
-
export const selected = Array.isArray(currentValue)
|
|
11
|
-
? currentValue.includes(value)
|
|
12
|
-
: currentValue === value
|
|
13
|
-
|
|
14
|
-
const baseClasses = 'relative cursor-pointer select-none py-2 pl-10 pr-4'
|
|
15
|
-
const stateClasses = active
|
|
16
|
-
? 'bg-blue-100 text-blue-900 dark:bg-blue-900 dark:text-blue-100'
|
|
17
|
-
: 'text-neutral-900 dark:text-neutral-100'
|
|
18
|
-
const disabledClasses = disabled
|
|
19
|
-
? 'opacity-50 cursor-not-allowed'
|
|
20
|
-
: ''
|
|
21
|
-
|
|
22
|
-
const optionClasses = `${baseClasses} ${stateClasses} ${disabledClasses} ${className}`.trim()
|
|
23
|
-
|
|
24
|
-
export function handleClick() {
|
|
25
|
-
if (disabled) return
|
|
26
|
-
onChange?.(value)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function handleMouseEnter() {
|
|
30
|
-
if (!disabled) active = true
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function handleMouseLeave() {
|
|
34
|
-
active = false
|
|
35
|
-
}
|
|
36
|
-
</script>
|
|
37
|
-
|
|
38
|
-
<component
|
|
39
|
-
:is="{{ as }}"
|
|
40
|
-
class="{{ optionClasses }}"
|
|
41
|
-
role="option"
|
|
42
|
-
aria-selected="{{ selected ? 'true' : 'false' }}"
|
|
43
|
-
@if(disabled)aria-disabled="true"@endif
|
|
44
|
-
@click="handleClick"
|
|
45
|
-
@mouseenter="handleMouseEnter"
|
|
46
|
-
@mouseleave="handleMouseLeave"
|
|
47
|
-
>
|
|
48
|
-
@if(selected)
|
|
49
|
-
<span class="absolute inset-y-0 left-0 flex items-center pl-3 text-blue-600 dark:text-blue-400">
|
|
50
|
-
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
|
51
|
-
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
|
|
52
|
-
</svg>
|
|
53
|
-
</span>
|
|
54
|
-
@endif
|
|
55
|
-
|
|
56
|
-
<slot :active="active" :selected="selected" :disabled="disabled" />
|
|
57
|
-
</component>
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
// Navigator Component Props
|
|
3
|
-
export const items = $props.items || []
|
|
4
|
-
export const active = $props.active || ''
|
|
5
|
-
export const orientation = $props.orientation || 'horizontal' // 'horizontal' | 'vertical'
|
|
6
|
-
export const variant = $props.variant || 'default' // 'default' | 'pills' | 'underline' | 'sidebar'
|
|
7
|
-
export const size = $props.size || 'md' // 'sm' | 'md' | 'lg'
|
|
8
|
-
export const onNavigate = $props.onNavigate
|
|
9
|
-
export const className = $props.className || ''
|
|
10
|
-
|
|
11
|
-
// Helper function to check if item is active
|
|
12
|
-
function isActive(item) {
|
|
13
|
-
if (typeof item.href === 'string' && typeof active === 'string') {
|
|
14
|
-
// Exact match
|
|
15
|
-
if (item.href === active) return true
|
|
16
|
-
// Match with query params/hash
|
|
17
|
-
if (active.startsWith(item.href)) return true
|
|
18
|
-
}
|
|
19
|
-
if (item.id && item.id === active) return true
|
|
20
|
-
return false
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Base classes
|
|
24
|
-
const containerBaseClasses = orientation === 'horizontal'
|
|
25
|
-
? 'flex items-center'
|
|
26
|
-
: 'flex flex-col'
|
|
27
|
-
|
|
28
|
-
const containerClasses = `${containerBaseClasses} ${className}`.trim()
|
|
29
|
-
|
|
30
|
-
// Item classes based on variant and size
|
|
31
|
-
function getItemClasses(item) {
|
|
32
|
-
const active = isActive(item)
|
|
33
|
-
let classes = ''
|
|
34
|
-
|
|
35
|
-
// Size classes
|
|
36
|
-
const sizeClasses = {
|
|
37
|
-
sm: 'px-2 py-1 text-sm',
|
|
38
|
-
md: 'px-3 py-2 text-base',
|
|
39
|
-
lg: 'px-4 py-3 text-lg',
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
classes += sizeClasses[size] || sizeClasses.md
|
|
43
|
-
|
|
44
|
-
// Variant classes
|
|
45
|
-
if (variant === 'default') {
|
|
46
|
-
classes += active
|
|
47
|
-
? ' text-gray-900 dark:text-gray-100 font-medium'
|
|
48
|
-
: ' text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'
|
|
49
|
-
} else if (variant === 'pills') {
|
|
50
|
-
classes += active
|
|
51
|
-
? ' bg-blue-600 text-white font-medium rounded-full'
|
|
52
|
-
: ' text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full'
|
|
53
|
-
} else if (variant === 'underline') {
|
|
54
|
-
classes += active
|
|
55
|
-
? ' text-blue-600 dark:text-blue-400 font-medium border-b-2 border-blue-600 dark:border-blue-400'
|
|
56
|
-
: ' text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 border-b-2 border-transparent'
|
|
57
|
-
} else if (variant === 'sidebar') {
|
|
58
|
-
classes += active
|
|
59
|
-
? ' bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 font-medium border-l-4 border-blue-600 dark:border-blue-400'
|
|
60
|
-
: ' text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 border-l-4 border-transparent'
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Common classes
|
|
64
|
-
classes += ' transition-all duration-200 cursor-pointer flex items-center gap-2'
|
|
65
|
-
|
|
66
|
-
if (item.disabled) {
|
|
67
|
-
classes += ' opacity-50 cursor-not-allowed pointer-events-none'
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return classes.trim()
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Gap classes between items
|
|
74
|
-
const gapClasses = orientation === 'horizontal'
|
|
75
|
-
? 'gap-1'
|
|
76
|
-
: 'gap-0.5'
|
|
77
|
-
|
|
78
|
-
function handleClick(item, event) {
|
|
79
|
-
if (item.disabled) {
|
|
80
|
-
event.preventDefault()
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (onNavigate) {
|
|
85
|
-
event.preventDefault()
|
|
86
|
-
onNavigate(item)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
</script>
|
|
90
|
-
|
|
91
|
-
<nav class="{{ containerClasses }} {{ gapClasses }}" role="navigation" aria-label="Main navigation">
|
|
92
|
-
@foreach(item in items)
|
|
93
|
-
@if(item.href)
|
|
94
|
-
<a
|
|
95
|
-
href="{{ item.href }}"
|
|
96
|
-
class="{{ getItemClasses(item) }}"
|
|
97
|
-
@click="handleClick(item, event)"
|
|
98
|
-
@if(isActive(item))
|
|
99
|
-
aria-current="page"
|
|
100
|
-
@endif
|
|
101
|
-
@if(item.disabled)
|
|
102
|
-
aria-disabled="true"
|
|
103
|
-
tabindex="-1"
|
|
104
|
-
@endif
|
|
105
|
-
>
|
|
106
|
-
@if(item.icon)
|
|
107
|
-
<span class="flex-shrink-0" innerHTML="{!! item.icon !!}"></span>
|
|
108
|
-
@endif
|
|
109
|
-
<span>{{ item.label }}</span>
|
|
110
|
-
@if(item.badge)
|
|
111
|
-
<span class="ml-auto px-2 py-0.5 text-xs font-semibold rounded-full bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300">
|
|
112
|
-
{{ item.badge }}
|
|
113
|
-
</span>
|
|
114
|
-
@endif
|
|
115
|
-
</a>
|
|
116
|
-
@else
|
|
117
|
-
<button
|
|
118
|
-
type="button"
|
|
119
|
-
class="{{ getItemClasses(item) }}"
|
|
120
|
-
@click="handleClick(item, event)"
|
|
121
|
-
@if(item.disabled)
|
|
122
|
-
disabled
|
|
123
|
-
aria-disabled="true"
|
|
124
|
-
@endif
|
|
125
|
-
>
|
|
126
|
-
@if(item.icon)
|
|
127
|
-
<span class="flex-shrink-0" innerHTML="{!! item.icon !!}"></span>
|
|
128
|
-
@endif
|
|
129
|
-
<span>{{ item.label }}</span>
|
|
130
|
-
@if(item.badge)
|
|
131
|
-
<span class="ml-auto px-2 py-0.5 text-xs font-semibold rounded-full bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300">
|
|
132
|
-
{{ item.badge }}
|
|
133
|
-
</span>
|
|
134
|
-
@endif
|
|
135
|
-
</button>
|
|
136
|
-
@endif
|
|
137
|
-
@endforeach
|
|
138
|
-
</nav>
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const show = $props.show !== false
|
|
3
|
-
export const title = $props.title || ''
|
|
4
|
-
export const message = $props.message || ''
|
|
5
|
-
export const type = $props.type || 'info'
|
|
6
|
-
export const position = $props.position || 'top-right'
|
|
7
|
-
export const duration = $props.duration || 5000
|
|
8
|
-
export const onClose = $props.onClose
|
|
9
|
-
export const className = $props.className || ''
|
|
10
|
-
|
|
11
|
-
const typeColors = {
|
|
12
|
-
info: 'bg-blue-50 text-blue-900 dark:bg-blue-900 dark:text-blue-100',
|
|
13
|
-
success: 'bg-green-50 text-green-900 dark:bg-green-900 dark:text-green-100',
|
|
14
|
-
warning: 'bg-yellow-50 text-yellow-900 dark:bg-yellow-900 dark:text-yellow-100',
|
|
15
|
-
error: 'bg-red-50 text-red-900 dark:bg-red-900 dark:text-red-100',
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const positions = {
|
|
19
|
-
'top-left': 'top-0 left-0',
|
|
20
|
-
'top-right': 'top-0 right-0',
|
|
21
|
-
'top-center': 'top-0 left-1/2 -translate-x-1/2',
|
|
22
|
-
'bottom-left': 'bottom-0 left-0',
|
|
23
|
-
'bottom-right': 'bottom-0 right-0',
|
|
24
|
-
'bottom-center': 'bottom-0 left-1/2 -translate-x-1/2',
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const baseClasses = 'fixed z-50 m-4 max-w-md w-full pointer-events-auto rounded-lg p-4 shadow-lg ring-1 ring-black ring-opacity-5 transition-all'
|
|
28
|
-
const notificationClasses = `${baseClasses} ${typeColors[type]} ${positions[position]} ${className}`.trim()
|
|
29
|
-
|
|
30
|
-
export function handleClose() {
|
|
31
|
-
onClose?.()
|
|
32
|
-
}
|
|
33
|
-
</script>
|
|
34
|
-
|
|
35
|
-
@if(show)
|
|
36
|
-
<div class="{{ notificationClasses }}" role="alert">
|
|
37
|
-
<div class="flex items-start">
|
|
38
|
-
<div class="flex-1">
|
|
39
|
-
@if(title)
|
|
40
|
-
<p class="text-sm font-medium">{{ title }}</p>
|
|
41
|
-
@endif
|
|
42
|
-
@if(message)
|
|
43
|
-
<p class="mt-1 text-sm {{ title ? 'opacity-90' : '' }}">{{ message }}</p>
|
|
44
|
-
@endif
|
|
45
|
-
@if(!title && !message)
|
|
46
|
-
<slot />
|
|
47
|
-
@endif
|
|
48
|
-
</div>
|
|
49
|
-
|
|
50
|
-
<button
|
|
51
|
-
type="button"
|
|
52
|
-
@click="handleClose"
|
|
53
|
-
class="ml-4 inline-flex rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2"
|
|
54
|
-
>
|
|
55
|
-
<span class="sr-only">Close</span>
|
|
56
|
-
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
|
57
|
-
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
|
|
58
|
-
</svg>
|
|
59
|
-
</button>
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
|
|
63
|
-
<script>
|
|
64
|
-
// Auto-hide after duration (client-side only)
|
|
65
|
-
if (typeof window !== 'undefined' && duration > 0) {
|
|
66
|
-
setTimeout(() => {
|
|
67
|
-
handleClose()
|
|
68
|
-
}, duration)
|
|
69
|
-
}
|
|
70
|
-
</script>
|
|
71
|
-
@endif
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const value = $props.value || ''
|
|
3
|
-
export const onChange = $props.onChange || (() => {})
|
|
4
|
-
export const placeholder = $props.placeholder || 'Enter your password'
|
|
5
|
-
export const disabled = $props.disabled || false
|
|
6
|
-
export const readonly = $props.readonly || false
|
|
7
|
-
export const size = $props.size || 'md'
|
|
8
|
-
export const error = $props.error || false
|
|
9
|
-
export const label = $props.label || ''
|
|
10
|
-
export const helperText = $props.helperText || ''
|
|
11
|
-
export const required = $props.required || false
|
|
12
|
-
export const showStrength = $props.showStrength || false
|
|
13
|
-
export const className = $props.className || ''
|
|
14
|
-
export const inputClassName = $props.inputClassName || ''
|
|
15
|
-
|
|
16
|
-
// State
|
|
17
|
-
let showPassword = false
|
|
18
|
-
|
|
19
|
-
// Size classes
|
|
20
|
-
const sizeClasses = {
|
|
21
|
-
sm: 'px-3 py-1.5 text-sm h-8',
|
|
22
|
-
md: 'px-4 py-2 text-base h-10',
|
|
23
|
-
lg: 'px-5 py-3 text-lg h-12',
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Icon size classes
|
|
27
|
-
const iconSizeClasses = {
|
|
28
|
-
sm: 'h-4 w-4',
|
|
29
|
-
md: 'h-5 w-5',
|
|
30
|
-
lg: 'h-6 w-6',
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Base and state classes
|
|
34
|
-
const baseClasses = 'block w-full border-0 rounded-md shadow-sm ring-1 ring-inset transition-colors duration-200 focus:ring-2 focus:ring-inset dark:bg-blue-gray-700 dark:text-gray-100 pr-10'
|
|
35
|
-
|
|
36
|
-
const stateClasses = error
|
|
37
|
-
? 'ring-red-300 dark:ring-red-600 text-red-900 dark:text-red-300 placeholder-red-300 dark:placeholder-red-500 focus:ring-red-500 dark:focus:ring-red-400'
|
|
38
|
-
: 'ring-gray-300 dark:ring-gray-600 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:ring-indigo-600 dark:focus:ring-indigo-400'
|
|
39
|
-
|
|
40
|
-
const disabledClasses = disabled
|
|
41
|
-
? 'opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-800'
|
|
42
|
-
: readonly
|
|
43
|
-
? 'bg-gray-50 dark:bg-gray-800 cursor-default'
|
|
44
|
-
: 'bg-white dark:bg-blue-gray-700'
|
|
45
|
-
|
|
46
|
-
export const inputClasses = `${baseClasses} ${sizeClasses[size]} ${stateClasses} ${disabledClasses} ${inputClassName}`.trim()
|
|
47
|
-
export const labelClasses = `block text-sm font-medium leading-6 mb-2 ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-900 dark:text-gray-100'}`.trim()
|
|
48
|
-
export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
|
|
49
|
-
export const iconClasses = iconSizeClasses[size]
|
|
50
|
-
|
|
51
|
-
// Password strength calculation
|
|
52
|
-
function calculateStrength(password) {
|
|
53
|
-
if (!password) return 0
|
|
54
|
-
let strength = 0
|
|
55
|
-
if (password.length >= 8) strength += 25
|
|
56
|
-
if (password.length >= 12) strength += 25
|
|
57
|
-
if (/[a-z]/.test(password) && /[A-Z]/.test(password)) strength += 25
|
|
58
|
-
if (/\d/.test(password)) strength += 15
|
|
59
|
-
if (/[^a-zA-Z\d]/.test(password)) strength += 10
|
|
60
|
-
return Math.min(strength, 100)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export const strength = calculateStrength(value)
|
|
64
|
-
export const strengthColor = strength < 40 ? 'bg-red-500' : strength < 70 ? 'bg-yellow-500' : 'bg-green-500'
|
|
65
|
-
export const strengthText = strength < 40 ? 'Weak' : strength < 70 ? 'Medium' : 'Strong'
|
|
66
|
-
</script>
|
|
67
|
-
|
|
68
|
-
<div class="w-full {{ className }}">
|
|
69
|
-
@if(label)
|
|
70
|
-
<label for="password-input" class="{{ labelClasses }}">
|
|
71
|
-
{{ label }}
|
|
72
|
-
@if(required)
|
|
73
|
-
<span class="text-red-500 ml-1">*</span>
|
|
74
|
-
@endif
|
|
75
|
-
</label>
|
|
76
|
-
@endif
|
|
77
|
-
|
|
78
|
-
<div class="relative">
|
|
79
|
-
<input
|
|
80
|
-
type="{{ showPassword ? 'text' : 'password' }}"
|
|
81
|
-
id="password-input"
|
|
82
|
-
class="{{ inputClasses }}"
|
|
83
|
-
value="{{ value }}"
|
|
84
|
-
placeholder="{{ placeholder }}"
|
|
85
|
-
disabled="{{ disabled }}"
|
|
86
|
-
readonly="{{ readonly }}"
|
|
87
|
-
required="{{ required }}"
|
|
88
|
-
oninput="handleInput(event)"
|
|
89
|
-
aria-invalid="{{ error ? 'true' : 'false' }}"
|
|
90
|
-
@if(helperText)aria-describedby="helper-text"@endif
|
|
91
|
-
/>
|
|
92
|
-
|
|
93
|
-
<!-- Toggle visibility button -->
|
|
94
|
-
<div class="absolute inset-y-0 right-0 flex items-center pr-3">
|
|
95
|
-
<button
|
|
96
|
-
type="button"
|
|
97
|
-
@click="toggleVisibility()"
|
|
98
|
-
class="text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 focus:outline-none"
|
|
99
|
-
aria-label="{{ showPassword ? 'Hide password' : 'Show password' }}"
|
|
100
|
-
>
|
|
101
|
-
@if(showPassword)
|
|
102
|
-
<!-- Eye slash icon (hide) -->
|
|
103
|
-
<svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
104
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21" />
|
|
105
|
-
</svg>
|
|
106
|
-
@else
|
|
107
|
-
<!-- Eye icon (show) -->
|
|
108
|
-
<svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
109
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
110
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
|
111
|
-
</svg>
|
|
112
|
-
@endif
|
|
113
|
-
</button>
|
|
114
|
-
</div>
|
|
115
|
-
</div>
|
|
116
|
-
|
|
117
|
-
@if(showStrength && value.length > 0)
|
|
118
|
-
<!-- Password strength indicator -->
|
|
119
|
-
<div class="mt-2">
|
|
120
|
-
<div class="flex items-center justify-between mb-1">
|
|
121
|
-
<span class="text-xs text-gray-600 dark:text-gray-400">Password strength</span>
|
|
122
|
-
<span class="text-xs font-medium {{ strength < 40 ? 'text-red-600' : strength < 70 ? 'text-yellow-600' : 'text-green-600' }}">
|
|
123
|
-
{{ strengthText }}
|
|
124
|
-
</span>
|
|
125
|
-
</div>
|
|
126
|
-
<div class="w-full h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
|
|
127
|
-
<div
|
|
128
|
-
class="{{ strengthColor }} h-full transition-all duration-300 rounded-full"
|
|
129
|
-
style="width: {{ strength }}%"
|
|
130
|
-
></div>
|
|
131
|
-
</div>
|
|
132
|
-
</div>
|
|
133
|
-
@endif
|
|
134
|
-
|
|
135
|
-
@if(helperText)
|
|
136
|
-
<p id="helper-text" class="{{ helperClasses }}">
|
|
137
|
-
{{ helperText }}
|
|
138
|
-
</p>
|
|
139
|
-
@endif
|
|
140
|
-
</div>
|
|
141
|
-
|
|
142
|
-
<script>
|
|
143
|
-
function handleInput(event) {
|
|
144
|
-
const newValue = event.target.value
|
|
145
|
-
|
|
146
|
-
if (onChange) {
|
|
147
|
-
onChange(newValue)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function toggleVisibility() {
|
|
152
|
-
showPassword = !showPassword
|
|
153
|
-
// Re-render would be handled by the framework
|
|
154
|
-
}
|
|
155
|
-
</script>
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const className = $props.className || ''
|
|
3
|
-
export const as = $props.as || 'div'
|
|
4
|
-
export let isOpen = false
|
|
5
|
-
|
|
6
|
-
export function toggle() {
|
|
7
|
-
isOpen = !isOpen
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function close() {
|
|
11
|
-
isOpen = false
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function open() {
|
|
15
|
-
isOpen = true
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const baseClasses = 'relative'
|
|
19
|
-
const popoverClasses = `${baseClasses} ${className}`.trim()
|
|
20
|
-
</script>
|
|
21
|
-
|
|
22
|
-
<component :is="{{ as }}" class="{{ popoverClasses }}">
|
|
23
|
-
<slot :isOpen="isOpen" :toggle="toggle" :close="close" :open="open" />
|
|
24
|
-
</component>
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const value = $props.value
|
|
3
|
-
export const onChange = $props.onChange
|
|
4
|
-
export const className = $props.className || ''
|
|
5
|
-
export const as = $props.as || 'div'
|
|
6
|
-
|
|
7
|
-
const baseClasses = 'w-full'
|
|
8
|
-
const groupClasses = `${baseClasses} ${className}`.trim()
|
|
9
|
-
</script>
|
|
10
|
-
|
|
11
|
-
<component :is="{{ as }}" class="{{ groupClasses }}" role="radiogroup">
|
|
12
|
-
<slot :value="value" :onChange="onChange" />
|
|
13
|
-
</component>
|