@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
@@ -10,18 +10,14 @@ export const height = $props.height
10
10
  export const lazy = $props.lazy ?? true
11
11
  export const placeholder = $props.placeholder || 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300"%3E%3Crect fill="%23e5e7eb" width="400" height="300"/%3E%3C/svg%3E'
12
12
  export const blurDataURL = $props.blurDataURL || ''
13
- export const onLoad = $props.onLoad
14
- export const onError = $props.onError
15
13
  export const aspectRatio = $props.aspectRatio
16
14
  export const objectFit = $props.objectFit || 'cover'
17
15
  export const rounded = $props.rounded ?? false
18
16
  export const zoomOnHover = $props.zoomOnHover || false
19
17
  export const className = $props.className || ''
20
18
 
21
- // Has WebP support
22
- export const hasWebP = webpSrc || webpSrcSet
19
+ export const hasWebP = !!(webpSrc || webpSrcSet)
23
20
 
24
- // Object fit classes
25
21
  const objectFitClasses = {
26
22
  contain: 'object-contain',
27
23
  cover: 'object-cover',
@@ -30,23 +26,69 @@ const objectFitClasses = {
30
26
  'scale-down': 'object-scale-down',
31
27
  }
32
28
 
33
- // Rounded classes
34
29
  const roundedClass = rounded === true ? 'rounded-lg' : rounded === 'full' ? 'rounded-full' : rounded ? `rounded-${rounded}` : ''
35
-
36
30
  const zoomClasses = zoomOnHover ? 'transform hover:scale-110 transition-transform duration-300 ease-in-out cursor-zoom-in' : ''
37
31
 
38
32
  export const containerClasses = `relative overflow-hidden ${roundedClass} ${className}`.trim()
39
33
  export const imageClasses = `w-full h-full transition-opacity duration-300 ${objectFitClasses[objectFit]} ${zoomClasses}`.trim()
40
- export const placeholderClasses = `absolute inset-0 bg-gray-200 dark:bg-gray-700 ${roundedClass}`.trim()
41
34
  export const blurPlaceholderClasses = `absolute inset-0 ${roundedClass} filter blur-lg scale-110`.trim()
35
+ export const containerStyle = aspectRatio ? `padding-bottom: ${(1 / aspectRatio) * 100}%` : ''
36
+ </script>
37
+
38
+ <script client>
39
+ const emit = defineEmits()
40
+ const lazy = {{ lazy }}
41
+ const realSrc = {{ src }}
42
+ const realSrcSet = {{ srcSet }}
43
+ const errorPlaceholder = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300"%3E%3Crect fill="%23e5e7eb" width="400" height="300"/%3E%3Ctext x="50%25" y="50%25" fill="%239ca3af" font-size="16" text-anchor="middle" dominant-baseline="middle"%3EImage not found%3C/text%3E%3C/svg%3E'
44
+
45
+ function onImageLoad(event) {
46
+ const img = event.target
47
+ img.classList.remove('opacity-0')
48
+ img.classList.add('opacity-100')
49
+ emit('load', event)
50
+ }
42
51
 
43
- // Generate aspect ratio padding if provided
44
- export const paddingBottom = aspectRatio ? `${(1 / aspectRatio) * 100}%` : undefined
52
+ function onImageError(event) {
53
+ const img = event.target
54
+ img.src = errorPlaceholder
55
+ emit('error', event)
56
+ }
57
+
58
+ onMount(() => {
59
+ if (!lazy) return
60
+ if (typeof IntersectionObserver === 'undefined') return
61
+ const lazyImages = document.querySelectorAll('.lazy-image:not([data-stx-img-loaded])')
62
+ const observer = new IntersectionObserver((entries, obs) => {
63
+ for (const entry of entries) {
64
+ if (!entry.isIntersecting) continue
65
+ const img = entry.target
66
+ img.setAttribute('data-stx-img-loaded', '1')
67
+ const dataSrc = img.getAttribute('data-src')
68
+ const dataSrcSet = img.getAttribute('data-srcset')
69
+ if (!dataSrc) continue
70
+ const probe = new Image()
71
+ probe.onload = () => {
72
+ img.src = dataSrc
73
+ if (dataSrcSet) img.srcset = dataSrcSet
74
+ img.classList.remove('opacity-0')
75
+ img.classList.add('opacity-100')
76
+ obs.unobserve(img)
77
+ }
78
+ probe.onerror = () => {
79
+ onImageError({ target: img })
80
+ obs.unobserve(img)
81
+ }
82
+ probe.src = dataSrc
83
+ if (dataSrcSet) probe.srcset = dataSrcSet
84
+ }
85
+ }, { rootMargin: '50px' })
86
+ for (const img of lazyImages) observer.observe(img)
87
+ })
45
88
  </script>
46
89
 
47
- <div class="{{ containerClasses }}" style="{{ paddingBottom ? `padding-bottom: ${paddingBottom}` : '' }}">
90
+ <div class="{{ containerClasses }}" style="{{ containerStyle }}">
48
91
  @if(blurDataURL)
49
- <!-- Blur placeholder -->
50
92
  <img
51
93
  src="{{ blurDataURL }}"
52
94
  alt=""
@@ -56,17 +98,13 @@ export const paddingBottom = aspectRatio ? `${(1 / aspectRatio) * 100}%` : undef
56
98
  @endif
57
99
 
58
100
  @if(hasWebP)
59
- <!-- Picture element with WebP support -->
60
101
  <picture>
61
- @if(webpSrcSet || webpSrc)
62
- <source
63
- type="image/webp"
64
- @if(webpSrcSet)srcset="{{ webpSrcSet }}"@endif
65
- @if(webpSrc && !webpSrcSet)srcset="{{ webpSrc }}"@endif
66
- @if(sizes)sizes="{{ sizes }}"@endif
67
- />
68
- @endif
69
-
102
+ <source
103
+ type="image/webp"
104
+ @if(webpSrcSet)srcset="{{ webpSrcSet }}"@endif
105
+ @if(webpSrc && !webpSrcSet)srcset="{{ webpSrc }}"@endif
106
+ @if(sizes)sizes="{{ sizes }}"@endif
107
+ />
70
108
  @if(lazy)
71
109
  <img
72
110
  src="{{ placeholder }}"
@@ -78,8 +116,8 @@ export const paddingBottom = aspectRatio ? `${(1 / aspectRatio) * 100}%` : undef
78
116
  width="{{ width }}"
79
117
  height="{{ height }}"
80
118
  loading="lazy"
81
- onload="handleImageLoad(event)"
82
- onerror="handleImageError(event)"
119
+ @load="onImageLoad($event)"
120
+ @error="onImageError($event)"
83
121
  />
84
122
  @else
85
123
  <img
@@ -90,13 +128,12 @@ export const paddingBottom = aspectRatio ? `${(1 / aspectRatio) * 100}%` : undef
90
128
  class="{{ imageClasses }}"
91
129
  width="{{ width }}"
92
130
  height="{{ height }}"
93
- onload="handleImageLoad(event)"
94
- onerror="handleImageError(event)"
131
+ @load="onImageLoad($event)"
132
+ @error="onImageError($event)"
95
133
  />
96
134
  @endif
97
135
  </picture>
98
136
  @else
99
- <!-- Regular img element -->
100
137
  @if(lazy)
101
138
  <img
102
139
  src="{{ placeholder }}"
@@ -108,8 +145,8 @@ export const paddingBottom = aspectRatio ? `${(1 / aspectRatio) * 100}%` : undef
108
145
  width="{{ width }}"
109
146
  height="{{ height }}"
110
147
  loading="lazy"
111
- onload="handleImageLoad(event)"
112
- onerror="handleImageError(event)"
148
+ @load="onImageLoad($event)"
149
+ @error="onImageError($event)"
113
150
  />
114
151
  @else
115
152
  <img
@@ -120,78 +157,9 @@ export const paddingBottom = aspectRatio ? `${(1 / aspectRatio) * 100}%` : undef
120
157
  class="{{ imageClasses }}"
121
158
  width="{{ width }}"
122
159
  height="{{ height }}"
123
- onload="handleImageLoad(event)"
124
- onerror="handleImageError(event)"
160
+ @load="onImageLoad($event)"
161
+ @error="onImageError($event)"
125
162
  />
126
163
  @endif
127
164
  @endif
128
-
129
- <!-- Loading skeleton -->
130
- <div class="{{ placeholderClasses }} skeleton" style="display: none;">
131
- <div class="animate-pulse w-full h-full bg-gray-300 dark:bg-gray-600"></div>
132
- </div>
133
165
  </div>
134
-
135
- <script>
136
- // Intersection Observer for lazy loading
137
- if (lazy && typeof window !== 'undefined' && 'IntersectionObserver' in window) {
138
- const lazyImages = document.querySelectorAll('.lazy-image')
139
-
140
- const imageObserver = new IntersectionObserver((entries, observer) => {
141
- entries.forEach(entry => {
142
- if (entry.isIntersecting) {
143
- const img = entry.target
144
- const realSrc = img.getAttribute('data-src')
145
- const realSrcSet = img.getAttribute('data-srcset')
146
-
147
- if (realSrc) {
148
- // Load the real image
149
- const tempImg = new Image()
150
- tempImg.onload = () => {
151
- img.src = realSrc
152
- if (realSrcSet) {
153
- img.srcset = realSrcSet
154
- }
155
- img.classList.remove('opacity-0')
156
- img.classList.add('opacity-100')
157
- observer.unobserve(img)
158
- }
159
- tempImg.onerror = () => {
160
- handleImageError({ target: img })
161
- observer.unobserve(img)
162
- }
163
- tempImg.src = realSrc
164
- if (realSrcSet) {
165
- tempImg.srcset = realSrcSet
166
- }
167
- }
168
- }
169
- })
170
- }, {
171
- rootMargin: '50px', // Start loading 50px before entering viewport
172
- })
173
-
174
- lazyImages.forEach(img => imageObserver.observe(img))
175
- }
176
-
177
- function handleImageLoad(event) {
178
- const img = event.target
179
- img.classList.remove('opacity-0')
180
- img.classList.add('opacity-100')
181
-
182
- if (onLoad) {
183
- onLoad(event)
184
- }
185
- }
186
-
187
- function handleImageError(event) {
188
- const img = event.target
189
-
190
- // Show a broken image placeholder
191
- img.src = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300"%3E%3Crect fill="%23e5e7eb" width="400" height="300"/%3E%3Ctext x="50%25" y="50%25" fill="%239ca3af" font-size="16" text-anchor="middle" dominant-baseline="middle"%3EImage not found%3C/text%3E%3C/svg%3E'
192
-
193
- if (onError) {
194
- onError(event)
195
- }
196
- }
197
- </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 || 'Enter your email'
5
4
  export const disabled = $props.disabled || false
6
5
  export const readonly = $props.readonly || false
@@ -11,31 +10,21 @@ export const helperText = $props.helperText || ''
11
10
  export const required = $props.required || false
12
11
  export const className = $props.className || ''
13
12
 
14
- // Email icon SVG
15
- const emailIcon = '<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" /></svg>'
13
+ export const emailIcon = '<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" /></svg>'
16
14
  </script>
17
15
 
18
- @component('TextInput', {
19
- value,
20
- onChange,
21
- placeholder,
22
- disabled,
23
- readonly,
24
- size,
25
- error,
26
- label,
27
- helperText,
28
- required,
29
- leftIcon: emailIcon,
30
- clearable: true,
31
- className,
32
- inputClassName: 'font-mono'
33
- })
34
- @endcomponent
35
-
36
- <script>
37
- // Add additional email validation logic if needed
38
- function validateEmail(email) {
39
- return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
40
- }
41
- </script>
16
+ <TextInput
17
+ :value="value"
18
+ :placeholder="placeholder"
19
+ :disabled="disabled"
20
+ :readonly="readonly"
21
+ :size="size"
22
+ :error="error"
23
+ :label="label"
24
+ :helperText="helperText"
25
+ :required="required"
26
+ :leftIcon="emailIcon"
27
+ :clearable="true"
28
+ :className="className"
29
+ inputClassName="font-mono"
30
+ />
@@ -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 || '0'
5
4
  export const disabled = $props.disabled || false
6
5
  export const readonly = $props.readonly || false
@@ -16,26 +15,16 @@ export const showControls = $props.showControls ?? true
16
15
  export const className = $props.className || ''
17
16
  export const inputClassName = $props.inputClassName || ''
18
17
 
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
- // Base and state classes
18
+ 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' }
27
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 dark:bg-blue-gray-700 dark:text-gray-100'
28
-
29
20
  const stateClasses = error
30
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'
31
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'
32
-
33
23
  const disabledClasses = disabled
34
24
  ? 'opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-800'
35
25
  : readonly
36
26
  ? 'bg-gray-50 dark:bg-gray-800 cursor-default'
37
27
  : 'bg-white dark:bg-blue-gray-700'
38
-
39
28
  const paddingClasses = showControls ? 'pr-10' : ''
40
29
 
41
30
  export const inputClasses = `${baseClasses} ${sizeClasses[size]} ${stateClasses} ${disabledClasses} ${paddingClasses} ${inputClassName}`.trim()
@@ -43,6 +32,37 @@ export const labelClasses = `block text-sm font-medium leading-6 mb-2 ${error ?
43
32
  export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
44
33
  </script>
45
34
 
35
+ <script client>
36
+ const emit = defineEmits()
37
+ const stepSize = {{ step }}
38
+ const minVal = {{ min === undefined ? 'undefined' : min }}
39
+ const maxVal = {{ max === undefined ? 'undefined' : max }}
40
+ const inputValue = state({{ value }})
41
+
42
+ function onInput(event) {
43
+ inputValue.set(event.target.value)
44
+ emit('input', inputValue())
45
+ }
46
+
47
+ function increment() {
48
+ const current = Number.parseFloat(inputValue()) || 0
49
+ const next = current + stepSize
50
+ if (maxVal !== undefined && next > maxVal) return
51
+ inputValue.set(String(next))
52
+ emit('input', String(next))
53
+ }
54
+
55
+ function decrement() {
56
+ const current = Number.parseFloat(inputValue()) || 0
57
+ const next = current - stepSize
58
+ if (minVal !== undefined && next < minVal) return
59
+ inputValue.set(String(next))
60
+ emit('input', String(next))
61
+ }
62
+
63
+ defineExpose({ value: inputValue, increment, decrement })
64
+ </script>
65
+
46
66
  <div class="w-full {{ className }}">
47
67
  @if(label)
48
68
  <label for="number-input" class="{{ labelClasses }}">
@@ -58,25 +78,24 @@ export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red
58
78
  type="number"
59
79
  id="number-input"
60
80
  class="{{ inputClasses }}"
61
- value="{{ value }}"
81
+ :value="inputValue()"
62
82
  placeholder="{{ placeholder }}"
63
- disabled="{{ disabled }}"
64
- readonly="{{ readonly }}"
65
- required="{{ required }}"
83
+ @if(disabled)disabled@endif
84
+ @if(readonly)readonly@endif
85
+ @if(required)required@endif
66
86
  @if(min !== undefined)min="{{ min }}"@endif
67
87
  @if(max !== undefined)max="{{ max }}"@endif
68
88
  step="{{ step }}"
69
- oninput="handleInput(event)"
70
- aria-invalid="{{ error ? 'true' : 'false' }}"
89
+ @input="onInput($event)"
90
+ :aria-invalid="{{ error ? 'true' : 'false' }}"
71
91
  @if(helperText)aria-describedby="helper-text"@endif
72
92
  />
73
93
 
74
94
  @if(showControls && !disabled && !readonly)
75
- <!-- Increment/Decrement controls -->
76
95
  <div class="absolute inset-y-0 right-0 flex flex-col">
77
96
  <button
78
97
  type="button"
79
- @click="handleIncrement()"
98
+ @click="increment()"
80
99
  class="flex items-center justify-center w-8 h-1/2 text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 focus:outline-none border-b border-gray-300 dark:border-gray-600"
81
100
  aria-label="Increment"
82
101
  >
@@ -86,7 +105,7 @@ export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red
86
105
  </button>
87
106
  <button
88
107
  type="button"
89
- @click="handleDecrement()"
108
+ @click="decrement()"
90
109
  class="flex items-center justify-center w-8 h-1/2 text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 focus:outline-none"
91
110
  aria-label="Decrement"
92
111
  >
@@ -104,35 +123,3 @@ export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red
104
123
  </p>
105
124
  @endif
106
125
  </div>
107
-
108
- <script>
109
- function handleInput(event) {
110
- const newValue = event.target.value
111
-
112
- if (onChange) {
113
- onChange(newValue)
114
- }
115
- }
116
-
117
- function handleIncrement() {
118
- const currentValue = parseFloat(value) || 0
119
- const newValue = currentValue + step
120
-
121
- if (max !== undefined && newValue > max) return
122
-
123
- if (onChange) {
124
- onChange(String(newValue))
125
- }
126
- }
127
-
128
- function handleDecrement() {
129
- const currentValue = parseFloat(value) || 0
130
- const newValue = currentValue - step
131
-
132
- if (min !== undefined && newValue < min) return
133
-
134
- if (onChange) {
135
- onChange(String(newValue))
136
- }
137
- }
138
- </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 || 'Enter your password'
5
4
  export const disabled = $props.disabled || false
6
5
  export const readonly = $props.readonly || false
@@ -13,30 +12,13 @@ export const showStrength = $props.showStrength || false
13
12
  export const className = $props.className || ''
14
13
  export const inputClassName = $props.inputClassName || ''
15
14
 
16
- // State
17
- let showPassword = false
15
+ 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' }
16
+ const iconSizeClasses = { sm: 'h-4 w-4', md: 'h-5 w-5', lg: 'h-6 w-6' }
18
17
 
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
18
  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
19
  const stateClasses = error
37
20
  ? '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
21
  : '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
22
  const disabledClasses = disabled
41
23
  ? 'opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-800'
42
24
  : readonly
@@ -47,22 +29,50 @@ export const inputClasses = `${baseClasses} ${sizeClasses[size]} ${stateClasses}
47
29
  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
30
  export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
49
31
  export const iconClasses = iconSizeClasses[size]
32
+ </script>
33
+
34
+ <script client>
35
+ const emit = defineEmits()
36
+ const showPassword = state(false)
37
+ const inputValue = state({{ value }})
38
+
39
+ function onInput(event) {
40
+ inputValue.set(event.target.value)
41
+ emit('input', inputValue())
42
+ }
50
43
 
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)
44
+ function toggleVisibility() {
45
+ showPassword.set(!showPassword())
46
+ }
47
+
48
+ function calcStrength(pw) {
49
+ if (!pw) return 0
50
+ let s = 0
51
+ if (pw.length >= 8) s += 25
52
+ if (pw.length >= 12) s += 25
53
+ if (/[a-z]/.test(pw) && /[A-Z]/.test(pw)) s += 25
54
+ if (/\d/.test(pw)) s += 15
55
+ if (/[^a-zA-Z\d]/.test(pw)) s += 10
56
+ return Math.min(s, 100)
61
57
  }
62
58
 
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'
59
+ const strength = derived(() => calcStrength(inputValue()))
60
+ const strengthText = derived(() => {
61
+ const s = strength()
62
+ return s < 40 ? 'Weak' : s < 70 ? 'Medium' : 'Strong'
63
+ })
64
+ const strengthColor = derived(() => {
65
+ const s = strength()
66
+ return s < 40 ? 'bg-red-500' : s < 70 ? 'bg-yellow-500' : 'bg-green-500'
67
+ })
68
+ const strengthLabelColor = derived(() => {
69
+ const s = strength()
70
+ return s < 40 ? 'text-red-600' : s < 70 ? 'text-yellow-600' : 'text-green-600'
71
+ })
72
+ const inputType = derived(() => showPassword() ? 'text' : 'password')
73
+ const toggleAriaLabel = derived(() => showPassword() ? 'Hide password' : 'Show password')
74
+
75
+ defineExpose({ value: inputValue })
66
76
  </script>
67
77
 
68
78
  <div class="w-full {{ className }}">
@@ -77,56 +87,48 @@ export const strengthText = strength < 40 ? 'Weak' : strength < 70 ? 'Medium' :
77
87
 
78
88
  <div class="relative">
79
89
  <input
80
- type="{{ showPassword ? 'text' : 'password' }}"
90
+ :type="inputType()"
81
91
  id="password-input"
82
92
  class="{{ inputClasses }}"
83
- value="{{ value }}"
93
+ :value="inputValue()"
84
94
  placeholder="{{ placeholder }}"
85
- disabled="{{ disabled }}"
86
- readonly="{{ readonly }}"
87
- required="{{ required }}"
88
- oninput="handleInput(event)"
89
- aria-invalid="{{ error ? 'true' : 'false' }}"
95
+ @if(disabled)disabled@endif
96
+ @if(readonly)readonly@endif
97
+ @if(required)required@endif
98
+ @input="onInput($event)"
99
+ :aria-invalid="{{ error ? 'true' : 'false' }}"
90
100
  @if(helperText)aria-describedby="helper-text"@endif
91
101
  />
92
102
 
93
- <!-- Toggle visibility button -->
94
103
  <div class="absolute inset-y-0 right-0 flex items-center pr-3">
95
104
  <button
96
105
  type="button"
97
106
  @click="toggleVisibility()"
98
107
  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' }}"
108
+ :aria-label="toggleAriaLabel()"
100
109
  >
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
110
+ <svg :show="showPassword()" class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
111
+ <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" />
112
+ </svg>
113
+ <svg :show="!showPassword()" class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
114
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
115
+ <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" />
116
+ </svg>
113
117
  </button>
114
118
  </div>
115
119
  </div>
116
120
 
117
- @if(showStrength && value.length > 0)
118
- <!-- Password strength indicator -->
119
- <div class="mt-2">
121
+ @if(showStrength)
122
+ <div :show="inputValue().length > 0" class="mt-2">
120
123
  <div class="flex items-center justify-between mb-1">
121
124
  <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
+ <span class="text-xs font-medium" :class="strengthLabelColor()" x-text="strengthText()"></span>
125
126
  </div>
126
127
  <div class="w-full h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
127
128
  <div
128
- class="{{ strengthColor }} h-full transition-all duration-300 rounded-full"
129
- style="width: {{ strength }}%"
129
+ class="h-full transition-all duration-300 rounded-full"
130
+ :class="strengthColor()"
131
+ :style="`width: ${strength()}%`"
130
132
  ></div>
131
133
  </div>
132
134
  </div>
@@ -138,18 +140,3 @@ export const strengthText = strength < 40 ? 'Weak' : strength < 70 ? 'Medium' :
138
140
  </p>
139
141
  @endif
140
142
  </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>