@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
package/src/ui/listbox/README.md
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
# Listbox Component
|
|
2
|
-
|
|
3
|
-
A custom select component for choosing one or multiple values from a list.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
bun add @stacksjs/components
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Usage
|
|
12
|
-
|
|
13
|
-
```stx
|
|
14
|
-
<script server>
|
|
15
|
-
const people = [
|
|
16
|
-
{ id: 1, name: 'Wade Cooper' },
|
|
17
|
-
{ id: 2, name: 'Arlene Mccoy' },
|
|
18
|
-
{ id: 3, name: 'Devon Webb' }
|
|
19
|
-
]
|
|
20
|
-
|
|
21
|
-
let selected = people[0]
|
|
22
|
-
|
|
23
|
-
function handleChange(person) {
|
|
24
|
-
selected = person
|
|
25
|
-
}
|
|
26
|
-
</script>
|
|
27
|
-
|
|
28
|
-
<Listbox :value="selected" :onChange="handleChange">
|
|
29
|
-
<ListboxLabel>Assign to</ListboxLabel>
|
|
30
|
-
|
|
31
|
-
<ListboxButton>{{ selected.name }}</ListboxButton>
|
|
32
|
-
|
|
33
|
-
<ListboxOptions>
|
|
34
|
-
@foreach(person in people)
|
|
35
|
-
<ListboxOption :value="person" :currentValue="selected" :onChange="handleChange">
|
|
36
|
-
{{ person.name }}
|
|
37
|
-
</ListboxOption>
|
|
38
|
-
@endforeach
|
|
39
|
-
</ListboxOptions>
|
|
40
|
-
</Listbox>
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Props
|
|
44
|
-
|
|
45
|
-
### Listbox
|
|
46
|
-
| Prop | Type | Default | Description |
|
|
47
|
-
|------|------|---------|-------------|
|
|
48
|
-
| `value` | `any` | - | Currently selected value(s) |
|
|
49
|
-
| `onChange` | `(value: any) => void` | - | Change handler |
|
|
50
|
-
| `multiple` | `boolean` | `false` | Allow multiple selection |
|
|
51
|
-
| `className` | `string` | `''` | Additional CSS classes |
|
|
52
|
-
| `as` | `string` | `'div'` | HTML element to render |
|
|
53
|
-
|
|
54
|
-
### ListboxButton
|
|
55
|
-
| Prop | Type | Default | Description |
|
|
56
|
-
|------|------|---------|-------------|
|
|
57
|
-
| `className` | `string` | `''` | Additional CSS classes |
|
|
58
|
-
| `as` | `string` | `'button'` | HTML element to render |
|
|
59
|
-
| `disabled` | `boolean` | `false` | Disable the button |
|
|
60
|
-
|
|
61
|
-
### ListboxOptions
|
|
62
|
-
| Prop | Type | Default | Description |
|
|
63
|
-
|------|------|---------|-------------|
|
|
64
|
-
| `className` | `string` | `''` | Additional CSS classes |
|
|
65
|
-
| `as` | `string` | `'ul'` | HTML element to render |
|
|
66
|
-
| `static` | `boolean` | `false` | Keep visible regardless of state |
|
|
67
|
-
|
|
68
|
-
### ListboxOption
|
|
69
|
-
| Prop | Type | Default | Description |
|
|
70
|
-
|------|------|---------|-------------|
|
|
71
|
-
| `value` | `any` | - | Option value |
|
|
72
|
-
| `disabled` | `boolean` | `false` | Disable the option |
|
|
73
|
-
| `className` | `string` | `''` | Additional CSS classes |
|
|
74
|
-
| `as` | `string` | `'li'` | HTML element to render |
|
|
75
|
-
| `currentValue` | `any` | - | Current selected value(s) |
|
|
76
|
-
| `onChange` | `(value: any) => void` | - | Change handler |
|
|
77
|
-
|
|
78
|
-
### ListboxLabel
|
|
79
|
-
| Prop | Type | Default | Description |
|
|
80
|
-
|------|------|---------|-------------|
|
|
81
|
-
| `className` | `string` | `''` | Additional CSS classes |
|
|
82
|
-
| `as` | `string` | `'label'` | HTML element to render |
|
|
83
|
-
|
|
84
|
-
## Examples
|
|
85
|
-
|
|
86
|
-
### Multiple Selection
|
|
87
|
-
|
|
88
|
-
```stx
|
|
89
|
-
<script server>
|
|
90
|
-
let selectedPeople = [people[0], people[1]]
|
|
91
|
-
|
|
92
|
-
function handleChange(person) {
|
|
93
|
-
if (selectedPeople.includes(person)) {
|
|
94
|
-
selectedPeople = selectedPeople.filter(p => p !== person)
|
|
95
|
-
} else {
|
|
96
|
-
selectedPeople = [...selectedPeople, person]
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
</script>
|
|
100
|
-
|
|
101
|
-
<Listbox :value="selectedPeople" :onChange="handleChange" multiple>
|
|
102
|
-
<!-- ... -->
|
|
103
|
-
</Listbox>
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### With Avatars
|
|
107
|
-
|
|
108
|
-
```stx
|
|
109
|
-
<ListboxOption :value="person">
|
|
110
|
-
<div class="flex items-center">
|
|
111
|
-
<img src="{{ person.avatar }}" alt="" class="h-6 w-6 rounded-full mr-2" />
|
|
112
|
-
{{ person.name }}
|
|
113
|
-
</div>
|
|
114
|
-
</ListboxOption>
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Disabled Option
|
|
118
|
-
|
|
119
|
-
```stx
|
|
120
|
-
<ListboxOption :value="person" disabled>
|
|
121
|
-
{{ person.name }} (unavailable)
|
|
122
|
-
</ListboxOption>
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
## Features
|
|
126
|
-
|
|
127
|
-
- Single or multiple selection
|
|
128
|
-
- Keyboard navigation
|
|
129
|
-
- Search/filter support
|
|
130
|
-
- Dark mode support
|
|
131
|
-
- Accessible (WAI-ARIA)
|
|
132
|
-
- Disabled state
|
|
133
|
-
- Active state on hover
|
|
134
|
-
- Check icon for selected items
|
|
135
|
-
- Customizable styling
|
package/src/ui/listbox/index.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
export { default as Listbox } from './Listbox.stx'
|
|
2
|
-
export { default as ListboxButton } from './ListboxButton.stx'
|
|
3
|
-
export { default as ListboxLabel } from './ListboxLabel.stx'
|
|
4
|
-
export { default as ListboxOption } from './ListboxOption.stx'
|
|
5
|
-
export { default as ListboxOptions } from './ListboxOptions.stx'
|
|
6
|
-
|
|
7
|
-
export interface ListboxProps {
|
|
8
|
-
value?: any
|
|
9
|
-
onChange?: (value: any) => void
|
|
10
|
-
multiple?: boolean
|
|
11
|
-
className?: string
|
|
12
|
-
as?: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface ListboxButtonProps {
|
|
16
|
-
className?: string
|
|
17
|
-
as?: string
|
|
18
|
-
disabled?: boolean
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface ListboxOptionsProps {
|
|
22
|
-
className?: string
|
|
23
|
-
as?: string
|
|
24
|
-
static?: boolean
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface ListboxOptionProps {
|
|
28
|
-
value: any
|
|
29
|
-
disabled?: boolean
|
|
30
|
-
className?: string
|
|
31
|
-
as?: string
|
|
32
|
-
currentValue?: any
|
|
33
|
-
onChange?: (value: any) => void
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface ListboxLabelProps {
|
|
37
|
-
className?: string
|
|
38
|
-
as?: string
|
|
39
|
-
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const items = $props.items || []
|
|
3
|
-
export const active = $props.active || ''
|
|
4
|
-
export const orientation = $props.orientation || 'horizontal'
|
|
5
|
-
export const variant = $props.variant || 'default'
|
|
6
|
-
export const size = $props.size || 'md'
|
|
7
|
-
export const className = $props.className || ''
|
|
8
|
-
|
|
9
|
-
const containerBaseClasses = orientation === 'horizontal' ? 'flex items-center' : 'flex flex-col'
|
|
10
|
-
export const containerClasses = `${containerBaseClasses} ${className}`.trim()
|
|
11
|
-
export const gapClasses = orientation === 'horizontal' ? 'gap-1' : 'gap-0.5'
|
|
12
|
-
</script>
|
|
13
|
-
|
|
14
|
-
<script client>
|
|
15
|
-
const emit = defineEmits()
|
|
16
|
-
const items = {{ items }}
|
|
17
|
-
const variant = {{ variant }}
|
|
18
|
-
const size = {{ size }}
|
|
19
|
-
const initialActive = {{ active }}
|
|
20
|
-
const activeKey = state(initialActive)
|
|
21
|
-
|
|
22
|
-
function isActive(item) {
|
|
23
|
-
const a = activeKey()
|
|
24
|
-
if (typeof item.href === 'string' && typeof a === 'string') {
|
|
25
|
-
if (item.href === a) return true
|
|
26
|
-
if (a.startsWith(item.href)) return true
|
|
27
|
-
}
|
|
28
|
-
if (item.id && item.id === a) return true
|
|
29
|
-
return false
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function getItemClasses(item) {
|
|
33
|
-
const isActiveItem = isActive(item)
|
|
34
|
-
const sizeClasses = { sm: 'px-2 py-1 text-sm', md: 'px-3 py-2 text-base', lg: 'px-4 py-3 text-lg' }
|
|
35
|
-
let cls = sizeClasses[size] || sizeClasses.md
|
|
36
|
-
if (variant === 'default') {
|
|
37
|
-
cls += isActiveItem
|
|
38
|
-
? ' text-gray-900 dark:text-gray-100 font-medium'
|
|
39
|
-
: ' text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'
|
|
40
|
-
}
|
|
41
|
-
else if (variant === 'pills') {
|
|
42
|
-
cls += isActiveItem
|
|
43
|
-
? ' bg-blue-600 text-white font-medium rounded-full'
|
|
44
|
-
: ' text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full'
|
|
45
|
-
}
|
|
46
|
-
else if (variant === 'underline') {
|
|
47
|
-
cls += isActiveItem
|
|
48
|
-
? ' text-blue-600 dark:text-blue-400 font-medium border-b-2 border-blue-600 dark:border-blue-400'
|
|
49
|
-
: ' text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 border-b-2 border-transparent'
|
|
50
|
-
}
|
|
51
|
-
else if (variant === 'sidebar') {
|
|
52
|
-
cls += isActiveItem
|
|
53
|
-
? ' bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 font-medium border-l-4 border-blue-600 dark:border-blue-400'
|
|
54
|
-
: ' text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 border-l-4 border-transparent'
|
|
55
|
-
}
|
|
56
|
-
cls += ' transition-all duration-200 cursor-pointer flex items-center gap-2'
|
|
57
|
-
if (item.disabled) cls += ' opacity-50 cursor-not-allowed pointer-events-none'
|
|
58
|
-
return cls.trim()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function onClickItem(item, event) {
|
|
62
|
-
if (item.disabled) {
|
|
63
|
-
event.preventDefault()
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
event.preventDefault()
|
|
67
|
-
activeKey.set(item.href || item.id || activeKey())
|
|
68
|
-
emit('navigate', item)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
defineExpose({ activeKey })
|
|
72
|
-
</script>
|
|
73
|
-
|
|
74
|
-
<nav class="{{ containerClasses }} {{ gapClasses }}" role="navigation" aria-label="Main navigation">
|
|
75
|
-
@foreach(item in items)
|
|
76
|
-
@if(item.href)
|
|
77
|
-
<a
|
|
78
|
-
href="{{ item.href }}"
|
|
79
|
-
:class="getItemClasses({{ JSON.stringify(item) }})"
|
|
80
|
-
@click="onClickItem({{ JSON.stringify(item) }}, $event)"
|
|
81
|
-
:aria-current="isActive({{ JSON.stringify(item) }}) ? 'page' : null"
|
|
82
|
-
@if(item.disabled)aria-disabled="true" tabindex="-1"@endif
|
|
83
|
-
>
|
|
84
|
-
@if(item.icon)
|
|
85
|
-
<span class="flex-shrink-0">{!! item.icon !!}</span>
|
|
86
|
-
@endif
|
|
87
|
-
<span>{{ item.label }}</span>
|
|
88
|
-
@if(item.badge)
|
|
89
|
-
<span class="ml-auto px-2 py-0.5 text-xs font-semibold rounded-full bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300">
|
|
90
|
-
{{ item.badge }}
|
|
91
|
-
</span>
|
|
92
|
-
@endif
|
|
93
|
-
</a>
|
|
94
|
-
@else
|
|
95
|
-
<button
|
|
96
|
-
type="button"
|
|
97
|
-
:class="getItemClasses({{ JSON.stringify(item) }})"
|
|
98
|
-
@click="onClickItem({{ JSON.stringify(item) }}, $event)"
|
|
99
|
-
@if(item.disabled)disabled aria-disabled="true"@endif
|
|
100
|
-
>
|
|
101
|
-
@if(item.icon)
|
|
102
|
-
<span class="flex-shrink-0">{!! item.icon !!}</span>
|
|
103
|
-
@endif
|
|
104
|
-
<span>{{ item.label }}</span>
|
|
105
|
-
@if(item.badge)
|
|
106
|
-
<span class="ml-auto px-2 py-0.5 text-xs font-semibold rounded-full bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300">
|
|
107
|
-
{{ item.badge }}
|
|
108
|
-
</span>
|
|
109
|
-
@endif
|
|
110
|
-
</button>
|
|
111
|
-
@endif
|
|
112
|
-
@endforeach
|
|
113
|
-
</nav>
|
|
@@ -1,352 +0,0 @@
|
|
|
1
|
-
# Navigator Component
|
|
2
|
-
|
|
3
|
-
A versatile navigation component that supports multiple orientations, variants, and styles. Perfect for main navigation, sidebars, tabs, and more.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- ✅ Multiple variants (default, pills, underline, sidebar)
|
|
8
|
-
- ✅ Horizontal and vertical orientations
|
|
9
|
-
- ✅ Active state handling
|
|
10
|
-
- ✅ Icon support
|
|
11
|
-
- ✅ Badge support
|
|
12
|
-
- ✅ Disabled states
|
|
13
|
-
- ✅ Multiple sizes (sm, md, lg)
|
|
14
|
-
- ✅ Custom navigation handlers
|
|
15
|
-
- ✅ Dark mode support
|
|
16
|
-
- ✅ Accessible with ARIA labels
|
|
17
|
-
- ✅ Keyboard navigation support
|
|
18
|
-
|
|
19
|
-
## Usage
|
|
20
|
-
|
|
21
|
-
### Basic Horizontal Navigation
|
|
22
|
-
|
|
23
|
-
```stx
|
|
24
|
-
<script>
|
|
25
|
-
import { Navigator } from '@stacksjs/components'
|
|
26
|
-
|
|
27
|
-
const items = [
|
|
28
|
-
{ id: 'home', label: 'Home', href: '/' },
|
|
29
|
-
{ id: 'about', label: 'About', href: '/about' },
|
|
30
|
-
{ id: 'contact', label: 'Contact', href: '/contact' },
|
|
31
|
-
]
|
|
32
|
-
|
|
33
|
-
let activeItem = 'home'
|
|
34
|
-
</script>
|
|
35
|
-
|
|
36
|
-
<Navigator items={items} active={activeItem} />
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### Vertical Sidebar Navigation
|
|
40
|
-
|
|
41
|
-
```stx
|
|
42
|
-
<script>
|
|
43
|
-
import { Navigator } from '@stacksjs/components'
|
|
44
|
-
|
|
45
|
-
const items = [
|
|
46
|
-
{ id: 'dashboard', label: 'Dashboard', href: '/dashboard' },
|
|
47
|
-
{ id: 'projects', label: 'Projects', href: '/projects' },
|
|
48
|
-
{ id: 'team', label: 'Team', href: '/team' },
|
|
49
|
-
{ id: 'settings', label: 'Settings', href: '/settings' },
|
|
50
|
-
]
|
|
51
|
-
</script>
|
|
52
|
-
|
|
53
|
-
<Navigator
|
|
54
|
-
items={items}
|
|
55
|
-
active="dashboard"
|
|
56
|
-
orientation="vertical"
|
|
57
|
-
variant="sidebar"
|
|
58
|
-
/>
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### Pills Navigation
|
|
62
|
-
|
|
63
|
-
```stx
|
|
64
|
-
<script>
|
|
65
|
-
import { Navigator } from '@stacksjs/components'
|
|
66
|
-
|
|
67
|
-
const items = [
|
|
68
|
-
{ id: 'overview', label: 'Overview', href: '/overview' },
|
|
69
|
-
{ id: 'analytics', label: 'Analytics', href: '/analytics' },
|
|
70
|
-
{ id: 'reports', label: 'Reports', href: '/reports' },
|
|
71
|
-
]
|
|
72
|
-
</script>
|
|
73
|
-
|
|
74
|
-
<Navigator
|
|
75
|
-
items={items}
|
|
76
|
-
active="overview"
|
|
77
|
-
variant="pills"
|
|
78
|
-
/>
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Underline Tabs
|
|
82
|
-
|
|
83
|
-
```stx
|
|
84
|
-
<script>
|
|
85
|
-
import { Navigator } from '@stacksjs/components'
|
|
86
|
-
|
|
87
|
-
const tabs = [
|
|
88
|
-
{ id: 'profile', label: 'Profile', href: '#profile' },
|
|
89
|
-
{ id: 'security', label: 'Security', href: '#security' },
|
|
90
|
-
{ id: 'notifications', label: 'Notifications', href: '#notifications' },
|
|
91
|
-
]
|
|
92
|
-
</script>
|
|
93
|
-
|
|
94
|
-
<Navigator
|
|
95
|
-
items={tabs}
|
|
96
|
-
active="profile"
|
|
97
|
-
variant="underline"
|
|
98
|
-
/>
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### With Icons
|
|
102
|
-
|
|
103
|
-
```stx
|
|
104
|
-
<script>
|
|
105
|
-
import { Navigator } from '@stacksjs/components'
|
|
106
|
-
|
|
107
|
-
const items = [
|
|
108
|
-
{
|
|
109
|
-
id: 'home',
|
|
110
|
-
label: 'Home',
|
|
111
|
-
href: '/',
|
|
112
|
-
icon: '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" /></svg>',
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
id: 'search',
|
|
116
|
-
label: 'Search',
|
|
117
|
-
href: '/search',
|
|
118
|
-
icon: '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><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>',
|
|
119
|
-
},
|
|
120
|
-
]
|
|
121
|
-
</script>
|
|
122
|
-
|
|
123
|
-
<Navigator items={items} active="home" />
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### With Badges
|
|
127
|
-
|
|
128
|
-
```stx
|
|
129
|
-
<script>
|
|
130
|
-
import { Navigator } from '@stacksjs/components'
|
|
131
|
-
|
|
132
|
-
const items = [
|
|
133
|
-
{ id: 'inbox', label: 'Inbox', href: '/inbox', badge: '12' },
|
|
134
|
-
{ id: 'drafts', label: 'Drafts', href: '/drafts', badge: '3' },
|
|
135
|
-
{ id: 'sent', label: 'Sent', href: '/sent' },
|
|
136
|
-
]
|
|
137
|
-
</script>
|
|
138
|
-
|
|
139
|
-
<Navigator items={items} active="inbox" variant="sidebar" orientation="vertical" />
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### With Disabled Items
|
|
143
|
-
|
|
144
|
-
```stx
|
|
145
|
-
<script>
|
|
146
|
-
import { Navigator } from '@stacksjs/components'
|
|
147
|
-
|
|
148
|
-
const items = [
|
|
149
|
-
{ id: 'enabled', label: 'Enabled', href: '/enabled' },
|
|
150
|
-
{ id: 'disabled', label: 'Disabled (Coming Soon)', href: '/disabled', disabled: true },
|
|
151
|
-
{ id: 'another', label: 'Another Link', href: '/another' },
|
|
152
|
-
]
|
|
153
|
-
</script>
|
|
154
|
-
|
|
155
|
-
<Navigator items={items} active="enabled" />
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### With Custom Navigation Handler
|
|
159
|
-
|
|
160
|
-
```stx
|
|
161
|
-
<script>
|
|
162
|
-
import { Navigator } from '@stacksjs/components'
|
|
163
|
-
|
|
164
|
-
const items = [
|
|
165
|
-
{ id: 'tab1', label: 'Tab 1' },
|
|
166
|
-
{ id: 'tab2', label: 'Tab 2' },
|
|
167
|
-
{ id: 'tab3', label: 'Tab 3' },
|
|
168
|
-
]
|
|
169
|
-
|
|
170
|
-
let activeTab = 'tab1'
|
|
171
|
-
|
|
172
|
-
function handleNavigate(item) {
|
|
173
|
-
activeTab = item.id
|
|
174
|
-
console.log('Navigated to:', item.label)
|
|
175
|
-
// Custom logic here (e.g., switch content, fetch data, etc.)
|
|
176
|
-
}
|
|
177
|
-
</script>
|
|
178
|
-
|
|
179
|
-
<Navigator
|
|
180
|
-
items={items}
|
|
181
|
-
active={activeTab}
|
|
182
|
-
onNavigate={handleNavigate}
|
|
183
|
-
variant="underline"
|
|
184
|
-
/>
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
## Props
|
|
188
|
-
|
|
189
|
-
| Prop | Type | Default | Description |
|
|
190
|
-
|------|------|---------|-------------|
|
|
191
|
-
| `items` | `NavigatorItem[]` | `[]` | Array of navigation items |
|
|
192
|
-
| `active` | `string` | `''` | ID or href of the currently active item |
|
|
193
|
-
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Layout orientation |
|
|
194
|
-
| `variant` | `'default' \| 'pills' \| 'underline' \| 'sidebar'` | `'default'` | Visual style variant |
|
|
195
|
-
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size of navigation items |
|
|
196
|
-
| `onNavigate` | `(item: NavigatorItem) => void` | - | Custom navigation handler (prevents default link behavior) |
|
|
197
|
-
| `className` | `string` | `''` | Additional CSS classes |
|
|
198
|
-
|
|
199
|
-
### NavigatorItem Interface
|
|
200
|
-
|
|
201
|
-
```typescript
|
|
202
|
-
interface NavigatorItem {
|
|
203
|
-
id?: string // Unique identifier
|
|
204
|
-
label: string // Display text
|
|
205
|
-
href?: string // Link URL (renders as <a> if provided, <button> otherwise)
|
|
206
|
-
icon?: string // SVG icon HTML
|
|
207
|
-
badge?: string | number // Badge text/number
|
|
208
|
-
disabled?: boolean // Whether the item is disabled
|
|
209
|
-
}
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
## Variants
|
|
213
|
-
|
|
214
|
-
### Default
|
|
215
|
-
Clean, simple navigation with subtle hover effects.
|
|
216
|
-
|
|
217
|
-
### Pills
|
|
218
|
-
Rounded pill-style navigation with filled active state.
|
|
219
|
-
|
|
220
|
-
### Underline
|
|
221
|
-
Tab-style navigation with bottom border indicator.
|
|
222
|
-
|
|
223
|
-
### Sidebar
|
|
224
|
-
Left-bordered navigation optimized for vertical sidebars.
|
|
225
|
-
|
|
226
|
-
## Sizes
|
|
227
|
-
|
|
228
|
-
- **sm**: Compact padding and text
|
|
229
|
-
- **md**: Default comfortable size
|
|
230
|
-
- **lg**: Large padding and text
|
|
231
|
-
|
|
232
|
-
## Examples
|
|
233
|
-
|
|
234
|
-
### App Header Navigation
|
|
235
|
-
|
|
236
|
-
```stx
|
|
237
|
-
<script>
|
|
238
|
-
import { Navigator } from '@stacksjs/components'
|
|
239
|
-
|
|
240
|
-
const mainNav = [
|
|
241
|
-
{ id: 'products', label: 'Products', href: '/products' },
|
|
242
|
-
{ id: 'pricing', label: 'Pricing', href: '/pricing' },
|
|
243
|
-
{ id: 'docs', label: 'Docs', href: '/docs' },
|
|
244
|
-
{ id: 'blog', label: 'Blog', href: '/blog' },
|
|
245
|
-
]
|
|
246
|
-
</script>
|
|
247
|
-
|
|
248
|
-
<header class="bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700">
|
|
249
|
-
<div class="max-w-7xl mx-auto px-4 py-4">
|
|
250
|
-
<Navigator items={mainNav} active="/products" />
|
|
251
|
-
</div>
|
|
252
|
-
</header>
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### Dashboard Sidebar
|
|
256
|
-
|
|
257
|
-
```stx
|
|
258
|
-
<script>
|
|
259
|
-
import { Navigator } from '@stacksjs/components'
|
|
260
|
-
|
|
261
|
-
const sidebarNav = [
|
|
262
|
-
{
|
|
263
|
-
id: 'dashboard',
|
|
264
|
-
label: 'Dashboard',
|
|
265
|
-
href: '/dashboard',
|
|
266
|
-
icon: '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" /></svg>',
|
|
267
|
-
},
|
|
268
|
-
{
|
|
269
|
-
id: 'projects',
|
|
270
|
-
label: 'Projects',
|
|
271
|
-
href: '/projects',
|
|
272
|
-
badge: '5',
|
|
273
|
-
icon: '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" /></svg>',
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
id: 'team',
|
|
277
|
-
label: 'Team',
|
|
278
|
-
href: '/team',
|
|
279
|
-
icon: '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" /></svg>',
|
|
280
|
-
},
|
|
281
|
-
]
|
|
282
|
-
</script>
|
|
283
|
-
|
|
284
|
-
<aside class="w-64 bg-white dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 h-full">
|
|
285
|
-
<Navigator
|
|
286
|
-
items={sidebarNav}
|
|
287
|
-
active="/dashboard"
|
|
288
|
-
orientation="vertical"
|
|
289
|
-
variant="sidebar"
|
|
290
|
-
/>
|
|
291
|
-
</aside>
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
### Settings Tabs
|
|
295
|
-
|
|
296
|
-
```stx
|
|
297
|
-
<script>
|
|
298
|
-
import { Navigator } from '@stacksjs/components'
|
|
299
|
-
|
|
300
|
-
const settingsTabs = [
|
|
301
|
-
{ id: 'general', label: 'General', href: '#general' },
|
|
302
|
-
{ id: 'security', label: 'Security', href: '#security' },
|
|
303
|
-
{ id: 'notifications', label: 'Notifications', href: '#notifications' },
|
|
304
|
-
{ id: 'billing', label: 'Billing', href: '#billing' },
|
|
305
|
-
]
|
|
306
|
-
|
|
307
|
-
let activeTab = 'general'
|
|
308
|
-
</script>
|
|
309
|
-
|
|
310
|
-
<div class="border-b border-gray-200 dark:border-gray-700 mb-6">
|
|
311
|
-
<Navigator
|
|
312
|
-
items={settingsTabs}
|
|
313
|
-
active={activeTab}
|
|
314
|
-
variant="underline"
|
|
315
|
-
/>
|
|
316
|
-
</div>
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
## Styling
|
|
320
|
-
|
|
321
|
-
The navigator uses utility-first CSS classes and supports dark mode. Customize appearance by passing additional classes:
|
|
322
|
-
|
|
323
|
-
```stx
|
|
324
|
-
<Navigator
|
|
325
|
-
className="bg-gray-50 dark:bg-gray-900 rounded-lg p-2"
|
|
326
|
-
items={items}
|
|
327
|
-
active="home"
|
|
328
|
-
/>
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
## Accessibility
|
|
332
|
-
|
|
333
|
-
- Semantic HTML (`<nav>`, `<a>`, `<button>`)
|
|
334
|
-
- ARIA labels for navigation role
|
|
335
|
-
- `aria-current="page"` for active items
|
|
336
|
-
- `aria-disabled` for disabled items
|
|
337
|
-
- Keyboard navigation support
|
|
338
|
-
- Focus indicators
|
|
339
|
-
|
|
340
|
-
## Browser Support
|
|
341
|
-
|
|
342
|
-
Works in all modern browsers that support:
|
|
343
|
-
- CSS Flexbox
|
|
344
|
-
- CSS custom properties
|
|
345
|
-
- ES6+ JavaScript
|
|
346
|
-
|
|
347
|
-
## Related Components
|
|
348
|
-
|
|
349
|
-
- **Breadcrumb**: Hierarchical navigation trail
|
|
350
|
-
- **Tabs**: Content switching interface
|
|
351
|
-
- **Sidebar**: Full sidebar layout with navigation
|
|
352
|
-
- **Menu**: Dropdown menu navigation
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export { default as Navigator } from './Navigator.stx'
|
|
2
|
-
|
|
3
|
-
export interface NavigatorItem {
|
|
4
|
-
id?: string
|
|
5
|
-
label: string
|
|
6
|
-
href?: string
|
|
7
|
-
icon?: string
|
|
8
|
-
badge?: string | number
|
|
9
|
-
disabled?: boolean
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface NavigatorProps {
|
|
13
|
-
items: NavigatorItem[]
|
|
14
|
-
active?: string // ID or href of active item
|
|
15
|
-
orientation?: 'horizontal' | 'vertical'
|
|
16
|
-
variant?: 'default' | 'pills' | 'underline' | 'sidebar'
|
|
17
|
-
size?: 'sm' | 'md' | 'lg'
|
|
18
|
-
onNavigate?: (item: NavigatorItem) => void
|
|
19
|
-
className?: string
|
|
20
|
-
}
|