@adea-ai/ui 0.61.0 → 0.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -6
- package/dist/LICENSE +201 -0
- package/dist/NOTICE +50 -0
- package/dist/components/composites/account-menu/index.js +2 -0
- package/dist/components/composites/list-row/index.js +2 -0
- package/dist/components/composites/settings/index.js +2 -0
- package/dist/components/composites/stat/index.js +2 -0
- package/dist/components/composites/update-dialog/index.js +2 -0
- package/dist/components/composites/workspace-mark/index.js +2 -0
- package/dist/components/conversation/index.js +6 -0
- package/dist/components/layout/app-shell/index.js +2 -0
- package/dist/components/layout/page/index.js +2 -0
- package/dist/components/layout/panel/index.js +2 -0
- package/dist/components/layout/side-rail/index.js +3 -0
- package/dist/components/layout/sidebar-nav/index.js +2 -0
- package/dist/components/layout/status-bar/index.js +2 -0
- package/dist/components/layout/top-bar/index.js +2 -0
- package/dist/components/motion/index.js +2 -2
- package/dist/components/theme/index.js +5 -0
- package/dist/components/ui/accordion/index.js +2 -0
- package/dist/components/ui/alert/index.js +2 -0
- package/dist/components/ui/alert-dialog/index.js +2 -0
- package/dist/components/ui/aspect-ratio/index.js +2 -0
- package/dist/components/ui/avatar/index.js +2 -0
- package/dist/components/ui/badge/index.js +2 -0
- package/dist/components/ui/board/index.js +2 -0
- package/dist/components/ui/breadcrumb/index.js +2 -0
- package/dist/components/ui/button/index.js +2 -0
- package/dist/components/ui/button-group/index.js +2 -0
- package/dist/components/ui/calendar/index.js +2 -0
- package/dist/components/ui/card/index.js +2 -0
- package/dist/components/ui/carousel/index.js +2 -0
- package/dist/components/ui/chart/index.js +2 -0
- package/dist/components/ui/checkbox/index.js +2 -0
- package/dist/components/ui/code-block/index.js +2 -0
- package/dist/components/ui/collapsible/index.js +2 -0
- package/dist/components/ui/combobox/index.js +2 -0
- package/dist/components/ui/command/index.js +2 -0
- package/dist/components/ui/context-menu/index.js +2 -0
- package/dist/components/ui/detail-panel/index.js +2 -0
- package/dist/components/ui/dialog/index.js +2 -0
- package/dist/components/ui/diff-block/index.js +2 -0
- package/dist/components/ui/drawer/index.js +2 -0
- package/dist/components/ui/dropdown-menu/index.js +2 -0
- package/dist/components/ui/empty/index.js +2 -0
- package/dist/components/ui/entity-icon/index.js +2 -0
- package/dist/components/ui/field/index.js +2 -0
- package/dist/components/ui/hover-card/index.js +2 -0
- package/dist/components/ui/input/index.js +2 -0
- package/dist/components/ui/input-group/index.js +2 -0
- package/dist/components/ui/input-otp/index.js +2 -0
- package/dist/components/ui/item/index.js +2 -0
- package/dist/components/ui/kbd/index.js +2 -0
- package/dist/components/ui/label/index.js +2 -0
- package/dist/components/ui/menubar/index.js +2 -0
- package/dist/components/ui/modal-dialog/index.js +2 -0
- package/dist/components/ui/navigation-menu/index.js +2 -0
- package/dist/components/ui/pagination/index.js +2 -0
- package/dist/components/ui/popover/index.js +2 -0
- package/dist/components/ui/progress/index.js +2 -0
- package/dist/components/ui/radio-group/index.js +2 -0
- package/dist/components/ui/resizable/index.js +2 -0
- package/dist/components/ui/scroll-area/index.js +2 -0
- package/dist/components/ui/select/index.js +2 -0
- package/dist/components/ui/separator/index.js +2 -0
- package/dist/components/ui/sheet/index.js +2 -0
- package/dist/components/ui/skeleton/index.js +2 -0
- package/dist/components/ui/slider/index.js +2 -0
- package/dist/components/ui/spinner/index.js +2 -0
- package/dist/components/ui/status-chip/index.js +2 -0
- package/dist/components/ui/switch/index.js +2 -0
- package/dist/components/ui/table/index.js +2 -0
- package/dist/components/ui/tabs/index.js +2 -0
- package/dist/components/ui/textarea/index.js +2 -0
- package/dist/components/ui/toast/index.js +2 -0
- package/dist/components/ui/toggle/index.js +2 -0
- package/dist/components/ui/toggle-group/index.js +2 -0
- package/dist/components/ui/tooltip/index.js +2 -0
- package/dist/index.d.ts +2 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/r/accordion.json +3 -1
- package/dist/r/account-menu.json +2 -1
- package/dist/r/alert-dialog.json +3 -1
- package/dist/r/alert.json +3 -1
- package/dist/r/app-shell.json +3 -1
- package/dist/r/aspect-ratio.json +3 -1
- package/dist/r/avatar.json +3 -1
- package/dist/r/badge.json +3 -1
- package/dist/r/board.json +3 -1
- package/dist/r/breadcrumb.json +3 -1
- package/dist/r/button-group.json +2 -1
- package/dist/r/button.json +3 -1
- package/dist/r/calendar.json +2 -1
- package/dist/r/card.json +3 -1
- package/dist/r/carousel.json +2 -1
- package/dist/r/chart.json +3 -1
- package/dist/r/checkbox.json +3 -1
- package/dist/r/code-block.json +2 -1
- package/dist/r/collapsible.json +3 -1
- package/dist/r/combobox.json +3 -1
- package/dist/r/command.json +3 -1
- package/dist/r/context-menu.json +3 -1
- package/dist/r/conversation.json +2 -1
- package/dist/r/detail-panel.json +2 -1
- package/dist/r/dialog.json +3 -1
- package/dist/r/diff-block.json +3 -1
- package/dist/r/drawer.json +3 -1
- package/dist/r/dropdown-menu.json +3 -1
- package/dist/r/empty.json +3 -1
- package/dist/r/entity-icon.json +3 -1
- package/dist/r/field.json +3 -1
- package/dist/r/hover-card.json +3 -1
- package/dist/r/input-group.json +3 -1
- package/dist/r/input-otp.json +3 -1
- package/dist/r/input.json +3 -1
- package/dist/r/item.json +3 -1
- package/dist/r/kbd.json +3 -1
- package/dist/r/label.json +3 -1
- package/dist/r/lib.json +50 -0
- package/dist/r/list-row.json +3 -1
- package/dist/r/menubar.json +3 -1
- package/dist/r/modal-dialog.json +2 -1
- package/dist/r/motion.json +22 -0
- package/dist/r/navigation-menu.json +3 -1
- package/dist/r/page.json +3 -1
- package/dist/r/pagination.json +3 -1
- package/dist/r/panel.json +3 -1
- package/dist/r/popover.json +3 -1
- package/dist/r/progress.json +3 -1
- package/dist/r/radio-group.json +3 -1
- package/dist/r/registry.json +320 -73
- package/dist/r/resizable.json +3 -1
- package/dist/r/scroll-area.json +3 -1
- package/dist/r/select.json +3 -1
- package/dist/r/separator.json +3 -1
- package/dist/r/settings.json +3 -1
- package/dist/r/sheet.json +2 -1
- package/dist/r/side-rail.json +3 -1
- package/dist/r/sidebar-nav.json +3 -1
- package/dist/r/skeleton.json +3 -1
- package/dist/r/slider.json +3 -1
- package/dist/r/spinner.json +3 -1
- package/dist/r/src/components/composites/account-menu/account-menu.tsx +150 -0
- package/dist/r/src/components/composites/account-menu/index.ts +1 -0
- package/dist/r/src/components/composites/list-row/index.ts +1 -0
- package/dist/r/src/components/composites/list-row/list-row.tsx +116 -0
- package/dist/r/src/components/composites/settings/index.ts +1 -0
- package/dist/r/src/components/composites/settings/settings.tsx +142 -0
- package/dist/r/src/components/composites/stat/index.ts +9 -0
- package/dist/r/src/components/composites/stat/stat.tsx +155 -0
- package/dist/r/src/components/composites/update-dialog/index.ts +7 -0
- package/dist/r/src/components/composites/update-dialog/update-dialog.tsx +529 -0
- package/dist/r/src/components/composites/workspace-mark/index.ts +1 -0
- package/dist/r/src/components/composites/workspace-mark/workspace-mark.tsx +72 -0
- package/dist/r/src/components/conversation/conversation-avatar.tsx +60 -0
- package/dist/r/src/components/conversation/conversation-surface.tsx +107 -0
- package/dist/r/src/components/conversation/index.ts +25 -0
- package/dist/r/src/components/conversation/message-composer.tsx +239 -0
- package/dist/r/src/components/conversation/message-row.tsx +387 -0
- package/dist/r/src/components/conversation/thread-panel.tsx +141 -0
- package/dist/r/src/components/layout/app-shell/app-shell.tsx +92 -0
- package/dist/r/src/components/layout/app-shell/index.ts +1 -0
- package/dist/r/src/components/layout/page/index.ts +9 -0
- package/dist/r/src/components/layout/page/page.tsx +122 -0
- package/dist/r/src/components/layout/panel/index.ts +12 -0
- package/dist/r/src/components/layout/panel/panel.tsx +166 -0
- package/dist/r/src/components/layout/side-rail/index.ts +12 -0
- package/dist/r/src/components/layout/side-rail/side-rail-context.ts +42 -0
- package/dist/r/src/components/layout/side-rail/side-rail.tsx +405 -0
- package/dist/r/src/components/layout/sidebar-nav/index.ts +14 -0
- package/dist/r/src/components/layout/sidebar-nav/sidebar-nav.tsx +244 -0
- package/dist/r/src/components/layout/status-bar/index.ts +1 -0
- package/dist/r/src/components/layout/status-bar/status-bar.tsx +73 -0
- package/dist/r/src/components/layout/top-bar/index.ts +10 -0
- package/dist/r/src/components/layout/top-bar/top-bar.tsx +166 -0
- package/dist/r/src/components/motion/index.ts +2 -0
- package/dist/r/src/components/motion/presence.tsx +32 -0
- package/dist/r/src/components/theme/appearance-panel.tsx +179 -0
- package/dist/r/src/components/theme/index.ts +22 -0
- package/dist/r/src/components/theme/theme-picker.tsx +174 -0
- package/dist/r/src/components/theme/theme-provider.tsx +309 -0
- package/dist/r/src/components/theme/theme-toggle.tsx +64 -0
- package/dist/r/src/components/ui/accordion/accordion.tsx +66 -0
- package/dist/r/src/components/ui/accordion/index.ts +1 -0
- package/dist/r/src/components/ui/alert/alert.tsx +95 -0
- package/dist/r/src/components/ui/alert/index.ts +1 -0
- package/dist/r/src/components/ui/alert-dialog/alert-dialog.tsx +176 -0
- package/dist/r/src/components/ui/alert-dialog/index.ts +13 -0
- package/dist/r/src/components/ui/aspect-ratio/aspect-ratio.tsx +38 -0
- package/dist/r/src/components/ui/aspect-ratio/index.ts +1 -0
- package/dist/r/src/components/ui/avatar/avatar.tsx +114 -0
- package/dist/r/src/components/ui/avatar/index.ts +9 -0
- package/dist/r/src/components/ui/badge/badge.tsx +59 -0
- package/dist/r/src/components/ui/badge/index.ts +1 -0
- package/dist/r/src/components/ui/board/board.tsx +254 -0
- package/dist/r/src/components/ui/board/index.ts +10 -0
- package/dist/r/src/components/ui/breadcrumb/breadcrumb.tsx +117 -0
- package/dist/r/src/components/ui/breadcrumb/index.ts +9 -0
- package/dist/r/src/components/ui/button/button.tsx +89 -0
- package/dist/r/src/components/ui/button/index.ts +1 -0
- package/dist/r/src/components/ui/button-group/button-group.tsx +92 -0
- package/dist/r/src/components/ui/button-group/index.ts +6 -0
- package/dist/r/src/components/ui/calendar/calendar.tsx +277 -0
- package/dist/r/src/components/ui/calendar/index.ts +1 -0
- package/dist/r/src/components/ui/card/card.tsx +82 -0
- package/dist/r/src/components/ui/card/index.ts +10 -0
- package/dist/r/src/components/ui/carousel/carousel.tsx +209 -0
- package/dist/r/src/components/ui/carousel/index.ts +1 -0
- package/dist/r/src/components/ui/chart/chart.tsx +413 -0
- package/dist/r/src/components/ui/chart/index.ts +17 -0
- package/dist/r/src/components/ui/checkbox/checkbox.tsx +99 -0
- package/dist/r/src/components/ui/checkbox/index.ts +1 -0
- package/dist/r/src/components/ui/code-block/code-block.tsx +238 -0
- package/dist/r/src/components/ui/code-block/index.ts +1 -0
- package/dist/r/src/components/ui/collapsible/collapsible.tsx +54 -0
- package/dist/r/src/components/ui/collapsible/index.ts +1 -0
- package/dist/r/src/components/ui/combobox/combobox.tsx +142 -0
- package/dist/r/src/components/ui/combobox/index.ts +10 -0
- package/dist/r/src/components/ui/command/command.tsx +214 -0
- package/dist/r/src/components/ui/command/index.ts +12 -0
- package/dist/r/src/components/ui/context-menu/context-menu.tsx +163 -0
- package/dist/r/src/components/ui/context-menu/index.ts +15 -0
- package/dist/r/src/components/ui/detail-panel/detail-panel.tsx +161 -0
- package/dist/r/src/components/ui/detail-panel/index.ts +9 -0
- package/dist/r/src/components/ui/dialog/dialog.tsx +138 -0
- package/dist/r/src/components/ui/dialog/index.ts +14 -0
- package/dist/r/src/components/ui/diff-block/diff-block.tsx +286 -0
- package/dist/r/src/components/ui/diff-block/index.ts +11 -0
- package/dist/r/src/components/ui/drawer/drawer.tsx +144 -0
- package/dist/r/src/components/ui/drawer/index.ts +13 -0
- package/dist/r/src/components/ui/dropdown-menu/dropdown-menu.tsx +203 -0
- package/dist/r/src/components/ui/dropdown-menu/index.ts +18 -0
- package/dist/r/src/components/ui/empty/empty.tsx +104 -0
- package/dist/r/src/components/ui/empty/index.ts +10 -0
- package/dist/r/src/components/ui/entity-icon/entity-icon.tsx +154 -0
- package/dist/r/src/components/ui/entity-icon/index.ts +1 -0
- package/dist/r/src/components/ui/field/field.tsx +131 -0
- package/dist/r/src/components/ui/field/index.ts +11 -0
- package/dist/r/src/components/ui/hover-card/hover-card.tsx +48 -0
- package/dist/r/src/components/ui/hover-card/index.ts +1 -0
- package/dist/r/src/components/ui/input/index.ts +1 -0
- package/dist/r/src/components/ui/input/input.tsx +41 -0
- package/dist/r/src/components/ui/input-group/index.ts +8 -0
- package/dist/r/src/components/ui/input-group/input-group.tsx +111 -0
- package/dist/r/src/components/ui/input-otp/index.ts +1 -0
- package/dist/r/src/components/ui/input-otp/input-otp.tsx +108 -0
- package/dist/r/src/components/ui/item/index.ts +10 -0
- package/dist/r/src/components/ui/item/item.tsx +146 -0
- package/dist/r/src/components/ui/kbd/index.ts +1 -0
- package/dist/r/src/components/ui/kbd/kbd.tsx +42 -0
- package/dist/r/src/components/ui/label/index.ts +1 -0
- package/dist/r/src/components/ui/label/label.tsx +36 -0
- package/dist/r/src/components/ui/menubar/index.ts +16 -0
- package/dist/r/src/components/ui/menubar/menubar.tsx +190 -0
- package/dist/r/src/components/ui/modal-dialog/index.ts +1 -0
- package/dist/r/src/components/ui/modal-dialog/modal-dialog.tsx +95 -0
- package/dist/r/src/components/ui/navigation-menu/index.ts +13 -0
- package/dist/r/src/components/ui/navigation-menu/navigation-menu.tsx +229 -0
- package/dist/r/src/components/ui/pagination/index.ts +8 -0
- package/dist/r/src/components/ui/pagination/pagination.tsx +144 -0
- package/dist/r/src/components/ui/popover/index.ts +10 -0
- package/dist/r/src/components/ui/popover/popover.tsx +81 -0
- package/dist/r/src/components/ui/progress/index.ts +1 -0
- package/dist/r/src/components/ui/progress/progress.tsx +67 -0
- package/dist/r/src/components/ui/radio-group/index.ts +1 -0
- package/dist/r/src/components/ui/radio-group/radio-group.tsx +78 -0
- package/dist/r/src/components/ui/resizable/index.ts +6 -0
- package/dist/r/src/components/ui/resizable/resizable.tsx +74 -0
- package/dist/r/src/components/ui/scroll-area/index.ts +1 -0
- package/dist/r/src/components/ui/scroll-area/scroll-area.tsx +66 -0
- package/dist/r/src/components/ui/select/index.ts +11 -0
- package/dist/r/src/components/ui/select/select.tsx +188 -0
- package/dist/r/src/components/ui/separator/index.ts +1 -0
- package/dist/r/src/components/ui/separator/separator.tsx +40 -0
- package/dist/r/src/components/ui/sheet/index.ts +13 -0
- package/dist/r/src/components/ui/sheet/sheet.tsx +132 -0
- package/dist/r/src/components/ui/skeleton/index.ts +1 -0
- package/dist/r/src/components/ui/skeleton/skeleton.tsx +28 -0
- package/dist/r/src/components/ui/slider/index.ts +1 -0
- package/dist/r/src/components/ui/slider/slider.tsx +81 -0
- package/dist/r/src/components/ui/spinner/index.ts +1 -0
- package/dist/r/src/components/ui/spinner/spinner.tsx +58 -0
- package/dist/r/src/components/ui/status-chip/index.ts +8 -0
- package/dist/r/src/components/ui/status-chip/status-chip.tsx +142 -0
- package/dist/r/src/components/ui/switch/index.ts +1 -0
- package/dist/r/src/components/ui/switch/switch.tsx +100 -0
- package/dist/r/src/components/ui/table/index.ts +11 -0
- package/dist/r/src/components/ui/table/table.tsx +125 -0
- package/dist/r/src/components/ui/tabs/index.ts +8 -0
- package/dist/r/src/components/ui/tabs/tabs.tsx +77 -0
- package/dist/r/src/components/ui/textarea/index.ts +1 -0
- package/dist/r/src/components/ui/textarea/textarea.tsx +36 -0
- package/dist/r/src/components/ui/toast/index.ts +1 -0
- package/dist/r/src/components/ui/toast/toast.tsx +220 -0
- package/dist/r/src/components/ui/toggle/index.ts +1 -0
- package/dist/r/src/components/ui/toggle/toggle.tsx +60 -0
- package/dist/r/src/components/ui/toggle-group/index.ts +6 -0
- package/dist/r/src/components/ui/toggle-group/toggle-group.tsx +66 -0
- package/dist/r/src/components/ui/tooltip/index.ts +9 -0
- package/dist/r/src/components/ui/tooltip/tooltip.tsx +102 -0
- package/dist/r/src/lib/keyed-rows.ts +68 -0
- package/dist/r/src/lib/overlay.ts +70 -0
- package/dist/r/src/lib/themes.ts +490 -0
- package/dist/r/src/lib/tokens.ts +688 -0
- package/dist/r/src/lib/utils.ts +76 -0
- package/dist/r/src/lib/variants.ts +62 -0
- package/dist/r/src/lib/version-notes.ts +65 -0
- package/dist/r/src/styles/base.css +644 -0
- package/dist/r/src/styles/fonts.css +26 -0
- package/dist/r/src/styles/globals.css +18 -0
- package/dist/r/src/styles/theme.css +864 -0
- package/dist/r/stat.json +3 -1
- package/dist/r/status-bar.json +3 -1
- package/dist/r/status-chip.json +2 -1
- package/dist/r/switch.json +3 -1
- package/dist/r/table.json +3 -1
- package/dist/r/tabs.json +3 -1
- package/dist/r/textarea.json +3 -1
- package/dist/r/theming.json +42 -0
- package/dist/r/toast.json +3 -1
- package/dist/r/toggle-group.json +2 -1
- package/dist/r/toggle.json +3 -1
- package/dist/r/tooltip.json +3 -1
- package/dist/r/top-bar.json +3 -1
- package/dist/r/update-dialog.json +2 -1
- package/dist/r/workspace-mark.json +2 -1
- package/package.json +10 -9
- package/registry.json +320 -73
- package/src/index.ts +2 -4
- package/dist/components/ui/diff-block/diff-block.test.d.ts +0 -2
- package/dist/components/ui/diff-block/diff-block.test.d.ts.map +0 -1
- package/dist/lib/keyed-rows.test.d.ts +0 -2
- package/dist/lib/keyed-rows.test.d.ts.map +0 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Checkbox as KobalteCheckbox } from '@kobalte/core/checkbox'
|
|
2
|
+
import { Check, Minus } from 'lucide-solid'
|
|
3
|
+
import type { ComponentProps, JSX } from 'solid-js'
|
|
4
|
+
import { splitProps } from 'solid-js'
|
|
5
|
+
import { cn } from '../../../lib/utils'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Checkbox.
|
|
9
|
+
*
|
|
10
|
+
* Three states: unchecked, checked, and indeterminate. Indeterminate is what a
|
|
11
|
+
* "select all" box shows when only some rows are selected; Kobalte expresses
|
|
12
|
+
* it through `checked="indeterminate"` rather than a second boolean, so there
|
|
13
|
+
* is no way to render a box that is both.
|
|
14
|
+
*
|
|
15
|
+
* The paint is `Control` and the value is a real hidden `Input`, so the control
|
|
16
|
+
* participates in a form submission and in native validation while looking
|
|
17
|
+
* nothing like a browser checkbox. Focus is tracked by the input, which is why
|
|
18
|
+
* the ring lives on the control and reads the input's focus state.
|
|
19
|
+
*/
|
|
20
|
+
export type CheckboxProps = Omit<ComponentProps<typeof KobalteCheckbox>, 'children'> & {
|
|
21
|
+
controlClass?: string
|
|
22
|
+
labelClass?: string
|
|
23
|
+
descriptionClass?: string
|
|
24
|
+
/**
|
|
25
|
+
* Replaces the control and label. Omit it to get the default control beside
|
|
26
|
+
* `label` and `description`; supply it to compose the parts yourself.
|
|
27
|
+
*/
|
|
28
|
+
children?: JSX.Element
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function Checkbox(props: CheckboxProps) {
|
|
32
|
+
const [local, rest] = splitProps(props, [
|
|
33
|
+
'class',
|
|
34
|
+
'controlClass',
|
|
35
|
+
'labelClass',
|
|
36
|
+
'descriptionClass',
|
|
37
|
+
'children',
|
|
38
|
+
'indeterminate',
|
|
39
|
+
'aria-label',
|
|
40
|
+
'aria-labelledby',
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<KobalteCheckbox class={cn('group/checkbox flex items-start gap-2.5', local.class)} {...rest}>
|
|
45
|
+
{/*
|
|
46
|
+
* The name goes on the input, which is what carries the value and takes
|
|
47
|
+
* focus. On the Root it would land on a plain div and name nothing — the
|
|
48
|
+
* box would announce its state with no subject.
|
|
49
|
+
*/}
|
|
50
|
+
<KobalteCheckbox.Input
|
|
51
|
+
aria-label={local['aria-label']}
|
|
52
|
+
aria-labelledby={local['aria-labelledby']}
|
|
53
|
+
/>
|
|
54
|
+
<KobalteCheckbox.Control
|
|
55
|
+
class={cn(
|
|
56
|
+
'border-input bg-transparent flex size-4 shrink-0 items-center justify-center rounded-sm border',
|
|
57
|
+
'transition-[color,box-shadow,border-color,background-color] ease-out outline-none',
|
|
58
|
+
'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',
|
|
59
|
+
'data-[checked]:bg-primary data-[checked]:border-primary data-[checked]:text-primary-foreground',
|
|
60
|
+
'data-[indeterminate]:bg-primary data-[indeterminate]:border-primary data-[indeterminate]:text-primary-foreground',
|
|
61
|
+
'data-[invalid]:border-destructive data-[invalid]:ring-3 data-[invalid]:ring-destructive-subtle',
|
|
62
|
+
'data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50',
|
|
63
|
+
local.controlClass
|
|
64
|
+
)}
|
|
65
|
+
>
|
|
66
|
+
<KobalteCheckbox.Indicator class="flex items-center justify-center">
|
|
67
|
+
{local.indeterminate ? <Minus class="size-3" /> : <Check class="size-3" />}
|
|
68
|
+
</KobalteCheckbox.Indicator>
|
|
69
|
+
</KobalteCheckbox.Control>
|
|
70
|
+
{local.children ?? (
|
|
71
|
+
<div class="grid gap-0.5 leading-none">
|
|
72
|
+
<KobalteCheckbox.Label class={cn('text-sm font-medium', local.labelClass)} />
|
|
73
|
+
<KobalteCheckbox.Description
|
|
74
|
+
class={cn('text-muted-foreground text-sm', local.descriptionClass)}
|
|
75
|
+
/>
|
|
76
|
+
</div>
|
|
77
|
+
)}
|
|
78
|
+
</KobalteCheckbox>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The box's own label. Valid only inside a `<Checkbox>`, for the same reason as
|
|
84
|
+
* `SwitchLabel`: outside its root there is no control to associate with.
|
|
85
|
+
*/
|
|
86
|
+
export function CheckboxLabel(props: ComponentProps<typeof KobalteCheckbox.Label>) {
|
|
87
|
+
const [local, rest] = splitProps(props, ['class'])
|
|
88
|
+
return <KobalteCheckbox.Label class={cn('text-sm font-medium', local.class)} {...rest} />
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function CheckboxDescription(props: ComponentProps<typeof KobalteCheckbox.Description>) {
|
|
92
|
+
const [local, rest] = splitProps(props, ['class'])
|
|
93
|
+
return (
|
|
94
|
+
<KobalteCheckbox.Description
|
|
95
|
+
class={cn('text-muted-foreground text-sm', local.class)}
|
|
96
|
+
{...rest}
|
|
97
|
+
/>
|
|
98
|
+
)
|
|
99
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Checkbox, CheckboxDescription, CheckboxLabel, type CheckboxProps } from './checkbox'
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createMemo,
|
|
3
|
+
createSignal,
|
|
4
|
+
For,
|
|
5
|
+
Show,
|
|
6
|
+
splitProps,
|
|
7
|
+
type ComponentProps,
|
|
8
|
+
type JSX,
|
|
9
|
+
} from 'solid-js'
|
|
10
|
+
import { Check, Copy } from 'lucide-solid'
|
|
11
|
+
import { Button } from '../button'
|
|
12
|
+
import { cn } from '../../../lib/utils'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* CodeBlock.
|
|
16
|
+
*
|
|
17
|
+
* A fenced block, rendered as a surface. The library ships no highlighter —
|
|
18
|
+
* syntax colouring is a large dependency with its own theme format, and a
|
|
19
|
+
* component that bundled one would force every consumer to pay for it. This
|
|
20
|
+
* renders the block, its chrome, and its behaviour; a caller that wants
|
|
21
|
+
* highlighting passes the result through `highlight`, which is the seam a
|
|
22
|
+
* Shiki/Pierre/Prism integration plugs into.
|
|
23
|
+
*
|
|
24
|
+
* Four details are the reason this exists rather than a styled `<pre>`:
|
|
25
|
+
*
|
|
26
|
+
* **Copy confirms only on success.** `navigator.clipboard.writeText` rejects
|
|
27
|
+
* outside a secure context, in a sandboxed frame, and when the document is not
|
|
28
|
+
* focused. Flipping to a tick unconditionally confirms a copy that did not
|
|
29
|
+
* happen, and the reader pastes something stale and does not know why. The
|
|
30
|
+
* rejection is caught and the button reports the failure instead.
|
|
31
|
+
*
|
|
32
|
+
* **A tall block repeats its action row at the bottom.** Copying from a block
|
|
33
|
+
* that is taller than the viewport otherwise costs a scroll back to the top and
|
|
34
|
+
* another scroll down to where you were. The threshold is a fixed 480px rather
|
|
35
|
+
* than viewport-relative so the behaviour does not change when the window is
|
|
36
|
+
* resized.
|
|
37
|
+
*
|
|
38
|
+
* **The scroller is focusable and named.** A horizontally scrollable region has
|
|
39
|
+
* to be reachable by keyboard — this is axe's `scrollable-region-focusable`, and
|
|
40
|
+
* a region that scrolls but cannot be focused is a WCAG 2.1.1 failure. It is a
|
|
41
|
+
* `region` with a label rather than a bare `tabindex`, so the tab stop announces
|
|
42
|
+
* what it is.
|
|
43
|
+
*
|
|
44
|
+
* **Resolving a streaming block must not move the reader.** When `complete` is
|
|
45
|
+
* false the block shows the code it has plus a generating indicator; the
|
|
46
|
+
* indicator is inside the scroller's own box and does not add a line, because a
|
|
47
|
+
* block that grows the moment its content resolves shifts everything below it.
|
|
48
|
+
* If a caller's `highlight` changes the line box, that is the caller's height to
|
|
49
|
+
* hold — `lineHeight` is a prop for exactly that reason.
|
|
50
|
+
*/
|
|
51
|
+
export type CodeBlockProps = Omit<ComponentProps<'div'>, 'children'> & {
|
|
52
|
+
code: string
|
|
53
|
+
/** The language, shown in the header and used as the region's label. */
|
|
54
|
+
language?: string
|
|
55
|
+
/** The code, transformed — highlighted HTML or a component. Omit for plain text. */
|
|
56
|
+
highlight?: (code: string) => JSX.Element
|
|
57
|
+
/** False while the block is still streaming. Adds a generating indicator. */
|
|
58
|
+
complete?: boolean
|
|
59
|
+
/** A filename or title, shown instead of the language. */
|
|
60
|
+
title?: string
|
|
61
|
+
/** Extra header controls, before the copy button. */
|
|
62
|
+
actions?: JSX.Element
|
|
63
|
+
/** Copy label. Override for a non-English application. */
|
|
64
|
+
copyLabel?: string
|
|
65
|
+
copiedLabel?: string
|
|
66
|
+
/** Line height of the rendered code. Set it when `highlight` changes the box. */
|
|
67
|
+
lineHeight?: string
|
|
68
|
+
/** A line-number gutter. Off by default; a short snippet rarely needs one. */
|
|
69
|
+
showLineNumbers?: boolean
|
|
70
|
+
/** The height above which the action row is repeated below the block. */
|
|
71
|
+
tallThreshold?: number
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** The height a block must exceed before its actions are repeated. */
|
|
75
|
+
export const TALL_CODE_BLOCK_PX = 480
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Copy, reporting whether it worked. `navigator.clipboard` is absent in an
|
|
79
|
+
* insecure context, and `writeText` rejects when the document is not focused —
|
|
80
|
+
* both are normal in an embedded or iframed application, and neither should
|
|
81
|
+
* silently look like success.
|
|
82
|
+
*/
|
|
83
|
+
async function copyText(text: string): Promise<boolean> {
|
|
84
|
+
try {
|
|
85
|
+
if (!navigator.clipboard) return false
|
|
86
|
+
await navigator.clipboard.writeText(text)
|
|
87
|
+
return true
|
|
88
|
+
} catch {
|
|
89
|
+
return false
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function CodeBlock(props: CodeBlockProps) {
|
|
94
|
+
const [local, rest] = splitProps(props, [
|
|
95
|
+
'code',
|
|
96
|
+
'language',
|
|
97
|
+
'highlight',
|
|
98
|
+
'complete',
|
|
99
|
+
'title',
|
|
100
|
+
'actions',
|
|
101
|
+
'copyLabel',
|
|
102
|
+
'copiedLabel',
|
|
103
|
+
'lineHeight',
|
|
104
|
+
'showLineNumbers',
|
|
105
|
+
'tallThreshold',
|
|
106
|
+
'class',
|
|
107
|
+
'ref',
|
|
108
|
+
])
|
|
109
|
+
|
|
110
|
+
const [copied, setCopied] = createSignal(false)
|
|
111
|
+
const [failed, setFailed] = createSignal(false)
|
|
112
|
+
const [tall, setTall] = createSignal(false)
|
|
113
|
+
|
|
114
|
+
const label = () => local.title ?? local.language ?? 'code'
|
|
115
|
+
const regionLabel = () => (local.language ? `${local.language} code` : 'code')
|
|
116
|
+
const lines = createMemo(() => local.code.replace(/\n$/, '').split('\n'))
|
|
117
|
+
|
|
118
|
+
const copy = async () => {
|
|
119
|
+
const ok = await copyText(local.code)
|
|
120
|
+
setCopied(ok)
|
|
121
|
+
setFailed(!ok)
|
|
122
|
+
if (ok) setTimeout(() => setCopied(false), 1500)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const Actions = () => (
|
|
126
|
+
<div class="flex items-center gap-1 opacity-0 transition-opacity group-focus-within/code:opacity-100 group-hover/code:opacity-100">
|
|
127
|
+
{local.actions}
|
|
128
|
+
<Button
|
|
129
|
+
variant="ghost"
|
|
130
|
+
size="icon-2xs"
|
|
131
|
+
aria-label={copied() ? (local.copiedLabel ?? 'Copied') : (local.copyLabel ?? 'Copy code')}
|
|
132
|
+
title={failed() ? 'Copying is unavailable in this context' : undefined}
|
|
133
|
+
onClick={() => void copy()}
|
|
134
|
+
>
|
|
135
|
+
<Show when={copied()} fallback={<Copy aria-hidden="true" />}>
|
|
136
|
+
<Check aria-hidden="true" />
|
|
137
|
+
</Show>
|
|
138
|
+
</Button>
|
|
139
|
+
</div>
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<div
|
|
144
|
+
class={cn('group/code overflow-hidden rounded-xl border border-border bg-card', local.class)}
|
|
145
|
+
{...rest}
|
|
146
|
+
ref={(element) => {
|
|
147
|
+
// Composed rather than replaced: a caller's ref must survive.
|
|
148
|
+
if (typeof local.ref === 'function') local.ref(element)
|
|
149
|
+
else if (local.ref) local.ref = element
|
|
150
|
+
// Measured rather than assumed: the caller controls the content, so only
|
|
151
|
+
// the rendered box can say whether the action row has scrolled away.
|
|
152
|
+
const observer = new ResizeObserver(() => {
|
|
153
|
+
setTall(element.offsetHeight > (local.tallThreshold ?? TALL_CODE_BLOCK_PX))
|
|
154
|
+
})
|
|
155
|
+
observer.observe(element)
|
|
156
|
+
}}
|
|
157
|
+
>
|
|
158
|
+
<div class="flex items-center justify-between gap-2 px-3 py-1">
|
|
159
|
+
<span class="truncate font-mono text-xs text-muted-foreground">{label()}</span>
|
|
160
|
+
<Actions />
|
|
161
|
+
</div>
|
|
162
|
+
<div
|
|
163
|
+
class="scroll-fade overflow-x-auto"
|
|
164
|
+
// A region that scrolls must be focusable, and a tab stop needs a name.
|
|
165
|
+
tabindex="0"
|
|
166
|
+
role="region"
|
|
167
|
+
aria-label={regionLabel()}
|
|
168
|
+
>
|
|
169
|
+
<Show
|
|
170
|
+
when={local.highlight}
|
|
171
|
+
fallback={
|
|
172
|
+
<pre class="m-0 px-3 py-2" style={{ 'line-height': local.lineHeight ?? '1.5' }}>
|
|
173
|
+
<code class="font-mono text-xs">
|
|
174
|
+
<Show when={local.showLineNumbers} fallback={local.code.replace(/\n$/, '')}>
|
|
175
|
+
<For each={lines()}>
|
|
176
|
+
{(line, index) => (
|
|
177
|
+
<span class="grid grid-cols-[3ch_1fr] gap-3">
|
|
178
|
+
<span
|
|
179
|
+
class="text-right text-muted-foreground select-none"
|
|
180
|
+
aria-hidden="true"
|
|
181
|
+
>
|
|
182
|
+
{index() + 1}
|
|
183
|
+
</span>
|
|
184
|
+
<span>{line || ' '}</span>
|
|
185
|
+
</span>
|
|
186
|
+
)}
|
|
187
|
+
</For>
|
|
188
|
+
</Show>
|
|
189
|
+
</code>
|
|
190
|
+
</pre>
|
|
191
|
+
}
|
|
192
|
+
>
|
|
193
|
+
{(highlight) => <div class="px-3 py-2">{highlight()(local.code)}</div>}
|
|
194
|
+
</Show>
|
|
195
|
+
{/*
|
|
196
|
+
In the scroller's box, and a single line: the indicator must not add
|
|
197
|
+
height when it disappears, or a streaming block shifts everything below
|
|
198
|
+
it as it resolves.
|
|
199
|
+
*/}
|
|
200
|
+
<Show when={!local.complete}>
|
|
201
|
+
<p class="px-3 pb-2 text-xs text-muted-foreground italic">Generating…</p>
|
|
202
|
+
</Show>
|
|
203
|
+
</div>
|
|
204
|
+
<Show when={tall()}>
|
|
205
|
+
<div
|
|
206
|
+
data-code-block-footer=""
|
|
207
|
+
class="flex items-center justify-end border-t border-transparent px-3 py-1 transition-colors group-focus-within/code:border-border group-hover/code:border-border"
|
|
208
|
+
>
|
|
209
|
+
<Actions />
|
|
210
|
+
</div>
|
|
211
|
+
</Show>
|
|
212
|
+
</div>
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* InlineCode.
|
|
218
|
+
*
|
|
219
|
+
* The `code` inside a sentence. It is a component rather than a class because it
|
|
220
|
+
* has to hold three properties at once: it must not break the line's rhythm
|
|
221
|
+
* (`font-size: 0.9em`, so it tracks the surrounding text), it must wrap rather
|
|
222
|
+
* than overflow a narrow column (`overflow-wrap: anywhere` — an identifier with
|
|
223
|
+
* no spaces is one long token), and it must be legible against whatever surface
|
|
224
|
+
* it lands on, which is why the fill is a token and not a fixed grey.
|
|
225
|
+
*/
|
|
226
|
+
export function InlineCode(props: ComponentProps<'code'>) {
|
|
227
|
+
const [local, rest] = splitProps(props, ['class'])
|
|
228
|
+
|
|
229
|
+
return (
|
|
230
|
+
<code
|
|
231
|
+
class={cn(
|
|
232
|
+
'rounded-sm bg-muted px-[0.4em] py-[0.15em] font-mono text-[0.9em] text-foreground [overflow-wrap:anywhere]',
|
|
233
|
+
local.class
|
|
234
|
+
)}
|
|
235
|
+
{...rest}
|
|
236
|
+
/>
|
|
237
|
+
)
|
|
238
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CodeBlock, InlineCode, TALL_CODE_BLOCK_PX, type CodeBlockProps } from './code-block'
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Collapsible as KobalteCollapsible } from '@kobalte/core/collapsible'
|
|
2
|
+
import type { ComponentProps } from 'solid-js'
|
|
3
|
+
import { splitProps } from 'solid-js'
|
|
4
|
+
import { cn } from '../../../lib/utils'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Collapsible.
|
|
8
|
+
*
|
|
9
|
+
* One region that shows and hides. Accordion is this in a list; reach for
|
|
10
|
+
* Collapsible when there is exactly one, so a caller does not have to build a
|
|
11
|
+
* one-item accordion whose semantics say "list of one".
|
|
12
|
+
*
|
|
13
|
+
* The content animates its height rather than appearing, which is what keeps a
|
|
14
|
+
* disclosure from reading as a layout jump. Kobalte publishes the measured
|
|
15
|
+
* height as `--kb-collapsible-content-height`.
|
|
16
|
+
*/
|
|
17
|
+
export function Collapsible(props: ComponentProps<typeof KobalteCollapsible>) {
|
|
18
|
+
const [local, rest] = splitProps(props, ['class'])
|
|
19
|
+
return <KobalteCollapsible class={cn('flex w-full flex-col', local.class)} {...rest} />
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function CollapsibleTrigger(props: ComponentProps<typeof KobalteCollapsible.Trigger>) {
|
|
23
|
+
const [local, rest] = splitProps(props, ['class'])
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<KobalteCollapsible.Trigger
|
|
27
|
+
class={cn(
|
|
28
|
+
'flex items-center gap-1.5 text-sm font-medium',
|
|
29
|
+
'transition-colors ease-out outline-none',
|
|
30
|
+
'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',
|
|
31
|
+
'disabled:pointer-events-none disabled:opacity-50',
|
|
32
|
+
local.class
|
|
33
|
+
)}
|
|
34
|
+
{...rest}
|
|
35
|
+
/>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function CollapsibleContent(props: ComponentProps<typeof KobalteCollapsible.Content>) {
|
|
40
|
+
const [local, rest] = splitProps(props, ['class'])
|
|
41
|
+
return (
|
|
42
|
+
<KobalteCollapsible.Content
|
|
43
|
+
class={cn(
|
|
44
|
+
'overflow-hidden',
|
|
45
|
+
/* Kobalte measures the content and exposes the height; the transition
|
|
46
|
+
reads it so the panel opens to its real size rather than a guess. */
|
|
47
|
+
'data-[expanded]:animate-in data-[expanded]:fade-in-0 data-[expanded]:slide-in-from-top-1',
|
|
48
|
+
'data-[closed]:animate-out data-[closed]:fade-out-0 data-[closed]:slide-out-to-top-1',
|
|
49
|
+
local.class
|
|
50
|
+
)}
|
|
51
|
+
{...rest}
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Collapsible, CollapsibleContent, CollapsibleTrigger } from './collapsible'
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { Combobox as KobalteCombobox } from '@kobalte/core/combobox'
|
|
2
|
+
import { Check, ChevronDown, X } from 'lucide-solid'
|
|
3
|
+
import type { ComponentProps } from 'solid-js'
|
|
4
|
+
import { Show, splitProps } from 'solid-js'
|
|
5
|
+
import { menuContentPadding, menuItem, popoverArrow } from '../../../lib/overlay'
|
|
6
|
+
import { cn } from '../../../lib/utils'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Combobox.
|
|
10
|
+
*
|
|
11
|
+
* A Select whose list is filterable by typing. The difference from Select is
|
|
12
|
+
* not cosmetic: a Combobox has a text input, so the user can narrow forty
|
|
13
|
+
* options to one without reading the list. Above roughly ten options the
|
|
14
|
+
* search is the feature; below it, a Select is quieter and a RadioGroup is
|
|
15
|
+
* better still.
|
|
16
|
+
*
|
|
17
|
+
* Kobalte supplies the filtering, the `aria-activedescendant` wiring, the
|
|
18
|
+
* keyboard selection and the multiple-selection mode, which is the part a
|
|
19
|
+
* hand-rolled version reliably gets wrong.
|
|
20
|
+
*/
|
|
21
|
+
export function Combobox<Option, OptGroup = never>(
|
|
22
|
+
props: ComponentProps<typeof KobalteCombobox<Option, OptGroup>>
|
|
23
|
+
) {
|
|
24
|
+
return <KobalteCombobox {...props} />
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function ComboboxControl(props: ComponentProps<typeof KobalteCombobox.Control>) {
|
|
28
|
+
const [local, rest] = splitProps(props, ['class'])
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<KobalteCombobox.Control
|
|
32
|
+
class={cn(
|
|
33
|
+
'border-input bg-transparent flex h-control-md w-full items-center gap-1.5 rounded-md border px-control-sm',
|
|
34
|
+
'transition-[color,box-shadow,border-color] ease-out',
|
|
35
|
+
'focus-within:border-ring focus-within:ring-3 focus-within:ring-primary-subtle',
|
|
36
|
+
'data-[invalid]:border-destructive data-[invalid]:ring-3 data-[invalid]:ring-destructive-subtle',
|
|
37
|
+
'data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50',
|
|
38
|
+
local.class
|
|
39
|
+
)}
|
|
40
|
+
{...rest}
|
|
41
|
+
/>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function ComboboxInput(props: ComponentProps<typeof KobalteCombobox.Input>) {
|
|
46
|
+
const [local, rest] = splitProps(props, ['class'])
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<KobalteCombobox.Input
|
|
50
|
+
class={cn(
|
|
51
|
+
'h-full flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground',
|
|
52
|
+
'disabled:cursor-not-allowed',
|
|
53
|
+
local.class
|
|
54
|
+
)}
|
|
55
|
+
{...rest}
|
|
56
|
+
/>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function ComboboxTrigger(props: ComponentProps<typeof KobalteCombobox.Trigger>) {
|
|
61
|
+
const [local, rest] = splitProps(props, ['class', 'children'])
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<KobalteCombobox.Trigger
|
|
65
|
+
class={cn(
|
|
66
|
+
'text-muted-foreground flex shrink-0 items-center justify-center rounded-sm outline-none',
|
|
67
|
+
'transition-colors ease-out hover:text-foreground',
|
|
68
|
+
'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',
|
|
69
|
+
'disabled:pointer-events-none disabled:opacity-50',
|
|
70
|
+
local.class
|
|
71
|
+
)}
|
|
72
|
+
{...rest}
|
|
73
|
+
>
|
|
74
|
+
{local.children}
|
|
75
|
+
<KobalteCombobox.Icon>
|
|
76
|
+
<ChevronDown class="size-4" />
|
|
77
|
+
</KobalteCombobox.Icon>
|
|
78
|
+
</KobalteCombobox.Trigger>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function ComboboxContent(props: ComponentProps<typeof KobalteCombobox.Content>) {
|
|
83
|
+
const [local, rest] = splitProps(props, ['class', 'children'])
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<KobalteCombobox.Portal>
|
|
87
|
+
<KobalteCombobox.Content
|
|
88
|
+
class={cn(
|
|
89
|
+
'bg-popover text-popover-foreground rounded-xl border border-border shadow-lg',
|
|
90
|
+
'z-(--z-menu) max-h-72 min-w-(--kb-popper-anchor-width) origin-(--kb-combobox-content-transform-origin) overflow-hidden',
|
|
91
|
+
'data-expanded:animate-in data-expanded:fade-in-0 data-expanded:zoom-in-95',
|
|
92
|
+
'data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',
|
|
93
|
+
'data-expanded:duration-150 data-closed:duration-100',
|
|
94
|
+
local.class
|
|
95
|
+
)}
|
|
96
|
+
{...rest}
|
|
97
|
+
>
|
|
98
|
+
<KobalteCombobox.Listbox class={cn('max-h-72 overflow-y-auto', menuContentPadding)} />
|
|
99
|
+
<KobalteCombobox.Arrow aria-hidden="true" class={popoverArrow} />
|
|
100
|
+
</KobalteCombobox.Content>
|
|
101
|
+
</KobalteCombobox.Portal>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function ComboboxItem(props: ComponentProps<typeof KobalteCombobox.Item>) {
|
|
106
|
+
const [local, rest] = splitProps(props, ['class', 'children'])
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<KobalteCombobox.Item class={cn(menuItem, 'pe-8', local.class)} {...rest}>
|
|
110
|
+
<KobalteCombobox.ItemLabel>{local.children}</KobalteCombobox.ItemLabel>
|
|
111
|
+
<KobalteCombobox.ItemIndicator class="absolute end-2 flex size-4 items-center justify-center">
|
|
112
|
+
<Check class="size-4" />
|
|
113
|
+
</KobalteCombobox.ItemIndicator>
|
|
114
|
+
</KobalteCombobox.Item>
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function ComboboxSection(props: ComponentProps<typeof KobalteCombobox.Section>) {
|
|
119
|
+
const [local, rest] = splitProps(props, ['class'])
|
|
120
|
+
return <KobalteCombobox.Section class={cn('flex flex-col', local.class)} {...rest} />
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** The clear affordance for a single-select Combobox with a value. */
|
|
124
|
+
export function ComboboxClear(props: { class?: string; onClear: () => void }) {
|
|
125
|
+
return (
|
|
126
|
+
<Show when={props.onClear}>
|
|
127
|
+
<button
|
|
128
|
+
type="button"
|
|
129
|
+
aria-label="Clear selection"
|
|
130
|
+
onClick={() => props.onClear()}
|
|
131
|
+
class={cn(
|
|
132
|
+
'text-muted-foreground flex size-4 shrink-0 items-center justify-center rounded-sm',
|
|
133
|
+
'transition-colors ease-out outline-none hover:text-foreground',
|
|
134
|
+
'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',
|
|
135
|
+
props.class
|
|
136
|
+
)}
|
|
137
|
+
>
|
|
138
|
+
<X class="size-3.5" />
|
|
139
|
+
</button>
|
|
140
|
+
</Show>
|
|
141
|
+
)
|
|
142
|
+
}
|