@stacksjs/components 0.2.92 → 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/{Sidebar-yb115a2w.stx → Sidebar-4hn7vw4n.stx} +18 -0
- package/dist/index.js +5 -5
- 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 -458
- 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,96 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const value = $props.value
|
|
3
|
-
export const className = $props.className || ''
|
|
4
|
-
export const as = $props.as || 'div'
|
|
5
|
-
|
|
6
|
-
const baseClasses = 'relative'
|
|
7
|
-
export const comboboxClasses = `${baseClasses} ${className}`.trim()
|
|
8
|
-
export const comboboxInstanceId = `stx-cb-${Math.random().toString(36).slice(2, 11)}`
|
|
9
|
-
</script>
|
|
10
|
-
|
|
11
|
-
<script client>
|
|
12
|
-
const emit = defineEmits()
|
|
13
|
-
const comboboxInstanceId = {{ comboboxInstanceId }}
|
|
14
|
-
const initialValue = {{ value === undefined ? 'null' : value }}
|
|
15
|
-
|
|
16
|
-
const isOpen = state(false)
|
|
17
|
-
const selected = state(initialValue)
|
|
18
|
-
const query = state('')
|
|
19
|
-
let rootEl = null
|
|
20
|
-
let outsideHandler = null
|
|
21
|
-
|
|
22
|
-
function isSelectedValue(v) {
|
|
23
|
-
return selected() === v
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function selectValue(v) {
|
|
27
|
-
selected.set(v)
|
|
28
|
-
isOpen.set(false)
|
|
29
|
-
syncOptionStates()
|
|
30
|
-
emit('change', v)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function syncOptionStates() {
|
|
34
|
-
if (!rootEl) return
|
|
35
|
-
const options = rootEl.querySelectorAll('[data-stx-combobox-option]')
|
|
36
|
-
for (const opt of options) {
|
|
37
|
-
const raw = opt.dataset.optionValue
|
|
38
|
-
let v
|
|
39
|
-
try { v = JSON.parse(raw ?? 'null') }
|
|
40
|
-
catch { v = raw }
|
|
41
|
-
const sel = isSelectedValue(v)
|
|
42
|
-
opt.setAttribute('aria-selected', sel ? 'true' : 'false')
|
|
43
|
-
opt.setAttribute('data-selected', sel ? 'true' : 'false')
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function open() { if (!isOpen()) { isOpen.set(true) } }
|
|
48
|
-
function close() { if (isOpen()) isOpen.set(false) }
|
|
49
|
-
function toggle() { isOpen() ? close() : open() }
|
|
50
|
-
|
|
51
|
-
function onToggle(event) { event.stopPropagation(); toggle() }
|
|
52
|
-
function onSelect(event) { event.stopPropagation(); selectValue(event.detail) }
|
|
53
|
-
function onQuery(event) {
|
|
54
|
-
event.stopPropagation()
|
|
55
|
-
query.set(event.detail)
|
|
56
|
-
if (!isOpen()) open()
|
|
57
|
-
emit('query', event.detail)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
onMount(() => {
|
|
61
|
-
rootEl = document.querySelector(`[data-combobox-id="${comboboxInstanceId}"]`)
|
|
62
|
-
syncOptionStates()
|
|
63
|
-
outsideHandler = (event) => {
|
|
64
|
-
if (!isOpen()) return
|
|
65
|
-
if (rootEl && !rootEl.contains(event.target)) close()
|
|
66
|
-
}
|
|
67
|
-
document.addEventListener('click', outsideHandler, true)
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
onDestroy(() => {
|
|
71
|
-
if (outsideHandler) document.removeEventListener('click', outsideHandler, true)
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
const dataState = derived(() => isOpen() ? 'open' : 'closed')
|
|
75
|
-
|
|
76
|
-
defineExpose({ isOpen, selected, query, toggle, open, close, selectValue })
|
|
77
|
-
</script>
|
|
78
|
-
|
|
79
|
-
<component
|
|
80
|
-
:is="{{ as }}"
|
|
81
|
-
class="{{ comboboxClasses }}"
|
|
82
|
-
data-stx-combobox
|
|
83
|
-
data-combobox-id="{{ comboboxInstanceId }}"
|
|
84
|
-
:data-state="dataState()"
|
|
85
|
-
@stx:combobox-toggle="onToggle($event)"
|
|
86
|
-
@stx:combobox-select="onSelect($event)"
|
|
87
|
-
@stx:combobox-query="onQuery($event)"
|
|
88
|
-
>
|
|
89
|
-
<slot />
|
|
90
|
-
</component>
|
|
91
|
-
|
|
92
|
-
<style>
|
|
93
|
-
[data-stx-combobox][data-state="closed"] [data-stx-combobox-options] {
|
|
94
|
-
display: none;
|
|
95
|
-
}
|
|
96
|
-
</style>
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const className = $props.className || ''
|
|
3
|
-
export const as = $props.as || 'button'
|
|
4
|
-
|
|
5
|
-
const baseClasses = 'absolute inset-y-0 right-0 flex items-center pr-2'
|
|
6
|
-
export const buttonClasses = `${baseClasses} ${className}`.trim()
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
<script client>
|
|
10
|
-
function onClick(event) {
|
|
11
|
-
event.currentTarget.dispatchEvent(new CustomEvent('stx:combobox-toggle', { bubbles: true }))
|
|
12
|
-
}
|
|
13
|
-
</script>
|
|
14
|
-
|
|
15
|
-
<component
|
|
16
|
-
:is="{{ as }}"
|
|
17
|
-
class="{{ buttonClasses }}"
|
|
18
|
-
data-stx-combobox-button
|
|
19
|
-
tabindex="-1"
|
|
20
|
-
@click="onClick($event)"
|
|
21
|
-
>
|
|
22
|
-
<svg class="h-5 w-5 text-neutral-400" viewBox="0 0 20 20" fill="none" stroke="currentColor">
|
|
23
|
-
<path d="M7 7l3-3 3 3m0 6l-3 3-3-3" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
|
24
|
-
</svg>
|
|
25
|
-
</component>
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const displayValue = $props.displayValue
|
|
3
|
-
export const className = $props.className || ''
|
|
4
|
-
export const placeholder = $props.placeholder || ''
|
|
5
|
-
export const disabled = $props.disabled || false
|
|
6
|
-
|
|
7
|
-
const baseClasses = 'w-full rounded-lg border-none bg-white dark:bg-neutral-800 py-2 pl-3 pr-10 text-sm leading-5 text-neutral-900 dark:text-white focus:ring-0 focus:outline-none focus-visible:border-blue-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2'
|
|
8
|
-
const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed' : ''
|
|
9
|
-
export const inputClasses = `${baseClasses} ${disabledClasses} ${className}`.trim()
|
|
10
|
-
</script>
|
|
11
|
-
|
|
12
|
-
<script client>
|
|
13
|
-
const isDisabled = {{ disabled }}
|
|
14
|
-
|
|
15
|
-
function onInput(event) {
|
|
16
|
-
if (isDisabled) return
|
|
17
|
-
event.currentTarget.dispatchEvent(
|
|
18
|
-
new CustomEvent('stx:combobox-query', { bubbles: true, detail: event.target.value }),
|
|
19
|
-
)
|
|
20
|
-
}
|
|
21
|
-
</script>
|
|
22
|
-
|
|
23
|
-
<input
|
|
24
|
-
type="text"
|
|
25
|
-
class="{{ inputClasses }}"
|
|
26
|
-
data-stx-combobox-input
|
|
27
|
-
placeholder="{{ placeholder }}"
|
|
28
|
-
value="{{ displayValue }}"
|
|
29
|
-
@if(disabled)disabled@endif
|
|
30
|
-
@input="onInput($event)"
|
|
31
|
-
autocomplete="off"
|
|
32
|
-
/>
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const value = $props.value
|
|
3
|
-
export const disabled = $props.disabled || false
|
|
4
|
-
export const className = $props.className || ''
|
|
5
|
-
export const as = $props.as || 'li'
|
|
6
|
-
|
|
7
|
-
const baseClasses = 'relative cursor-pointer select-none py-2 pl-10 pr-4 text-neutral-900 dark:text-neutral-100 hover:bg-blue-100 dark:hover:bg-blue-900'
|
|
8
|
-
const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed' : ''
|
|
9
|
-
export const optionClasses = `${baseClasses} ${disabledClasses} ${className}`.trim()
|
|
10
|
-
export const valueJson = JSON.stringify(value === undefined ? null : value)
|
|
11
|
-
</script>
|
|
12
|
-
|
|
13
|
-
<script client>
|
|
14
|
-
const isDisabled = {{ disabled }}
|
|
15
|
-
const optionValue = {{ value === undefined ? 'null' : value }}
|
|
16
|
-
|
|
17
|
-
function onClick(event) {
|
|
18
|
-
if (isDisabled) return
|
|
19
|
-
event.currentTarget.dispatchEvent(
|
|
20
|
-
new CustomEvent('stx:combobox-select', { bubbles: true, detail: optionValue }),
|
|
21
|
-
)
|
|
22
|
-
}
|
|
23
|
-
</script>
|
|
24
|
-
|
|
25
|
-
<component
|
|
26
|
-
:is="{{ as }}"
|
|
27
|
-
class="{{ optionClasses }}"
|
|
28
|
-
data-stx-combobox-option
|
|
29
|
-
data-option-value="{{ valueJson }}"
|
|
30
|
-
role="option"
|
|
31
|
-
aria-selected="false"
|
|
32
|
-
@if(disabled)aria-disabled="true"@endif
|
|
33
|
-
@click="onClick($event)"
|
|
34
|
-
>
|
|
35
|
-
<span class="absolute inset-y-0 left-0 flex items-center pl-3 text-blue-600 dark:text-blue-400" data-stx-combobox-check>
|
|
36
|
-
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
|
37
|
-
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
|
|
38
|
-
</svg>
|
|
39
|
-
</span>
|
|
40
|
-
|
|
41
|
-
<slot :disabled="disabled" />
|
|
42
|
-
</component>
|
|
43
|
-
|
|
44
|
-
<style>
|
|
45
|
-
[data-stx-combobox-option][data-selected="false"] [data-stx-combobox-check],
|
|
46
|
-
[data-stx-combobox-option]:not([data-selected]) [data-stx-combobox-check] {
|
|
47
|
-
display: none;
|
|
48
|
-
}
|
|
49
|
-
</style>
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const className = $props.className || ''
|
|
3
|
-
export const as = $props.as || 'ul'
|
|
4
|
-
|
|
5
|
-
const baseClasses = 'absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white dark:bg-neutral-800 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none'
|
|
6
|
-
export const optionsClasses = `${baseClasses} ${className}`.trim()
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
<component
|
|
10
|
-
:is="{{ as }}"
|
|
11
|
-
class="{{ optionsClasses }}"
|
|
12
|
-
data-stx-combobox-options
|
|
13
|
-
role="listbox"
|
|
14
|
-
>
|
|
15
|
-
<slot />
|
|
16
|
-
</component>
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
# Combobox Component
|
|
2
|
-
|
|
3
|
-
A searchable select component that combines an input with a listbox.
|
|
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
|
-
let query = ''
|
|
23
|
-
|
|
24
|
-
const filtered = query === ''
|
|
25
|
-
? people
|
|
26
|
-
: people.filter(person =>
|
|
27
|
-
person.name.toLowerCase().includes(query.toLowerCase())
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
function handleChange(person) {
|
|
31
|
-
selected = person
|
|
32
|
-
query = ''
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function handleQueryChange(value) {
|
|
36
|
-
query = value
|
|
37
|
-
}
|
|
38
|
-
</script>
|
|
39
|
-
|
|
40
|
-
<Combobox :value="selected" :onChange="handleChange">
|
|
41
|
-
<div class="relative mt-1">
|
|
42
|
-
<ComboboxInput
|
|
43
|
-
:displayValue="selected.name"
|
|
44
|
-
:onChange="handleQueryChange"
|
|
45
|
-
placeholder="Search people..."
|
|
46
|
-
/>
|
|
47
|
-
|
|
48
|
-
<ComboboxButton />
|
|
49
|
-
|
|
50
|
-
<ComboboxOptions>
|
|
51
|
-
@if(filtered.length === 0 && query !== '')
|
|
52
|
-
<div class="relative cursor-default select-none py-2 px-4 text-neutral-700 dark:text-neutral-300">
|
|
53
|
-
Nothing found.
|
|
54
|
-
</div>
|
|
55
|
-
@else
|
|
56
|
-
@foreach(person in filtered)
|
|
57
|
-
<ComboboxOption :value="person" :currentValue="selected" :onChange="handleChange">
|
|
58
|
-
{{ person.name }}
|
|
59
|
-
</ComboboxOption>
|
|
60
|
-
@endforeach
|
|
61
|
-
@endif
|
|
62
|
-
</ComboboxOptions>
|
|
63
|
-
</div>
|
|
64
|
-
</Combobox>
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Props
|
|
68
|
-
|
|
69
|
-
### Combobox
|
|
70
|
-
| Prop | Type | Default | Description |
|
|
71
|
-
|------|------|---------|-------------|
|
|
72
|
-
| `value` | `any` | - | Currently selected value |
|
|
73
|
-
| `onChange` | `(value: any) => void` | - | Change handler |
|
|
74
|
-
| `className` | `string` | `''` | Additional CSS classes |
|
|
75
|
-
| `as` | `string` | `'div'` | HTML element to render |
|
|
76
|
-
|
|
77
|
-
### ComboboxInput
|
|
78
|
-
| Prop | Type | Default | Description |
|
|
79
|
-
|------|------|---------|-------------|
|
|
80
|
-
| `displayValue` | `any` | - | Value to display in input |
|
|
81
|
-
| `onChange` | `(value: string) => void` | - | Input change handler |
|
|
82
|
-
| `className` | `string` | `''` | Additional CSS classes |
|
|
83
|
-
| `placeholder` | `string` | `''` | Input placeholder |
|
|
84
|
-
| `disabled` | `boolean` | `false` | Disable the input |
|
|
85
|
-
|
|
86
|
-
### ComboboxButton
|
|
87
|
-
| Prop | Type | Default | Description |
|
|
88
|
-
|------|------|---------|-------------|
|
|
89
|
-
| `className` | `string` | `''` | Additional CSS classes |
|
|
90
|
-
| `as` | `string` | `'button'` | HTML element to render |
|
|
91
|
-
|
|
92
|
-
### ComboboxOptions
|
|
93
|
-
| Prop | Type | Default | Description |
|
|
94
|
-
|------|------|---------|-------------|
|
|
95
|
-
| `className` | `string` | `''` | Additional CSS classes |
|
|
96
|
-
| `as` | `string` | `'ul'` | HTML element to render |
|
|
97
|
-
| `static` | `boolean` | `false` | Keep visible regardless of state |
|
|
98
|
-
|
|
99
|
-
### ComboboxOption
|
|
100
|
-
| Prop | Type | Default | Description |
|
|
101
|
-
|------|------|---------|-------------|
|
|
102
|
-
| `value` | `any` | - | Option value |
|
|
103
|
-
| `disabled` | `boolean` | `false` | Disable the option |
|
|
104
|
-
| `className` | `string` | `''` | Additional CSS classes |
|
|
105
|
-
| `as` | `string` | `'li'` | HTML element to render |
|
|
106
|
-
| `currentValue` | `any` | - | Current selected value |
|
|
107
|
-
| `onChange` | `(value: any) => void` | - | Change handler |
|
|
108
|
-
|
|
109
|
-
## Examples
|
|
110
|
-
|
|
111
|
-
### With Empty State
|
|
112
|
-
|
|
113
|
-
```stx
|
|
114
|
-
<ComboboxOptions>
|
|
115
|
-
@if(filtered.length === 0)
|
|
116
|
-
<div class="py-2 px-4 text-neutral-500 dark:text-neutral-400">
|
|
117
|
-
No results found for "{{ query }}"
|
|
118
|
-
</div>
|
|
119
|
-
@else
|
|
120
|
-
@foreach(item in filtered)
|
|
121
|
-
<ComboboxOption :value="item">
|
|
122
|
-
{{ item.name }}
|
|
123
|
-
</ComboboxOption>
|
|
124
|
-
@endforeach
|
|
125
|
-
@endif
|
|
126
|
-
</ComboboxOptions>
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### With Avatars
|
|
130
|
-
|
|
131
|
-
```stx
|
|
132
|
-
<ComboboxOption :value="person">
|
|
133
|
-
<div class="flex items-center gap-2">
|
|
134
|
-
<img src="{{ person.avatar }}" alt="" class="h-6 w-6 rounded-full" />
|
|
135
|
-
<span>{{ person.name }}</span>
|
|
136
|
-
</div>
|
|
137
|
-
</ComboboxOption>
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
## Features
|
|
141
|
-
|
|
142
|
-
- Searchable/filterable
|
|
143
|
-
- Keyboard navigation
|
|
144
|
-
- Empty state support
|
|
145
|
-
- Dark mode support
|
|
146
|
-
- Accessible (WAI-ARIA)
|
|
147
|
-
- Disabled state
|
|
148
|
-
- Active state on hover
|
|
149
|
-
- Check icon for selected item
|
|
150
|
-
- Customizable styling
|
package/src/ui/combobox/index.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
export { default as Combobox } from './Combobox.stx'
|
|
2
|
-
export { default as ComboboxButton } from './ComboboxButton.stx'
|
|
3
|
-
export { default as ComboboxInput } from './ComboboxInput.stx'
|
|
4
|
-
export { default as ComboboxOption } from './ComboboxOption.stx'
|
|
5
|
-
export { default as ComboboxOptions } from './ComboboxOptions.stx'
|
|
6
|
-
|
|
7
|
-
export interface ComboboxProps {
|
|
8
|
-
value?: any
|
|
9
|
-
onChange?: (value: any) => void
|
|
10
|
-
className?: string
|
|
11
|
-
as?: string
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface ComboboxInputProps {
|
|
15
|
-
displayValue?: any
|
|
16
|
-
onChange?: (value: string) => void
|
|
17
|
-
className?: string
|
|
18
|
-
placeholder?: string
|
|
19
|
-
disabled?: boolean
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface ComboboxButtonProps {
|
|
23
|
-
className?: string
|
|
24
|
-
as?: string
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface ComboboxOptionsProps {
|
|
28
|
-
className?: string
|
|
29
|
-
as?: string
|
|
30
|
-
static?: boolean
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface ComboboxOptionProps {
|
|
34
|
-
value: any
|
|
35
|
-
disabled?: boolean
|
|
36
|
-
className?: string
|
|
37
|
-
as?: string
|
|
38
|
-
currentValue?: any
|
|
39
|
-
onChange?: (value: any) => void
|
|
40
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const open = $props.open || false
|
|
3
|
-
export const initialQuery = $props.query || ''
|
|
4
|
-
export const className = $props.className || ''
|
|
5
|
-
|
|
6
|
-
const baseClasses = 'fixed inset-0 z-50 overflow-y-auto p-4 sm:p-6 md:p-20'
|
|
7
|
-
export const paletteClasses = `${baseClasses} ${className}`.trim()
|
|
8
|
-
export const paletteInstanceId = `stx-cmd-${Math.random().toString(36).slice(2, 11)}`
|
|
9
|
-
</script>
|
|
10
|
-
|
|
11
|
-
<script client>
|
|
12
|
-
const emit = defineEmits()
|
|
13
|
-
const paletteInstanceId = {{ paletteInstanceId }}
|
|
14
|
-
const isOpen = state({{ open }})
|
|
15
|
-
const query = state({{ initialQuery }})
|
|
16
|
-
let escHandler = null
|
|
17
|
-
|
|
18
|
-
function close() {
|
|
19
|
-
if (!isOpen()) return
|
|
20
|
-
isOpen.set(false)
|
|
21
|
-
emit('close')
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function show() {
|
|
25
|
-
if (isOpen()) return
|
|
26
|
-
isOpen.set(true)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function onQueryInput(event) {
|
|
30
|
-
query.set(event.target.value)
|
|
31
|
-
emit('query', event.target.value)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function onItemSelect(event) {
|
|
35
|
-
event.stopPropagation()
|
|
36
|
-
emit('select', event.detail)
|
|
37
|
-
close()
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
onMount(() => {
|
|
41
|
-
escHandler = (event) => {
|
|
42
|
-
if (event.key === 'Escape' && isOpen()) close()
|
|
43
|
-
}
|
|
44
|
-
document.addEventListener('keydown', escHandler)
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
onDestroy(() => {
|
|
48
|
-
if (escHandler) document.removeEventListener('keydown', escHandler)
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
defineExpose({ isOpen, query, show, close })
|
|
52
|
-
</script>
|
|
53
|
-
|
|
54
|
-
<div
|
|
55
|
-
:show="isOpen()"
|
|
56
|
-
class="{{ paletteClasses }}"
|
|
57
|
-
data-stx-command-palette
|
|
58
|
-
data-palette-id="{{ paletteInstanceId }}"
|
|
59
|
-
@stx:command-select="onItemSelect($event)"
|
|
60
|
-
>
|
|
61
|
-
<div class="fixed inset-0 bg-neutral-500 bg-opacity-25 dark:bg-opacity-50 transition-opacity" @click="close()"></div>
|
|
62
|
-
|
|
63
|
-
<div class="mx-auto max-w-xl transform divide-y divide-neutral-100 dark:divide-neutral-800 overflow-hidden rounded-xl bg-white dark:bg-neutral-900 shadow-2xl ring-1 ring-black ring-opacity-5 transition-all relative">
|
|
64
|
-
<div class="relative">
|
|
65
|
-
<svg class="pointer-events-none absolute top-3.5 left-4 h-5 w-5 text-neutral-400" viewBox="0 0 20 20" fill="currentColor">
|
|
66
|
-
<path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd" />
|
|
67
|
-
</svg>
|
|
68
|
-
<input
|
|
69
|
-
type="text"
|
|
70
|
-
class="h-12 w-full border-0 bg-transparent pl-11 pr-4 text-neutral-900 dark:text-white placeholder-neutral-400 focus:ring-0 sm:text-sm"
|
|
71
|
-
placeholder="Search..."
|
|
72
|
-
:value="query()"
|
|
73
|
-
@input="onQueryInput($event)"
|
|
74
|
-
/>
|
|
75
|
-
</div>
|
|
76
|
-
|
|
77
|
-
<div class="max-h-96 overflow-y-auto py-2">
|
|
78
|
-
<slot />
|
|
79
|
-
</div>
|
|
80
|
-
</div>
|
|
81
|
-
</div>
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const className = $props.className || ''
|
|
3
|
-
export const value = $props.value
|
|
4
|
-
|
|
5
|
-
const baseClasses = 'flex cursor-pointer select-none items-center px-4 py-2 text-neutral-900 dark:text-neutral-100 hover:bg-blue-600 hover:text-white'
|
|
6
|
-
export const itemClasses = `${baseClasses} ${className}`.trim()
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
<script client>
|
|
10
|
-
const emit = defineEmits()
|
|
11
|
-
const itemValue = {{ value === undefined ? 'null' : value }}
|
|
12
|
-
|
|
13
|
-
function onClick(event) {
|
|
14
|
-
emit('click', event)
|
|
15
|
-
event.currentTarget.dispatchEvent(
|
|
16
|
-
new CustomEvent('stx:command-select', { bubbles: true, detail: itemValue }),
|
|
17
|
-
)
|
|
18
|
-
}
|
|
19
|
-
</script>
|
|
20
|
-
|
|
21
|
-
<div
|
|
22
|
-
class="{{ itemClasses }}"
|
|
23
|
-
data-stx-command-item
|
|
24
|
-
@click="onClick($event)"
|
|
25
|
-
>
|
|
26
|
-
<slot />
|
|
27
|
-
</div>
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Command Palette Component
|
|
2
|
-
|
|
3
|
-
A searchable command menu for quick actions and navigation.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
bun add @stacksjs/components
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Usage
|
|
12
|
-
|
|
13
|
-
```stx
|
|
14
|
-
<script server>
|
|
15
|
-
let open = false
|
|
16
|
-
let query = ''
|
|
17
|
-
|
|
18
|
-
const commands = [
|
|
19
|
-
{ name: 'Create new file', action: () => console.log('create') },
|
|
20
|
-
{ name: 'Open settings', action: () => console.log('settings') }
|
|
21
|
-
]
|
|
22
|
-
|
|
23
|
-
const filtered = query === ''
|
|
24
|
-
? commands
|
|
25
|
-
: commands.filter(cmd => cmd.name.toLowerCase().includes(query.toLowerCase()))
|
|
26
|
-
</script>
|
|
27
|
-
|
|
28
|
-
<CommandPalette :open="open" :onClose="() => open = false" :query="query" :onQueryChange="(q) => query = q">
|
|
29
|
-
@foreach(command in filtered)
|
|
30
|
-
<CommandPaletteItem :onClick="command.action">
|
|
31
|
-
{{ command.name }}
|
|
32
|
-
</CommandPaletteItem>
|
|
33
|
-
@endforeach
|
|
34
|
-
</CommandPalette>
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Features
|
|
38
|
-
|
|
39
|
-
- Searchable
|
|
40
|
-
- Keyboard navigation
|
|
41
|
-
- Dark mode support
|
|
42
|
-
- Accessible
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export { default as CommandPalette } from './CommandPalette.stx'
|
|
2
|
-
export { default as CommandPaletteItem } from './CommandPaletteItem.stx'
|
|
3
|
-
|
|
4
|
-
export interface CommandPaletteProps {
|
|
5
|
-
open?: boolean
|
|
6
|
-
onClose?: () => void
|
|
7
|
-
query?: string
|
|
8
|
-
onQueryChange?: (query: string) => void
|
|
9
|
-
className?: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface CommandPaletteItemProps {
|
|
13
|
-
className?: string
|
|
14
|
-
onClick?: () => void
|
|
15
|
-
}
|
package/src/ui/dialog/Dialog.stx
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const open = $props.open || false
|
|
3
|
-
export const className = $props.className || ''
|
|
4
|
-
|
|
5
|
-
const baseClasses = 'relative z-50'
|
|
6
|
-
export const dialogClasses = `${baseClasses} ${className}`.trim()
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
<script client>
|
|
10
|
-
const emit = defineEmits()
|
|
11
|
-
// useReactiveProp wires `:open="parentSignal()"` from the parent into our
|
|
12
|
-
// local `isOpen` signal — when the parent's signal changes, bindAttr
|
|
13
|
-
// updates the root's `open` attribute, our MutationObserver picks it up,
|
|
14
|
-
// and isOpen flips. See stacksjs/stx#1704.
|
|
15
|
-
const isOpen = useReactiveProp('open', {{ open }})
|
|
16
|
-
|
|
17
|
-
function close() {
|
|
18
|
-
isOpen.set(false)
|
|
19
|
-
emit('close')
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function onBackdropKey(event) {
|
|
23
|
-
if (event.key === 'Escape') close()
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
defineExpose({
|
|
27
|
-
open: () => isOpen.set(true),
|
|
28
|
-
close,
|
|
29
|
-
isOpen,
|
|
30
|
-
})
|
|
31
|
-
</script>
|
|
32
|
-
|
|
33
|
-
<div
|
|
34
|
-
:show="isOpen()"
|
|
35
|
-
class="{{ dialogClasses }}"
|
|
36
|
-
role="dialog"
|
|
37
|
-
aria-modal="true"
|
|
38
|
-
@keydown="onBackdropKey($event)"
|
|
39
|
-
>
|
|
40
|
-
<slot />
|
|
41
|
-
</div>
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const className = $props.className || ''
|
|
3
|
-
export const as = $props.as || 'div'
|
|
4
|
-
|
|
5
|
-
const baseClasses = 'fixed inset-0 bg-black bg-opacity-25 dark:bg-opacity-50 transition-opacity'
|
|
6
|
-
const backdropClasses = `${baseClasses} ${className}`.trim()
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
<component :is="{{ as }}" class="{{ backdropClasses }}" aria-hidden="true" />
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const className = $props.className || ''
|
|
3
|
-
export const as = $props.as || 'p'
|
|
4
|
-
|
|
5
|
-
const baseClasses = 'mt-2 text-sm text-neutral-500 dark:text-neutral-400'
|
|
6
|
-
const descriptionClasses = `${baseClasses} ${className}`.trim()
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
<component :is="{{ as }}" class="{{ descriptionClasses }}">
|
|
10
|
-
<slot />
|
|
11
|
-
</component>
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const className = $props.className || ''
|
|
3
|
-
export const as = $props.as || 'div'
|
|
4
|
-
|
|
5
|
-
const baseClasses = 'fixed inset-0 overflow-y-auto'
|
|
6
|
-
const panelWrapperClasses = 'flex min-h-full items-center justify-center p-4 text-center'
|
|
7
|
-
const panelClasses = `transform overflow-hidden rounded-lg bg-white dark:bg-neutral-800 p-6 text-left align-middle shadow-xl transition-all ${className}`.trim()
|
|
8
|
-
</script>
|
|
9
|
-
|
|
10
|
-
<component :is="{{ as }}" class="{{ baseClasses }}">
|
|
11
|
-
<div class="{{ panelWrapperClasses }}">
|
|
12
|
-
<div class="{{ panelClasses }}">
|
|
13
|
-
<slot />
|
|
14
|
-
</div>
|
|
15
|
-
</div>
|
|
16
|
-
</component>
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
export const className = $props.className || ''
|
|
3
|
-
export const as = $props.as || 'h3'
|
|
4
|
-
|
|
5
|
-
const baseClasses = 'text-lg font-medium leading-6 text-neutral-900 dark:text-white'
|
|
6
|
-
const titleClasses = `${baseClasses} ${className}`.trim()
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
<component :is="{{ as }}" class="{{ titleClasses }}">
|
|
10
|
-
<slot />
|
|
11
|
-
</component>
|