@stacksjs/components 0.2.93 → 0.2.94
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +4 -4
- package/package.json +5 -6
- package/src/components/CodeBlock.stx +0 -54
- package/src/components/Footer.stx +0 -66
- package/src/components/Hero.stx +0 -25
- package/src/components/Installation.stx +0 -37
- package/src/components/index.ts +0 -4
- package/src/composables/index.ts +0 -4
- package/src/composables/useCopyCode.ts +0 -73
- package/src/composables/useDarkMode.ts +0 -100
- package/src/composables/useSEO.ts +0 -230
- package/src/composables/utilities/index.ts +0 -7
- package/src/composables/utilities/useClickOutside.ts +0 -72
- package/src/composables/utilities/useFocusTrap.ts +0 -159
- package/src/composables/utilities/useKeyboard.ts +0 -124
- package/src/composables/utilities/useLocalStorage.ts +0 -132
- package/src/composables/utilities/useMediaQuery.ts +0 -118
- package/src/index.ts +0 -99
- package/src/stx.d.ts +0 -4
- package/src/ui/accordion/Accordion.stx +0 -146
- package/src/ui/accordion/AccordionItem.stx +0 -37
- package/src/ui/accordion/index.ts +0 -47
- package/src/ui/audio/Audio.stx +0 -50
- package/src/ui/audio/README.md +0 -41
- package/src/ui/audio/index.ts +0 -13
- package/src/ui/auth/Login.stx +0 -161
- package/src/ui/auth/README.md +0 -142
- package/src/ui/auth/Signup.stx +0 -159
- package/src/ui/auth/TwoFactorChallenge.stx +0 -111
- package/src/ui/auth/index.ts +0 -32
- package/src/ui/avatar/Avatar.stx +0 -77
- package/src/ui/avatar/index.ts +0 -12
- package/src/ui/badge/Badge.stx +0 -62
- package/src/ui/badge/index.ts +0 -10
- package/src/ui/breadcrumb/Breadcrumb.stx +0 -79
- package/src/ui/breadcrumb/index.ts +0 -15
- package/src/ui/button/Button.stx +0 -74
- package/src/ui/button/README.md +0 -80
- package/src/ui/button/index.ts +0 -85
- package/src/ui/calendar/Calendar.stx +0 -189
- package/src/ui/calendar/README.md +0 -254
- package/src/ui/calendar/index.ts +0 -14
- package/src/ui/card/Card.stx +0 -68
- package/src/ui/card/index.ts +0 -13
- package/src/ui/checkbox/Checkbox.stx +0 -86
- package/src/ui/checkbox/index.ts +0 -16
- package/src/ui/combobox/Combobox.stx +0 -96
- package/src/ui/combobox/ComboboxButton.stx +0 -25
- package/src/ui/combobox/ComboboxInput.stx +0 -32
- package/src/ui/combobox/ComboboxOption.stx +0 -49
- package/src/ui/combobox/ComboboxOptions.stx +0 -16
- package/src/ui/combobox/README.md +0 -150
- package/src/ui/combobox/index.ts +0 -40
- package/src/ui/command-palette/CommandPalette.stx +0 -81
- package/src/ui/command-palette/CommandPaletteItem.stx +0 -27
- package/src/ui/command-palette/README.md +0 -42
- package/src/ui/command-palette/index.ts +0 -15
- package/src/ui/dialog/Dialog.stx +0 -41
- package/src/ui/dialog/DialogBackdrop.stx +0 -9
- package/src/ui/dialog/DialogDescription.stx +0 -11
- package/src/ui/dialog/DialogPanel.stx +0 -16
- package/src/ui/dialog/DialogTitle.stx +0 -11
- package/src/ui/dialog/README.md +0 -121
- package/src/ui/dialog/index.ts +0 -32
- package/src/ui/drawer/Drawer.stx +0 -120
- package/src/ui/drawer/README.md +0 -90
- package/src/ui/drawer/index.ts +0 -9
- package/src/ui/dropdown/Dropdown.stx +0 -82
- package/src/ui/dropdown/DropdownButton.stx +0 -29
- package/src/ui/dropdown/DropdownItem.stx +0 -35
- package/src/ui/dropdown/DropdownItems.stx +0 -18
- package/src/ui/dropdown/README.md +0 -114
- package/src/ui/dropdown/index.ts +0 -29
- package/src/ui/form/Form.stx +0 -95
- package/src/ui/form/index.ts +0 -67
- package/src/ui/heatmap/Heatmap.stx +0 -294
- package/src/ui/image/Image.stx +0 -165
- package/src/ui/image/README.md +0 -164
- package/src/ui/image/index.ts +0 -22
- package/src/ui/input/EmailInput.stx +0 -30
- package/src/ui/input/NumberInput.stx +0 -126
- package/src/ui/input/PasswordInput.stx +0 -143
- package/src/ui/input/SearchInput.stx +0 -44
- package/src/ui/input/TextInput.stx +0 -132
- package/src/ui/input/index.ts +0 -180
- package/src/ui/listbox/Listbox.stx +0 -101
- package/src/ui/listbox/ListboxButton.stx +0 -28
- package/src/ui/listbox/ListboxLabel.stx +0 -11
- package/src/ui/listbox/ListboxOption.stx +0 -49
- package/src/ui/listbox/ListboxOptions.stx +0 -16
- package/src/ui/listbox/README.md +0 -135
- package/src/ui/listbox/index.ts +0 -39
- package/src/ui/navigator/Navigator.stx +0 -113
- package/src/ui/navigator/README.md +0 -352
- package/src/ui/navigator/index.ts +0 -20
- package/src/ui/notification/Notification.stx +0 -117
- package/src/ui/notification/README.md +0 -114
- package/src/ui/notification/index.ts +0 -12
- package/src/ui/pagination/Pagination.stx +0 -150
- package/src/ui/pagination/index.ts +0 -11
- package/src/ui/payment/Checkout.stx +0 -31
- package/src/ui/payment/DefaultPaymentMethod.stx +0 -62
- package/src/ui/payment/PaymentMethods.stx +0 -104
- package/src/ui/payment/README.md +0 -345
- package/src/ui/payment/SubscriptionCheckout.stx +0 -323
- package/src/ui/payment/index.ts +0 -59
- package/src/ui/popover/Popover.stx +0 -60
- package/src/ui/popover/PopoverButton.stx +0 -29
- package/src/ui/popover/PopoverPanel.stx +0 -23
- package/src/ui/popover/README.md +0 -91
- package/src/ui/popover/index.ts +0 -22
- package/src/ui/portal/Portal.stx +0 -57
- package/src/ui/portal/index.ts +0 -6
- package/src/ui/progress/Progress.stx +0 -131
- package/src/ui/progress/index.ts +0 -12
- package/src/ui/radio/Radio.stx +0 -77
- package/src/ui/radio/index.ts +0 -15
- package/src/ui/radio-group/README.md +0 -139
- package/src/ui/radio-group/RadioGroup.stx +0 -60
- package/src/ui/radio-group/RadioGroupDescription.stx +0 -11
- package/src/ui/radio-group/RadioGroupLabel.stx +0 -11
- package/src/ui/radio-group/RadioGroupOption.stx +0 -58
- package/src/ui/radio-group/index.ts +0 -30
- package/src/ui/select/README.md +0 -180
- package/src/ui/select/Select.stx +0 -82
- package/src/ui/select/index.ts +0 -21
- package/src/ui/sidebar/Sidebar.stx +0 -476
- package/src/ui/sidebar/SidebarFooter.stx +0 -71
- package/src/ui/sidebar/SidebarHeader.stx +0 -103
- package/src/ui/sidebar/SidebarItem.stx +0 -86
- package/src/ui/sidebar/SidebarSection.stx +0 -83
- package/src/ui/sidebar/index.ts +0 -153
- package/src/ui/sidebar/themes.ts +0 -240
- package/src/ui/skeleton/Skeleton.stx +0 -48
- package/src/ui/skeleton/index.ts +0 -11
- package/src/ui/spinner/Spinner.stx +0 -109
- package/src/ui/spinner/index.ts +0 -9
- package/src/ui/stepper/README.md +0 -36
- package/src/ui/stepper/Stepper.stx +0 -17
- package/src/ui/stepper/StepperStep.stx +0 -57
- package/src/ui/stepper/index.ts +0 -19
- package/src/ui/storage/README.md +0 -193
- package/src/ui/storage/index.ts +0 -347
- package/src/ui/switch/README.md +0 -114
- package/src/ui/switch/Switch.stx +0 -72
- package/src/ui/switch/index.ts +0 -10
- package/src/ui/table/README.md +0 -39
- package/src/ui/table/Table.stx +0 -14
- package/src/ui/table/TableBody.stx +0 -10
- package/src/ui/table/TableCell.stx +0 -10
- package/src/ui/table/TableHead.stx +0 -10
- package/src/ui/table/TableHeader.stx +0 -20
- package/src/ui/table/TableRow.stx +0 -11
- package/src/ui/table/index.ts +0 -35
- package/src/ui/tabs/TabPanel.stx +0 -25
- package/src/ui/tabs/Tabs.stx +0 -202
- package/src/ui/tabs/index.ts +0 -50
- package/src/ui/teleport/Teleport.stx +0 -65
- package/src/ui/teleport/index.ts +0 -7
- package/src/ui/textarea/Textarea.stx +0 -108
- package/src/ui/textarea/index.ts +0 -20
- package/src/ui/tooltip/Tooltip.stx +0 -71
- package/src/ui/tooltip/index.ts +0 -10
- package/src/ui/transition/README.md +0 -30
- package/src/ui/transition/Transition.stx +0 -102
- package/src/ui/transition/index.ts +0 -25
- package/src/ui/video/README.md +0 -47
- package/src/ui/video/Video.stx +0 -45
- package/src/ui/video/index.ts +0 -16
- package/src/ui/virtual-list/VirtualList.stx +0 -67
- package/src/ui/virtual-list/index.ts +0 -10
- package/src/ui/virtual-table/VirtualTable.stx +0 -103
- package/src/ui/virtual-table/index.ts +0 -21
- package/src/utils/PROP_VALIDATION.md +0 -458
- package/src/utils/THEME_SYSTEM.md +0 -702
- package/src/utils/accessibility.ts +0 -841
- package/src/utils/animation/easing.ts +0 -368
- package/src/utils/animation/helpers.ts +0 -223
- package/src/utils/animation/index.ts +0 -5
- package/src/utils/animation/keyframes.ts +0 -230
- package/src/utils/error-handling.ts +0 -475
- package/src/utils/highlighter.ts +0 -93
- package/src/utils/i18n.ts +0 -634
- package/src/utils/keep-alive.ts +0 -819
- package/src/utils/lazy-loading.ts +0 -530
- package/src/utils/prop-validation.ts +0 -478
- package/src/utils/theme.ts +0 -626
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Detects clicks outside a specified element
|
|
3
|
-
*
|
|
4
|
-
* @example
|
|
5
|
-
* ```ts
|
|
6
|
-
* const cleanup = useClickOutside(
|
|
7
|
-
* modalRef,
|
|
8
|
-
* () => closeModal(),
|
|
9
|
-
* { enabled: isOpen, ignore: ['.tooltip'] }
|
|
10
|
-
* )
|
|
11
|
-
* ```
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Options for useClickOutside hook
|
|
16
|
-
*/
|
|
17
|
-
export interface UseClickOutsideOptions {
|
|
18
|
-
/** Whether the hook is enabled */
|
|
19
|
-
enabled?: boolean
|
|
20
|
-
/** CSS selectors to ignore (clicks on these elements won't trigger callback) */
|
|
21
|
-
ignore?: string[]
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Hook to detect clicks outside an element
|
|
26
|
-
*
|
|
27
|
-
* @param elementRef - The element to detect clicks outside of
|
|
28
|
-
* @param callback - Function to call when click occurs outside element
|
|
29
|
-
* @param options - Configuration options
|
|
30
|
-
* @returns Cleanup function to remove event listeners
|
|
31
|
-
*/
|
|
32
|
-
export function useClickOutside(
|
|
33
|
-
elementRef: HTMLElement | null,
|
|
34
|
-
callback: (event: MouseEvent | TouchEvent) => void,
|
|
35
|
-
options: UseClickOutsideOptions = {},
|
|
36
|
-
): () => void {
|
|
37
|
-
const { enabled = true, ignore = [] } = options
|
|
38
|
-
|
|
39
|
-
const handleClick = (event: MouseEvent | TouchEvent) => {
|
|
40
|
-
if (!enabled || !elementRef)
|
|
41
|
-
return
|
|
42
|
-
|
|
43
|
-
const target = event.target as Node
|
|
44
|
-
|
|
45
|
-
// Check if click is outside element
|
|
46
|
-
if (!elementRef.contains(target)) {
|
|
47
|
-
// Check if target matches any ignore selectors
|
|
48
|
-
const shouldIgnore = ignore.some((selector) => {
|
|
49
|
-
const elements = document.querySelectorAll(selector)
|
|
50
|
-
return Array.from(elements).some(el => el.contains(target))
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
if (!shouldIgnore) {
|
|
54
|
-
callback(event)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Add event listeners
|
|
60
|
-
if (typeof document !== 'undefined') {
|
|
61
|
-
document.addEventListener('mousedown', handleClick)
|
|
62
|
-
document.addEventListener('touchstart', handleClick)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Return cleanup function
|
|
66
|
-
return () => {
|
|
67
|
-
if (typeof document !== 'undefined') {
|
|
68
|
-
document.removeEventListener('mousedown', handleClick)
|
|
69
|
-
document.removeEventListener('touchstart', handleClick)
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Traps focus within a container element (useful for modals, dialogs, dropdowns)
|
|
3
|
-
*
|
|
4
|
-
* @example
|
|
5
|
-
* ```ts
|
|
6
|
-
* const { activate, deactivate } = useFocusTrap(modalRef, {
|
|
7
|
-
* initialFocus: firstInputRef,
|
|
8
|
-
* returnFocus: true
|
|
9
|
-
* })
|
|
10
|
-
*
|
|
11
|
-
* // When modal opens
|
|
12
|
-
* activate()
|
|
13
|
-
*
|
|
14
|
-
* // When modal closes
|
|
15
|
-
* deactivate()
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Options for useFocusTrap hook
|
|
21
|
-
*/
|
|
22
|
-
export interface UseFocusTrapOptions {
|
|
23
|
-
/** Whether the focus trap is enabled */
|
|
24
|
-
enabled?: boolean
|
|
25
|
-
/** Element to focus initially (defaults to first focusable element) */
|
|
26
|
-
initialFocus?: HTMLElement | null
|
|
27
|
-
/** Whether to return focus to previously focused element on deactivate */
|
|
28
|
-
returnFocus?: boolean
|
|
29
|
-
/** Fallback element to focus if no focusable elements found */
|
|
30
|
-
fallbackFocus?: HTMLElement | null
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Hook to trap focus within an element
|
|
35
|
-
*
|
|
36
|
-
* @param containerRef - The container element to trap focus within
|
|
37
|
-
* @param options - Configuration options
|
|
38
|
-
* @returns Object with activate and deactivate functions
|
|
39
|
-
*/
|
|
40
|
-
export function useFocusTrap(
|
|
41
|
-
containerRef: HTMLElement | null,
|
|
42
|
-
options: UseFocusTrapOptions = {},
|
|
43
|
-
): { activate: () => void, deactivate: () => void } {
|
|
44
|
-
const {
|
|
45
|
-
enabled = true,
|
|
46
|
-
initialFocus = null,
|
|
47
|
-
returnFocus = true,
|
|
48
|
-
fallbackFocus = null,
|
|
49
|
-
} = options
|
|
50
|
-
|
|
51
|
-
let previouslyFocusedElement: HTMLElement | null = null
|
|
52
|
-
let isActive = false
|
|
53
|
-
|
|
54
|
-
// Get all focusable elements within container
|
|
55
|
-
function getFocusableElements(): HTMLElement[] {
|
|
56
|
-
if (!containerRef)
|
|
57
|
-
return []
|
|
58
|
-
|
|
59
|
-
const focusableSelectors = [
|
|
60
|
-
'a[href]',
|
|
61
|
-
'button:not([disabled])',
|
|
62
|
-
'textarea:not([disabled])',
|
|
63
|
-
'input:not([disabled])',
|
|
64
|
-
'select:not([disabled])',
|
|
65
|
-
'[tabindex]:not([tabindex="-1"])',
|
|
66
|
-
].join(',')
|
|
67
|
-
|
|
68
|
-
return Array.from(containerRef.querySelectorAll(focusableSelectors))
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Handle tab key
|
|
72
|
-
function handleTab(event: KeyboardEvent) {
|
|
73
|
-
if (!enabled || !isActive || !containerRef)
|
|
74
|
-
return
|
|
75
|
-
|
|
76
|
-
const focusableElements = getFocusableElements()
|
|
77
|
-
|
|
78
|
-
if (focusableElements.length === 0) {
|
|
79
|
-
event.preventDefault()
|
|
80
|
-
return
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const firstElement = focusableElements[0]
|
|
84
|
-
const lastElement = focusableElements[focusableElements.length - 1]
|
|
85
|
-
|
|
86
|
-
if (event.shiftKey) {
|
|
87
|
-
// Shift + Tab
|
|
88
|
-
if (document.activeElement === firstElement || document.activeElement === containerRef) {
|
|
89
|
-
event.preventDefault()
|
|
90
|
-
lastElement.focus()
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
// Tab
|
|
95
|
-
if (document.activeElement === lastElement) {
|
|
96
|
-
event.preventDefault()
|
|
97
|
-
firstElement.focus()
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Handle escape key
|
|
103
|
-
function handleEscape(event: KeyboardEvent) {
|
|
104
|
-
if (event.key === 'Escape' && enabled && isActive) {
|
|
105
|
-
deactivate()
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Activate focus trap
|
|
110
|
-
function activate() {
|
|
111
|
-
if (!enabled || !containerRef || isActive)
|
|
112
|
-
return
|
|
113
|
-
|
|
114
|
-
// Store previously focused element
|
|
115
|
-
previouslyFocusedElement = document.activeElement as HTMLElement
|
|
116
|
-
|
|
117
|
-
// Focus initial element
|
|
118
|
-
if (initialFocus) {
|
|
119
|
-
initialFocus.focus()
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
const focusableElements = getFocusableElements()
|
|
123
|
-
if (focusableElements.length > 0) {
|
|
124
|
-
focusableElements[0].focus()
|
|
125
|
-
}
|
|
126
|
-
else if (fallbackFocus) {
|
|
127
|
-
fallbackFocus.focus()
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
containerRef.focus()
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Add event listeners
|
|
135
|
-
document.addEventListener('keydown', handleTab)
|
|
136
|
-
document.addEventListener('keydown', handleEscape)
|
|
137
|
-
|
|
138
|
-
isActive = true
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Deactivate focus trap
|
|
142
|
-
function deactivate() {
|
|
143
|
-
if (!isActive)
|
|
144
|
-
return
|
|
145
|
-
|
|
146
|
-
// Remove event listeners
|
|
147
|
-
document.removeEventListener('keydown', handleTab)
|
|
148
|
-
document.removeEventListener('keydown', handleEscape)
|
|
149
|
-
|
|
150
|
-
// Return focus
|
|
151
|
-
if (returnFocus && previouslyFocusedElement) {
|
|
152
|
-
previouslyFocusedElement.focus()
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
isActive = false
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return { activate, deactivate }
|
|
159
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hook for keyboard event handling with support for shortcuts and modifiers
|
|
3
|
-
*
|
|
4
|
-
* @example
|
|
5
|
-
* ```ts
|
|
6
|
-
* useKeyboard([
|
|
7
|
-
* { key: 'Escape', handler: () => closeModal() },
|
|
8
|
-
* { key: 's', ctrl: true, handler: () => save() },
|
|
9
|
-
* { key: ['ArrowUp', 'ArrowDown'], handler: (e) => navigate(e.key) }
|
|
10
|
-
* ])
|
|
11
|
-
* ```
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Options for useKeyboard hook
|
|
16
|
-
*/
|
|
17
|
-
export interface UseKeyboardOptions {
|
|
18
|
-
/** Whether the hook is enabled */
|
|
19
|
-
enabled?: boolean
|
|
20
|
-
/** Whether to prevent default browser behavior */
|
|
21
|
-
preventDefault?: boolean
|
|
22
|
-
/** Whether to stop event propagation */
|
|
23
|
-
stopPropagation?: boolean
|
|
24
|
-
/** Target element for event listener (defaults to document) */
|
|
25
|
-
target?: HTMLElement | Document | Window | null
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Keyboard event handler configuration
|
|
30
|
-
*/
|
|
31
|
-
export interface KeyboardHandler {
|
|
32
|
-
/** Key or keys to listen for */
|
|
33
|
-
key: string | string[]
|
|
34
|
-
/** Handler function to execute */
|
|
35
|
-
handler: (event: KeyboardEvent) => void
|
|
36
|
-
/** Whether Ctrl key must be pressed */
|
|
37
|
-
ctrl?: boolean
|
|
38
|
-
/** Whether Shift key must be pressed */
|
|
39
|
-
shift?: boolean
|
|
40
|
-
/** Whether Alt key must be pressed */
|
|
41
|
-
alt?: boolean
|
|
42
|
-
/** Whether Meta (Command on Mac) key must be pressed */
|
|
43
|
-
meta?: boolean
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Hook for keyboard event handling
|
|
48
|
-
*
|
|
49
|
-
* @param handlers - Single handler or array of keyboard handlers
|
|
50
|
-
* @param options - Configuration options
|
|
51
|
-
* @returns Cleanup function to remove event listeners
|
|
52
|
-
*/
|
|
53
|
-
export function useKeyboard(
|
|
54
|
-
handlers: KeyboardHandler | KeyboardHandler[],
|
|
55
|
-
options: UseKeyboardOptions = {},
|
|
56
|
-
): () => void {
|
|
57
|
-
const {
|
|
58
|
-
enabled = true,
|
|
59
|
-
preventDefault = true,
|
|
60
|
-
stopPropagation = false,
|
|
61
|
-
target = typeof document !== 'undefined' ? document : null,
|
|
62
|
-
} = options
|
|
63
|
-
|
|
64
|
-
const handlerArray = Array.isArray(handlers) ? handlers : [handlers]
|
|
65
|
-
|
|
66
|
-
const handleKeydown = (event: KeyboardEvent) => {
|
|
67
|
-
if (!enabled)
|
|
68
|
-
return
|
|
69
|
-
|
|
70
|
-
handlerArray.forEach((handler) => {
|
|
71
|
-
const keys = Array.isArray(handler.key) ? handler.key : [handler.key]
|
|
72
|
-
const keyMatches = keys.some(k => k.toLowerCase() === event.key.toLowerCase())
|
|
73
|
-
|
|
74
|
-
if (!keyMatches)
|
|
75
|
-
return
|
|
76
|
-
|
|
77
|
-
// Check modifier keys
|
|
78
|
-
if (handler.ctrl !== undefined && handler.ctrl !== event.ctrlKey)
|
|
79
|
-
return
|
|
80
|
-
if (handler.shift !== undefined && handler.shift !== event.shiftKey)
|
|
81
|
-
return
|
|
82
|
-
if (handler.alt !== undefined && handler.alt !== event.altKey)
|
|
83
|
-
return
|
|
84
|
-
if (handler.meta !== undefined && handler.meta !== event.metaKey)
|
|
85
|
-
return
|
|
86
|
-
|
|
87
|
-
// Execute handler
|
|
88
|
-
if (preventDefault)
|
|
89
|
-
event.preventDefault()
|
|
90
|
-
if (stopPropagation)
|
|
91
|
-
event.stopPropagation()
|
|
92
|
-
|
|
93
|
-
handler.handler(event)
|
|
94
|
-
})
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Add event listener
|
|
98
|
-
if (target) {
|
|
99
|
-
target.addEventListener('keydown', handleKeydown as EventListener)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Return cleanup function
|
|
103
|
-
return () => {
|
|
104
|
-
if (target) {
|
|
105
|
-
target.removeEventListener('keydown', handleKeydown as EventListener)
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Common keyboard shortcuts
|
|
111
|
-
export const KeyboardShortcuts = {
|
|
112
|
-
ESCAPE: 'Escape',
|
|
113
|
-
ENTER: 'Enter',
|
|
114
|
-
SPACE: ' ',
|
|
115
|
-
TAB: 'Tab',
|
|
116
|
-
ARROW_UP: 'ArrowUp',
|
|
117
|
-
ARROW_DOWN: 'ArrowDown',
|
|
118
|
-
ARROW_LEFT: 'ArrowLeft',
|
|
119
|
-
ARROW_RIGHT: 'ArrowRight',
|
|
120
|
-
HOME: 'Home',
|
|
121
|
-
END: 'End',
|
|
122
|
-
PAGE_UP: 'PageUp',
|
|
123
|
-
PAGE_DOWN: 'PageDown',
|
|
124
|
-
} as const
|
|
@@ -1,132 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,118 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
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
DELETED