@stacksjs/components 0.2.35 → 0.2.54

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.
Files changed (237) hide show
  1. package/dist/Accordion-19x8q4rj.stx +88 -0
  2. package/dist/{Audio-vdmg1258.stx → Audio-hjywk3qc.stx} +4 -4
  3. package/dist/{Avatar-365cvrh4.stx → Avatar-h3jmwcq0.stx} +23 -34
  4. package/dist/{Badge-8m3qete4.stx → Badge-k8dy3d53.stx} +11 -19
  5. package/dist/{Button-3tt4vsqt.stx → Button-1vknasy3.stx} +18 -33
  6. package/dist/Calendar-reny0et7.stx +189 -0
  7. package/dist/{Card-6wdbexqr.stx → Card-c1g1fd1w.stx} +27 -33
  8. package/dist/{Checkbox-p3q3e3nf.stx → Checkbox-zgdmy3p5.stx} +36 -44
  9. package/dist/{Checkout-e4037tyy.stx → Checkout-agt0ngpw.stx} +8 -16
  10. package/dist/Combobox-fdkr6cdq.stx +96 -0
  11. package/dist/{ComboboxButton-8gxwkhdx.stx → ComboboxButton-g76stp1e.stx} +14 -2
  12. package/dist/{ComboboxInput-mk99z65n.stx → ComboboxInput-z1293bbh.stx} +12 -5
  13. package/dist/ComboboxOption-hmxt3gte.stx +49 -0
  14. package/dist/{ListboxOptions-8kqvfp7z.stx → ComboboxOptions-sq5360ae.stx} +2 -2
  15. package/dist/CommandPalette-36mxf05w.stx +81 -0
  16. package/dist/CommandPaletteItem-mvk6q7a2.stx +27 -0
  17. package/dist/Dialog-hczpexs4.stx +37 -0
  18. package/dist/{Drawer-p7m351bn.stx → Drawer-xhevp5cw.stx} +29 -49
  19. package/dist/Dropdown-vvhemtc0.stx +82 -0
  20. package/dist/{DropdownButton-9w8zkfwj.stx → DropdownButton-wcz67dxy.stx} +12 -6
  21. package/dist/DropdownItem-c7rz08e5.stx +35 -0
  22. package/dist/{DropdownItems-aygjpxkx.stx → DropdownItems-1sxnd5qn.stx} +2 -2
  23. package/dist/EmailInput-vak3kkmk.stx +30 -0
  24. package/dist/Form-mas630hy.stx +95 -0
  25. package/dist/{Image-jhkm6w1f.stx → Image-yhxcvgzs.stx} +68 -100
  26. package/dist/Listbox-q49tnr90.stx +101 -0
  27. package/dist/{ListboxButton-spwx7513.stx → ListboxButton-keb8gm0q.stx} +12 -1
  28. package/dist/ListboxOption-e0dtv1gc.stx +49 -0
  29. package/dist/{ComboboxOptions-6b5ywc5x.stx → ListboxOptions-ejkatcfg.stx} +7 -3
  30. package/dist/{Login-rx9gyqhx.stx → Login-gepemsth.stx} +17 -19
  31. package/dist/Navigator-rk2a5wvk.stx +113 -0
  32. package/dist/Notification-tb9b525s.stx +78 -0
  33. package/dist/{NumberInput-nzpkx1ry.stx → NumberInput-drnvtqej.stx} +40 -53
  34. package/dist/{Pagination-h61eq390.stx → Pagination-n3d31cns.stx} +73 -108
  35. package/dist/PasswordInput-n02x6053.stx +142 -0
  36. package/dist/{PaymentMethods-j42jsk5x.stx → PaymentMethods-x4vrx9yb.stx} +21 -30
  37. package/dist/Popover-et2q44m7.stx +60 -0
  38. package/dist/{PopoverButton-fnaqc77g.stx → PopoverButton-mffzc9pr.stx} +12 -6
  39. package/dist/{PopoverPanel-y0vtf5w9.stx → PopoverPanel-054yh38h.stx} +6 -6
  40. package/dist/{Portal-s2q37yp0.stx → Portal-1vf14s4x.stx} +20 -37
  41. package/dist/{Progress-vmdkm06p.stx → Progress-yxcntr4x.stx} +36 -48
  42. package/dist/{Radio-04bs3d21.stx → Radio-cgjv2hb2.stx} +29 -34
  43. package/dist/RadioGroup-qxmnm3xm.stx +60 -0
  44. package/dist/RadioGroupOption-s1d6r221.stx +58 -0
  45. package/dist/SearchInput-pdx7agn0.stx +44 -0
  46. package/dist/{Select-g4mmvfv8.stx → Select-28y0pg83.stx} +23 -31
  47. package/dist/Sidebar-73vc78as.stx +236 -0
  48. package/dist/SidebarFooter-zsfsgcxb.stx +109 -0
  49. package/dist/SidebarHeader-7v174a9c.stx +122 -0
  50. package/dist/SidebarItem-3y3e8g2t.stx +92 -0
  51. package/dist/SidebarSection-z5ey6awe.stx +113 -0
  52. package/dist/{Signup-c4dyv6f3.stx → Signup-hxm5hwkr.stx} +26 -28
  53. package/dist/{StepperStep-en4r00zv.stx → StepperStep-wxgembat.stx} +9 -5
  54. package/dist/{SubscriptionCheckout-gawjzf3q.stx → SubscriptionCheckout-zy2ycrmw.stx} +99 -129
  55. package/dist/Switch-r5t5w04w.stx +70 -0
  56. package/dist/{TableHeader-ydys9rzz.stx → TableHeader-0eyzbqpz.stx} +10 -3
  57. package/dist/Tabs-bzvvn4ke.stx +126 -0
  58. package/dist/Teleport-tsx4bt4n.stx +65 -0
  59. package/dist/{TextInput-k2kfkgy1.stx → TextInput-kf084763.stx} +42 -59
  60. package/dist/{Textarea-szad57dz.stx → Textarea-xg4rr2xz.stx} +42 -54
  61. package/dist/{Tooltip-em7t551n.stx → Tooltip-m0tqd72e.stx} +34 -40
  62. package/dist/Transition-7smenaz8.stx +102 -0
  63. package/dist/{TwoFactorChallenge-an9yvxvq.stx → TwoFactorChallenge-y5m3nk79.stx} +49 -63
  64. package/dist/{Video-crxva65p.stx → Video-84j4pv6h.stx} +4 -4
  65. package/dist/VirtualList-fa7v5a3h.stx +67 -0
  66. package/dist/VirtualTable-f9crbfjr.stx +103 -0
  67. package/dist/components/CodeBlock.stx +1 -6
  68. package/dist/index.js +13 -13
  69. package/dist/ui/accordion/Accordion.stx +1 -3
  70. package/dist/ui/auth/Login.stx +0 -1
  71. package/dist/ui/auth/Signup.stx +0 -1
  72. package/dist/ui/auth/TwoFactorChallenge.stx +1 -3
  73. package/dist/ui/avatar/Avatar.stx +0 -2
  74. package/dist/ui/badge/Badge.stx +0 -1
  75. package/dist/ui/button/Button.stx +1 -2
  76. package/dist/ui/calendar/Calendar.stx +12 -2
  77. package/dist/ui/card/Card.stx +0 -2
  78. package/dist/ui/checkbox/Checkbox.stx +2 -2
  79. package/dist/ui/combobox/Combobox.stx +2 -1
  80. package/dist/ui/combobox/ComboboxButton.stx +1 -0
  81. package/dist/ui/combobox/ComboboxInput.stx +1 -4
  82. package/dist/ui/combobox/ComboboxOption.stx +2 -9
  83. package/dist/ui/combobox/ComboboxOptions.stx +1 -1
  84. package/dist/ui/command-palette/CommandPalette.stx +3 -6
  85. package/dist/ui/command-palette/CommandPaletteItem.stx +2 -7
  86. package/dist/ui/dialog/Dialog.stx +1 -3
  87. package/dist/ui/drawer/Drawer.stx +1 -3
  88. package/dist/ui/dropdown/Dropdown.stx +2 -5
  89. package/dist/ui/dropdown/DropdownButton.stx +1 -3
  90. package/dist/ui/dropdown/DropdownItem.stx +2 -7
  91. package/dist/ui/dropdown/DropdownItems.stx +1 -1
  92. package/dist/ui/form/Form.stx +0 -5
  93. package/dist/ui/image/Image.stx +1 -6
  94. package/dist/ui/input/EmailInput.stx +1 -1
  95. package/dist/ui/input/NumberInput.stx +0 -1
  96. package/dist/ui/input/PasswordInput.stx +1 -4
  97. package/dist/ui/input/SearchInput.stx +2 -2
  98. package/dist/ui/input/TextInput.stx +1 -2
  99. package/dist/ui/listbox/Listbox.stx +2 -1
  100. package/dist/ui/listbox/ListboxButton.stx +1 -0
  101. package/dist/ui/listbox/ListboxOption.stx +2 -9
  102. package/dist/ui/listbox/ListboxOptions.stx +1 -1
  103. package/dist/ui/navigator/Navigator.stx +4 -4
  104. package/dist/ui/notification/Notification.stx +1 -5
  105. package/dist/ui/pagination/Pagination.stx +1 -2
  106. package/dist/ui/payment/Checkout.stx +0 -4
  107. package/dist/ui/payment/PaymentMethods.stx +15 -2
  108. package/dist/ui/payment/SubscriptionCheckout.stx +3 -184
  109. package/dist/ui/popover/Popover.stx +2 -5
  110. package/dist/ui/popover/PopoverButton.stx +1 -3
  111. package/dist/ui/popover/PopoverPanel.stx +1 -1
  112. package/dist/ui/portal/Portal.stx +1 -0
  113. package/dist/ui/progress/Progress.stx +6 -1
  114. package/dist/ui/radio/Radio.stx +1 -1
  115. package/dist/ui/radio-group/RadioGroup.stx +2 -1
  116. package/dist/ui/radio-group/RadioGroupOption.stx +2 -9
  117. package/dist/ui/select/Select.stx +1 -1
  118. package/dist/ui/sidebar/Sidebar.stx +9 -26
  119. package/dist/ui/sidebar/SidebarFooter.stx +6 -21
  120. package/dist/ui/sidebar/SidebarHeader.stx +7 -18
  121. package/dist/ui/sidebar/SidebarItem.stx +4 -20
  122. package/dist/ui/sidebar/SidebarSection.stx +5 -18
  123. package/dist/ui/sidebar/index.d.ts +13 -1
  124. package/dist/ui/stepper/StepperStep.stx +1 -5
  125. package/dist/ui/switch/Switch.stx +4 -10
  126. package/dist/ui/table/TableHeader.stx +1 -1
  127. package/dist/ui/tabs/Tabs.stx +0 -1
  128. package/dist/ui/teleport/Teleport.stx +1 -0
  129. package/dist/ui/textarea/Textarea.stx +1 -1
  130. package/dist/ui/tooltip/Tooltip.stx +1 -2
  131. package/dist/ui/transition/Transition.stx +9 -16
  132. package/dist/ui/virtual-list/VirtualList.stx +2 -4
  133. package/dist/ui/virtual-table/VirtualTable.stx +1 -1
  134. package/package.json +5 -5
  135. package/src/components/CodeBlock.stx +26 -29
  136. package/src/components/Footer.stx +1 -1
  137. package/src/components/Hero.stx +1 -1
  138. package/src/components/Installation.stx +5 -7
  139. package/src/ui/accordion/Accordion.stx +48 -68
  140. package/src/ui/audio/Audio.stx +4 -4
  141. package/src/ui/auth/Login.stx +17 -19
  142. package/src/ui/auth/Signup.stx +26 -28
  143. package/src/ui/auth/TwoFactorChallenge.stx +49 -63
  144. package/src/ui/avatar/Avatar.stx +23 -34
  145. package/src/ui/badge/Badge.stx +11 -19
  146. package/src/ui/button/Button.stx +18 -33
  147. package/src/ui/calendar/Calendar.stx +93 -136
  148. package/src/ui/card/Card.stx +27 -33
  149. package/src/ui/checkbox/Checkbox.stx +36 -44
  150. package/src/ui/combobox/Combobox.stx +87 -4
  151. package/src/ui/combobox/ComboboxButton.stx +14 -2
  152. package/src/ui/combobox/ComboboxInput.stx +12 -5
  153. package/src/ui/combobox/ComboboxOption.stx +29 -32
  154. package/src/ui/combobox/ComboboxOptions.stx +7 -3
  155. package/src/ui/command-palette/CommandPalette.stx +70 -28
  156. package/src/ui/command-palette/CommandPaletteItem.stx +15 -20
  157. package/src/ui/dialog/Dialog.stx +28 -10
  158. package/src/ui/drawer/Drawer.stx +29 -49
  159. package/src/ui/dropdown/Dropdown.stx +69 -11
  160. package/src/ui/dropdown/DropdownButton.stx +12 -6
  161. package/src/ui/dropdown/DropdownItem.stx +18 -26
  162. package/src/ui/dropdown/DropdownItems.stx +2 -2
  163. package/src/ui/form/Form.stx +50 -164
  164. package/src/ui/heatmap/Heatmap.stx +16 -37
  165. package/src/ui/image/Image.stx +68 -100
  166. package/src/ui/input/EmailInput.stx +16 -27
  167. package/src/ui/input/NumberInput.stx +40 -53
  168. package/src/ui/input/PasswordInput.stx +64 -77
  169. package/src/ui/input/SearchInput.stx +27 -46
  170. package/src/ui/input/TextInput.stx +42 -59
  171. package/src/ui/listbox/Listbox.stx +91 -4
  172. package/src/ui/listbox/ListboxButton.stx +12 -1
  173. package/src/ui/listbox/ListboxOption.stx +30 -38
  174. package/src/ui/listbox/ListboxOptions.stx +2 -2
  175. package/src/ui/navigator/Navigator.stx +52 -77
  176. package/src/ui/notification/Notification.stx +46 -39
  177. package/src/ui/pagination/Pagination.stx +73 -108
  178. package/src/ui/payment/Checkout.stx +8 -16
  179. package/src/ui/payment/PaymentMethods.stx +21 -30
  180. package/src/ui/payment/SubscriptionCheckout.stx +99 -129
  181. package/src/ui/popover/Popover.stx +50 -14
  182. package/src/ui/popover/PopoverButton.stx +12 -6
  183. package/src/ui/popover/PopoverPanel.stx +6 -6
  184. package/src/ui/portal/Portal.stx +20 -37
  185. package/src/ui/progress/Progress.stx +36 -48
  186. package/src/ui/radio/Radio.stx +29 -34
  187. package/src/ui/radio-group/RadioGroup.stx +51 -4
  188. package/src/ui/radio-group/RadioGroupOption.stx +37 -30
  189. package/src/ui/select/Select.stx +23 -31
  190. package/src/ui/sidebar/Sidebar.stx +136 -188
  191. package/src/ui/sidebar/SidebarFooter.stx +49 -35
  192. package/src/ui/sidebar/SidebarHeader.stx +52 -30
  193. package/src/ui/sidebar/SidebarItem.stx +52 -78
  194. package/src/ui/sidebar/SidebarSection.stx +56 -51
  195. package/src/ui/sidebar/index.ts +21 -1
  196. package/src/ui/stepper/StepperStep.stx +9 -5
  197. package/src/ui/switch/Switch.stx +38 -42
  198. package/src/ui/table/TableHeader.stx +10 -3
  199. package/src/ui/tabs/Tabs.stx +68 -87
  200. package/src/ui/teleport/Teleport.stx +23 -59
  201. package/src/ui/textarea/Textarea.stx +42 -54
  202. package/src/ui/tooltip/Tooltip.stx +34 -40
  203. package/src/ui/transition/Transition.stx +76 -148
  204. package/src/ui/video/Video.stx +4 -4
  205. package/src/ui/virtual-list/VirtualList.stx +45 -61
  206. package/src/ui/virtual-table/VirtualTable.stx +62 -72
  207. package/dist/Accordion-sbfra0mz.stx +0 -108
  208. package/dist/Calendar-58nnkdh8.stx +0 -232
  209. package/dist/Combobox-th5ebw62.stx +0 -13
  210. package/dist/ComboboxOption-an9zyan6.stx +0 -52
  211. package/dist/CommandPalette-kwmdf2np.stx +0 -39
  212. package/dist/CommandPaletteItem-zx2fbpts.stx +0 -32
  213. package/dist/Dialog-rgmj8q2j.stx +0 -19
  214. package/dist/Dropdown-jz4jy0n3.stx +0 -24
  215. package/dist/DropdownItem-wagdspb8.stx +0 -43
  216. package/dist/EmailInput-ajsp9vw6.stx +0 -41
  217. package/dist/Form-1mdmx9b6.stx +0 -209
  218. package/dist/Listbox-pqqh72g8.stx +0 -14
  219. package/dist/ListboxOption-7nxzaexq.stx +0 -57
  220. package/dist/Navigator-aay8bjab.stx +0 -138
  221. package/dist/Notification-gk33gv7b.stx +0 -71
  222. package/dist/PasswordInput-zv4hm43j.stx +0 -155
  223. package/dist/Popover-469gbt6r.stx +0 -24
  224. package/dist/RadioGroup-bvb1mrhd.stx +0 -13
  225. package/dist/RadioGroupOption-cpdwgnhw.stx +0 -51
  226. package/dist/SearchInput-2521m475.stx +0 -63
  227. package/dist/Sidebar-40ckbzh8.stx +0 -288
  228. package/dist/SidebarFooter-hnth56mg.stx +0 -95
  229. package/dist/SidebarHeader-3wrte2p2.stx +0 -100
  230. package/dist/SidebarItem-zqtvvzpc.stx +0 -118
  231. package/dist/SidebarSection-3etwnbjr.stx +0 -108
  232. package/dist/Switch-036j9vm1.stx +0 -74
  233. package/dist/Tabs-svh721m0.stx +0 -145
  234. package/dist/Teleport-qfch3w0b.stx +0 -101
  235. package/dist/Transition-0hmr6zxb.stx +0 -174
  236. package/dist/VirtualList-cndhjejh.stx +0 -83
  237. package/dist/VirtualTable-ng0b48yp.stx +0 -113
@@ -1,6 +1,5 @@
1
1
  <script server>
2
2
  export const value = $props.value || ''
3
- export const onChange = $props.onChange || (() => {})
4
3
  export const placeholder = $props.placeholder || ''
5
4
  export const disabled = $props.disabled || false
6
5
  export const readonly = $props.readonly || false
@@ -17,45 +16,51 @@ export const showCount = $props.showCount || false
17
16
  export const className = $props.className || ''
18
17
  export const inputClassName = $props.inputClassName || ''
19
18
 
20
- // Size classes
21
- const sizeClasses = {
22
- sm: 'px-3 py-1.5 text-sm h-8',
23
- md: 'px-4 py-2 text-base h-10',
24
- lg: 'px-5 py-3 text-lg h-12',
25
- }
26
-
27
- // Icon size classes
28
- const iconSizeClasses = {
29
- sm: 'h-4 w-4',
30
- md: 'h-5 w-5',
31
- lg: 'h-6 w-6',
32
- }
19
+ const sizeClasses = { sm: 'px-3 py-1.5 text-sm h-8', md: 'px-4 py-2 text-base h-10', lg: 'px-5 py-3 text-lg h-12' }
20
+ const iconSizeClasses = { sm: 'h-4 w-4', md: 'h-5 w-5', lg: 'h-6 w-6' }
33
21
 
34
- // Base and state classes
35
22
  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'
36
-
37
23
  const stateClasses = error
38
24
  ? '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'
39
25
  : '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'
40
-
41
26
  const disabledClasses = disabled
42
27
  ? 'opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-800'
43
28
  : readonly
44
29
  ? 'bg-gray-50 dark:bg-gray-800 cursor-default'
45
30
  : 'bg-white dark:bg-blue-gray-700'
46
-
47
31
  const paddingClasses = leftIcon ? 'pl-10' : rightIcon || clearable ? 'pr-10' : ''
48
32
 
49
33
  export const inputClasses = `${baseClasses} ${sizeClasses[size]} ${stateClasses} ${disabledClasses} ${paddingClasses} ${inputClassName}`.trim()
50
34
  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()
51
35
  export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
52
36
  export const iconClasses = iconSizeClasses[size]
53
- export const hasValue = value && value.length > 0
37
+ export const inputId = `input-${label}`
38
+ </script>
39
+
40
+ <script client>
41
+ const emit = defineEmits()
42
+ const inputValue = state({{ value }})
43
+
44
+ function onInput(event) {
45
+ inputValue.set(event.target.value)
46
+ emit('input', inputValue())
47
+ }
48
+
49
+ function onClear() {
50
+ inputValue.set('')
51
+ emit('input', '')
52
+ emit('clear')
53
+ }
54
+
55
+ const hasValue = derived(() => inputValue().length > 0)
56
+ const charCount = derived(() => `${inputValue().length} / {{ maxLength || 0 }}`)
57
+
58
+ defineExpose({ value: inputValue, clear: onClear })
54
59
  </script>
55
60
 
56
61
  <div class="w-full {{ className }}">
57
62
  @if(label)
58
- <label for="input-{{ label }}" class="{{ labelClasses }}">
63
+ <label for="{{ inputId }}" class="{{ labelClasses }}">
59
64
  {{ label }}
60
65
  @if(required)
61
66
  <span class="text-red-500 ml-1">*</span>
@@ -65,33 +70,31 @@ export const hasValue = value && value.length > 0
65
70
 
66
71
  <div class="relative">
67
72
  @if(leftIcon)
68
- <!-- Left icon -->
69
73
  <div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
70
- <span class="{{ iconClasses }} text-gray-400 dark:text-gray-500" innerHTML="{!! leftIcon !!}"></span>
74
+ <span class="{{ iconClasses }} text-gray-400 dark:text-gray-500">{!! leftIcon !!}</span>
71
75
  </div>
72
76
  @endif
73
77
 
74
78
  <input
75
79
  type="text"
76
- id="input-{{ label }}"
80
+ id="{{ inputId }}"
77
81
  class="{{ inputClasses }}"
78
- value="{{ value }}"
82
+ :value="inputValue()"
79
83
  placeholder="{{ placeholder }}"
80
- disabled="{{ disabled }}"
81
- readonly="{{ readonly }}"
82
- required="{{ required }}"
84
+ @if(disabled)disabled@endif
85
+ @if(readonly)readonly@endif
86
+ @if(required)required@endif
83
87
  @if(maxLength)maxlength="{{ maxLength }}"@endif
84
- oninput="handleInput(event)"
85
- aria-invalid="{{ error ? 'true' : 'false' }}"
88
+ @input="onInput($event)"
89
+ :aria-invalid="{{ error ? 'true' : 'false' }}"
86
90
  @if(helperText)aria-describedby="helper-text"@endif
87
91
  />
88
92
 
89
- @if(clearable && hasValue && !disabled && !readonly)
90
- <!-- Clear button -->
91
- <div class="absolute inset-y-0 right-0 flex items-center pr-3">
93
+ @if(clearable)
94
+ <div :show="hasValue() && !{{ disabled }} && !{{ readonly }}" class="absolute inset-y-0 right-0 flex items-center pr-3">
92
95
  <button
93
96
  type="button"
94
- @click="handleClear()"
97
+ @click="onClear()"
95
98
  class="text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 focus:outline-none"
96
99
  aria-label="Clear input"
97
100
  >
@@ -100,13 +103,11 @@ export const hasValue = value && value.length > 0
100
103
  </svg>
101
104
  </button>
102
105
  </div>
103
- @else
104
- @if(rightIcon && !clearable)
105
- <!-- Right icon -->
106
- <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
107
- <span class="{{ iconClasses }} text-gray-400 dark:text-gray-500" innerHTML="{!! rightIcon !!}"></span>
108
- </div>
109
- @endif
106
+ @endif
107
+ @if(rightIcon && !clearable)
108
+ <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
109
+ <span class="{{ iconClasses }} text-gray-400 dark:text-gray-500">{!! rightIcon !!}</span>
110
+ </div>
110
111
  @endif
111
112
  </div>
112
113
 
@@ -121,26 +122,8 @@ export const hasValue = value && value.length > 0
121
122
  @endif
122
123
 
123
124
  @if(showCount && maxLength)
124
- <p class="text-sm text-gray-500 dark:text-gray-400">
125
- {{ value.length }} / {{ maxLength }}
126
- </p>
125
+ <p class="text-sm text-gray-500 dark:text-gray-400" x-text="charCount()"></p>
127
126
  @endif
128
127
  </div>
129
128
  @endif
130
129
  </div>
131
-
132
- <script>
133
- function handleInput(event) {
134
- const newValue = event.target.value
135
-
136
- if (onChange) {
137
- onChange(newValue)
138
- }
139
- }
140
-
141
- function handleClear() {
142
- if (onChange) {
143
- onChange('')
144
- }
145
- }
146
- </script>
@@ -1,6 +1,5 @@
1
1
  <script server>
2
2
  export const value = $props.value || ''
3
- export const onChange = $props.onChange || (() => {})
4
3
  export const placeholder = $props.placeholder || ''
5
4
  export const disabled = $props.disabled || false
6
5
  export const readonly = $props.readonly || false
@@ -13,24 +12,14 @@ export const helperText = $props.helperText || ''
13
12
  export const required = $props.required || false
14
13
  export const maxLength = $props.maxLength
15
14
  export const showCount = $props.showCount || false
16
- export const resize = $props.resize || 'vertical' // 'none' | 'vertical' | 'horizontal' | 'both'
15
+ export const resize = $props.resize || 'vertical'
17
16
  export const className = $props.className || ''
18
17
 
19
- // Resize classes
20
- const resizeClasses = {
21
- none: 'resize-none',
22
- vertical: 'resize-y',
23
- horizontal: 'resize-x',
24
- both: 'resize',
25
- }
26
-
27
- // Base and state classes
18
+ const resizeClasses = { none: 'resize-none', vertical: 'resize-y', horizontal: 'resize-x', both: 'resize' }
28
19
  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 px-4 py-2 text-base dark:bg-blue-gray-700 dark:text-gray-100'
29
-
30
20
  const stateClasses = error
31
21
  ? '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'
32
22
  : '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'
33
-
34
23
  const disabledClasses = disabled
35
24
  ? 'opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-800'
36
25
  : readonly
@@ -42,6 +31,40 @@ export const labelClasses = `block text-sm font-medium leading-6 mb-2 ${error ?
42
31
  export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
43
32
  </script>
44
33
 
34
+ <script client>
35
+ const emit = defineEmits()
36
+ const autoResize = {{ autoResize }}
37
+ const maxRows = {{ maxRows }}
38
+ const inputValue = state({{ value }})
39
+
40
+ function resizeTextarea(el) {
41
+ if (!autoResize) return
42
+ el.style.height = 'auto'
43
+ const scrollHeight = el.scrollHeight
44
+ const lineHeight = Number.parseInt(window.getComputedStyle(el).lineHeight) || 20
45
+ const maxHeight = lineHeight * maxRows
46
+ el.style.height = `${Math.min(scrollHeight, maxHeight)}px`
47
+ el.style.overflowY = scrollHeight > maxHeight ? 'auto' : 'hidden'
48
+ }
49
+
50
+ function onInput(event) {
51
+ inputValue.set(event.target.value)
52
+ resizeTextarea(event.target)
53
+ emit('input', inputValue())
54
+ }
55
+
56
+ onMount(() => {
57
+ if (autoResize) {
58
+ const el = document.getElementById('textarea-input')
59
+ if (el) resizeTextarea(el)
60
+ }
61
+ })
62
+
63
+ const charCount = derived(() => `${inputValue().length} / {{ maxLength || 0 }}`)
64
+
65
+ defineExpose({ value: inputValue })
66
+ </script>
67
+
45
68
  <div class="w-full">
46
69
  @if(label)
47
70
  <label for="textarea-input" class="{{ labelClasses }}">
@@ -57,12 +80,12 @@ export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red
57
80
  class="{{ textareaClasses }}"
58
81
  rows="{{ rows }}"
59
82
  placeholder="{{ placeholder }}"
60
- disabled="{{ disabled }}"
61
- readonly="{{ readonly }}"
62
- required="{{ required }}"
83
+ @if(disabled)disabled@endif
84
+ @if(readonly)readonly@endif
85
+ @if(required)required@endif
63
86
  @if(maxLength)maxlength="{{ maxLength }}"@endif
64
- oninput="handleInput(event)"
65
- aria-invalid="{{ error ? 'true' : 'false' }}"
87
+ @input="onInput($event)"
88
+ :aria-invalid="{{ error ? 'true' : 'false' }}"
66
89
  @if(helperText)aria-describedby="helper-text"@endif
67
90
  >{{ value }}</textarea>
68
91
 
@@ -77,43 +100,8 @@ export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red
77
100
  @endif
78
101
 
79
102
  @if(showCount && maxLength)
80
- <p class="text-sm text-gray-500 dark:text-gray-400">
81
- {{ value.length }} / {{ maxLength }}
82
- </p>
103
+ <p class="text-sm text-gray-500 dark:text-gray-400" x-text="charCount()"></p>
83
104
  @endif
84
105
  </div>
85
106
  @endif
86
107
  </div>
87
-
88
- <script>
89
- function handleInput(event) {
90
- const textarea = event.target
91
- const newValue = textarea.value
92
-
93
- if (autoResize && typeof window !== 'undefined') {
94
- // Auto-resize functionality
95
- textarea.style.height = 'auto'
96
- const scrollHeight = textarea.scrollHeight
97
- const lineHeight = parseInt(window.getComputedStyle(textarea).lineHeight)
98
- const maxHeight = lineHeight * maxRows
99
-
100
- textarea.style.height = Math.min(scrollHeight, maxHeight) + 'px'
101
- textarea.style.overflowY = scrollHeight > maxHeight ? 'auto' : 'hidden'
102
- }
103
-
104
- if (onChange) {
105
- onChange(newValue)
106
- }
107
- }
108
-
109
- // Initialize auto-resize on mount
110
- if (autoResize && typeof window !== 'undefined') {
111
- window.addEventListener('DOMContentLoaded', () => {
112
- const textarea = document.getElementById('textarea-input')
113
- if (textarea && value) {
114
- // Trigger initial resize
115
- textarea.dispatchEvent(new Event('input'))
116
- }
117
- })
118
- }
119
- </script>
@@ -6,7 +6,6 @@ export const className = $props.className || ''
6
6
  export const show = $props.show || false
7
7
  export const disabled = $props.disabled || false
8
8
 
9
- // Position classes
10
9
  const positionClasses = {
11
10
  top: 'bottom-full left-1/2 -translate-x-1/2 mb-2',
12
11
  bottom: 'top-full left-1/2 -translate-x-1/2 mt-2',
@@ -14,7 +13,6 @@ const positionClasses = {
14
13
  right: 'left-full top-1/2 -translate-y-1/2 ml-2',
15
14
  }
16
15
 
17
- // Arrow classes
18
16
  const arrowClasses = {
19
17
  top: 'top-full left-1/2 -translate-x-1/2 border-t-gray-900 dark:border-t-gray-700',
20
18
  bottom: 'bottom-full left-1/2 -translate-x-1/2 border-b-gray-900 dark:border-b-gray-700',
@@ -22,55 +20,51 @@ const arrowClasses = {
22
20
  right: 'right-full top-1/2 -translate-y-1/2 border-r-gray-900 dark:border-r-gray-700',
23
21
  }
24
22
 
25
- export const tooltipClasses = `absolute z-50 px-3 py-2 text-sm font-medium text-white bg-gray-900 dark:bg-gray-700 rounded-lg shadow-lg whitespace-nowrap pointer-events-none opacity-0 transition-opacity duration-200 ${positionClasses[position]} ${className}`.trim()
23
+ export const tooltipClasses = `absolute z-50 px-3 py-2 text-sm font-medium text-white bg-gray-900 dark:bg-gray-700 rounded-lg shadow-lg whitespace-nowrap pointer-events-none transition-opacity duration-200 ${positionClasses[position]} ${className}`.trim()
26
24
  export const arrowClass = `absolute w-0 h-0 border-4 border-transparent ${arrowClasses[position]}`.trim()
27
-
28
- let isVisible = show
29
- let timeoutId = null
30
25
  </script>
31
26
 
32
- <div class="relative inline-block {{ disabled ? 'cursor-not-allowed' : '' }}">
33
- <!-- Trigger element (slot) -->
34
- <div
35
- onmouseenter="handleMouseEnter()"
36
- onmouseleave="handleMouseLeave()"
37
- onfocus="handleMouseEnter()"
38
- onblur="handleMouseLeave()"
39
- >
40
- <slot />
41
- </div>
42
-
43
- <!-- Tooltip -->
44
- @if(isVisible && !disabled)
45
- <div
46
- class="{{ tooltipClasses }}"
47
- role="tooltip"
48
- style="opacity: 1"
49
- >
50
- {{ content }}
51
- <div class="{{ arrowClass }}"></div>
52
- </div>
53
- @endif
54
- </div>
55
-
56
- <script>
57
- function handleMouseEnter() {
58
- if (disabled) return
27
+ <script client>
28
+ const delay = {{ delay }}
29
+ const isDisabled = {{ disabled }}
30
+ const isVisible = state({{ show }})
31
+ let timeoutId = null
59
32
 
33
+ function showTooltip() {
34
+ if (isDisabled) return
60
35
  if (delay > 0) {
61
- timeoutId = setTimeout(() => {
62
- isVisible = true
63
- }, delay)
64
- } else {
65
- isVisible = true
36
+ timeoutId = setTimeout(() => isVisible.set(true), delay)
37
+ }
38
+ else {
39
+ isVisible.set(true)
66
40
  }
67
41
  }
68
42
 
69
- function handleMouseLeave() {
43
+ function hideTooltip() {
70
44
  if (timeoutId) {
71
45
  clearTimeout(timeoutId)
72
46
  timeoutId = null
73
47
  }
74
- isVisible = false
48
+ isVisible.set(false)
75
49
  }
76
50
  </script>
51
+
52
+ <div class="relative inline-block {{ disabled ? 'cursor-not-allowed' : '' }}">
53
+ <div
54
+ @mouseenter="showTooltip()"
55
+ @mouseleave="hideTooltip()"
56
+ @focusin="showTooltip()"
57
+ @focusout="hideTooltip()"
58
+ >
59
+ <slot />
60
+ </div>
61
+
62
+ <div
63
+ :show="isVisible() && !{{ disabled }}"
64
+ class="{{ tooltipClasses }}"
65
+ role="tooltip"
66
+ >
67
+ {{ content }}
68
+ <div class="{{ arrowClass }}"></div>
69
+ </div>
70
+ </div>
@@ -0,0 +1,102 @@
1
+ <script server>
2
+ export const show = $props.show !== false
3
+ export const enter = $props.enter || 'transition-opacity duration-300'
4
+ export const enterFrom = $props.enterFrom || 'opacity-0'
5
+ export const enterTo = $props.enterTo || 'opacity-100'
6
+ export const leave = $props.leave || 'transition-opacity duration-200'
7
+ export const leaveFrom = $props.leaveFrom || 'opacity-100'
8
+ export const leaveTo = $props.leaveTo || 'opacity-0'
9
+ export const appear = $props.appear || false
10
+ export const duration = $props.duration || 300
11
+ export const delay = $props.delay || 0
12
+ export const preset = $props.preset || ''
13
+ export const className = $props.className || ''
14
+
15
+ const presets = {
16
+ fade: { enter: 'transition-opacity', enterFrom: 'opacity-0', enterTo: 'opacity-100', leave: 'transition-opacity', leaveFrom: 'opacity-100', leaveTo: 'opacity-0' },
17
+ slide: { enter: 'transition-transform', enterFrom: 'translate-y-2', enterTo: 'translate-y-0', leave: 'transition-transform', leaveFrom: 'translate-y-0', leaveTo: 'translate-y-2' },
18
+ slideLeft: { enter: 'transition-transform', enterFrom: 'translate-x-full', enterTo: 'translate-x-0', leave: 'transition-transform', leaveFrom: 'translate-x-0', leaveTo: '-translate-x-full' },
19
+ slideRight: { enter: 'transition-transform', enterFrom: '-translate-x-full', enterTo: 'translate-x-0', leave: 'transition-transform', leaveFrom: 'translate-x-0', leaveTo: 'translate-x-full' },
20
+ scale: { enter: 'transition-transform', enterFrom: 'scale-95', enterTo: 'scale-100', leave: 'transition-transform', leaveFrom: 'scale-100', leaveTo: 'scale-95' },
21
+ rotate: { enter: 'transition-transform', enterFrom: 'rotate-12 scale-95', enterTo: 'rotate-0 scale-100', leave: 'transition-transform', leaveFrom: 'rotate-0 scale-100', leaveTo: '-rotate-12 scale-95' },
22
+ zoom: { enter: 'transition-all', enterFrom: 'scale-0 opacity-0', enterTo: 'scale-100 opacity-100', leave: 'transition-all', leaveFrom: 'scale-100 opacity-100', leaveTo: 'scale-0 opacity-0' },
23
+ }
24
+
25
+ const p = preset && presets[preset] ? presets[preset] : {}
26
+ export const enterClass = p.enter || enter
27
+ export const enterFromClass = p.enterFrom || enterFrom
28
+ export const enterToClass = p.enterTo || enterTo
29
+ export const leaveClass = p.leave || leave
30
+ export const leaveFromClass = p.leaveFrom || leaveFrom
31
+ export const leaveToClass = p.leaveTo || leaveTo
32
+
33
+ export const durationStyle = `transition-duration: ${duration}ms; transition-delay: ${delay}ms;`
34
+ export const extraClass = className
35
+ </script>
36
+
37
+ <script client>
38
+ const emit = defineEmits()
39
+ const showProp = {{ show }}
40
+ const appear = {{ appear }}
41
+ const duration = {{ duration }}
42
+ const delay = {{ delay }}
43
+ const enterClass = {{ enterClass }}
44
+ const enterFromClass = {{ enterFromClass }}
45
+ const enterToClass = {{ enterToClass }}
46
+ const leaveClass = {{ leaveClass }}
47
+ const leaveFromClass = {{ leaveFromClass }}
48
+ const leaveToClass = {{ leaveToClass }}
49
+ const extraClass = {{ extraClass }}
50
+
51
+ const visible = state(showProp)
52
+ const isEntering = state(appear && showProp)
53
+ const isLeaving = state(false)
54
+ const shouldRender = state(showProp)
55
+
56
+ const transitionClass = derived(() => {
57
+ if (visible()) {
58
+ return isEntering() ? `${enterClass} ${enterFromClass}` : enterToClass
59
+ }
60
+ return isLeaving() ? `${leaveClass} ${leaveFromClass}` : leaveToClass
61
+ })
62
+
63
+ const componentClass = derived(() => `${transitionClass()} ${extraClass}`.trim())
64
+
65
+ function setShow(next) {
66
+ if (next === visible()) return
67
+ if (next) {
68
+ emit('beforeEnter')
69
+ shouldRender.set(true)
70
+ visible.set(true)
71
+ isEntering.set(true)
72
+ setTimeout(() => emit('enter'), delay)
73
+ setTimeout(() => {
74
+ isEntering.set(false)
75
+ emit('afterEnter')
76
+ }, duration + delay)
77
+ }
78
+ else {
79
+ emit('beforeLeave')
80
+ visible.set(false)
81
+ isLeaving.set(true)
82
+ setTimeout(() => emit('leave'), delay)
83
+ setTimeout(() => {
84
+ isLeaving.set(false)
85
+ shouldRender.set(false)
86
+ emit('afterLeave')
87
+ }, duration + delay)
88
+ }
89
+ }
90
+
91
+ onMount(() => {
92
+ if (appear && showProp) {
93
+ setTimeout(() => isEntering.set(false), duration + delay)
94
+ }
95
+ })
96
+
97
+ defineExpose({ visible, setShow })
98
+ </script>
99
+
100
+ <div :show="shouldRender()" :class="componentClass()" style="{{ durationStyle }}">
101
+ <slot />
102
+ </div>
@@ -3,12 +3,53 @@ export const headingText = $props.headingText || 'Two Factor Authentication'
3
3
  export const labelText = $props.labelText || 'Authentication code'
4
4
  export const instructionText = $props.instructionText || 'Open your Symantec 2FA app to view your authentication code.'
5
5
  export const codeLength = $props.codeLength || 6
6
- export const onSubmit = $props.onSubmit || (() => {})
7
- export const onUseRecoveryCode = $props.onUseRecoveryCode
6
+ export const showRecoveryCode = $props.showRecoveryCode ?? true
8
7
  export const className = $props.className || ''
9
8
 
10
9
  export const containerClasses = `py-32 dark:bg-blue-gray-900 ${className}`.trim()
11
- export const codes = Array(codeLength).fill('')
10
+ </script>
11
+
12
+ <script client>
13
+ const emit = defineEmits()
14
+ const codeLength = {{ codeLength }}
15
+
16
+ function onCodeInput(event, index) {
17
+ const input = event.target
18
+ const value = input.value
19
+ if (!/^\d*$/.test(value)) {
20
+ input.value = ''
21
+ return
22
+ }
23
+ if (value.length === 1 && index < codeLength - 1) {
24
+ document.getElementById(`code-${index + 1}`)?.focus()
25
+ }
26
+ }
27
+
28
+ function onKeyDown(event, index) {
29
+ if (event.key === 'Backspace' && !event.target.value && index > 0) {
30
+ document.getElementById(`code-${index - 1}`)?.focus()
31
+ }
32
+ }
33
+
34
+ function onSubmit(event) {
35
+ event.preventDefault()
36
+ const code = []
37
+ for (let i = 0; i < codeLength; i++) {
38
+ const input = document.getElementById(`code-${i}`)
39
+ if (input?.value) code.push(input.value)
40
+ }
41
+ if (code.length === codeLength) {
42
+ emit('submit', code.join(''))
43
+ }
44
+ else {
45
+ emit('error', { message: 'Please enter all digits' })
46
+ }
47
+ }
48
+
49
+ function onRecoveryCode(event) {
50
+ event.preventDefault()
51
+ emit('useRecoveryCode')
52
+ }
12
53
  </script>
13
54
 
14
55
  <div class="{{ containerClasses }}">
@@ -21,7 +62,7 @@ export const codes = Array(codeLength).fill('')
21
62
  <label for="code-0" class="mt-4 block text-sm text-gray-900 dark:text-gray-100 font-medium leading-6">
22
63
  {{ labelText }}
23
64
  </label>
24
- <form onsubmit="event.preventDefault(); handleSubmit(event)">
65
+ <form @submit="onSubmit($event)">
25
66
  <div class="mt-2 flex rounded-md shadow-sm space-x-2">
26
67
  @for(i in Array(codeLength).keys())
27
68
  <input
@@ -31,8 +72,8 @@ export const codes = Array(codeLength).fill('')
31
72
  name="code-{{ i }}"
32
73
  placeholder="-"
33
74
  class="block w-full border-0 rounded-md px-2 py-2 text-center text-gray-900 dark:text-gray-100 ring-1 ring-gray-300 dark:ring-gray-600 ring-inset sm:text-sm placeholder:text-gray-400 dark:placeholder:text-gray-500 sm:leading-6 focus:ring-2 focus:ring-indigo-600 focus:ring-inset dark:bg-blue-gray-700"
34
- oninput="handleCodeInput(event, {{ i }})"
35
- onkeydown="handleKeyDown(event, {{ i }})"
75
+ @input="onCodeInput($event, {{ i }})"
76
+ @keydown="onKeyDown($event, {{ i }})"
36
77
  />
37
78
  @endfor
38
79
  </div>
@@ -50,14 +91,14 @@ export const codes = Array(codeLength).fill('')
50
91
  {{ instructionText }}
51
92
  </p>
52
93
  </div>
53
- @if(onUseRecoveryCode)
94
+ @if(showRecoveryCode)
54
95
  <div class="mt-4">
55
96
  <p class="text-xs text-gray-700 dark:text-gray-300 font-semibold">
56
97
  Having Problems?
57
98
  </p>
58
99
  <a
59
100
  href="#"
60
- @click="event.preventDefault(); handleRecoveryCode()"
101
+ @click="onRecoveryCode($event)"
61
102
  class="text-xs text-blue-500 hover:underline"
62
103
  >
63
104
  Use recovery code instead
@@ -68,58 +109,3 @@ export const codes = Array(codeLength).fill('')
68
109
  </div>
69
110
  </div>
70
111
  </div>
71
-
72
- <script>
73
- function handleCodeInput(event, index) {
74
- const input = event.target
75
- const value = input.value
76
-
77
- // Only allow digits
78
- if (!/^\d*$/.test(value)) {
79
- input.value = ''
80
- return
81
- }
82
-
83
- // Auto-focus next input
84
- if (value.length === 1 && index < codeLength - 1) {
85
- const nextInput = document.getElementById(`code-${index + 1}`)
86
- if (nextInput) {
87
- nextInput.focus()
88
- }
89
- }
90
- }
91
-
92
- function handleKeyDown(event, index) {
93
- // Handle backspace to move to previous input
94
- if (event.key === 'Backspace' && !event.target.value && index > 0) {
95
- const prevInput = document.getElementById(`code-${index - 1}`)
96
- if (prevInput) {
97
- prevInput.focus()
98
- }
99
- }
100
- }
101
-
102
- function handleSubmit(event) {
103
- const code = []
104
- for (let i = 0; i < codeLength; i++) {
105
- const input = document.getElementById(`code-${i}`)
106
- if (input && input.value) {
107
- code.push(input.value)
108
- }
109
- }
110
-
111
- if (code.length === codeLength) {
112
- if (onSubmit) {
113
- onSubmit(code.join(''))
114
- }
115
- } else {
116
- alert('Please enter all digits')
117
- }
118
- }
119
-
120
- function handleRecoveryCode() {
121
- if (onUseRecoveryCode) {
122
- onUseRecoveryCode()
123
- }
124
- }
125
- </script>
@@ -31,10 +31,10 @@ export const aspectRatioClass = aspectRatio === '16/9' ? 'aspect-video' : aspect
31
31
  class="{{ videoClasses }}"
32
32
  src="{{ src }}"
33
33
  poster="{{ poster }}"
34
- controls="{{ controls }}"
35
- autoplay="{{ autoplay }}"
36
- loop="{{ loop }}"
37
- muted="{{ muted }}"
34
+ @if(controls)controls@endif
35
+ @if(autoplay)autoplay@endif
36
+ @if(loop)loop@endif
37
+ @if(muted)muted@endif
38
38
  preload="{{ preload }}"
39
39
  width="{{ width }}"
40
40
  height="{{ height }}"