@stacksjs/components 0.2.3
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/README.md +477 -0
- package/dist/Accordion-x2gjedap.stx +108 -0
- package/dist/Audio-0fk6p9tn.stx +50 -0
- package/dist/Avatar-5m0v0s4x.stx +88 -0
- package/dist/Badge-ynes82vv.stx +70 -0
- package/dist/Breadcrumb-h9n427sk.stx +79 -0
- package/dist/Button-7xtrzn14.stx +89 -0
- package/dist/Calendar-egvx1pma.stx +232 -0
- package/dist/Card-r9w7vy1a.stx +74 -0
- package/dist/Checkbox-m8v46pmx.stx +92 -0
- package/dist/Checkout-vcnnr176.stx +39 -0
- package/dist/CodeBlock-mwex82cm.stx +57 -0
- package/dist/Combobox-npb08vkp.stx +13 -0
- package/dist/ComboboxButton-vcdyq4zw.stx +13 -0
- package/dist/ComboboxInput-c9d2p02m.stx +25 -0
- package/dist/ComboboxOption-7d0h9ash.stx +52 -0
- package/dist/ComboboxOptions-4dtqc0qa.stx +12 -0
- package/dist/CommandPalette-ah00bf8v.stx +39 -0
- package/dist/CommandPaletteItem-2yx0gvtj.stx +32 -0
- package/dist/DefaultPaymentMethod-emw5fg8s.stx +62 -0
- package/dist/Dialog-1w4rz7x0.stx +19 -0
- package/dist/DialogBackdrop-qbm3y5ab.stx +9 -0
- package/dist/DialogDescription-01w5j74b.stx +11 -0
- package/dist/DialogPanel-brsszrrs.stx +16 -0
- package/dist/DialogTitle-3rxhwg21.stx +11 -0
- package/dist/Drawer-yfaz8q7f.stx +137 -0
- package/dist/Dropdown-ng7nx556.stx +24 -0
- package/dist/DropdownButton-vc4zpyrb.stx +23 -0
- package/dist/DropdownItem-z491y23c.stx +43 -0
- package/dist/DropdownItems-7ykf29sj.stx +18 -0
- package/dist/EmailInput-bfshpj92.stx +41 -0
- package/dist/Footer-xdaf02nr.stx +66 -0
- package/dist/Form-z4f7w6r1.stx +209 -0
- package/dist/Hero-9vvp7pxf.stx +25 -0
- package/dist/Image-ktk0451c.stx +197 -0
- package/dist/Installation-33bj4rm7.stx +39 -0
- package/dist/Listbox-xcejcmyc.stx +14 -0
- package/dist/ListboxButton-nx5kmw19.stx +17 -0
- package/dist/ListboxLabel-aky8a73n.stx +11 -0
- package/dist/ListboxOption-6h4hsdz5.stx +57 -0
- package/dist/ListboxOptions-2sacdtm5.stx +16 -0
- package/dist/Login-s2jkvd9y.stx +163 -0
- package/dist/Navigator-tqqdgdkw.stx +138 -0
- package/dist/Notification-sry8egea.stx +71 -0
- package/dist/NumberInput-zm93ddfw.stx +138 -0
- package/dist/Pagination-yza9v4qw.stx +183 -0
- package/dist/PasswordInput-4xnndp5y.stx +155 -0
- package/dist/PaymentMethods-jxba6kek.stx +113 -0
- package/dist/Popover-scbqatjq.stx +24 -0
- package/dist/PopoverButton-rbxhzj4k.stx +23 -0
- package/dist/PopoverPanel-9ng1rm6e.stx +23 -0
- package/dist/Portal-j111yvqp.stx +74 -0
- package/dist/Progress-gbmw3akr.stx +142 -0
- package/dist/Radio-1n9qamv1.stx +81 -0
- package/dist/RadioGroup-12dw2vhk.stx +13 -0
- package/dist/RadioGroupDescription-bjm3mdht.stx +11 -0
- package/dist/RadioGroupLabel-aky8a73n.stx +11 -0
- package/dist/RadioGroupOption-9pcxgwmd.stx +51 -0
- package/dist/SearchInput-g240e2nq.stx +63 -0
- package/dist/Select-p9f94b20.stx +89 -0
- package/dist/Sidebar-gwxw8q38.stx +288 -0
- package/dist/SidebarFooter-887kxret.stx +95 -0
- package/dist/SidebarHeader-qjeyx0hv.stx +100 -0
- package/dist/SidebarItem-4dpwtmb4.stx +118 -0
- package/dist/SidebarSection-kh92fk4m.stx +108 -0
- package/dist/Signup-3nxq5zag.stx +161 -0
- package/dist/Skeleton-g0nx1njm.stx +48 -0
- package/dist/Spinner-w4zj58xp.stx +109 -0
- package/dist/Stepper-rwc5actp.stx +17 -0
- package/dist/StepperStep-h0k657nm.stx +53 -0
- package/dist/SubscriptionCheckout-4cbxdg7w.stx +353 -0
- package/dist/Switch-kjq8qd2p.stx +74 -0
- package/dist/Table-59j9qwp0.stx +14 -0
- package/dist/TableBody-reka2gwv.stx +10 -0
- package/dist/TableCell-j7nh4sgr.stx +10 -0
- package/dist/TableHead-ecbrwpqm.stx +10 -0
- package/dist/TableHeader-jn2shwsv.stx +13 -0
- package/dist/TableRow-xz8rrxhc.stx +11 -0
- package/dist/Tabs-kb6ex6m7.stx +145 -0
- package/dist/Teleport-819cg9zm.stx +101 -0
- package/dist/TextInput-zx9kgr79.stx +146 -0
- package/dist/Textarea-5xvmrb0z.stx +119 -0
- package/dist/Tooltip-5ehqsy49.stx +76 -0
- package/dist/Transition-2j39s044.stx +174 -0
- package/dist/TwoFactorChallenge-2q4gg89m.stx +125 -0
- package/dist/Video-6aq4shh4.stx +45 -0
- package/dist/VirtualList-weh5qtm1.stx +83 -0
- package/dist/VirtualTable-59a1eskc.stx +113 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/composables/index.d.ts +4 -0
- package/dist/composables/index.js +3 -0
- package/dist/composables/useCopyCode.d.ts +19 -0
- package/dist/composables/useDarkMode.d.ts +25 -0
- package/dist/composables/useSEO.d.ts +36 -0
- package/dist/composables/utilities/index.d.ts +5 -0
- package/dist/composables/utilities/useClickOutside.d.ts +28 -0
- package/dist/composables/utilities/useFocusTrap.d.ts +34 -0
- package/dist/composables/utilities/useKeyboard.d.ts +55 -0
- package/dist/composables/utilities/useLocalStorage.d.ts +33 -0
- package/dist/composables/utilities/useMediaQuery.d.ts +64 -0
- package/dist/index.d.ts +86 -0
- package/dist/index.js +19 -0
- package/dist/ui/accordion/index.d.ts +12 -0
- package/dist/ui/audio/index.d.ts +12 -0
- package/dist/ui/auth/index.d.ts +29 -0
- package/dist/ui/avatar/index.d.ts +11 -0
- package/dist/ui/badge/index.d.ts +9 -0
- package/dist/ui/breadcrumb/index.d.ts +13 -0
- package/dist/ui/button/index.d.ts +45 -0
- package/dist/ui/calendar/index.d.ts +13 -0
- package/dist/ui/card/index.d.ts +12 -0
- package/dist/ui/checkbox/index.d.ts +15 -0
- package/dist/ui/combobox/index.d.ts +35 -0
- package/dist/ui/command-palette/index.d.ts +13 -0
- package/dist/ui/dialog/index.d.ts +27 -0
- package/dist/ui/drawer/index.d.ts +8 -0
- package/dist/ui/dropdown/index.d.ts +25 -0
- package/dist/ui/form/index.d.ts +48 -0
- package/dist/ui/image/index.d.ts +21 -0
- package/dist/ui/input/index.d.ts +73 -0
- package/dist/ui/listbox/index.d.ts +34 -0
- package/dist/ui/navigator/index.d.ts +18 -0
- package/dist/ui/notification/index.d.ts +11 -0
- package/dist/ui/pagination/index.d.ts +10 -0
- package/dist/ui/payment/index.d.ts +53 -0
- package/dist/ui/popover/index.d.ts +19 -0
- package/dist/ui/portal/index.d.ts +5 -0
- package/dist/ui/progress/index.d.ts +11 -0
- package/dist/ui/radio/index.d.ts +14 -0
- package/dist/ui/radio-group/index.d.ts +26 -0
- package/dist/ui/select/index.d.ts +19 -0
- package/dist/ui/sidebar/index.d.ts +129 -0
- package/dist/ui/skeleton/index.d.ts +10 -0
- package/dist/ui/spinner/index.d.ts +8 -0
- package/dist/ui/stepper/index.d.ts +17 -0
- package/dist/ui/storage/index.d.ts +40 -0
- package/dist/ui/switch/index.d.ts +9 -0
- package/dist/ui/table/index.d.ts +29 -0
- package/dist/ui/tabs/index.d.ts +14 -0
- package/dist/ui/teleport/index.d.ts +6 -0
- package/dist/ui/textarea/index.d.ts +19 -0
- package/dist/ui/tooltip/index.d.ts +9 -0
- package/dist/ui/transition/index.d.ts +24 -0
- package/dist/ui/video/index.d.ts +15 -0
- package/dist/ui/virtual-list/index.d.ts +9 -0
- package/dist/ui/virtual-table/index.d.ts +19 -0
- package/dist/utils/accessibility.d.ts +285 -0
- package/dist/utils/animation/easing.d.ts +112 -0
- package/dist/utils/animation/helpers.d.ts +119 -0
- package/dist/utils/animation/index.d.ts +3 -0
- package/dist/utils/animation/keyframes.d.ts +334 -0
- package/dist/utils/error-handling.d.ts +182 -0
- package/dist/utils/highlighter.d.ts +27 -0
- package/dist/utils/highlighter.js +2 -0
- package/dist/utils/i18n.d.ts +245 -0
- package/dist/utils/keep-alive.d.ts +171 -0
- package/dist/utils/lazy-loading.d.ts +174 -0
- package/dist/utils/prop-validation.d.ts +106 -0
- package/dist/utils/theme.d.ts +234 -0
- package/package.json +69 -0
- package/src/components/CodeBlock.stx +57 -0
- package/src/components/Footer.stx +66 -0
- package/src/components/Hero.stx +25 -0
- package/src/components/Installation.stx +39 -0
- package/src/components/index.ts +4 -0
- package/src/composables/index.ts +4 -0
- package/src/composables/useCopyCode.ts +73 -0
- package/src/composables/useDarkMode.ts +100 -0
- package/src/composables/useSEO.ts +229 -0
- package/src/composables/utilities/index.ts +7 -0
- package/src/composables/utilities/useClickOutside.ts +72 -0
- package/src/composables/utilities/useFocusTrap.ts +159 -0
- package/src/composables/utilities/useKeyboard.ts +124 -0
- package/src/composables/utilities/useLocalStorage.ts +132 -0
- package/src/composables/utilities/useMediaQuery.ts +118 -0
- package/src/index.ts +99 -0
- package/src/stx.d.ts +4 -0
- package/src/ui/accordion/Accordion.stx +108 -0
- package/src/ui/accordion/index.ts +14 -0
- package/src/ui/audio/Audio.stx +50 -0
- package/src/ui/audio/README.md +42 -0
- package/src/ui/audio/index.ts +13 -0
- package/src/ui/auth/Login.stx +163 -0
- package/src/ui/auth/README.md +145 -0
- package/src/ui/auth/Signup.stx +161 -0
- package/src/ui/auth/TwoFactorChallenge.stx +125 -0
- package/src/ui/auth/index.ts +32 -0
- package/src/ui/avatar/Avatar.stx +88 -0
- package/src/ui/avatar/index.ts +12 -0
- package/src/ui/badge/Badge.stx +70 -0
- package/src/ui/badge/index.ts +10 -0
- package/src/ui/breadcrumb/Breadcrumb.stx +79 -0
- package/src/ui/breadcrumb/index.ts +15 -0
- package/src/ui/button/Button.stx +89 -0
- package/src/ui/button/README.md +100 -0
- package/src/ui/button/index.ts +85 -0
- package/src/ui/calendar/Calendar.stx +232 -0
- package/src/ui/calendar/README.md +254 -0
- package/src/ui/calendar/index.ts +14 -0
- package/src/ui/card/Card.stx +74 -0
- package/src/ui/card/index.ts +13 -0
- package/src/ui/checkbox/Checkbox.stx +92 -0
- package/src/ui/checkbox/index.ts +16 -0
- package/src/ui/combobox/Combobox.stx +13 -0
- package/src/ui/combobox/ComboboxButton.stx +13 -0
- package/src/ui/combobox/ComboboxInput.stx +25 -0
- package/src/ui/combobox/ComboboxOption.stx +52 -0
- package/src/ui/combobox/ComboboxOptions.stx +12 -0
- package/src/ui/combobox/README.md +154 -0
- package/src/ui/combobox/index.ts +40 -0
- package/src/ui/command-palette/CommandPalette.stx +39 -0
- package/src/ui/command-palette/CommandPaletteItem.stx +32 -0
- package/src/ui/command-palette/README.md +42 -0
- package/src/ui/command-palette/index.ts +15 -0
- package/src/ui/dialog/Dialog.stx +19 -0
- package/src/ui/dialog/DialogBackdrop.stx +9 -0
- package/src/ui/dialog/DialogDescription.stx +11 -0
- package/src/ui/dialog/DialogPanel.stx +16 -0
- package/src/ui/dialog/DialogTitle.stx +11 -0
- package/src/ui/dialog/README.md +133 -0
- package/src/ui/dialog/index.ts +32 -0
- package/src/ui/drawer/Drawer.stx +137 -0
- package/src/ui/drawer/README.md +110 -0
- package/src/ui/drawer/index.ts +9 -0
- package/src/ui/dropdown/Dropdown.stx +24 -0
- package/src/ui/dropdown/DropdownButton.stx +23 -0
- package/src/ui/dropdown/DropdownItem.stx +43 -0
- package/src/ui/dropdown/DropdownItems.stx +18 -0
- package/src/ui/dropdown/README.md +142 -0
- package/src/ui/dropdown/index.ts +29 -0
- package/src/ui/form/Form.stx +209 -0
- package/src/ui/form/index.ts +67 -0
- package/src/ui/heatmap/Heatmap.stx +315 -0
- package/src/ui/image/Image.stx +197 -0
- package/src/ui/image/README.md +171 -0
- package/src/ui/image/index.ts +22 -0
- package/src/ui/input/EmailInput.stx +41 -0
- package/src/ui/input/NumberInput.stx +138 -0
- package/src/ui/input/PasswordInput.stx +155 -0
- package/src/ui/input/SearchInput.stx +63 -0
- package/src/ui/input/TextInput.stx +146 -0
- package/src/ui/input/index.ts +180 -0
- package/src/ui/listbox/Listbox.stx +14 -0
- package/src/ui/listbox/ListboxButton.stx +17 -0
- package/src/ui/listbox/ListboxLabel.stx +11 -0
- package/src/ui/listbox/ListboxOption.stx +57 -0
- package/src/ui/listbox/ListboxOptions.stx +16 -0
- package/src/ui/listbox/README.md +143 -0
- package/src/ui/listbox/index.ts +39 -0
- package/src/ui/navigator/Navigator.stx +138 -0
- package/src/ui/navigator/README.md +352 -0
- package/src/ui/navigator/index.ts +20 -0
- package/src/ui/notification/Notification.stx +71 -0
- package/src/ui/notification/README.md +118 -0
- package/src/ui/notification/index.ts +12 -0
- package/src/ui/pagination/Pagination.stx +183 -0
- package/src/ui/pagination/index.ts +11 -0
- package/src/ui/payment/Checkout.stx +39 -0
- package/src/ui/payment/DefaultPaymentMethod.stx +62 -0
- package/src/ui/payment/PaymentMethods.stx +113 -0
- package/src/ui/payment/README.md +427 -0
- package/src/ui/payment/SubscriptionCheckout.stx +353 -0
- package/src/ui/payment/index.ts +59 -0
- package/src/ui/popover/Popover.stx +24 -0
- package/src/ui/popover/PopoverButton.stx +23 -0
- package/src/ui/popover/PopoverPanel.stx +23 -0
- package/src/ui/popover/README.md +95 -0
- package/src/ui/popover/index.ts +22 -0
- package/src/ui/portal/Portal.stx +74 -0
- package/src/ui/portal/index.ts +6 -0
- package/src/ui/progress/Progress.stx +142 -0
- package/src/ui/progress/index.ts +12 -0
- package/src/ui/radio/Radio.stx +81 -0
- package/src/ui/radio/index.ts +15 -0
- package/src/ui/radio-group/README.md +145 -0
- package/src/ui/radio-group/RadioGroup.stx +13 -0
- package/src/ui/radio-group/RadioGroupDescription.stx +11 -0
- package/src/ui/radio-group/RadioGroupLabel.stx +11 -0
- package/src/ui/radio-group/RadioGroupOption.stx +51 -0
- package/src/ui/radio-group/index.ts +30 -0
- package/src/ui/select/README.md +204 -0
- package/src/ui/select/Select.stx +89 -0
- package/src/ui/select/index.ts +21 -0
- package/src/ui/sidebar/Sidebar.stx +288 -0
- package/src/ui/sidebar/SidebarFooter.stx +95 -0
- package/src/ui/sidebar/SidebarHeader.stx +100 -0
- package/src/ui/sidebar/SidebarItem.stx +118 -0
- package/src/ui/sidebar/SidebarSection.stx +108 -0
- package/src/ui/sidebar/index.ts +175 -0
- package/src/ui/skeleton/Skeleton.stx +48 -0
- package/src/ui/skeleton/index.ts +11 -0
- package/src/ui/spinner/Spinner.stx +109 -0
- package/src/ui/spinner/index.ts +9 -0
- package/src/ui/stepper/README.md +36 -0
- package/src/ui/stepper/Stepper.stx +17 -0
- package/src/ui/stepper/StepperStep.stx +53 -0
- package/src/ui/stepper/index.ts +19 -0
- package/src/ui/storage/README.md +193 -0
- package/src/ui/storage/index.ts +347 -0
- package/src/ui/switch/README.md +133 -0
- package/src/ui/switch/Switch.stx +74 -0
- package/src/ui/switch/index.ts +10 -0
- package/src/ui/table/README.md +39 -0
- package/src/ui/table/Table.stx +14 -0
- package/src/ui/table/TableBody.stx +10 -0
- package/src/ui/table/TableCell.stx +10 -0
- package/src/ui/table/TableHead.stx +10 -0
- package/src/ui/table/TableHeader.stx +13 -0
- package/src/ui/table/TableRow.stx +11 -0
- package/src/ui/table/index.ts +35 -0
- package/src/ui/tabs/Tabs.stx +145 -0
- package/src/ui/tabs/index.ts +16 -0
- package/src/ui/teleport/Teleport.stx +101 -0
- package/src/ui/teleport/index.ts +7 -0
- package/src/ui/textarea/Textarea.stx +119 -0
- package/src/ui/textarea/index.ts +20 -0
- package/src/ui/tooltip/Tooltip.stx +76 -0
- package/src/ui/tooltip/index.ts +10 -0
- package/src/ui/transition/README.md +30 -0
- package/src/ui/transition/Transition.stx +174 -0
- package/src/ui/transition/index.ts +25 -0
- package/src/ui/video/README.md +48 -0
- package/src/ui/video/Video.stx +45 -0
- package/src/ui/video/index.ts +16 -0
- package/src/ui/virtual-list/VirtualList.stx +83 -0
- package/src/ui/virtual-list/index.ts +10 -0
- package/src/ui/virtual-table/VirtualTable.stx +113 -0
- package/src/ui/virtual-table/index.ts +21 -0
- package/src/utils/PROP_VALIDATION.md +458 -0
- package/src/utils/THEME_SYSTEM.md +702 -0
- package/src/utils/accessibility.ts +841 -0
- package/src/utils/animation/easing.ts +368 -0
- package/src/utils/animation/helpers.ts +223 -0
- package/src/utils/animation/index.ts +5 -0
- package/src/utils/animation/keyframes.ts +230 -0
- package/src/utils/error-handling.ts +473 -0
- package/src/utils/highlighter.ts +93 -0
- package/src/utils/i18n.ts +634 -0
- package/src/utils/keep-alive.ts +818 -0
- package/src/utils/lazy-loading.ts +530 -0
- package/src/utils/prop-validation.ts +478 -0
- package/src/utils/theme.ts +626 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
<script>
|
|
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
|
+
onclick="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>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
export const value = $props.value || ''
|
|
3
|
+
export const onChange = $props.onChange || (() => {})
|
|
4
|
+
export const onSearch = $props.onSearch || (() => {})
|
|
5
|
+
export const placeholder = $props.placeholder || 'Search...'
|
|
6
|
+
export const disabled = $props.disabled || 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 loading = $props.loading || false
|
|
12
|
+
export const className = $props.className || ''
|
|
13
|
+
|
|
14
|
+
// Search icon SVG
|
|
15
|
+
const searchIcon = '<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" /></svg>'
|
|
16
|
+
|
|
17
|
+
// Loading spinner SVG
|
|
18
|
+
const spinnerIcon = '<svg class="animate-spin" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>'
|
|
19
|
+
|
|
20
|
+
export const rightIcon = loading ? spinnerIcon : undefined
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
@component('TextInput', {
|
|
24
|
+
value,
|
|
25
|
+
onChange,
|
|
26
|
+
placeholder,
|
|
27
|
+
disabled,
|
|
28
|
+
size,
|
|
29
|
+
error,
|
|
30
|
+
label,
|
|
31
|
+
helperText,
|
|
32
|
+
leftIcon: searchIcon,
|
|
33
|
+
rightIcon,
|
|
34
|
+
clearable: !loading,
|
|
35
|
+
className,
|
|
36
|
+
inputClassName: 'pr-20'
|
|
37
|
+
})
|
|
38
|
+
@endcomponent
|
|
39
|
+
|
|
40
|
+
<script>
|
|
41
|
+
// Debounce search to avoid excessive calls
|
|
42
|
+
let searchTimeout = null
|
|
43
|
+
|
|
44
|
+
function handleSearchInput(newValue) {
|
|
45
|
+
if (onChange) {
|
|
46
|
+
onChange(newValue)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Debounce the onSearch callback
|
|
50
|
+
if (searchTimeout) {
|
|
51
|
+
clearTimeout(searchTimeout)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
searchTimeout = setTimeout(() => {
|
|
55
|
+
if (onSearch) {
|
|
56
|
+
onSearch(newValue)
|
|
57
|
+
}
|
|
58
|
+
}, 300) // 300ms debounce
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Expose enhanced onChange handler
|
|
62
|
+
export const enhancedOnChange = handleSearchInput
|
|
63
|
+
</script>
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
export const value = $props.value || ''
|
|
3
|
+
export const onChange = $props.onChange || (() => {})
|
|
4
|
+
export const placeholder = $props.placeholder || ''
|
|
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 leftIcon = $props.leftIcon || ''
|
|
13
|
+
export const rightIcon = $props.rightIcon || ''
|
|
14
|
+
export const clearable = $props.clearable || false
|
|
15
|
+
export const maxLength = $props.maxLength
|
|
16
|
+
export const showCount = $props.showCount || false
|
|
17
|
+
export const className = $props.className || ''
|
|
18
|
+
export const inputClassName = $props.inputClassName || ''
|
|
19
|
+
|
|
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
|
+
}
|
|
33
|
+
|
|
34
|
+
// Base and state classes
|
|
35
|
+
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
|
+
const stateClasses = error
|
|
38
|
+
? '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
|
+
: '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
|
+
const disabledClasses = disabled
|
|
42
|
+
? 'opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-800'
|
|
43
|
+
: readonly
|
|
44
|
+
? 'bg-gray-50 dark:bg-gray-800 cursor-default'
|
|
45
|
+
: 'bg-white dark:bg-blue-gray-700'
|
|
46
|
+
|
|
47
|
+
const paddingClasses = leftIcon ? 'pl-10' : rightIcon || clearable ? 'pr-10' : ''
|
|
48
|
+
|
|
49
|
+
export const inputClasses = `${baseClasses} ${sizeClasses[size]} ${stateClasses} ${disabledClasses} ${paddingClasses} ${inputClassName}`.trim()
|
|
50
|
+
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
|
+
export const helperClasses = `mt-2 text-sm ${error ? 'text-red-600 dark:text-red-400' : 'text-gray-500 dark:text-gray-400'}`.trim()
|
|
52
|
+
export const iconClasses = iconSizeClasses[size]
|
|
53
|
+
export const hasValue = value && value.length > 0
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<div class="w-full {{ className }}">
|
|
57
|
+
@if(label)
|
|
58
|
+
<label for="input-{{ label }}" class="{{ labelClasses }}">
|
|
59
|
+
{{ label }}
|
|
60
|
+
@if(required)
|
|
61
|
+
<span class="text-red-500 ml-1">*</span>
|
|
62
|
+
@endif
|
|
63
|
+
</label>
|
|
64
|
+
@endif
|
|
65
|
+
|
|
66
|
+
<div class="relative">
|
|
67
|
+
@if(leftIcon)
|
|
68
|
+
<!-- Left icon -->
|
|
69
|
+
<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>
|
|
71
|
+
</div>
|
|
72
|
+
@endif
|
|
73
|
+
|
|
74
|
+
<input
|
|
75
|
+
type="text"
|
|
76
|
+
id="input-{{ label }}"
|
|
77
|
+
class="{{ inputClasses }}"
|
|
78
|
+
value="{{ value }}"
|
|
79
|
+
placeholder="{{ placeholder }}"
|
|
80
|
+
disabled="{{ disabled }}"
|
|
81
|
+
readonly="{{ readonly }}"
|
|
82
|
+
required="{{ required }}"
|
|
83
|
+
@if(maxLength)maxlength="{{ maxLength }}"@endif
|
|
84
|
+
oninput="handleInput(event)"
|
|
85
|
+
aria-invalid="{{ error ? 'true' : 'false' }}"
|
|
86
|
+
@if(helperText)aria-describedby="helper-text"@endif
|
|
87
|
+
/>
|
|
88
|
+
|
|
89
|
+
@if(clearable && hasValue && !disabled && !readonly)
|
|
90
|
+
<!-- Clear button -->
|
|
91
|
+
<div class="absolute inset-y-0 right-0 flex items-center pr-3">
|
|
92
|
+
<button
|
|
93
|
+
type="button"
|
|
94
|
+
onclick="handleClear()"
|
|
95
|
+
class="text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 focus:outline-none"
|
|
96
|
+
aria-label="Clear input"
|
|
97
|
+
>
|
|
98
|
+
<svg class="{{ iconClasses }}" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
99
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
100
|
+
</svg>
|
|
101
|
+
</button>
|
|
102
|
+
</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
|
|
110
|
+
@endif
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
@if(helperText || (showCount && maxLength))
|
|
114
|
+
<div class="flex items-center justify-between mt-2">
|
|
115
|
+
@if(helperText)
|
|
116
|
+
<p id="helper-text" class="{{ helperClasses }}">
|
|
117
|
+
{{ helperText }}
|
|
118
|
+
</p>
|
|
119
|
+
@else
|
|
120
|
+
<span></span>
|
|
121
|
+
@endif
|
|
122
|
+
|
|
123
|
+
@if(showCount && maxLength)
|
|
124
|
+
<p class="text-sm text-gray-500 dark:text-gray-400">
|
|
125
|
+
{{ value.length }} / {{ maxLength }}
|
|
126
|
+
</p>
|
|
127
|
+
@endif
|
|
128
|
+
</div>
|
|
129
|
+
@endif
|
|
130
|
+
</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>
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import type { PropSchema, ValidationResult } from '../../utils/prop-validation'
|
|
2
|
+
import { createPropValidator, PropTypes } from '../../utils/prop-validation'
|
|
3
|
+
|
|
4
|
+
export { default as EmailInput } from './EmailInput.stx'
|
|
5
|
+
export { default as NumberInput } from './NumberInput.stx'
|
|
6
|
+
export { default as PasswordInput } from './PasswordInput.stx'
|
|
7
|
+
export { default as SearchInput } from './SearchInput.stx'
|
|
8
|
+
export { default as TextInput } from './TextInput.stx'
|
|
9
|
+
|
|
10
|
+
export interface BaseInputProps {
|
|
11
|
+
value?: string
|
|
12
|
+
onChange?: (value: string) => void
|
|
13
|
+
placeholder?: string
|
|
14
|
+
disabled?: boolean
|
|
15
|
+
readonly?: boolean
|
|
16
|
+
size?: 'sm' | 'md' | 'lg'
|
|
17
|
+
error?: boolean
|
|
18
|
+
label?: string
|
|
19
|
+
helperText?: string
|
|
20
|
+
required?: boolean
|
|
21
|
+
className?: string
|
|
22
|
+
inputClassName?: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface TextInputProps extends BaseInputProps {
|
|
26
|
+
leftIcon?: string
|
|
27
|
+
rightIcon?: string
|
|
28
|
+
clearable?: boolean
|
|
29
|
+
maxLength?: number
|
|
30
|
+
showCount?: boolean
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface EmailInputProps extends Omit<BaseInputProps, 'placeholder'> {
|
|
34
|
+
placeholder?: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface PasswordInputProps extends Omit<BaseInputProps, 'placeholder'> {
|
|
38
|
+
placeholder?: string
|
|
39
|
+
showStrength?: boolean
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface NumberInputProps extends BaseInputProps {
|
|
43
|
+
min?: number
|
|
44
|
+
max?: number
|
|
45
|
+
step?: number
|
|
46
|
+
showControls?: boolean
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface SearchInputProps extends Omit<BaseInputProps, 'placeholder'> {
|
|
50
|
+
placeholder?: string
|
|
51
|
+
onSearch?: (value: string) => void
|
|
52
|
+
loading?: boolean
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Base input prop validation schema
|
|
57
|
+
*/
|
|
58
|
+
const baseInputPropSchema: PropSchema = {
|
|
59
|
+
value: PropTypes.string,
|
|
60
|
+
onChange: PropTypes.func,
|
|
61
|
+
placeholder: PropTypes.string,
|
|
62
|
+
disabled: PropTypes.boolean,
|
|
63
|
+
readonly: PropTypes.boolean,
|
|
64
|
+
size: PropTypes.oneOf(['sm', 'md', 'lg']),
|
|
65
|
+
error: PropTypes.boolean,
|
|
66
|
+
label: PropTypes.string,
|
|
67
|
+
helperText: PropTypes.string,
|
|
68
|
+
required: PropTypes.boolean,
|
|
69
|
+
className: PropTypes.string,
|
|
70
|
+
inputClassName: PropTypes.string,
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* TextInput prop validation schema
|
|
75
|
+
*/
|
|
76
|
+
export const textInputPropSchema: PropSchema = {
|
|
77
|
+
value: PropTypes.string,
|
|
78
|
+
onChange: PropTypes.func,
|
|
79
|
+
placeholder: PropTypes.string,
|
|
80
|
+
disabled: PropTypes.boolean,
|
|
81
|
+
readonly: PropTypes.boolean,
|
|
82
|
+
size: PropTypes.oneOf(['sm', 'md', 'lg']),
|
|
83
|
+
error: PropTypes.boolean,
|
|
84
|
+
label: PropTypes.string,
|
|
85
|
+
helperText: PropTypes.string,
|
|
86
|
+
required: PropTypes.boolean,
|
|
87
|
+
className: PropTypes.string,
|
|
88
|
+
inputClassName: PropTypes.string,
|
|
89
|
+
leftIcon: PropTypes.string,
|
|
90
|
+
rightIcon: PropTypes.string,
|
|
91
|
+
clearable: PropTypes.boolean,
|
|
92
|
+
maxLength: PropTypes.number,
|
|
93
|
+
showCount: PropTypes.boolean,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* NumberInput prop validation schema
|
|
98
|
+
*/
|
|
99
|
+
export const numberInputPropSchema: PropSchema = {
|
|
100
|
+
value: PropTypes.string,
|
|
101
|
+
onChange: PropTypes.func,
|
|
102
|
+
placeholder: PropTypes.string,
|
|
103
|
+
disabled: PropTypes.boolean,
|
|
104
|
+
readonly: PropTypes.boolean,
|
|
105
|
+
size: PropTypes.oneOf(['sm', 'md', 'lg']),
|
|
106
|
+
error: PropTypes.boolean,
|
|
107
|
+
label: PropTypes.string,
|
|
108
|
+
helperText: PropTypes.string,
|
|
109
|
+
required: PropTypes.boolean,
|
|
110
|
+
className: PropTypes.string,
|
|
111
|
+
inputClassName: PropTypes.string,
|
|
112
|
+
min: PropTypes.number,
|
|
113
|
+
max: PropTypes.number,
|
|
114
|
+
step: PropTypes.number,
|
|
115
|
+
showControls: PropTypes.boolean,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* PasswordInput prop validation schema
|
|
120
|
+
*/
|
|
121
|
+
const passwordInputPropSchema: PropSchema = {
|
|
122
|
+
value: PropTypes.string,
|
|
123
|
+
onChange: PropTypes.func,
|
|
124
|
+
placeholder: PropTypes.string,
|
|
125
|
+
disabled: PropTypes.boolean,
|
|
126
|
+
readonly: PropTypes.boolean,
|
|
127
|
+
size: PropTypes.oneOf(['sm', 'md', 'lg']),
|
|
128
|
+
error: PropTypes.boolean,
|
|
129
|
+
label: PropTypes.string,
|
|
130
|
+
helperText: PropTypes.string,
|
|
131
|
+
required: PropTypes.boolean,
|
|
132
|
+
className: PropTypes.string,
|
|
133
|
+
inputClassName: PropTypes.string,
|
|
134
|
+
showStrength: PropTypes.boolean,
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* SearchInput prop validation schema
|
|
139
|
+
*/
|
|
140
|
+
const searchInputPropSchema: PropSchema = {
|
|
141
|
+
value: PropTypes.string,
|
|
142
|
+
onChange: PropTypes.func,
|
|
143
|
+
placeholder: PropTypes.string,
|
|
144
|
+
disabled: PropTypes.boolean,
|
|
145
|
+
readonly: PropTypes.boolean,
|
|
146
|
+
size: PropTypes.oneOf(['sm', 'md', 'lg']),
|
|
147
|
+
error: PropTypes.boolean,
|
|
148
|
+
label: PropTypes.string,
|
|
149
|
+
helperText: PropTypes.string,
|
|
150
|
+
required: PropTypes.boolean,
|
|
151
|
+
className: PropTypes.string,
|
|
152
|
+
inputClassName: PropTypes.string,
|
|
153
|
+
onSearch: PropTypes.func,
|
|
154
|
+
loading: PropTypes.boolean,
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Validate TextInput component props
|
|
159
|
+
*/
|
|
160
|
+
export const validateTextInputProps: (props: Record<string, any>) => ValidationResult = createPropValidator('TextInput', textInputPropSchema)
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Validate EmailInput component props
|
|
164
|
+
*/
|
|
165
|
+
export const validateEmailInputProps: (props: Record<string, any>) => ValidationResult = createPropValidator('EmailInput', baseInputPropSchema)
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Validate PasswordInput component props
|
|
169
|
+
*/
|
|
170
|
+
export const validatePasswordInputProps: (props: Record<string, any>) => ValidationResult = createPropValidator('PasswordInput', passwordInputPropSchema)
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Validate NumberInput component props
|
|
174
|
+
*/
|
|
175
|
+
export const validateNumberInputProps: (props: Record<string, any>) => ValidationResult = createPropValidator('NumberInput', numberInputPropSchema)
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Validate SearchInput component props
|
|
179
|
+
*/
|
|
180
|
+
export const validateSearchInputProps: (props: Record<string, any>) => ValidationResult = createPropValidator('SearchInput', searchInputPropSchema)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script>
|
|
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>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
export const className = $props.className || ''
|
|
3
|
+
export const as = $props.as || 'button'
|
|
4
|
+
export const disabled = $props.disabled || false
|
|
5
|
+
|
|
6
|
+
const baseClasses = 'relative w-full cursor-pointer rounded-lg bg-white dark:bg-neutral-800 py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-blue-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-blue-300'
|
|
7
|
+
const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed' : ''
|
|
8
|
+
const buttonClasses = `${baseClasses} ${disabledClasses} ${className}`.trim()
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<component
|
|
12
|
+
:is="{{ as }}"
|
|
13
|
+
class="{{ buttonClasses }}"
|
|
14
|
+
@if(disabled)disabled aria-disabled="true"@endif
|
|
15
|
+
>
|
|
16
|
+
<slot />
|
|
17
|
+
</component>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
export const className = $props.className || ''
|
|
3
|
+
export const as = $props.as || 'label'
|
|
4
|
+
|
|
5
|
+
const baseClasses = 'block text-sm font-medium text-neutral-900 dark:text-white'
|
|
6
|
+
const labelClasses = `${baseClasses} ${className}`.trim()
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<component :is="{{ as }}" class="{{ labelClasses }}">
|
|
10
|
+
<slot />
|
|
11
|
+
</component>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script>
|
|
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>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
export const className = $props.className || ''
|
|
3
|
+
export const as = $props.as || 'ul'
|
|
4
|
+
export const static_ = $props.static || false
|
|
5
|
+
|
|
6
|
+
const baseClasses = 'absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white dark:bg-neutral-800 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none'
|
|
7
|
+
const optionsClasses = `${baseClasses} ${className}`.trim()
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<component
|
|
11
|
+
:is="{{ as }}"
|
|
12
|
+
class="{{ optionsClasses }}"
|
|
13
|
+
role="listbox"
|
|
14
|
+
>
|
|
15
|
+
<slot />
|
|
16
|
+
</component>
|