@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,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactive localStorage hook with cross-tab synchronization
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* const { value, setValue, removeValue } = useLocalStorage('user', { name: 'John' })
|
|
7
|
+
*
|
|
8
|
+
* setValue({ name: 'Jane' })
|
|
9
|
+
* setValue(prev => ({ ...prev, age: 30 }))
|
|
10
|
+
* removeValue()
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Options for useLocalStorage hook
|
|
16
|
+
*/
|
|
17
|
+
export interface UseLocalStorageOptions<T> {
|
|
18
|
+
/** Custom serializer function (defaults to JSON.stringify) */
|
|
19
|
+
serializer?: (value: T) => string
|
|
20
|
+
/** Custom deserializer function (defaults to JSON.parse) */
|
|
21
|
+
deserializer?: (value: string) => T
|
|
22
|
+
/** Error handler function */
|
|
23
|
+
onError?: (error: Error) => void
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Hook for reactive localStorage with cross-tab sync
|
|
28
|
+
*
|
|
29
|
+
* @param key - Storage key
|
|
30
|
+
* @param initialValue - Initial value if key doesn't exist
|
|
31
|
+
* @param options - Configuration options
|
|
32
|
+
* @returns Object with value, setValue, and removeValue
|
|
33
|
+
*/
|
|
34
|
+
export function useLocalStorage<T>(
|
|
35
|
+
key: string,
|
|
36
|
+
initialValue: T,
|
|
37
|
+
options: UseLocalStorageOptions<T> = {},
|
|
38
|
+
): {
|
|
39
|
+
value: T
|
|
40
|
+
setValue: (newValue: T | ((prev: T) => T)) => void
|
|
41
|
+
removeValue: () => void
|
|
42
|
+
} {
|
|
43
|
+
const {
|
|
44
|
+
serializer = JSON.stringify,
|
|
45
|
+
deserializer = JSON.parse,
|
|
46
|
+
onError = console.error,
|
|
47
|
+
} = options
|
|
48
|
+
|
|
49
|
+
// Get initial value from storage
|
|
50
|
+
let storedValue: T = initialValue
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
if (typeof window !== 'undefined') {
|
|
54
|
+
const item = window.localStorage.getItem(key)
|
|
55
|
+
if (item !== null) {
|
|
56
|
+
storedValue = deserializer(item)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
onError(error as Error)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let value = storedValue
|
|
65
|
+
const listeners = new Set<(newValue: T) => void>()
|
|
66
|
+
|
|
67
|
+
// Set value
|
|
68
|
+
function setValue(newValue: T | ((prev: T) => T)) {
|
|
69
|
+
try {
|
|
70
|
+
// Allow value to be a function for same API as useState
|
|
71
|
+
const valueToStore = typeof newValue === 'function' ? (newValue as (prev: T) => T)(value) : newValue
|
|
72
|
+
|
|
73
|
+
value = valueToStore
|
|
74
|
+
|
|
75
|
+
// Save to localStorage
|
|
76
|
+
if (typeof window !== 'undefined') {
|
|
77
|
+
window.localStorage.setItem(key, serializer(valueToStore))
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Notify listeners
|
|
81
|
+
listeners.forEach(listener => listener(valueToStore))
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
onError(error as Error)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Remove value
|
|
89
|
+
function removeValue() {
|
|
90
|
+
try {
|
|
91
|
+
value = initialValue
|
|
92
|
+
|
|
93
|
+
if (typeof window !== 'undefined') {
|
|
94
|
+
window.localStorage.removeItem(key)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Notify listeners
|
|
98
|
+
listeners.forEach(listener => listener(initialValue))
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
onError(error as Error)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Listen for storage events (changes from other tabs/windows)
|
|
106
|
+
if (typeof window !== 'undefined') {
|
|
107
|
+
const handleStorageChange = (event: StorageEvent) => {
|
|
108
|
+
if (event.key === key && event.newValue !== null) {
|
|
109
|
+
try {
|
|
110
|
+
const newValue = deserializer(event.newValue)
|
|
111
|
+
value = newValue
|
|
112
|
+
listeners.forEach(listener => listener(newValue))
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
onError(error as Error)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else if (event.key === key && event.newValue === null) {
|
|
119
|
+
value = initialValue
|
|
120
|
+
listeners.forEach(listener => listener(initialValue))
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
window.addEventListener('storage', handleStorageChange)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
value,
|
|
129
|
+
setValue,
|
|
130
|
+
removeValue,
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for responsive media queries
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* const { matches } = useMediaQuery('(min-width: 768px)')
|
|
7
|
+
* const { matches: isDark } = useIsDarkMode()
|
|
8
|
+
* const { matches: isMobile } = useIsMobile()
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Options for useMediaQuery hook
|
|
14
|
+
*/
|
|
15
|
+
export interface UseMediaQueryOptions {
|
|
16
|
+
/** Default value when window.matchMedia is not available */
|
|
17
|
+
defaultValue?: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Hook for responsive media queries
|
|
22
|
+
*
|
|
23
|
+
* @param query - Media query string
|
|
24
|
+
* @param options - Configuration options
|
|
25
|
+
* @returns Object with matches boolean and updateMatches function
|
|
26
|
+
*/
|
|
27
|
+
export function useMediaQuery(
|
|
28
|
+
query: string,
|
|
29
|
+
options: UseMediaQueryOptions = {},
|
|
30
|
+
): { matches: boolean, updateMatches: () => void } {
|
|
31
|
+
const { defaultValue = false } = options
|
|
32
|
+
|
|
33
|
+
let matches = defaultValue
|
|
34
|
+
let mediaQueryList: MediaQueryList | null = null
|
|
35
|
+
|
|
36
|
+
// Initialize
|
|
37
|
+
if (typeof window !== 'undefined' && 'matchMedia' in window) {
|
|
38
|
+
mediaQueryList = window.matchMedia(query)
|
|
39
|
+
matches = mediaQueryList.matches
|
|
40
|
+
|
|
41
|
+
// Listen for changes
|
|
42
|
+
const handleChange = (event: MediaQueryListEvent) => {
|
|
43
|
+
matches = event.matches
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (mediaQueryList.addEventListener) {
|
|
47
|
+
mediaQueryList.addEventListener('change', handleChange)
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// Fallback for older browsers
|
|
51
|
+
mediaQueryList.addListener(handleChange)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function updateMatches() {
|
|
56
|
+
if (mediaQueryList) {
|
|
57
|
+
matches = mediaQueryList.matches
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return { matches, updateMatches }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Common responsive breakpoints
|
|
66
|
+
*/
|
|
67
|
+
export const Breakpoints = {
|
|
68
|
+
'xs': '(min-width: 320px)',
|
|
69
|
+
'sm': '(min-width: 640px)',
|
|
70
|
+
'md': '(min-width: 768px)',
|
|
71
|
+
'lg': '(min-width: 1024px)',
|
|
72
|
+
'xl': '(min-width: 1280px)',
|
|
73
|
+
'2xl': '(min-width: 1536px)',
|
|
74
|
+
'mobile': '(max-width: 767px)',
|
|
75
|
+
'tablet': '(min-width: 768px) and (max-width: 1023px)',
|
|
76
|
+
'desktop': '(min-width: 1024px)',
|
|
77
|
+
'dark': '(prefers-color-scheme: dark)',
|
|
78
|
+
'light': '(prefers-color-scheme: light)',
|
|
79
|
+
'reducedMotion': '(prefers-reduced-motion: reduce)',
|
|
80
|
+
'portrait': '(orientation: portrait)',
|
|
81
|
+
'landscape': '(orientation: landscape)',
|
|
82
|
+
} as const
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Use a predefined breakpoint
|
|
86
|
+
* @param breakpoint - Breakpoint name from Breakpoints constant
|
|
87
|
+
*/
|
|
88
|
+
export function useBreakpoint(breakpoint: keyof typeof Breakpoints): { matches: boolean, updateMatches: () => void } {
|
|
89
|
+
return useMediaQuery(Breakpoints[breakpoint])
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Check if viewport is mobile (max-width: 767px)
|
|
94
|
+
*/
|
|
95
|
+
export function useIsMobile(): { matches: boolean, updateMatches: () => void } {
|
|
96
|
+
return useMediaQuery(Breakpoints.mobile)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Check if viewport is desktop (min-width: 1024px)
|
|
101
|
+
*/
|
|
102
|
+
export function useIsDesktop(): { matches: boolean, updateMatches: () => void } {
|
|
103
|
+
return useMediaQuery(Breakpoints.desktop)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Check if user prefers dark color scheme
|
|
108
|
+
*/
|
|
109
|
+
export function useIsDarkMode(): { matches: boolean, updateMatches: () => void } {
|
|
110
|
+
return useMediaQuery(Breakpoints.dark)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Check if user prefers reduced motion
|
|
115
|
+
*/
|
|
116
|
+
export function usePrefersReducedMotion(): { matches: boolean, updateMatches: () => void } {
|
|
117
|
+
return useMediaQuery(Breakpoints.reducedMotion)
|
|
118
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Export shared components (these will be imported as .stx files)
|
|
2
|
+
export { default as CodeBlock } from './components/CodeBlock.stx'
|
|
3
|
+
|
|
4
|
+
export { default as Footer } from './components/Footer.stx'
|
|
5
|
+
export { default as Hero } from './components/Hero.stx'
|
|
6
|
+
export { default as Installation } from './components/Installation.stx'
|
|
7
|
+
// Export composables
|
|
8
|
+
export * from './composables'
|
|
9
|
+
// Export UI components
|
|
10
|
+
export * from './ui/accordion'
|
|
11
|
+
export * from './ui/audio'
|
|
12
|
+
export * from './ui/auth'
|
|
13
|
+
export * from './ui/avatar'
|
|
14
|
+
export * from './ui/badge'
|
|
15
|
+
|
|
16
|
+
export * from './ui/breadcrumb'
|
|
17
|
+
export * from './ui/button'
|
|
18
|
+
export * from './ui/calendar'
|
|
19
|
+
export * from './ui/card'
|
|
20
|
+
|
|
21
|
+
export * from './ui/checkbox'
|
|
22
|
+
export * from './ui/combobox'
|
|
23
|
+
export * from './ui/command-palette'
|
|
24
|
+
export * from './ui/dialog'
|
|
25
|
+
export * from './ui/drawer'
|
|
26
|
+
export * from './ui/dropdown'
|
|
27
|
+
export * from './ui/form'
|
|
28
|
+
export * from './ui/image'
|
|
29
|
+
export * from './ui/input'
|
|
30
|
+
export * from './ui/listbox'
|
|
31
|
+
export * from './ui/navigator'
|
|
32
|
+
export * from './ui/notification'
|
|
33
|
+
export * from './ui/pagination'
|
|
34
|
+
export * from './ui/payment'
|
|
35
|
+
export * from './ui/popover'
|
|
36
|
+
export * from './ui/portal'
|
|
37
|
+
export * from './ui/progress'
|
|
38
|
+
export * from './ui/radio'
|
|
39
|
+
export * from './ui/radio-group'
|
|
40
|
+
export * from './ui/select'
|
|
41
|
+
export * from './ui/sidebar'
|
|
42
|
+
export * from './ui/skeleton'
|
|
43
|
+
export * from './ui/spinner'
|
|
44
|
+
export * from './ui/stepper'
|
|
45
|
+
export * from './ui/storage'
|
|
46
|
+
export * from './ui/switch'
|
|
47
|
+
export * from './ui/table'
|
|
48
|
+
export * from './ui/tabs'
|
|
49
|
+
export * from './ui/teleport'
|
|
50
|
+
export * from './ui/textarea'
|
|
51
|
+
export * from './ui/tooltip'
|
|
52
|
+
export * from './ui/transition'
|
|
53
|
+
export * from './ui/video'
|
|
54
|
+
export * from './ui/virtual-list'
|
|
55
|
+
export * from './ui/virtual-table'
|
|
56
|
+
export * from './utils/accessibility'
|
|
57
|
+
export * from './utils/animation'
|
|
58
|
+
export * from './utils/error-handling'
|
|
59
|
+
// Export utilities
|
|
60
|
+
export * from './utils/highlighter'
|
|
61
|
+
export * from './utils/i18n'
|
|
62
|
+
export * from './utils/keep-alive'
|
|
63
|
+
export * from './utils/lazy-loading'
|
|
64
|
+
export * from './utils/prop-validation'
|
|
65
|
+
export * from './utils/theme'
|
|
66
|
+
|
|
67
|
+
// Types
|
|
68
|
+
export interface ComponentProps {
|
|
69
|
+
className?: string
|
|
70
|
+
[key: string]: any
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface CodeBlockProps extends ComponentProps {
|
|
74
|
+
code: string
|
|
75
|
+
language?: string
|
|
76
|
+
theme?: 'light' | 'dark' | 'auto'
|
|
77
|
+
lineNumbers?: boolean
|
|
78
|
+
copyable?: boolean
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface HeroProps extends ComponentProps {
|
|
82
|
+
title?: string
|
|
83
|
+
description?: string
|
|
84
|
+
githubUrl?: string
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface FooterProps extends ComponentProps {
|
|
88
|
+
author?: string
|
|
89
|
+
authorUrl?: string
|
|
90
|
+
project?: string
|
|
91
|
+
projectUrl?: string
|
|
92
|
+
twitterUrl?: string
|
|
93
|
+
sponsorUrl?: string
|
|
94
|
+
coffeeUrl?: string
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface InstallationProps extends ComponentProps {
|
|
98
|
+
packageName?: string
|
|
99
|
+
}
|
package/src/stx.d.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
export const items = $props.items || []
|
|
3
|
+
export const allowMultiple = $props.allowMultiple || false
|
|
4
|
+
export const defaultOpen = $props.defaultOpen || []
|
|
5
|
+
export const className = $props.className || ''
|
|
6
|
+
export const onChange = $props.onChange
|
|
7
|
+
|
|
8
|
+
// Track which items are open
|
|
9
|
+
let openItems = defaultOpen
|
|
10
|
+
|
|
11
|
+
// Toggle an item
|
|
12
|
+
function toggleItem(index) {
|
|
13
|
+
if (allowMultiple) {
|
|
14
|
+
// Multiple items can be open
|
|
15
|
+
if (openItems.includes(index)) {
|
|
16
|
+
openItems = openItems.filter(i => i !== index)
|
|
17
|
+
} else {
|
|
18
|
+
openItems = [...openItems, index]
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
// Only one item can be open
|
|
22
|
+
if (openItems.includes(index)) {
|
|
23
|
+
openItems = []
|
|
24
|
+
} else {
|
|
25
|
+
openItems = [index]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (onChange) {
|
|
30
|
+
onChange(openItems)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Check if item is open
|
|
35
|
+
function isOpen(index) {
|
|
36
|
+
return openItems.includes(index)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const accordionClasses = `divide-y divide-gray-200 dark:divide-gray-700 border border-gray-200 dark:border-gray-700 rounded-lg ${className}`.trim()
|
|
40
|
+
export const itemClasses = ``.trim()
|
|
41
|
+
export const headerClasses = `w-full flex items-center justify-between px-4 py-3 text-left font-medium text-gray-900 dark:text-gray-100 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900`.trim()
|
|
42
|
+
export const iconClasses = `w-5 h-5 text-gray-500 dark:text-gray-400 transition-transform duration-200`.trim()
|
|
43
|
+
export const contentClasses = `px-4 py-3 text-gray-700 dark:text-gray-300`.trim()
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<div class="{{ accordionClasses }}" role="region">
|
|
47
|
+
@foreach(item in items)
|
|
48
|
+
<div class="{{ itemClasses }}">
|
|
49
|
+
<button
|
|
50
|
+
type="button"
|
|
51
|
+
class="{{ headerClasses }}"
|
|
52
|
+
onclick="toggleItem({{ $loop.index }})"
|
|
53
|
+
aria-expanded="{{ isOpen($loop.index) ? 'true' : 'false' }}"
|
|
54
|
+
aria-controls="accordion-content-{{ $loop.index }}"
|
|
55
|
+
>
|
|
56
|
+
<span>{{ item.title }}</span>
|
|
57
|
+
<svg
|
|
58
|
+
class="{{ iconClasses }}"
|
|
59
|
+
style="transform: rotate({{ isOpen($loop.index) ? '180' : '0' }}deg)"
|
|
60
|
+
fill="none"
|
|
61
|
+
viewBox="0 0 24 24"
|
|
62
|
+
stroke="currentColor"
|
|
63
|
+
>
|
|
64
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
|
65
|
+
</svg>
|
|
66
|
+
</button>
|
|
67
|
+
|
|
68
|
+
@if(isOpen($loop.index))
|
|
69
|
+
<div
|
|
70
|
+
id="accordion-content-{{ $loop.index }}"
|
|
71
|
+
class="{{ contentClasses }}"
|
|
72
|
+
role="region"
|
|
73
|
+
>
|
|
74
|
+
{!! item.content !!}
|
|
75
|
+
</div>
|
|
76
|
+
@endif
|
|
77
|
+
</div>
|
|
78
|
+
@endforeach
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<script>
|
|
82
|
+
// Keyboard navigation
|
|
83
|
+
if (typeof window !== 'undefined') {
|
|
84
|
+
window.addEventListener('DOMContentLoaded', () => {
|
|
85
|
+
const buttons = document.querySelectorAll('[aria-expanded]')
|
|
86
|
+
|
|
87
|
+
buttons.forEach((button, index) => {
|
|
88
|
+
button.addEventListener('keydown', (event) => {
|
|
89
|
+
if (event.key === 'ArrowDown') {
|
|
90
|
+
event.preventDefault()
|
|
91
|
+
const nextButton = buttons[index + 1]
|
|
92
|
+
if (nextButton) nextButton.focus()
|
|
93
|
+
} else if (event.key === 'ArrowUp') {
|
|
94
|
+
event.preventDefault()
|
|
95
|
+
const prevButton = buttons[index - 1]
|
|
96
|
+
if (prevButton) prevButton.focus()
|
|
97
|
+
} else if (event.key === 'Home') {
|
|
98
|
+
event.preventDefault()
|
|
99
|
+
buttons[0].focus()
|
|
100
|
+
} else if (event.key === 'End') {
|
|
101
|
+
event.preventDefault()
|
|
102
|
+
buttons[buttons.length - 1].focus()
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
</script>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { default as Accordion } from './Accordion.stx'
|
|
2
|
+
|
|
3
|
+
export interface AccordionItem {
|
|
4
|
+
title: string
|
|
5
|
+
content: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface AccordionProps {
|
|
9
|
+
items: AccordionItem[]
|
|
10
|
+
allowMultiple?: boolean
|
|
11
|
+
defaultOpen?: number[]
|
|
12
|
+
onChange?: (openItems: number[]) => void
|
|
13
|
+
className?: string
|
|
14
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
export const src = $props.src || ''
|
|
3
|
+
export const autoplay = $props.autoplay || false
|
|
4
|
+
export const loop = $props.loop || false
|
|
5
|
+
export const muted = $props.muted || false
|
|
6
|
+
export const controls = $props.controls ?? true
|
|
7
|
+
export const preload = $props.preload || 'metadata'
|
|
8
|
+
export const className = $props.className || ''
|
|
9
|
+
export const showWaveform = $props.showWaveform || false
|
|
10
|
+
export const title = $props.title || ''
|
|
11
|
+
|
|
12
|
+
export const containerClasses = `relative w-full ${className}`.trim()
|
|
13
|
+
export const audioClasses = 'w-full rounded-md bg-gray-100 dark:bg-gray-800'
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<div class="{{ containerClasses }}">
|
|
17
|
+
@if(title)
|
|
18
|
+
<div class="mb-2 px-1">
|
|
19
|
+
<h3 class="text-sm font-medium text-gray-900 dark:text-gray-100">
|
|
20
|
+
{{ title }}
|
|
21
|
+
</h3>
|
|
22
|
+
</div>
|
|
23
|
+
@endif
|
|
24
|
+
|
|
25
|
+
<audio
|
|
26
|
+
class="{{ audioClasses }}"
|
|
27
|
+
src="{{ src }}"
|
|
28
|
+
controls="{{ controls }}"
|
|
29
|
+
autoplay="{{ autoplay }}"
|
|
30
|
+
loop="{{ loop }}"
|
|
31
|
+
muted="{{ muted }}"
|
|
32
|
+
preload="{{ preload }}"
|
|
33
|
+
>
|
|
34
|
+
Your browser does not support the audio element.
|
|
35
|
+
</audio>
|
|
36
|
+
|
|
37
|
+
@if(showWaveform)
|
|
38
|
+
<div class="mt-2 h-16 bg-gray-100 dark:bg-gray-800 rounded-md flex items-center justify-center">
|
|
39
|
+
<svg class="w-full h-full px-4" viewBox="0 0 100 40" preserveAspectRatio="none">
|
|
40
|
+
<path
|
|
41
|
+
d="M 0,20 L 10,15 L 20,10 L 30,5 L 40,15 L 50,20 L 60,25 L 70,30 L 80,20 L 90,15 L 100,20"
|
|
42
|
+
fill="none"
|
|
43
|
+
stroke="currentColor"
|
|
44
|
+
stroke-width="2"
|
|
45
|
+
class="text-indigo-500 dark:text-indigo-400"
|
|
46
|
+
/>
|
|
47
|
+
</svg>
|
|
48
|
+
</div>
|
|
49
|
+
@endif
|
|
50
|
+
</div>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Audio Component
|
|
2
|
+
|
|
3
|
+
A styled audio player with optional waveform visualization.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @stacksjs/components
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```stx
|
|
14
|
+
@component('Audio', {
|
|
15
|
+
src: '/audio/podcast.mp3',
|
|
16
|
+
title: 'Episode 42: Building with STX',
|
|
17
|
+
controls: true
|
|
18
|
+
})
|
|
19
|
+
@endcomponent
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Props
|
|
23
|
+
|
|
24
|
+
| Prop | Type | Default | Description |
|
|
25
|
+
|------|------|---------|-------------|
|
|
26
|
+
| `src` | `string` | - | Audio file URL (required) |
|
|
27
|
+
| `autoplay` | `boolean` | `false` | Auto-play on load |
|
|
28
|
+
| `loop` | `boolean` | `false` | Loop playback |
|
|
29
|
+
| `muted` | `boolean` | `false` | Start muted |
|
|
30
|
+
| `controls` | `boolean` | `true` | Show native controls |
|
|
31
|
+
| `preload` | `'none' \| 'metadata' \| 'auto'` | `'metadata'` | Preload strategy |
|
|
32
|
+
| `className` | `string` | `''` | Additional CSS classes |
|
|
33
|
+
| `showWaveform` | `boolean` | `false` | Show waveform visualization |
|
|
34
|
+
| `title` | `string` | `''` | Optional title above player |
|
|
35
|
+
|
|
36
|
+
## Features
|
|
37
|
+
|
|
38
|
+
- **Native controls** - Uses browser's native audio controls
|
|
39
|
+
- **Dark mode** - Styled for dark mode
|
|
40
|
+
- **Waveform** - Optional visual waveform display
|
|
41
|
+
- **Accessible** - Proper fallback text
|
|
42
|
+
- **Responsive** - Full-width design
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { default as Audio } from './Audio.stx'
|
|
2
|
+
|
|
3
|
+
export interface AudioProps {
|
|
4
|
+
src: string
|
|
5
|
+
autoplay?: boolean
|
|
6
|
+
loop?: boolean
|
|
7
|
+
muted?: boolean
|
|
8
|
+
controls?: boolean
|
|
9
|
+
preload?: 'none' | 'metadata' | 'auto'
|
|
10
|
+
className?: string
|
|
11
|
+
showWaveform?: boolean
|
|
12
|
+
title?: string
|
|
13
|
+
}
|