@cueplusplus/ui 0.1.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/dist/charts/_token.js +39 -0
- package/dist/charts/container.d.ts +58 -0
- package/dist/charts/container.js +77 -0
- package/dist/charts/index.d.ts +5 -0
- package/dist/charts/index.js +5 -0
- package/dist/charts/ramps.d.ts +140 -0
- package/dist/charts/ramps.js +615 -0
- package/dist/charts/theme.d.ts +112 -0
- package/dist/charts/theme.js +165 -0
- package/dist/charts/tones.d.ts +111 -0
- package/dist/charts/tones.js +127 -0
- package/dist/chat/_glyphs.js +55 -0
- package/dist/chat/agent-color.d.ts +84 -0
- package/dist/chat/agent-color.js +101 -0
- package/dist/chat/agent-pile.d.ts +55 -0
- package/dist/chat/agent-pile.js +121 -0
- package/dist/chat/ask-box.d.ts +88 -0
- package/dist/chat/ask-box.js +341 -0
- package/dist/chat/composer.d.ts +66 -0
- package/dist/chat/composer.js +144 -0
- package/dist/chat/delegation-card.d.ts +60 -0
- package/dist/chat/delegation-card.js +129 -0
- package/dist/chat/index.d.ts +8 -0
- package/dist/chat/index.js +8 -0
- package/dist/chat/message-list.d.ts +39 -0
- package/dist/chat/message-list.js +105 -0
- package/dist/chat/message.d.ts +47 -0
- package/dist/chat/message.js +108 -0
- package/dist/chrome/_glyphs.js +101 -0
- package/dist/chrome/_tabs-scroll.d.ts +62 -0
- package/dist/chrome/_tabs-scroll.js +68 -0
- package/dist/chrome/_tree.d.ts +75 -0
- package/dist/chrome/_tree.js +49 -0
- package/dist/chrome/empty-state.d.ts +37 -0
- package/dist/chrome/empty-state.js +57 -0
- package/dist/chrome/eyebrow.d.ts +29 -0
- package/dist/chrome/eyebrow.js +36 -0
- package/dist/chrome/index.d.ts +17 -0
- package/dist/chrome/index.js +17 -0
- package/dist/chrome/navigation-menu.d.ts +80 -0
- package/dist/chrome/navigation-menu.js +121 -0
- package/dist/chrome/page-shell.d.ts +38 -0
- package/dist/chrome/page-shell.js +66 -0
- package/dist/chrome/panel.d.ts +55 -0
- package/dist/chrome/panel.js +67 -0
- package/dist/chrome/row.d.ts +82 -0
- package/dist/chrome/row.js +106 -0
- package/dist/chrome/scroll-area.d.ts +39 -0
- package/dist/chrome/scroll-area.js +70 -0
- package/dist/chrome/section-header.d.ts +42 -0
- package/dist/chrome/section-header.js +79 -0
- package/dist/chrome/segmented-control.d.ts +58 -0
- package/dist/chrome/segmented-control.js +76 -0
- package/dist/chrome/status-bar.d.ts +46 -0
- package/dist/chrome/status-bar.js +56 -0
- package/dist/chrome/tabs.d.ts +80 -0
- package/dist/chrome/tabs.js +176 -0
- package/dist/chrome/title-bar.d.ts +37 -0
- package/dist/chrome/title-bar.js +45 -0
- package/dist/chrome/toolbar.d.ts +46 -0
- package/dist/chrome/toolbar.js +62 -0
- package/dist/chrome/tree.d.ts +98 -0
- package/dist/chrome/tree.js +248 -0
- package/dist/color/_checker.js +14 -0
- package/dist/color/_convert.d.ts +52 -0
- package/dist/color/_convert.js +66 -0
- package/dist/color/_glyphs.js +28 -0
- package/dist/color/_thumb.js +15 -0
- package/dist/color/_value.js +28 -0
- package/dist/color/color-area.d.ts +27 -0
- package/dist/color/color-area.js +40 -0
- package/dist/color/color-field.d.ts +32 -0
- package/dist/color/color-field.js +43 -0
- package/dist/color/color-picker.d.ts +71 -0
- package/dist/color/color-picker.js +178 -0
- package/dist/color/color-slider.d.ts +31 -0
- package/dist/color/color-slider.js +51 -0
- package/dist/color/color-swatch.d.ts +32 -0
- package/dist/color/color-swatch.js +44 -0
- package/dist/color/index.d.ts +7 -0
- package/dist/color/index.js +7 -0
- package/dist/configurator/_export.d.ts +78 -0
- package/dist/configurator/_export.js +261 -0
- package/dist/configurator/_glyphs.js +92 -0
- package/dist/configurator/_overrides.d.ts +247 -0
- package/dist/configurator/_overrides.js +514 -0
- package/dist/configurator/configurator.d.ts +71 -0
- package/dist/configurator/configurator.js +279 -0
- package/dist/configurator/export-dialog.d.ts +30 -0
- package/dist/configurator/export-dialog.js +121 -0
- package/dist/configurator/index.d.ts +8 -0
- package/dist/configurator/index.js +8 -0
- package/dist/configurator/panel-sections.d.ts +86 -0
- package/dist/configurator/panel-sections.js +316 -0
- package/dist/configurator/token-editor.d.ts +74 -0
- package/dist/configurator/token-editor.js +149 -0
- package/dist/configurator/use-zoom.d.ts +87 -0
- package/dist/configurator/use-zoom.js +113 -0
- package/dist/date/_glyphs.js +34 -0
- package/dist/date/_segments.js +55 -0
- package/dist/date/_trigger.js +31 -0
- package/dist/date/calendar.d.ts +25 -0
- package/dist/date/calendar.js +125 -0
- package/dist/date/date-field.d.ts +34 -0
- package/dist/date/date-field.js +41 -0
- package/dist/date/date-picker.d.ts +69 -0
- package/dist/date/date-picker.js +89 -0
- package/dist/date/date-range-picker.d.ts +65 -0
- package/dist/date/date-range-picker.js +92 -0
- package/dist/date/index.d.ts +6 -0
- package/dist/date/index.js +6 -0
- package/dist/date/time-field.d.ts +29 -0
- package/dist/date/time-field.js +36 -0
- package/dist/dmx/_ramp.d.ts +77 -0
- package/dist/dmx/_ramp.js +169 -0
- package/dist/dmx/_readout.js +53 -0
- package/dist/dmx/_universe.d.ts +105 -0
- package/dist/dmx/_universe.js +112 -0
- package/dist/dmx/channel-matrix.d.ts +81 -0
- package/dist/dmx/channel-matrix.js +285 -0
- package/dist/dmx/dmx-bar.d.ts +50 -0
- package/dist/dmx/dmx-bar.js +107 -0
- package/dist/dmx/dmx-strip.d.ts +41 -0
- package/dist/dmx/dmx-strip.js +196 -0
- package/dist/dmx/index.d.ts +7 -0
- package/dist/dmx/index.js +7 -0
- package/dist/dmx/universe-grid.d.ts +61 -0
- package/dist/dmx/universe-grid.js +182 -0
- package/dist/flow/_frame.d.ts +52 -0
- package/dist/flow/_frame.js +38 -0
- package/dist/flow/controls.d.ts +41 -0
- package/dist/flow/controls.js +53 -0
- package/dist/flow/flow.css +121 -0
- package/dist/flow/handles.d.ts +40 -0
- package/dist/flow/handles.js +61 -0
- package/dist/flow/index.d.ts +7 -0
- package/dist/flow/index.js +7 -0
- package/dist/flow/node-card.d.ts +71 -0
- package/dist/flow/node-card.js +102 -0
- package/dist/flow/signal-edge.d.ts +60 -0
- package/dist/flow/signal-edge.js +108 -0
- package/dist/flow/use-flow-theme.d.ts +69 -0
- package/dist/flow/use-flow-theme.js +109 -0
- package/dist/forms/_chassis.d.ts +64 -0
- package/dist/forms/_chassis.js +59 -0
- package/dist/forms/_glyphs.js +143 -0
- package/dist/forms/_listbox.js +55 -0
- package/dist/forms/autocomplete.d.ts +61 -0
- package/dist/forms/autocomplete.js +88 -0
- package/dist/forms/button-group.d.ts +47 -0
- package/dist/forms/button-group.js +52 -0
- package/dist/forms/checkbox.d.ts +51 -0
- package/dist/forms/checkbox.js +98 -0
- package/dist/forms/combobox.d.ts +73 -0
- package/dist/forms/combobox.js +108 -0
- package/dist/forms/env-var-input.d.ts +74 -0
- package/dist/forms/env-var-input.js +116 -0
- package/dist/forms/field.d.ts +89 -0
- package/dist/forms/field.js +102 -0
- package/dist/forms/file-upload.d.ts +113 -0
- package/dist/forms/file-upload.js +232 -0
- package/dist/forms/index.d.ts +26 -0
- package/dist/forms/index.js +26 -0
- package/dist/forms/input-group.d.ts +31 -0
- package/dist/forms/input-group.js +54 -0
- package/dist/forms/input.d.ts +33 -0
- package/dist/forms/input.js +36 -0
- package/dist/forms/multi-select.d.ts +62 -0
- package/dist/forms/multi-select.js +107 -0
- package/dist/forms/number-field.d.ts +38 -0
- package/dist/forms/number-field.js +64 -0
- package/dist/forms/otp-field.d.ts +54 -0
- package/dist/forms/otp-field.js +59 -0
- package/dist/forms/password-input.d.ts +46 -0
- package/dist/forms/password-input.js +62 -0
- package/dist/forms/radio-group.d.ts +50 -0
- package/dist/forms/radio-group.js +64 -0
- package/dist/forms/rating.d.ts +69 -0
- package/dist/forms/rating.js +103 -0
- package/dist/forms/scrub-input.d.ts +81 -0
- package/dist/forms/scrub-input.js +249 -0
- package/dist/forms/search-input.d.ts +54 -0
- package/dist/forms/search-input.js +112 -0
- package/dist/forms/select.d.ts +75 -0
- package/dist/forms/select.js +91 -0
- package/dist/forms/slider.d.ts +44 -0
- package/dist/forms/slider.js +65 -0
- package/dist/forms/switch.d.ts +36 -0
- package/dist/forms/switch.js +71 -0
- package/dist/forms/tags-input.d.ts +69 -0
- package/dist/forms/tags-input.js +148 -0
- package/dist/forms/textarea.d.ts +27 -0
- package/dist/forms/textarea.js +37 -0
- package/dist/forms/toggle-group.d.ts +41 -0
- package/dist/forms/toggle-group.js +56 -0
- package/dist/forms/toggle.d.ts +41 -0
- package/dist/forms/toggle.js +100 -0
- package/dist/index.d.ts +112 -0
- package/dist/index.js +104 -0
- package/dist/instruments/_ansi.js +116 -0
- package/dist/instruments/_glyphs.js +90 -0
- package/dist/instruments/_motion.js +56 -0
- package/dist/instruments/_rem.js +21 -0
- package/dist/instruments/app-window-frame.d.ts +48 -0
- package/dist/instruments/app-window-frame.js +76 -0
- package/dist/instruments/copy-button.d.ts +41 -0
- package/dist/instruments/copy-button.js +112 -0
- package/dist/instruments/data-table.d.ts +168 -0
- package/dist/instruments/data-table.js +212 -0
- package/dist/instruments/group-bar.d.ts +63 -0
- package/dist/instruments/group-bar.js +122 -0
- package/dist/instruments/index.d.ts +13 -0
- package/dist/instruments/index.js +13 -0
- package/dist/instruments/log-viewer.d.ts +74 -0
- package/dist/instruments/log-viewer.js +215 -0
- package/dist/instruments/meter.d.ts +77 -0
- package/dist/instruments/meter.js +96 -0
- package/dist/instruments/progress.d.ts +45 -0
- package/dist/instruments/progress.js +61 -0
- package/dist/instruments/seam-grid.d.ts +66 -0
- package/dist/instruments/seam-grid.js +78 -0
- package/dist/instruments/sparkline.d.ts +39 -0
- package/dist/instruments/sparkline.js +85 -0
- package/dist/instruments/stat.d.ts +35 -0
- package/dist/instruments/stat.js +59 -0
- package/dist/instruments/table.d.ts +51 -0
- package/dist/instruments/table.js +92 -0
- package/dist/instruments/terminal-frame.d.ts +89 -0
- package/dist/instruments/terminal-frame.js +256 -0
- package/dist/instruments/two-step-button.d.ts +47 -0
- package/dist/instruments/two-step-button.js +147 -0
- package/dist/instruments/usage-chart.d.ts +55 -0
- package/dist/instruments/usage-chart.js +235 -0
- package/dist/layout/_collapse.js +46 -0
- package/dist/layout/_glyphs.js +45 -0
- package/dist/layout/accordion.d.ts +52 -0
- package/dist/layout/accordion.js +81 -0
- package/dist/layout/breadcrumb.d.ts +35 -0
- package/dist/layout/breadcrumb.js +67 -0
- package/dist/layout/card.d.ts +51 -0
- package/dist/layout/card.js +76 -0
- package/dist/layout/carousel.d.ts +96 -0
- package/dist/layout/carousel.js +211 -0
- package/dist/layout/collapsible.d.ts +74 -0
- package/dist/layout/collapsible.js +126 -0
- package/dist/layout/container.d.ts +27 -0
- package/dist/layout/container.js +40 -0
- package/dist/layout/description-list.d.ts +24 -0
- package/dist/layout/description-list.js +37 -0
- package/dist/layout/grid.d.ts +40 -0
- package/dist/layout/grid.js +48 -0
- package/dist/layout/index.d.ts +15 -0
- package/dist/layout/index.js +15 -0
- package/dist/layout/item.d.ts +65 -0
- package/dist/layout/item.js +100 -0
- package/dist/layout/link.d.ts +48 -0
- package/dist/layout/link.js +63 -0
- package/dist/layout/pagination.d.ts +54 -0
- package/dist/layout/pagination.js +121 -0
- package/dist/layout/resizable.d.ts +38 -0
- package/dist/layout/resizable.js +68 -0
- package/dist/layout/sidebar.d.ts +67 -0
- package/dist/layout/sidebar.js +129 -0
- package/dist/layout/stack.d.ts +46 -0
- package/dist/layout/stack.js +62 -0
- package/dist/layout/stepper.d.ts +49 -0
- package/dist/layout/stepper.js +81 -0
- package/dist/layout/timeline.d.ts +43 -0
- package/dist/layout/timeline.js +63 -0
- package/dist/lib/aria-class.js +24 -0
- package/dist/lib/cn.js +18 -0
- package/dist/lib/compose.js +38 -0
- package/dist/lib/cva.d.ts +18 -0
- package/dist/lib/cva.js +65 -0
- package/dist/midi/_notes.d.ts +101 -0
- package/dist/midi/_notes.js +183 -0
- package/dist/midi/_ruler.d.ts +100 -0
- package/dist/midi/_ruler.js +105 -0
- package/dist/midi/_time.d.ts +107 -0
- package/dist/midi/_time.js +130 -0
- package/dist/midi/index.d.ts +9 -0
- package/dist/midi/index.js +9 -0
- package/dist/midi/musical-time-input.d.ts +48 -0
- package/dist/midi/musical-time-input.js +154 -0
- package/dist/midi/piano-keyboard.d.ts +50 -0
- package/dist/midi/piano-keyboard.js +193 -0
- package/dist/midi/spectrum-visualizer.d.ts +65 -0
- package/dist/midi/spectrum-visualizer.js +213 -0
- package/dist/midi/threshold-rail.d.ts +72 -0
- package/dist/midi/threshold-rail.js +214 -0
- package/dist/midi/timeline-ruler.d.ts +83 -0
- package/dist/midi/timeline-ruler.js +152 -0
- package/dist/overlays/_debounce.js +34 -0
- package/dist/overlays/_glyphs.js +59 -0
- package/dist/overlays/_surface.d.ts +70 -0
- package/dist/overlays/_surface.js +70 -0
- package/dist/overlays/_wheel.js +42 -0
- package/dist/overlays/alert-dialog.d.ts +67 -0
- package/dist/overlays/alert-dialog.js +117 -0
- package/dist/overlays/command-palette.d.ts +93 -0
- package/dist/overlays/command-palette.js +193 -0
- package/dist/overlays/context-menu.d.ts +64 -0
- package/dist/overlays/context-menu.js +78 -0
- package/dist/overlays/dialog.d.ts +72 -0
- package/dist/overlays/dialog.js +124 -0
- package/dist/overlays/drawer.d.ts +75 -0
- package/dist/overlays/drawer.js +151 -0
- package/dist/overlays/dropdown-menu.d.ts +79 -0
- package/dist/overlays/dropdown-menu.js +156 -0
- package/dist/overlays/hover-card.d.ts +58 -0
- package/dist/overlays/hover-card.js +91 -0
- package/dist/overlays/index.d.ts +15 -0
- package/dist/overlays/index.js +15 -0
- package/dist/overlays/info-tip.d.ts +41 -0
- package/dist/overlays/info-tip.js +45 -0
- package/dist/overlays/menubar.d.ts +72 -0
- package/dist/overlays/menubar.js +100 -0
- package/dist/overlays/popover.d.ts +66 -0
- package/dist/overlays/popover.js +114 -0
- package/dist/overlays/sheet.d.ts +78 -0
- package/dist/overlays/sheet.js +131 -0
- package/dist/overlays/toast.d.ts +106 -0
- package/dist/overlays/toast.js +146 -0
- package/dist/overlays/tooltip.d.ts +57 -0
- package/dist/overlays/tooltip.js +95 -0
- package/dist/primitives/avatar.d.ts +51 -0
- package/dist/primitives/avatar.js +93 -0
- package/dist/primitives/button.d.ts +46 -0
- package/dist/primitives/button.js +94 -0
- package/dist/primitives/chip.d.ts +47 -0
- package/dist/primitives/chip.js +152 -0
- package/dist/primitives/icon-button.d.ts +41 -0
- package/dist/primitives/icon-button.js +59 -0
- package/dist/primitives/index.d.ts +10 -0
- package/dist/primitives/index.js +10 -0
- package/dist/primitives/kbd.d.ts +17 -0
- package/dist/primitives/kbd.js +24 -0
- package/dist/primitives/separator.d.ts +25 -0
- package/dist/primitives/separator.js +30 -0
- package/dist/primitives/skeleton.d.ts +20 -0
- package/dist/primitives/skeleton.js +27 -0
- package/dist/primitives/spinner.d.ts +26 -0
- package/dist/primitives/spinner.js +31 -0
- package/dist/primitives/status-dot.d.ts +44 -0
- package/dist/primitives/status-dot.js +50 -0
- package/dist/styles.css +19 -0
- package/dist/system/density.d.ts +33 -0
- package/dist/system/density.js +49 -0
- package/dist/system/index.d.ts +8 -0
- package/dist/system/index.js +7 -0
- package/dist/system/portal.d.ts +51 -0
- package/dist/system/portal.js +122 -0
- package/dist/system/prepaint.d.ts +38 -0
- package/dist/system/prepaint.js +37 -0
- package/dist/system/theme-provider.d.ts +72 -0
- package/dist/system/theme-provider.js +252 -0
- package/dist/system/use-density.d.ts +33 -0
- package/dist/system/use-density.js +84 -0
- package/dist/system/use-isomorphic-layout-effect.js +15 -0
- package/dist/system/use-theme.d.ts +19 -0
- package/dist/system/use-theme.js +25 -0
- package/dist/theming/_presets.d.ts +11 -0
- package/dist/theming/_presets.js +487 -0
- package/dist/theming/contrast.d.ts +110 -0
- package/dist/theming/contrast.js +167 -0
- package/dist/theming/create-theme.d.ts +165 -0
- package/dist/theming/create-theme.js +442 -0
- package/dist/theming/index.d.ts +5 -0
- package/dist/theming/index.js +5 -0
- package/dist/theming/serialize.d.ts +145 -0
- package/dist/theming/serialize.js +165 -0
- package/package.json +216 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/chrome/title-bar.tsx
|
|
6
|
+
/** `app-region` needs the unprefixed and the WebKit form to cover both shells. */
|
|
7
|
+
const DRAG_CLASSES = "[app-region:drag] [-webkit-app-region:drag]";
|
|
8
|
+
const NO_DRAG_CLASSES = "[app-region:no-drag] [-webkit-app-region:no-drag]";
|
|
9
|
+
/**
|
|
10
|
+
* The window's own bar: app mark left, document name centred, controls right.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <TitleBar platformDrag center="untitled.cue" actions={<WindowControls />}>
|
|
14
|
+
* <Eyebrow>CUE++</Eyebrow>
|
|
15
|
+
* </TitleBar>
|
|
16
|
+
*/
|
|
17
|
+
const TitleBar = React.forwardRef(function TitleBar({ className, platformDrag = false, center, actions, children, ...elementProps }, ref) {
|
|
18
|
+
const clusterClasses = cn("flex min-w-0 items-center gap-(--cue-space-2)", platformDrag ? NO_DRAG_CLASSES : void 0);
|
|
19
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
20
|
+
ref,
|
|
21
|
+
"data-slot": "title-bar",
|
|
22
|
+
"data-tauri-drag-region": platformDrag ? "" : void 0,
|
|
23
|
+
className: cn("relative flex h-(--cue-chrome-titlebar) w-full shrink-0 items-center justify-between gap-(--cue-space-3) border-b border-border bg-surface-1 px-(--cue-pad-row-x) select-none", platformDrag ? DRAG_CLASSES : void 0, className),
|
|
24
|
+
...elementProps,
|
|
25
|
+
children: [
|
|
26
|
+
/* @__PURE__ */ jsx("div", {
|
|
27
|
+
"data-slot": "title-bar-leading",
|
|
28
|
+
className: clusterClasses,
|
|
29
|
+
children
|
|
30
|
+
}),
|
|
31
|
+
center === void 0 ? null : /* @__PURE__ */ jsx("div", {
|
|
32
|
+
"data-slot": "title-bar-center",
|
|
33
|
+
className: "pointer-events-none absolute left-1/2 flex -translate-x-1/2 items-center gap-(--cue-space-2) font-mono text-(length:--cue-text-label) text-fg-muted",
|
|
34
|
+
children: center
|
|
35
|
+
}),
|
|
36
|
+
actions === void 0 ? null : /* @__PURE__ */ jsx("div", {
|
|
37
|
+
"data-slot": "title-bar-actions",
|
|
38
|
+
className: cn(clusterClasses, "shrink-0"),
|
|
39
|
+
children: actions
|
|
40
|
+
})
|
|
41
|
+
]
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
//#endregion
|
|
45
|
+
export { TitleBar };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Toolbar } from "@base-ui/react/toolbar";
|
|
3
|
+
//#region src/chrome/toolbar.d.ts
|
|
4
|
+
interface ToolbarRootProps extends Omit<Toolbar.Root.Props, "className"> {
|
|
5
|
+
/** Extra classes for the bar. */
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
interface ToolbarButtonProps extends Omit<Toolbar.Button.Props, "className"> {
|
|
9
|
+
/** Extra classes for the button. */
|
|
10
|
+
className?: string;
|
|
11
|
+
/** Optional leading icon (e.g. a lucide icon), drawn `aria-hidden`. */
|
|
12
|
+
icon?: React.ElementType;
|
|
13
|
+
}
|
|
14
|
+
interface ToolbarGroupProps extends Omit<Toolbar.Group.Props, "className"> {
|
|
15
|
+
/** Extra classes for the group. */
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
interface ToolbarSeparatorProps extends Omit<Toolbar.Separator.Props, "className"> {
|
|
19
|
+
/** Extra classes for the rule. */
|
|
20
|
+
className?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The strip of controls across the top of a view.
|
|
24
|
+
*
|
|
25
|
+
* Wraps Base UI's `Toolbar`, so the whole bar is one tab stop with arrow-key
|
|
26
|
+
* roving focus inside it — which is the entire point of the ARIA toolbar
|
|
27
|
+
* pattern and the reason not to hand-roll this out of a flex row of buttons.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* <Toolbar.Root aria-label="Cue actions">
|
|
31
|
+
* <Toolbar.Group aria-label="Playback">
|
|
32
|
+
* <Toolbar.Button icon={Play}>Go</Toolbar.Button>
|
|
33
|
+
* <Toolbar.Button icon={Square}>Stop</Toolbar.Button>
|
|
34
|
+
* </Toolbar.Group>
|
|
35
|
+
* <Toolbar.Separator />
|
|
36
|
+
* <Toolbar.Button icon={Save}>Save</Toolbar.Button>
|
|
37
|
+
* </Toolbar.Root>
|
|
38
|
+
*/
|
|
39
|
+
declare const Toolbar$1: {
|
|
40
|
+
Root: React.ForwardRefExoticComponent<Omit<ToolbarRootProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
41
|
+
Button: React.ForwardRefExoticComponent<Omit<ToolbarButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
42
|
+
Group: React.ForwardRefExoticComponent<Omit<ToolbarGroupProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
43
|
+
Separator: React.ForwardRefExoticComponent<Omit<ToolbarSeparatorProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
export { Toolbar$1 as Toolbar, ToolbarButtonProps, ToolbarGroupProps, ToolbarRootProps, ToolbarSeparatorProps };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { Toolbar } from "@base-ui/react/toolbar";
|
|
6
|
+
/**
|
|
7
|
+
* The strip of controls across the top of a view.
|
|
8
|
+
*
|
|
9
|
+
* Wraps Base UI's `Toolbar`, so the whole bar is one tab stop with arrow-key
|
|
10
|
+
* roving focus inside it — which is the entire point of the ARIA toolbar
|
|
11
|
+
* pattern and the reason not to hand-roll this out of a flex row of buttons.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* <Toolbar.Root aria-label="Cue actions">
|
|
15
|
+
* <Toolbar.Group aria-label="Playback">
|
|
16
|
+
* <Toolbar.Button icon={Play}>Go</Toolbar.Button>
|
|
17
|
+
* <Toolbar.Button icon={Square}>Stop</Toolbar.Button>
|
|
18
|
+
* </Toolbar.Group>
|
|
19
|
+
* <Toolbar.Separator />
|
|
20
|
+
* <Toolbar.Button icon={Save}>Save</Toolbar.Button>
|
|
21
|
+
* </Toolbar.Root>
|
|
22
|
+
*/
|
|
23
|
+
const Toolbar$1 = {
|
|
24
|
+
Root: React.forwardRef(function ToolbarRoot({ className, ...elementProps }, ref) {
|
|
25
|
+
return /* @__PURE__ */ jsx(Toolbar.Root, {
|
|
26
|
+
ref,
|
|
27
|
+
"data-slot": "toolbar",
|
|
28
|
+
className: cn("flex h-(--cue-chrome-toolbar) w-full shrink-0 items-center gap-(--cue-space-2) border-b border-border bg-surface-1 px-(--cue-pad-row-x) data-[orientation=vertical]:h-auto data-[orientation=vertical]:w-(--cue-chrome-toolbar) data-[orientation=vertical]:flex-col data-[orientation=vertical]:border-r data-[orientation=vertical]:border-b-0", className),
|
|
29
|
+
...elementProps
|
|
30
|
+
});
|
|
31
|
+
}),
|
|
32
|
+
Button: React.forwardRef(function ToolbarButton({ className, icon: Icon, children, ...elementProps }, ref) {
|
|
33
|
+
return /* @__PURE__ */ jsxs(Toolbar.Button, {
|
|
34
|
+
ref,
|
|
35
|
+
"data-slot": "toolbar-button",
|
|
36
|
+
className: cn("inline-flex h-control-md shrink-0 cursor-pointer items-center justify-center gap-(--cue-space-2) rounded-(--radius-control) px-(--cue-space-3) font-mono text-(length:--cue-text-ui) whitespace-nowrap text-fg-muted transition-colors duration-150 outline-none select-none hover:bg-surface-2 hover:text-fg focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-1 focus-visible:outline-accent data-[disabled]:pointer-events-none data-[disabled]:opacity-40", className),
|
|
37
|
+
...elementProps,
|
|
38
|
+
children: [Icon === void 0 ? null : /* @__PURE__ */ jsx(Icon, {
|
|
39
|
+
"aria-hidden": "true",
|
|
40
|
+
className: "size-icon-md shrink-0"
|
|
41
|
+
}), children]
|
|
42
|
+
});
|
|
43
|
+
}),
|
|
44
|
+
Group: React.forwardRef(function ToolbarGroup({ className, ...elementProps }, ref) {
|
|
45
|
+
return /* @__PURE__ */ jsx(Toolbar.Group, {
|
|
46
|
+
ref,
|
|
47
|
+
"data-slot": "toolbar-group",
|
|
48
|
+
className: cn("inline-flex items-center gap-(--cue-space-1)", className),
|
|
49
|
+
...elementProps
|
|
50
|
+
});
|
|
51
|
+
}),
|
|
52
|
+
Separator: React.forwardRef(function ToolbarSeparator({ className, ...elementProps }, ref) {
|
|
53
|
+
return /* @__PURE__ */ jsx(Toolbar.Separator, {
|
|
54
|
+
ref,
|
|
55
|
+
"data-slot": "toolbar-separator",
|
|
56
|
+
className: cn("shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:mx-(--cue-space-1) data-[orientation=vertical]:h-[60%] data-[orientation=vertical]:w-px", className),
|
|
57
|
+
...elementProps
|
|
58
|
+
});
|
|
59
|
+
})
|
|
60
|
+
};
|
|
61
|
+
//#endregion
|
|
62
|
+
export { Toolbar$1 as Toolbar };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { TreeItem, TreeRow } from "./_tree.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
//#region src/chrome/tree.d.ts
|
|
4
|
+
interface TreeProps extends Omit<React.ComponentPropsWithoutRef<"div">, "onSelect"> {
|
|
5
|
+
/** The roots, in display order. */
|
|
6
|
+
items: readonly TreeItem[];
|
|
7
|
+
/** Expanded ids when controlled. Pass with `onExpandedChange`. */
|
|
8
|
+
expanded?: readonly string[];
|
|
9
|
+
/** Initially expanded ids when uncontrolled. */
|
|
10
|
+
defaultExpanded?: readonly string[];
|
|
11
|
+
/** Called with the whole next expanded set whenever a row is folded or unfolded. */
|
|
12
|
+
onExpandedChange?: (expanded: string[]) => void;
|
|
13
|
+
/** Selected id when controlled. Pass with `onSelect`. */
|
|
14
|
+
selected?: string | null;
|
|
15
|
+
/** Initially selected id when uncontrolled. */
|
|
16
|
+
defaultSelected?: string | null;
|
|
17
|
+
/** Called with the id of the row the user selected. */
|
|
18
|
+
onSelect?: (id: string) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Replace the *body* of a row — the icon, label and badge.
|
|
21
|
+
*
|
|
22
|
+
* The row element itself, its ARIA, its tab index and its indent gutter stay
|
|
23
|
+
* with the component on purpose: those are the parts a call site cannot get
|
|
24
|
+
* wrong without breaking keyboard navigation for everyone.
|
|
25
|
+
*/
|
|
26
|
+
renderRow?: (row: TreeRow) => React.ReactNode;
|
|
27
|
+
/**
|
|
28
|
+
* Controls hung off the right of each row, revealed on hover or focus.
|
|
29
|
+
*
|
|
30
|
+
* This is where the three-state visibility idiom goes — see
|
|
31
|
+
* {@link TreeVisibilityToggle} — along with focus, rename and delete
|
|
32
|
+
* affordances. Anything essential belongs in the row body or a context menu
|
|
33
|
+
* instead: hover-revealed controls are invisible on touch.
|
|
34
|
+
*/
|
|
35
|
+
rowControls?: (item: TreeItem, row: TreeRow) => React.ReactNode;
|
|
36
|
+
/** Draw the box-drawing indent gutter. Defaults to `true`. */
|
|
37
|
+
guides?: boolean;
|
|
38
|
+
/** Accessible name for the tree. Required in practice — name what it lists. */
|
|
39
|
+
"aria-label"?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A hierarchical outline: a rig, a scene graph, a folder of shows.
|
|
43
|
+
*
|
|
44
|
+
* Hand-built rather than wrapped, because the pattern's whole cost is in three
|
|
45
|
+
* details no primitive here provides together:
|
|
46
|
+
*
|
|
47
|
+
* - **Roving tabindex.** The tree is one tab stop; the arrow keys move inside
|
|
48
|
+
* it. Eighty rows must never mean eighty presses of Tab.
|
|
49
|
+
* - **A flat DOM.** Rows carry `aria-level` / `aria-posinset` / `aria-setsize`
|
|
50
|
+
* instead of nesting `role="group"` wrappers, which is both valid ARIA and the
|
|
51
|
+
* shape a virtualizer needs when the outline grows past a screenful.
|
|
52
|
+
* - **The gutter.** `└ ├ │` in the mono grid, `aria-hidden` — structure you can
|
|
53
|
+
* see at a glance without indentation alone having to carry it.
|
|
54
|
+
*
|
|
55
|
+
* Selection is a tint (`accent-soft` ground, accent ink), never a solid fill —
|
|
56
|
+
* the same ruling as the sidebar item and the active tab.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* <Tree
|
|
60
|
+
* aria-label="Rig"
|
|
61
|
+
* items={rig}
|
|
62
|
+
* selected={selected}
|
|
63
|
+
* onSelect={setSelected}
|
|
64
|
+
* rowControls={(item) => (
|
|
65
|
+
* <TreeVisibilityToggle value={visibility[item.id]} onValueChange={set(item.id)} />
|
|
66
|
+
* )}
|
|
67
|
+
* />
|
|
68
|
+
*/
|
|
69
|
+
declare const Tree: React.ForwardRefExoticComponent<TreeProps & React.RefAttributes<HTMLDivElement>>;
|
|
70
|
+
/** The three states a node can be drawn in. */
|
|
71
|
+
type TreeVisibility = "visible" | "ghost" | "hidden";
|
|
72
|
+
interface TreeVisibilityToggleProps extends Omit<React.ComponentPropsWithoutRef<"button">, "value" | "onChange" | "children"> {
|
|
73
|
+
/** The node's current visibility. */
|
|
74
|
+
value: TreeVisibility;
|
|
75
|
+
/** Called with the next state in the cycle. */
|
|
76
|
+
onValueChange: (value: TreeVisibility) => void;
|
|
77
|
+
/** Override the state names used in the accessible label. */
|
|
78
|
+
labels?: Partial<Record<TreeVisibility, string>>;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The outliner's three-state visibility control: shown → ghosted → hidden.
|
|
82
|
+
*
|
|
83
|
+
* Three states rather than a checkbox because a rig has three answers, not two:
|
|
84
|
+
* *there*, *there but out of the way*, and *not drawn*. Ghost is the one that
|
|
85
|
+
* earns the extra state — it is how you keep a truss as spatial reference while
|
|
86
|
+
* working behind it — and collapsing it into "hidden" is what makes people
|
|
87
|
+
* toggle things off and lose their bearings.
|
|
88
|
+
*
|
|
89
|
+
* Meant for {@link TreeProps.rowControls}. The accessible name states the
|
|
90
|
+
* *current* state ("Visibility: ghosted") rather than the next action, because
|
|
91
|
+
* with three states "toggle" names nothing useful; pressing cycles.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* <TreeVisibilityToggle value={state} onValueChange={setState} />
|
|
95
|
+
*/
|
|
96
|
+
declare const TreeVisibilityToggle: React.ForwardRefExoticComponent<TreeVisibilityToggleProps & React.RefAttributes<HTMLButtonElement>>;
|
|
97
|
+
//#endregion
|
|
98
|
+
export { Tree, TreeProps, TreeVisibility, TreeVisibilityToggle, TreeVisibilityToggleProps };
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { TREE_GUIDE_GLYPHS, flattenTree } from "./_tree.js";
|
|
4
|
+
import { ChevronRightGlyph, EyeGlyph, EyeOffGlyph, GhostGlyph } from "./_glyphs.js";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
//#region src/chrome/tree.tsx
|
|
8
|
+
/**
|
|
9
|
+
* A hierarchical outline: a rig, a scene graph, a folder of shows.
|
|
10
|
+
*
|
|
11
|
+
* Hand-built rather than wrapped, because the pattern's whole cost is in three
|
|
12
|
+
* details no primitive here provides together:
|
|
13
|
+
*
|
|
14
|
+
* - **Roving tabindex.** The tree is one tab stop; the arrow keys move inside
|
|
15
|
+
* it. Eighty rows must never mean eighty presses of Tab.
|
|
16
|
+
* - **A flat DOM.** Rows carry `aria-level` / `aria-posinset` / `aria-setsize`
|
|
17
|
+
* instead of nesting `role="group"` wrappers, which is both valid ARIA and the
|
|
18
|
+
* shape a virtualizer needs when the outline grows past a screenful.
|
|
19
|
+
* - **The gutter.** `└ ├ │` in the mono grid, `aria-hidden` — structure you can
|
|
20
|
+
* see at a glance without indentation alone having to carry it.
|
|
21
|
+
*
|
|
22
|
+
* Selection is a tint (`accent-soft` ground, accent ink), never a solid fill —
|
|
23
|
+
* the same ruling as the sidebar item and the active tab.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* <Tree
|
|
27
|
+
* aria-label="Rig"
|
|
28
|
+
* items={rig}
|
|
29
|
+
* selected={selected}
|
|
30
|
+
* onSelect={setSelected}
|
|
31
|
+
* rowControls={(item) => (
|
|
32
|
+
* <TreeVisibilityToggle value={visibility[item.id]} onValueChange={set(item.id)} />
|
|
33
|
+
* )}
|
|
34
|
+
* />
|
|
35
|
+
*/
|
|
36
|
+
const Tree = React.forwardRef(function Tree({ className, items, expanded: expandedProp, defaultExpanded, onExpandedChange, selected: selectedProp, defaultSelected = null, onSelect, renderRow, rowControls, guides = true, onKeyDown, ...elementProps }, ref) {
|
|
37
|
+
const [uncontrolledExpanded, setUncontrolledExpanded] = React.useState(defaultExpanded ?? []);
|
|
38
|
+
const expandedList = expandedProp ?? uncontrolledExpanded;
|
|
39
|
+
const expandedSet = React.useMemo(() => new Set(expandedList), [expandedList]);
|
|
40
|
+
const [uncontrolledSelected, setUncontrolledSelected] = React.useState(defaultSelected);
|
|
41
|
+
const selected = selectedProp === void 0 ? uncontrolledSelected : selectedProp;
|
|
42
|
+
const rows = React.useMemo(() => flattenTree(items, expandedSet), [items, expandedSet]);
|
|
43
|
+
const [activeId, setActiveId] = React.useState(null);
|
|
44
|
+
const activeRowId = activeId !== null && rows.some((row) => row.item.id === activeId) ? activeId : rows[0]?.item.id ?? null;
|
|
45
|
+
const rowRefs = React.useRef(/* @__PURE__ */ new Map());
|
|
46
|
+
const registerRow = React.useCallback((id, element) => {
|
|
47
|
+
if (element === null) rowRefs.current.delete(id);
|
|
48
|
+
else rowRefs.current.set(id, element);
|
|
49
|
+
}, []);
|
|
50
|
+
const focusRow = React.useCallback((id) => {
|
|
51
|
+
setActiveId(id);
|
|
52
|
+
rowRefs.current.get(id)?.focus();
|
|
53
|
+
}, []);
|
|
54
|
+
const setExpanded = React.useCallback((id, next) => {
|
|
55
|
+
const current = expandedProp ?? uncontrolledExpanded;
|
|
56
|
+
const result = next ? current.includes(id) ? [...current] : [...current, id] : current.filter((entry) => entry !== id);
|
|
57
|
+
if (expandedProp === void 0) setUncontrolledExpanded(result);
|
|
58
|
+
onExpandedChange?.(result);
|
|
59
|
+
}, [
|
|
60
|
+
expandedProp,
|
|
61
|
+
onExpandedChange,
|
|
62
|
+
uncontrolledExpanded
|
|
63
|
+
]);
|
|
64
|
+
const select = React.useCallback((row) => {
|
|
65
|
+
if (row.item.disabled === true) return;
|
|
66
|
+
if (selectedProp === void 0) setUncontrolledSelected(row.item.id);
|
|
67
|
+
onSelect?.(row.item.id);
|
|
68
|
+
}, [onSelect, selectedProp]);
|
|
69
|
+
const handleKeyDown = React.useCallback((event) => {
|
|
70
|
+
onKeyDown?.(event);
|
|
71
|
+
if (event.defaultPrevented) return;
|
|
72
|
+
if (event.target.getAttribute("data-slot") !== "tree-row") return;
|
|
73
|
+
const index = rows.findIndex((row) => row.item.id === activeRowId);
|
|
74
|
+
const row = rows[index];
|
|
75
|
+
if (row === void 0) return;
|
|
76
|
+
const move = (target) => {
|
|
77
|
+
if (target === void 0) return;
|
|
78
|
+
event.preventDefault();
|
|
79
|
+
focusRow(target.item.id);
|
|
80
|
+
};
|
|
81
|
+
switch (event.key) {
|
|
82
|
+
case "ArrowDown":
|
|
83
|
+
move(rows[index + 1]);
|
|
84
|
+
return;
|
|
85
|
+
case "ArrowUp":
|
|
86
|
+
move(rows[index - 1]);
|
|
87
|
+
return;
|
|
88
|
+
case "Home":
|
|
89
|
+
move(rows[0]);
|
|
90
|
+
return;
|
|
91
|
+
case "End":
|
|
92
|
+
move(rows[rows.length - 1]);
|
|
93
|
+
return;
|
|
94
|
+
case "ArrowRight": {
|
|
95
|
+
event.preventDefault();
|
|
96
|
+
if (row.hasChildren && !row.expanded) {
|
|
97
|
+
setExpanded(row.item.id, true);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const child = rows[index + 1];
|
|
101
|
+
if (row.expanded && child?.parentId === row.item.id) focusRow(child.item.id);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
case "ArrowLeft":
|
|
105
|
+
event.preventDefault();
|
|
106
|
+
if (row.expanded) setExpanded(row.item.id, false);
|
|
107
|
+
else if (row.parentId !== null) focusRow(row.parentId);
|
|
108
|
+
return;
|
|
109
|
+
case "Enter":
|
|
110
|
+
case " ":
|
|
111
|
+
event.preventDefault();
|
|
112
|
+
select(row);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
}, [
|
|
116
|
+
activeRowId,
|
|
117
|
+
focusRow,
|
|
118
|
+
onKeyDown,
|
|
119
|
+
rows,
|
|
120
|
+
select,
|
|
121
|
+
setExpanded
|
|
122
|
+
]);
|
|
123
|
+
return /* @__PURE__ */ jsx("div", {
|
|
124
|
+
ref,
|
|
125
|
+
role: "tree",
|
|
126
|
+
"data-slot": "tree",
|
|
127
|
+
className: cn("flex flex-col", className),
|
|
128
|
+
onKeyDown: handleKeyDown,
|
|
129
|
+
...elementProps,
|
|
130
|
+
children: rows.map((row) => {
|
|
131
|
+
const { item } = row;
|
|
132
|
+
const Icon = item.icon;
|
|
133
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
134
|
+
ref: (element) => registerRow(item.id, element),
|
|
135
|
+
role: "treeitem",
|
|
136
|
+
tabIndex: activeRowId === item.id ? 0 : -1,
|
|
137
|
+
"aria-level": row.level + 1,
|
|
138
|
+
"aria-posinset": row.position,
|
|
139
|
+
"aria-setsize": row.setSize,
|
|
140
|
+
"aria-expanded": row.hasChildren ? row.expanded : void 0,
|
|
141
|
+
"aria-selected": selected === item.id,
|
|
142
|
+
"aria-disabled": item.disabled === true ? true : void 0,
|
|
143
|
+
"data-slot": "tree-row",
|
|
144
|
+
"data-selected": selected === item.id ? "" : void 0,
|
|
145
|
+
"data-disabled": item.disabled === true ? "" : void 0,
|
|
146
|
+
onFocus: () => setActiveId(item.id),
|
|
147
|
+
onClick: () => select(row),
|
|
148
|
+
className: "group/tree-row flex h-control-sm cursor-default items-center gap-(--cue-space-1) rounded-(--radius-control) pr-(--cue-space-2) font-mono text-(length:--cue-text-ui) whitespace-nowrap text-fg-muted outline-none select-none hover:bg-surface-2 hover:text-fg focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-1 focus-visible:outline-accent data-[selected]:bg-accent-soft data-[selected]:text-accent data-[disabled]:pointer-events-none data-[disabled]:opacity-40",
|
|
149
|
+
children: [
|
|
150
|
+
guides ? row.guides.map((guide, depth) => /* @__PURE__ */ jsx("span", {
|
|
151
|
+
"aria-hidden": "true",
|
|
152
|
+
"data-slot": "tree-guide",
|
|
153
|
+
className: "w-(--cue-space-4) shrink-0 text-center text-fg-subtle",
|
|
154
|
+
children: TREE_GUIDE_GLYPHS[guide]
|
|
155
|
+
}, depth)) : null,
|
|
156
|
+
row.hasChildren ? /* @__PURE__ */ jsx("span", {
|
|
157
|
+
role: "presentation",
|
|
158
|
+
"data-slot": "tree-toggle",
|
|
159
|
+
"aria-hidden": "true",
|
|
160
|
+
onClick: (event) => {
|
|
161
|
+
event.stopPropagation();
|
|
162
|
+
setExpanded(item.id, !row.expanded);
|
|
163
|
+
},
|
|
164
|
+
className: "flex size-icon-sm shrink-0 cursor-pointer items-center justify-center text-fg-subtle",
|
|
165
|
+
children: /* @__PURE__ */ jsx(ChevronRightGlyph, { className: cn("size-icon-sm transition-transform duration-150 motion-reduce:transition-none", row.expanded ? "rotate-90" : null) })
|
|
166
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
167
|
+
"aria-hidden": "true",
|
|
168
|
+
className: "size-icon-sm shrink-0"
|
|
169
|
+
}),
|
|
170
|
+
renderRow === void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
171
|
+
Icon === void 0 ? null : /* @__PURE__ */ jsx(Icon, {
|
|
172
|
+
"aria-hidden": "true",
|
|
173
|
+
className: "size-icon-sm shrink-0"
|
|
174
|
+
}),
|
|
175
|
+
/* @__PURE__ */ jsx("span", {
|
|
176
|
+
"data-slot": "tree-label",
|
|
177
|
+
className: "min-w-0 flex-1 truncate",
|
|
178
|
+
children: item.label
|
|
179
|
+
}),
|
|
180
|
+
item.badge === void 0 ? null : /* @__PURE__ */ jsx("span", {
|
|
181
|
+
"data-slot": "tree-badge",
|
|
182
|
+
className: "shrink-0 text-fg-subtle",
|
|
183
|
+
children: item.badge
|
|
184
|
+
})
|
|
185
|
+
] }) : /* @__PURE__ */ jsx("span", {
|
|
186
|
+
className: "min-w-0 flex-1 truncate",
|
|
187
|
+
children: renderRow(row)
|
|
188
|
+
}),
|
|
189
|
+
rowControls === void 0 ? null : /* @__PURE__ */ jsx("span", {
|
|
190
|
+
"data-slot": "tree-row-controls",
|
|
191
|
+
onClick: (event) => event.stopPropagation(),
|
|
192
|
+
className: "flex shrink-0 items-center gap-(--cue-space-1) opacity-0 transition-opacity duration-150 group-hover/tree-row:opacity-100 group-focus-within/tree-row:opacity-100 motion-reduce:transition-none",
|
|
193
|
+
children: rowControls(item, row)
|
|
194
|
+
})
|
|
195
|
+
]
|
|
196
|
+
}, item.id);
|
|
197
|
+
})
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
/** Which state the toggle moves to next. */
|
|
201
|
+
const NEXT_VISIBILITY = {
|
|
202
|
+
visible: "ghost",
|
|
203
|
+
ghost: "hidden",
|
|
204
|
+
hidden: "visible"
|
|
205
|
+
};
|
|
206
|
+
/** What each state is called when the button announces itself. */
|
|
207
|
+
const VISIBILITY_LABELS = {
|
|
208
|
+
visible: "visible",
|
|
209
|
+
ghost: "ghosted",
|
|
210
|
+
hidden: "hidden"
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* The outliner's three-state visibility control: shown → ghosted → hidden.
|
|
214
|
+
*
|
|
215
|
+
* Three states rather than a checkbox because a rig has three answers, not two:
|
|
216
|
+
* *there*, *there but out of the way*, and *not drawn*. Ghost is the one that
|
|
217
|
+
* earns the extra state — it is how you keep a truss as spatial reference while
|
|
218
|
+
* working behind it — and collapsing it into "hidden" is what makes people
|
|
219
|
+
* toggle things off and lose their bearings.
|
|
220
|
+
*
|
|
221
|
+
* Meant for {@link TreeProps.rowControls}. The accessible name states the
|
|
222
|
+
* *current* state ("Visibility: ghosted") rather than the next action, because
|
|
223
|
+
* with three states "toggle" names nothing useful; pressing cycles.
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* <TreeVisibilityToggle value={state} onValueChange={setState} />
|
|
227
|
+
*/
|
|
228
|
+
const TreeVisibilityToggle = React.forwardRef(function TreeVisibilityToggle({ className, value, onValueChange, labels, onClick, ...elementProps }, ref) {
|
|
229
|
+
const Glyph = value === "visible" ? EyeGlyph : value === "ghost" ? GhostGlyph : EyeOffGlyph;
|
|
230
|
+
const name = labels?.[value] ?? VISIBILITY_LABELS[value];
|
|
231
|
+
return /* @__PURE__ */ jsx("button", {
|
|
232
|
+
ref,
|
|
233
|
+
type: "button",
|
|
234
|
+
"aria-label": `Visibility: ${name}`,
|
|
235
|
+
"data-slot": "tree-visibility-toggle",
|
|
236
|
+
"data-state": value,
|
|
237
|
+
onClick: (event) => {
|
|
238
|
+
onClick?.(event);
|
|
239
|
+
if (event.defaultPrevented) return;
|
|
240
|
+
onValueChange(NEXT_VISIBILITY[value]);
|
|
241
|
+
},
|
|
242
|
+
className: cn("flex size-icon-md shrink-0 cursor-pointer items-center justify-center rounded-(--radius-control) border-0 bg-transparent p-0 outline-none transition-colors duration-150 hover:text-fg focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-1 focus-visible:outline-accent motion-reduce:transition-none data-[state=visible]:text-fg-subtle data-[state=ghost]:text-info data-[state=hidden]:text-warn", className),
|
|
243
|
+
...elementProps,
|
|
244
|
+
children: /* @__PURE__ */ jsx(Glyph, { className: "size-icon-sm" })
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
//#endregion
|
|
248
|
+
export { Tree, TreeVisibilityToggle };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/color/_checker.ts
|
|
2
|
+
/**
|
|
3
|
+
* The transparency checkerboard.
|
|
4
|
+
*
|
|
5
|
+
* Anywhere a colour with alpha is shown — a swatch, an alpha rail — something
|
|
6
|
+
* has to sit behind it or "50% transparent white" and "opaque light grey" look
|
|
7
|
+
* identical. Drawn as a token-coloured conic gradient rather than an image so it
|
|
8
|
+
* follows the theme (and stays a two-line class string instead of an asset).
|
|
9
|
+
*
|
|
10
|
+
* @internal Not part of the public API.
|
|
11
|
+
*/
|
|
12
|
+
const checkerClasses = "bg-[repeating-conic-gradient(var(--cue-surface-3)_0%_25%,var(--cue-surface-1)_0%_50%)] bg-[length:0.5rem_0.5rem]";
|
|
13
|
+
//#endregion
|
|
14
|
+
export { checkerClasses };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//#region src/color/_convert.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The notations this suite reads and writes.
|
|
4
|
+
*
|
|
5
|
+
* Two, not ten: hex is what a colour picker natively speaks, oklch is what this
|
|
6
|
+
* system's tokens are authored in. Everything else (`rgb()`, `hsl()`, named
|
|
7
|
+
* colours) is *readable* — {@link toHexString} takes whatever CSS understands —
|
|
8
|
+
* but writing back in a third notation would only invite a token file with
|
|
9
|
+
* three spellings of the same colour.
|
|
10
|
+
*/
|
|
11
|
+
type ColorFormat = "hex" | "oklch";
|
|
12
|
+
/**
|
|
13
|
+
* Convert any CSS colour string to `#rrggbb` (or `#rrggbbaa` when it carries
|
|
14
|
+
* alpha).
|
|
15
|
+
*
|
|
16
|
+
* The bridge into React Aria's colour parts, which only parse sRGB notations —
|
|
17
|
+
* hand them an `oklch()` token value and they throw. Colours outside the sRGB
|
|
18
|
+
* gamut have their **chroma** pulled in rather than their channels clipped:
|
|
19
|
+
* clipping `oklch(0.7 0.4 30)` gives pure red, losing the lightness the author
|
|
20
|
+
* chose, while clamping keeps it at `#ff6551`.
|
|
21
|
+
*
|
|
22
|
+
* @param input - Any CSS colour string.
|
|
23
|
+
* @returns The lower-case hex string, or `null` if the input is not a colour.
|
|
24
|
+
* @example
|
|
25
|
+
* toHexString("oklch(0.7 0.15 30)") // "#ed7665"
|
|
26
|
+
*/
|
|
27
|
+
declare function toHexString(input: string): string | null;
|
|
28
|
+
/**
|
|
29
|
+
* Re-print a colour in one of the two notations the suite writes.
|
|
30
|
+
*
|
|
31
|
+
* The oklch form is emitted at the precision a round trip needs — four decimals
|
|
32
|
+
* of lightness and chroma, two of hue — which is exactly enough for
|
|
33
|
+
* `toHexString(formatColorString(hex, "oklch")) === hex` across the sRGB cube.
|
|
34
|
+
* An achromatic colour has no hue, so it prints `0` rather than `NaN`.
|
|
35
|
+
*
|
|
36
|
+
* @param input - Any CSS colour string.
|
|
37
|
+
* @param format - The notation to write.
|
|
38
|
+
* @returns The formatted colour, or `null` if the input is not a colour.
|
|
39
|
+
* @example
|
|
40
|
+
* formatColorString("#3fa9f5", "oklch") // "oklch(0.7083 0.1466 244.05)"
|
|
41
|
+
*/
|
|
42
|
+
declare function formatColorString(input: string, format: ColorFormat): string | null;
|
|
43
|
+
/**
|
|
44
|
+
* Which notation a value is authored in, so a control can hand back what it was
|
|
45
|
+
* given instead of quietly rewriting a token file into hex.
|
|
46
|
+
*
|
|
47
|
+
* @param input - Any CSS colour string.
|
|
48
|
+
* @returns `"oklch"` for an `oklch()` value, `"hex"` for everything else.
|
|
49
|
+
*/
|
|
50
|
+
declare function detectColorFormat(input: string): ColorFormat;
|
|
51
|
+
//#endregion
|
|
52
|
+
export { ColorFormat, detectColorFormat, formatColorString, toHexString };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { clampChroma, converter, formatHex, formatHex8, inGamut, parse } from "culori";
|
|
2
|
+
//#region src/color/_convert.ts
|
|
3
|
+
const toOklch = converter("oklch");
|
|
4
|
+
const srgb = inGamut("rgb");
|
|
5
|
+
/** Round to `digits` and drop trailing zeros, so `0.70000` prints as `0.7`. */
|
|
6
|
+
function round(value, digits) {
|
|
7
|
+
return String(Number(value.toFixed(digits)));
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Convert any CSS colour string to `#rrggbb` (or `#rrggbbaa` when it carries
|
|
11
|
+
* alpha).
|
|
12
|
+
*
|
|
13
|
+
* The bridge into React Aria's colour parts, which only parse sRGB notations —
|
|
14
|
+
* hand them an `oklch()` token value and they throw. Colours outside the sRGB
|
|
15
|
+
* gamut have their **chroma** pulled in rather than their channels clipped:
|
|
16
|
+
* clipping `oklch(0.7 0.4 30)` gives pure red, losing the lightness the author
|
|
17
|
+
* chose, while clamping keeps it at `#ff6551`.
|
|
18
|
+
*
|
|
19
|
+
* @param input - Any CSS colour string.
|
|
20
|
+
* @returns The lower-case hex string, or `null` if the input is not a colour.
|
|
21
|
+
* @example
|
|
22
|
+
* toHexString("oklch(0.7 0.15 30)") // "#ed7665"
|
|
23
|
+
*/
|
|
24
|
+
function toHexString(input) {
|
|
25
|
+
const parsed = parse(input);
|
|
26
|
+
if (parsed === void 0) return null;
|
|
27
|
+
const inSrgb = srgb(parsed) ? parsed : clampChroma(parsed, "oklch", "rgb");
|
|
28
|
+
const alpha = parsed.alpha;
|
|
29
|
+
return alpha === void 0 || alpha >= 1 ? formatHex(inSrgb) : formatHex8(inSrgb);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Re-print a colour in one of the two notations the suite writes.
|
|
33
|
+
*
|
|
34
|
+
* The oklch form is emitted at the precision a round trip needs — four decimals
|
|
35
|
+
* of lightness and chroma, two of hue — which is exactly enough for
|
|
36
|
+
* `toHexString(formatColorString(hex, "oklch")) === hex` across the sRGB cube.
|
|
37
|
+
* An achromatic colour has no hue, so it prints `0` rather than `NaN`.
|
|
38
|
+
*
|
|
39
|
+
* @param input - Any CSS colour string.
|
|
40
|
+
* @param format - The notation to write.
|
|
41
|
+
* @returns The formatted colour, or `null` if the input is not a colour.
|
|
42
|
+
* @example
|
|
43
|
+
* formatColorString("#3fa9f5", "oklch") // "oklch(0.7083 0.1466 244.05)"
|
|
44
|
+
*/
|
|
45
|
+
function formatColorString(input, format) {
|
|
46
|
+
const hex = toHexString(input);
|
|
47
|
+
if (hex === null) return null;
|
|
48
|
+
if (format === "hex") return hex;
|
|
49
|
+
const color = toOklch(parse(hex));
|
|
50
|
+
if (color === void 0) return null;
|
|
51
|
+
const body = `${round(color.l, 4)} ${round(color.c, 4)} ${round(color.h ?? 0, 2)}`;
|
|
52
|
+
const alpha = color.alpha;
|
|
53
|
+
return alpha === void 0 || alpha >= 1 ? `oklch(${body})` : `oklch(${body} / ${round(alpha, 3)})`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Which notation a value is authored in, so a control can hand back what it was
|
|
57
|
+
* given instead of quietly rewriting a token file into hex.
|
|
58
|
+
*
|
|
59
|
+
* @param input - Any CSS colour string.
|
|
60
|
+
* @returns `"oklch"` for an `oklch()` value, `"hex"` for everything else.
|
|
61
|
+
*/
|
|
62
|
+
function detectColorFormat(input) {
|
|
63
|
+
return /^\s*oklch\(/i.test(input) ? "oklch" : "hex";
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
export { detectColorFormat, formatColorString, toHexString };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import "react";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
//#region src/color/_glyphs.tsx
|
|
4
|
+
/**
|
|
5
|
+
* Glyphs for the colour group.
|
|
6
|
+
*
|
|
7
|
+
* Drawn inline for the same reason as `forms/_glyphs.tsx`: one icon on one
|
|
8
|
+
* button should not put an icon dependency on the render path, and hand-set
|
|
9
|
+
* strokes stay hairline-thin at the 8–12px sizes console density asks for.
|
|
10
|
+
*
|
|
11
|
+
* @internal Not part of the public API.
|
|
12
|
+
*/
|
|
13
|
+
/** An eyedropper: sample a colour from anywhere on the screen. */
|
|
14
|
+
function EyedropperGlyph(props) {
|
|
15
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
16
|
+
viewBox: "0 0 16 16",
|
|
17
|
+
fill: "none",
|
|
18
|
+
stroke: "currentColor",
|
|
19
|
+
strokeWidth: "1.25",
|
|
20
|
+
strokeLinecap: "round",
|
|
21
|
+
strokeLinejoin: "round",
|
|
22
|
+
"aria-hidden": "true",
|
|
23
|
+
...props,
|
|
24
|
+
children: /* @__PURE__ */ jsx("path", { d: "M10.5 2.5a1.8 1.8 0 0 1 2.5 2.5l-1.4 1.4 1 1-1.2 1.2-1-1-4.3 4.3-2.6.6.6-2.6 4.3-4.3-1-1L8.6 3.4l1 1z" })
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { EyedropperGlyph };
|