@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,42 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
//#region src/chrome/section-header.d.ts
|
|
3
|
+
interface SectionHeaderProps extends Omit<React.ComponentPropsWithoutRef<"div">, "onToggle"> {
|
|
4
|
+
/** The group's name. Rendered uppercase in the smallest mono label type. */
|
|
5
|
+
label: React.ReactNode;
|
|
6
|
+
/** Optional count shown after the label — how many things are in the group. */
|
|
7
|
+
count?: number;
|
|
8
|
+
/**
|
|
9
|
+
* Right-hand slot. Rendered *outside* the collapse toggle so clicking an
|
|
10
|
+
* action never folds the section shut under the user's cursor.
|
|
11
|
+
*/
|
|
12
|
+
action?: React.ReactNode;
|
|
13
|
+
/** Turn the label into a disclosure button that shows and hides `children`. */
|
|
14
|
+
collapsible?: boolean;
|
|
15
|
+
/** Initial open state when uncontrolled. Defaults to `true`. */
|
|
16
|
+
defaultOpen?: boolean;
|
|
17
|
+
/** Open state when controlled. Pass with `onOpenChange`. */
|
|
18
|
+
open?: boolean;
|
|
19
|
+
/** Called with the next open state whenever the toggle is pressed. */
|
|
20
|
+
onOpenChange?: (open: boolean) => void;
|
|
21
|
+
/** The section body. Hidden while a collapsible section is closed. */
|
|
22
|
+
children?: React.ReactNode;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A faint label with a rule running off it — the heading for a group of rows.
|
|
26
|
+
*
|
|
27
|
+
* A label and a hairline, deliberately, not a bordered box: a heading that is
|
|
28
|
+
* itself a panel competes with the panels underneath it and reads as another
|
|
29
|
+
* object rather than as their title (the quotamate `AccountGroup` ruling). The
|
|
30
|
+
* rule is a `flex-1` block, so it always fills exactly the space the label and
|
|
31
|
+
* the count leave behind.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* <SectionHeader label="Universes" count={4} />
|
|
35
|
+
* @example
|
|
36
|
+
* <SectionHeader label="Scenes" collapsible action={<IconButton aria-label="Add" icon={Plus} />}>
|
|
37
|
+
* <SeamList>{scenes.map((s) => <Row seam key={s.id}>{s.name}</Row>)}</SeamList>
|
|
38
|
+
* </SectionHeader>
|
|
39
|
+
*/
|
|
40
|
+
declare const SectionHeader: React.ForwardRefExoticComponent<SectionHeaderProps & React.RefAttributes<HTMLDivElement>>;
|
|
41
|
+
//#endregion
|
|
42
|
+
export { SectionHeader, SectionHeaderProps };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { ChevronRightGlyph } from "./_glyphs.js";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/chrome/section-header.tsx
|
|
7
|
+
/**
|
|
8
|
+
* A faint label with a rule running off it — the heading for a group of rows.
|
|
9
|
+
*
|
|
10
|
+
* A label and a hairline, deliberately, not a bordered box: a heading that is
|
|
11
|
+
* itself a panel competes with the panels underneath it and reads as another
|
|
12
|
+
* object rather than as their title (the quotamate `AccountGroup` ruling). The
|
|
13
|
+
* rule is a `flex-1` block, so it always fills exactly the space the label and
|
|
14
|
+
* the count leave behind.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* <SectionHeader label="Universes" count={4} />
|
|
18
|
+
* @example
|
|
19
|
+
* <SectionHeader label="Scenes" collapsible action={<IconButton aria-label="Add" icon={Plus} />}>
|
|
20
|
+
* <SeamList>{scenes.map((s) => <Row seam key={s.id}>{s.name}</Row>)}</SeamList>
|
|
21
|
+
* </SectionHeader>
|
|
22
|
+
*/
|
|
23
|
+
const SectionHeader = React.forwardRef(function SectionHeader({ className, label, count, action, collapsible = false, defaultOpen = true, open: openProp, onOpenChange, children, ...elementProps }, ref) {
|
|
24
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
|
|
25
|
+
const open = openProp ?? uncontrolledOpen;
|
|
26
|
+
const toggle = () => {
|
|
27
|
+
const next = !open;
|
|
28
|
+
if (openProp === void 0) setUncontrolledOpen(next);
|
|
29
|
+
onOpenChange?.(next);
|
|
30
|
+
};
|
|
31
|
+
const headContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
32
|
+
collapsible ? /* @__PURE__ */ jsx(ChevronRightGlyph, {
|
|
33
|
+
"data-slot": "section-header-chevron",
|
|
34
|
+
className: cn("size-icon-sm shrink-0 text-fg-subtle transition-transform duration-150 motion-reduce:transition-none", open ? "rotate-90" : "rotate-0")
|
|
35
|
+
}) : null,
|
|
36
|
+
/* @__PURE__ */ jsx("span", {
|
|
37
|
+
"data-slot": "section-header-label",
|
|
38
|
+
className: "shrink-0 font-mono text-(length:--cue-text-label) tracking-[0.15em] text-fg-muted uppercase",
|
|
39
|
+
children: label
|
|
40
|
+
}),
|
|
41
|
+
count === void 0 ? null : /* @__PURE__ */ jsx("span", {
|
|
42
|
+
"data-slot": "section-header-count",
|
|
43
|
+
className: "shrink-0 font-mono text-(length:--cue-text-label) tabular-nums text-fg-subtle",
|
|
44
|
+
children: count
|
|
45
|
+
}),
|
|
46
|
+
/* @__PURE__ */ jsx("span", {
|
|
47
|
+
"data-slot": "section-header-rule",
|
|
48
|
+
"aria-hidden": "true",
|
|
49
|
+
className: "h-px min-w-(--cue-space-4) flex-1 bg-border"
|
|
50
|
+
})
|
|
51
|
+
] });
|
|
52
|
+
const headClasses = "flex min-w-0 flex-1 items-center gap-(--cue-space-3)";
|
|
53
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
54
|
+
ref,
|
|
55
|
+
"data-slot": "section-header",
|
|
56
|
+
className: cn("flex w-full flex-col gap-(--cue-space-3)", className),
|
|
57
|
+
...elementProps,
|
|
58
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
59
|
+
className: "flex items-center gap-(--cue-space-3)",
|
|
60
|
+
children: [collapsible ? /* @__PURE__ */ jsx("button", {
|
|
61
|
+
type: "button",
|
|
62
|
+
"aria-expanded": open,
|
|
63
|
+
onClick: toggle,
|
|
64
|
+
"data-slot": "section-header-toggle",
|
|
65
|
+
className: cn(headClasses, "cursor-pointer text-left outline-none hover:text-fg focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-accent"),
|
|
66
|
+
children: headContent
|
|
67
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
68
|
+
className: headClasses,
|
|
69
|
+
children: headContent
|
|
70
|
+
}), action === void 0 ? null : /* @__PURE__ */ jsx("div", {
|
|
71
|
+
"data-slot": "section-header-action",
|
|
72
|
+
className: "flex shrink-0 items-center gap-(--cue-space-2)",
|
|
73
|
+
children: action
|
|
74
|
+
})]
|
|
75
|
+
}), children !== void 0 && (!collapsible || open) ? children : null]
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
//#endregion
|
|
79
|
+
export { SectionHeader };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { ToggleGroup } from "@base-ui/react/toggle-group";
|
|
3
|
+
//#region src/chrome/segmented-control.d.ts
|
|
4
|
+
/** The rung of the density control ladder a segmented control sits on. */
|
|
5
|
+
type SegmentedControlSize = "sm" | "md" | "lg";
|
|
6
|
+
/** One segment of a {@link SegmentedControl}. */
|
|
7
|
+
interface SegmentedControlItem {
|
|
8
|
+
/** The value reported when this segment is picked. Must be unique. */
|
|
9
|
+
value: string;
|
|
10
|
+
/** What the segment says. Keep it to one word where possible. */
|
|
11
|
+
label: React.ReactNode;
|
|
12
|
+
/** Optional leading icon (e.g. a lucide icon), drawn `aria-hidden`. */
|
|
13
|
+
icon?: React.ElementType;
|
|
14
|
+
/** Grey this segment out and make it unpickable. */
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
}
|
|
17
|
+
interface SegmentedControlProps extends Omit<ToggleGroup.Props<string>, "value" | "defaultValue" | "onValueChange" | "multiple" | "className" | "children"> {
|
|
18
|
+
/** The segments, in display order. */
|
|
19
|
+
items: readonly SegmentedControlItem[];
|
|
20
|
+
/** The picked value when controlled. Pass with `onValueChange`. */
|
|
21
|
+
value?: string;
|
|
22
|
+
/** The initially picked value when uncontrolled. */
|
|
23
|
+
defaultValue?: string;
|
|
24
|
+
/** Called with the newly picked value. Never called with `undefined`. */
|
|
25
|
+
onValueChange?: (value: string) => void;
|
|
26
|
+
/** Which rung of the control ladder to sit on. Defaults to `"md"`. */
|
|
27
|
+
size?: SegmentedControlSize;
|
|
28
|
+
/** Extra classes for the group frame. */
|
|
29
|
+
className?: string;
|
|
30
|
+
/** Extra classes for every segment. */
|
|
31
|
+
itemClassName?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A one-of-N switch drawn as a row of segments: the console's view picker.
|
|
35
|
+
*
|
|
36
|
+
* Built on Base UI's `ToggleGroup`, so arrow-key roving focus and the
|
|
37
|
+
* pressed-state ARIA come from the primitive. Two rules are added on top:
|
|
38
|
+
*
|
|
39
|
+
* 1. **It cannot be emptied.** A toggle group lets you unpress the pressed
|
|
40
|
+
* item; a segmented control is a choice between N things, so clicking the
|
|
41
|
+
* active segment is a no-op rather than a way to end up with nothing
|
|
42
|
+
* selected. This is why the underlying group is always controlled here, even
|
|
43
|
+
* when the wrapper is not.
|
|
44
|
+
* 2. **The active segment is tinted, not filled** — see {@link ITEM_CLASSES}.
|
|
45
|
+
*
|
|
46
|
+
* Give the group an `aria-label`: on its own it is an unnamed group of buttons.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* <SegmentedControl
|
|
50
|
+
* aria-label="View"
|
|
51
|
+
* value={view}
|
|
52
|
+
* onValueChange={setView}
|
|
53
|
+
* items={[{ value: "beams", label: "Beams" }, { value: "patch", label: "Patch" }]}
|
|
54
|
+
* />
|
|
55
|
+
*/
|
|
56
|
+
declare const SegmentedControl: React.ForwardRefExoticComponent<Omit<SegmentedControlProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
57
|
+
//#endregion
|
|
58
|
+
export { SegmentedControl, SegmentedControlItem, SegmentedControlProps, SegmentedControlSize };
|
|
@@ -0,0 +1,76 @@
|
|
|
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 { Toggle } from "@base-ui/react/toggle";
|
|
6
|
+
import { ToggleGroup } from "@base-ui/react/toggle-group";
|
|
7
|
+
//#region src/chrome/segmented-control.tsx
|
|
8
|
+
const ITEM_SIZES = {
|
|
9
|
+
sm: "h-control-sm px-(--cue-space-3) text-(length:--cue-text-label)",
|
|
10
|
+
md: "h-control-md px-(--cue-space-4) text-(length:--cue-text-ui)",
|
|
11
|
+
lg: "h-control-lg px-(--cue-space-5) text-(length:--cue-text-body)"
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* The pressed segment is marked with `accent-soft` and accent ink — never a
|
|
15
|
+
* solid accent fill. A solid bar inside a small control reads as a second,
|
|
16
|
+
* louder button and drowns the labels around it (the luma defect ruling); the
|
|
17
|
+
* soft tint says "this one" at exactly the volume a view switcher deserves.
|
|
18
|
+
*/
|
|
19
|
+
const ITEM_CLASSES = "inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-(--cue-space-2) whitespace-nowrap rounded-(--radius-control) font-mono text-fg-muted transition-colors duration-150 outline-none hover:text-fg data-[pressed]:bg-accent-soft data-[pressed]:text-accent focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-1 focus-visible:outline-accent disabled:pointer-events-none disabled:opacity-40 data-[disabled]:pointer-events-none data-[disabled]:opacity-40";
|
|
20
|
+
/**
|
|
21
|
+
* A one-of-N switch drawn as a row of segments: the console's view picker.
|
|
22
|
+
*
|
|
23
|
+
* Built on Base UI's `ToggleGroup`, so arrow-key roving focus and the
|
|
24
|
+
* pressed-state ARIA come from the primitive. Two rules are added on top:
|
|
25
|
+
*
|
|
26
|
+
* 1. **It cannot be emptied.** A toggle group lets you unpress the pressed
|
|
27
|
+
* item; a segmented control is a choice between N things, so clicking the
|
|
28
|
+
* active segment is a no-op rather than a way to end up with nothing
|
|
29
|
+
* selected. This is why the underlying group is always controlled here, even
|
|
30
|
+
* when the wrapper is not.
|
|
31
|
+
* 2. **The active segment is tinted, not filled** — see {@link ITEM_CLASSES}.
|
|
32
|
+
*
|
|
33
|
+
* Give the group an `aria-label`: on its own it is an unnamed group of buttons.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* <SegmentedControl
|
|
37
|
+
* aria-label="View"
|
|
38
|
+
* value={view}
|
|
39
|
+
* onValueChange={setView}
|
|
40
|
+
* items={[{ value: "beams", label: "Beams" }, { value: "patch", label: "Patch" }]}
|
|
41
|
+
* />
|
|
42
|
+
*/
|
|
43
|
+
const SegmentedControl = React.forwardRef(function SegmentedControl({ items, value: valueProp, defaultValue, onValueChange, size = "md", className, itemClassName, ...groupProps }, ref) {
|
|
44
|
+
const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue);
|
|
45
|
+
const value = valueProp ?? uncontrolledValue;
|
|
46
|
+
const handleValueChange = (groupValue) => {
|
|
47
|
+
const next = groupValue[0];
|
|
48
|
+
if (next === void 0 || next === value) return;
|
|
49
|
+
if (valueProp === void 0) setUncontrolledValue(next);
|
|
50
|
+
onValueChange?.(next);
|
|
51
|
+
};
|
|
52
|
+
const iconSize = size === "sm" ? "size-icon-sm" : "size-icon-md";
|
|
53
|
+
return /* @__PURE__ */ jsx(ToggleGroup, {
|
|
54
|
+
ref,
|
|
55
|
+
value: value === void 0 ? [] : [value],
|
|
56
|
+
onValueChange: handleValueChange,
|
|
57
|
+
"data-slot": "segmented-control",
|
|
58
|
+
className: cn("inline-flex items-center gap-(--cue-space-1) rounded-(--radius-control) border border-border bg-surface-1 p-(--cue-space-1)", className),
|
|
59
|
+
...groupProps,
|
|
60
|
+
children: items.map((item) => {
|
|
61
|
+
const Icon = item.icon;
|
|
62
|
+
return /* @__PURE__ */ jsxs(Toggle, {
|
|
63
|
+
value: item.value,
|
|
64
|
+
disabled: item.disabled,
|
|
65
|
+
"data-slot": "segmented-control-item",
|
|
66
|
+
className: cn(ITEM_CLASSES, ITEM_SIZES[size], itemClassName),
|
|
67
|
+
children: [Icon === void 0 ? null : /* @__PURE__ */ jsx(Icon, {
|
|
68
|
+
"aria-hidden": "true",
|
|
69
|
+
className: cn("shrink-0", iconSize)
|
|
70
|
+
}), item.label]
|
|
71
|
+
}, item.value);
|
|
72
|
+
})
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
//#endregion
|
|
76
|
+
export { SegmentedControl };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
//#region src/chrome/status-bar.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Ink for a status-bar item. `neutral` inherits the bar's own subtle grey; the
|
|
5
|
+
* rest are the shared status vocabulary, so "3 faults" in the status bar is the
|
|
6
|
+
* same red as the danger `Chip` that raised it.
|
|
7
|
+
*/
|
|
8
|
+
type StatusBarTone = "neutral" | "accent" | "ok" | "busy" | "warn" | "danger" | "info";
|
|
9
|
+
/** Props for {@link StatusBar}: the native `<div>` surface plus `className`. */
|
|
10
|
+
type StatusBarProps = React.ComponentPropsWithoutRef<"div">;
|
|
11
|
+
interface StatusBarItemProps extends React.ComponentPropsWithoutRef<"div"> {
|
|
12
|
+
/** Ink for this item. Defaults to the bar's own subtle grey. */
|
|
13
|
+
tone?: StatusBarTone;
|
|
14
|
+
/**
|
|
15
|
+
* Start the trailing cluster here: pushes this item and everything after it
|
|
16
|
+
* to the far edge. Cheaper and more robust than a spacer element, which a
|
|
17
|
+
* caller has to remember to keep in the right place.
|
|
18
|
+
*/
|
|
19
|
+
push?: boolean;
|
|
20
|
+
/** Optional leading icon (e.g. a lucide icon), drawn `aria-hidden`. */
|
|
21
|
+
icon?: React.ElementType;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The quiet strip along the bottom of a window.
|
|
25
|
+
*
|
|
26
|
+
* The smallest type in the system in the subtlest ink: a status bar is read
|
|
27
|
+
* when you go looking for it and ignored otherwise, so it must never compete
|
|
28
|
+
* with the work above it. Height comes from `--cue-chrome-statusbar`.
|
|
29
|
+
*
|
|
30
|
+
* Not a live region — a status bar changes constantly (frame counters, DMX
|
|
31
|
+
* output), and announcing every change would make the app unusable with a
|
|
32
|
+
* screen reader. Put anything that genuinely must be announced in a `Toast`.
|
|
33
|
+
*
|
|
34
|
+
* Static markup — no `"use client"`.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* <StatusBar>
|
|
38
|
+
* <StatusBar.Item icon={Plug} tone="ok">Art-Net connected</StatusBar.Item>
|
|
39
|
+
* <StatusBar.Item push>512 channels</StatusBar.Item>
|
|
40
|
+
* </StatusBar>
|
|
41
|
+
*/
|
|
42
|
+
declare const StatusBar: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>> & {
|
|
43
|
+
Item: React.ForwardRefExoticComponent<StatusBarItemProps & React.RefAttributes<HTMLDivElement>>;
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
export { StatusBar, StatusBarItemProps, StatusBarProps, StatusBarTone };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { cn } from "../lib/cn.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
//#region src/chrome/status-bar.tsx
|
|
5
|
+
const ITEM_TONES = {
|
|
6
|
+
neutral: "",
|
|
7
|
+
accent: "text-accent",
|
|
8
|
+
ok: "text-ok",
|
|
9
|
+
busy: "text-busy",
|
|
10
|
+
warn: "text-warn",
|
|
11
|
+
danger: "text-danger",
|
|
12
|
+
info: "text-info"
|
|
13
|
+
};
|
|
14
|
+
const StatusBarRoot = React.forwardRef(function StatusBar({ className, ...elementProps }, ref) {
|
|
15
|
+
return /* @__PURE__ */ jsx("div", {
|
|
16
|
+
ref,
|
|
17
|
+
"data-slot": "status-bar",
|
|
18
|
+
className: cn("flex h-(--cue-chrome-statusbar) w-full shrink-0 items-center gap-(--cue-space-4) border-t border-border bg-surface-1 px-(--cue-pad-row-x) font-mono text-(length:--cue-text-label) text-fg-subtle", className),
|
|
19
|
+
...elementProps
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
/** One reading in the bar: a mode, a count, a connection state. */
|
|
23
|
+
const StatusBarItem = React.forwardRef(function StatusBarItem({ className, tone = "neutral", push = false, icon: Icon, children, ...elementProps }, ref) {
|
|
24
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
25
|
+
ref,
|
|
26
|
+
"data-slot": "status-bar-item",
|
|
27
|
+
className: cn("inline-flex min-w-0 shrink-0 items-center gap-(--cue-space-2) whitespace-nowrap", ITEM_TONES[tone], push ? "ml-auto" : void 0, className),
|
|
28
|
+
...elementProps,
|
|
29
|
+
children: [Icon === void 0 ? null : /* @__PURE__ */ jsx(Icon, {
|
|
30
|
+
"aria-hidden": "true",
|
|
31
|
+
className: "size-icon-sm shrink-0"
|
|
32
|
+
}), children]
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
/**
|
|
36
|
+
* The quiet strip along the bottom of a window.
|
|
37
|
+
*
|
|
38
|
+
* The smallest type in the system in the subtlest ink: a status bar is read
|
|
39
|
+
* when you go looking for it and ignored otherwise, so it must never compete
|
|
40
|
+
* with the work above it. Height comes from `--cue-chrome-statusbar`.
|
|
41
|
+
*
|
|
42
|
+
* Not a live region — a status bar changes constantly (frame counters, DMX
|
|
43
|
+
* output), and announcing every change would make the app unusable with a
|
|
44
|
+
* screen reader. Put anything that genuinely must be announced in a `Toast`.
|
|
45
|
+
*
|
|
46
|
+
* Static markup — no `"use client"`.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* <StatusBar>
|
|
50
|
+
* <StatusBar.Item icon={Plug} tone="ok">Art-Net connected</StatusBar.Item>
|
|
51
|
+
* <StatusBar.Item push>512 channels</StatusBar.Item>
|
|
52
|
+
* </StatusBar>
|
|
53
|
+
*/
|
|
54
|
+
const StatusBar = Object.assign(StatusBarRoot, { Item: StatusBarItem });
|
|
55
|
+
//#endregion
|
|
56
|
+
export { StatusBar };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Tabs } from "@base-ui/react/tabs";
|
|
3
|
+
//#region src/chrome/tabs.d.ts
|
|
4
|
+
interface TabsRootProps extends Omit<Tabs.Root.Props, "className"> {
|
|
5
|
+
/** Extra classes for the tabs frame. */
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
interface TabsListProps extends Omit<Tabs.List.Props, "className"> {
|
|
9
|
+
/** Extra classes for the strip. */
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
interface TabsTabProps extends Omit<Tabs.Tab.Props, "className"> {
|
|
13
|
+
/** Extra classes for the tab button. */
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
interface TabsPanelProps extends Omit<Tabs.Panel.Props, "className"> {
|
|
17
|
+
/** Extra classes for the panel. */
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
interface ScrollableTabsListProps extends TabsListProps {
|
|
21
|
+
/**
|
|
22
|
+
* Classes for the outer frame (background, rim). It spans the full width even
|
|
23
|
+
* while the strip inside it is scrolled.
|
|
24
|
+
*/
|
|
25
|
+
containerClassName?: string;
|
|
26
|
+
/**
|
|
27
|
+
* The active tab's value. When it changes, that tab is scrolled into view — a
|
|
28
|
+
* tab selected in code (a deep link, a keyboard shortcut) can be off-screen.
|
|
29
|
+
*/
|
|
30
|
+
activeValue?: Tabs.Tab.Value;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A {@link TabsList} that scrolls when its tabs do not fit, and says so.
|
|
34
|
+
*
|
|
35
|
+
* Use instead of `Tabs.List` wherever the tab count can outgrow the container:
|
|
36
|
+
* a plain flex row silently clips its labels ("SETTINGS" rendering as "INGS"),
|
|
37
|
+
* which reads as a layout bug rather than as "scroll me".
|
|
38
|
+
*
|
|
39
|
+
* The affordance is two things, and it needs both. The mask fades the content
|
|
40
|
+
* at whichever edge still hides tabs; the chevron buttons are the visible half,
|
|
41
|
+
* because what sits at an overflowing edge is usually the gap *between* two
|
|
42
|
+
* tabs and fading empty space produces nothing anyone can see. The chevrons
|
|
43
|
+
* double as the control for anyone without a horizontal-scroll device.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* <Tabs.Root defaultValue={view}>
|
|
47
|
+
* <ScrollableTabsList activeValue={view}>
|
|
48
|
+
* {views.map((v) => <Tabs.Tab key={v} value={v}>{v}</Tabs.Tab>)}
|
|
49
|
+
* </ScrollableTabsList>
|
|
50
|
+
* </Tabs.Root>
|
|
51
|
+
*/
|
|
52
|
+
declare const ScrollableTabsList: React.ForwardRefExoticComponent<Omit<ScrollableTabsListProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
53
|
+
/**
|
|
54
|
+
* One surface, several views.
|
|
55
|
+
*
|
|
56
|
+
* Wraps Base UI's `Tabs`, so roving focus, `aria-controls` wiring and
|
|
57
|
+
* activation semantics are the primitive's. This layer adds the console skin:
|
|
58
|
+
* a hairline strip, mono labels and an accent underline for the active tab.
|
|
59
|
+
*
|
|
60
|
+
* Reach for {@link ScrollableTabsList} instead of `Tabs.List` when the number of
|
|
61
|
+
* tabs is data-driven and can outgrow its container.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* <Tabs.Root defaultValue="patch">
|
|
65
|
+
* <Tabs.List>
|
|
66
|
+
* <Tabs.Tab value="patch">Patch</Tabs.Tab>
|
|
67
|
+
* <Tabs.Tab value="cues">Cues</Tabs.Tab>
|
|
68
|
+
* </Tabs.List>
|
|
69
|
+
* <Tabs.Panel value="patch">…</Tabs.Panel>
|
|
70
|
+
* <Tabs.Panel value="cues">…</Tabs.Panel>
|
|
71
|
+
* </Tabs.Root>
|
|
72
|
+
*/
|
|
73
|
+
declare const Tabs$1: {
|
|
74
|
+
Root: React.ForwardRefExoticComponent<Omit<TabsRootProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
75
|
+
List: React.ForwardRefExoticComponent<Omit<TabsListProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
76
|
+
Tab: React.ForwardRefExoticComponent<Omit<TabsTabProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
77
|
+
Panel: React.ForwardRefExoticComponent<Omit<TabsPanelProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
78
|
+
};
|
|
79
|
+
//#endregion
|
|
80
|
+
export { ScrollableTabsList, ScrollableTabsListProps, Tabs$1 as Tabs, TabsListProps, TabsPanelProps, TabsRootProps, TabsTabProps };
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { computeScrollEdges, edgeFadeMask } from "./_tabs-scroll.js";
|
|
4
|
+
import { ChevronLeftGlyph, ChevronRightGlyph } from "./_glyphs.js";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { Tabs } from "@base-ui/react/tabs";
|
|
8
|
+
//#region src/chrome/tabs.tsx
|
|
9
|
+
/** Groups a tab list with its panels and owns the selected value. */
|
|
10
|
+
const TabsRoot = React.forwardRef(function TabsRoot({ className, ...elementProps }, ref) {
|
|
11
|
+
return /* @__PURE__ */ jsx(Tabs.Root, {
|
|
12
|
+
ref,
|
|
13
|
+
"data-slot": "tabs",
|
|
14
|
+
className: cn("flex min-w-0 flex-col gap-(--cue-space-4) data-[orientation=vertical]:flex-row", className),
|
|
15
|
+
...elementProps
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* The strip of tabs, hung off a hairline.
|
|
20
|
+
*
|
|
21
|
+
* The rule belongs to the list rather than to the active tab so it spans the
|
|
22
|
+
* full width even when the tabs do not — which is what makes the selected tab's
|
|
23
|
+
* accent underline read as a mark *on* a rule rather than as a floating dash.
|
|
24
|
+
*/
|
|
25
|
+
const TabsList = React.forwardRef(function TabsList({ className, ...elementProps }, ref) {
|
|
26
|
+
return /* @__PURE__ */ jsx(Tabs.List, {
|
|
27
|
+
ref,
|
|
28
|
+
"data-slot": "tabs-list",
|
|
29
|
+
className: cn("relative flex items-center gap-(--cue-space-1) border-b border-border data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch data-[orientation=vertical]:border-b-0 data-[orientation=vertical]:border-r", className),
|
|
30
|
+
...elementProps
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* One tab. Selected state is an accent underline sitting on the list's rule —
|
|
35
|
+
* never a filled pill, which at console density turns a row of four tabs into a
|
|
36
|
+
* row of four buttons and loses the "one surface, several views" reading.
|
|
37
|
+
*/
|
|
38
|
+
const TabsTab = React.forwardRef(function TabsTab({ className, ...elementProps }, ref) {
|
|
39
|
+
return /* @__PURE__ */ jsx(Tabs.Tab, {
|
|
40
|
+
ref,
|
|
41
|
+
"data-slot": "tabs-tab",
|
|
42
|
+
className: cn("relative inline-flex h-control-md shrink-0 cursor-pointer items-center justify-center gap-(--cue-space-2) rounded-t-(--radius-control) px-(--cue-space-4) font-mono text-(length:--cue-text-ui) whitespace-nowrap text-fg-muted transition-colors duration-150 outline-none select-none", "hover:text-fg focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-2 focus-visible:outline-accent", "data-[disabled]:pointer-events-none data-[disabled]:opacity-40", "after:absolute after:inset-x-0 after:-bottom-px after:h-px after:bg-transparent after:content-['']", "data-[active]:text-accent data-[active]:after:bg-accent", className),
|
|
43
|
+
...elementProps
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
/** The body shown for the matching tab. Focusable, so keyboard users land in it. */
|
|
47
|
+
const TabsPanel = React.forwardRef(function TabsPanel({ className, ...elementProps }, ref) {
|
|
48
|
+
return /* @__PURE__ */ jsx(Tabs.Panel, {
|
|
49
|
+
ref,
|
|
50
|
+
"data-slot": "tabs-panel",
|
|
51
|
+
className: cn("min-w-0 outline-none focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-accent", className),
|
|
52
|
+
...elementProps
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
/** Page the strip by most of a screenful, keeping a sliver of context. */
|
|
56
|
+
const NUDGE_FRACTION = .7;
|
|
57
|
+
/**
|
|
58
|
+
* A {@link TabsList} that scrolls when its tabs do not fit, and says so.
|
|
59
|
+
*
|
|
60
|
+
* Use instead of `Tabs.List` wherever the tab count can outgrow the container:
|
|
61
|
+
* a plain flex row silently clips its labels ("SETTINGS" rendering as "INGS"),
|
|
62
|
+
* which reads as a layout bug rather than as "scroll me".
|
|
63
|
+
*
|
|
64
|
+
* The affordance is two things, and it needs both. The mask fades the content
|
|
65
|
+
* at whichever edge still hides tabs; the chevron buttons are the visible half,
|
|
66
|
+
* because what sits at an overflowing edge is usually the gap *between* two
|
|
67
|
+
* tabs and fading empty space produces nothing anyone can see. The chevrons
|
|
68
|
+
* double as the control for anyone without a horizontal-scroll device.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* <Tabs.Root defaultValue={view}>
|
|
72
|
+
* <ScrollableTabsList activeValue={view}>
|
|
73
|
+
* {views.map((v) => <Tabs.Tab key={v} value={v}>{v}</Tabs.Tab>)}
|
|
74
|
+
* </ScrollableTabsList>
|
|
75
|
+
* </Tabs.Root>
|
|
76
|
+
*/
|
|
77
|
+
const ScrollableTabsList = React.forwardRef(function ScrollableTabsList({ className, containerClassName, activeValue, children, ...listProps }, ref) {
|
|
78
|
+
const scrollerRef = React.useRef(null);
|
|
79
|
+
const [edges, setEdges] = React.useState({
|
|
80
|
+
start: false,
|
|
81
|
+
end: false
|
|
82
|
+
});
|
|
83
|
+
const sync = React.useCallback(() => {
|
|
84
|
+
const el = scrollerRef.current;
|
|
85
|
+
if (el === null) return;
|
|
86
|
+
setEdges(computeScrollEdges(el.scrollLeft, el.scrollWidth, el.clientWidth));
|
|
87
|
+
}, []);
|
|
88
|
+
React.useEffect(() => {
|
|
89
|
+
const el = scrollerRef.current;
|
|
90
|
+
if (el === null) return;
|
|
91
|
+
sync();
|
|
92
|
+
el.addEventListener("scroll", sync, { passive: true });
|
|
93
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(() => sync());
|
|
94
|
+
observer?.observe(el);
|
|
95
|
+
if (el.firstElementChild !== null) observer?.observe(el.firstElementChild);
|
|
96
|
+
return () => {
|
|
97
|
+
el.removeEventListener("scroll", sync);
|
|
98
|
+
observer?.disconnect();
|
|
99
|
+
};
|
|
100
|
+
}, [sync]);
|
|
101
|
+
React.useEffect(() => {
|
|
102
|
+
scrollerRef.current?.querySelector("[data-slot='tabs-tab'][data-active]")?.scrollIntoView?.({
|
|
103
|
+
block: "nearest",
|
|
104
|
+
inline: "nearest"
|
|
105
|
+
});
|
|
106
|
+
}, [activeValue]);
|
|
107
|
+
const nudge = (direction) => {
|
|
108
|
+
const el = scrollerRef.current;
|
|
109
|
+
el?.scrollBy?.({
|
|
110
|
+
left: direction * el.clientWidth * NUDGE_FRACTION,
|
|
111
|
+
behavior: "smooth"
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
const mask = edgeFadeMask(edges);
|
|
115
|
+
const chevronClasses = "absolute inset-y-0 z-10 flex w-(--cue-space-5) cursor-pointer items-center justify-center bg-surface-2 text-fg-muted outline-none hover:text-fg focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-2 focus-visible:outline-accent";
|
|
116
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
117
|
+
"data-slot": "tabs-scroll-frame",
|
|
118
|
+
className: cn("relative min-w-0", containerClassName),
|
|
119
|
+
children: [
|
|
120
|
+
/* @__PURE__ */ jsx("div", {
|
|
121
|
+
ref: scrollerRef,
|
|
122
|
+
"data-slot": "tabs-scroller",
|
|
123
|
+
className: "overflow-x-auto [mask-image:var(--cue-tabs-fade)] [-webkit-mask-image:var(--cue-tabs-fade)] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
124
|
+
style: mask === void 0 ? void 0 : { "--cue-tabs-fade": mask },
|
|
125
|
+
children: /* @__PURE__ */ jsx(TabsList, {
|
|
126
|
+
ref,
|
|
127
|
+
className: cn("w-max", className),
|
|
128
|
+
...listProps,
|
|
129
|
+
children
|
|
130
|
+
})
|
|
131
|
+
}),
|
|
132
|
+
edges.start ? /* @__PURE__ */ jsx("button", {
|
|
133
|
+
type: "button",
|
|
134
|
+
"aria-label": "Show earlier tabs",
|
|
135
|
+
onClick: () => nudge(-1),
|
|
136
|
+
className: cn(chevronClasses, "left-0"),
|
|
137
|
+
children: /* @__PURE__ */ jsx(ChevronLeftGlyph, { className: "size-icon-sm" })
|
|
138
|
+
}) : null,
|
|
139
|
+
edges.end ? /* @__PURE__ */ jsx("button", {
|
|
140
|
+
type: "button",
|
|
141
|
+
"aria-label": "Show later tabs",
|
|
142
|
+
onClick: () => nudge(1),
|
|
143
|
+
className: cn(chevronClasses, "right-0"),
|
|
144
|
+
children: /* @__PURE__ */ jsx(ChevronRightGlyph, { className: "size-icon-sm" })
|
|
145
|
+
}) : null
|
|
146
|
+
]
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
/**
|
|
150
|
+
* One surface, several views.
|
|
151
|
+
*
|
|
152
|
+
* Wraps Base UI's `Tabs`, so roving focus, `aria-controls` wiring and
|
|
153
|
+
* activation semantics are the primitive's. This layer adds the console skin:
|
|
154
|
+
* a hairline strip, mono labels and an accent underline for the active tab.
|
|
155
|
+
*
|
|
156
|
+
* Reach for {@link ScrollableTabsList} instead of `Tabs.List` when the number of
|
|
157
|
+
* tabs is data-driven and can outgrow its container.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* <Tabs.Root defaultValue="patch">
|
|
161
|
+
* <Tabs.List>
|
|
162
|
+
* <Tabs.Tab value="patch">Patch</Tabs.Tab>
|
|
163
|
+
* <Tabs.Tab value="cues">Cues</Tabs.Tab>
|
|
164
|
+
* </Tabs.List>
|
|
165
|
+
* <Tabs.Panel value="patch">…</Tabs.Panel>
|
|
166
|
+
* <Tabs.Panel value="cues">…</Tabs.Panel>
|
|
167
|
+
* </Tabs.Root>
|
|
168
|
+
*/
|
|
169
|
+
const Tabs$1 = {
|
|
170
|
+
Root: TabsRoot,
|
|
171
|
+
List: TabsList,
|
|
172
|
+
Tab: TabsTab,
|
|
173
|
+
Panel: TabsPanel
|
|
174
|
+
};
|
|
175
|
+
//#endregion
|
|
176
|
+
export { ScrollableTabsList, Tabs$1 as Tabs };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
//#region src/chrome/title-bar.d.ts
|
|
3
|
+
interface TitleBarProps extends React.ComponentPropsWithoutRef<"div"> {
|
|
4
|
+
/**
|
|
5
|
+
* Make the bar a window drag handle.
|
|
6
|
+
*
|
|
7
|
+
* Emits `data-tauri-drag-region` (Tauri reads the attribute) *and* the
|
|
8
|
+
* `app-region: drag` CSS property (Electron and Chromium read that), because
|
|
9
|
+
* the same component ships into both shells and neither one recognises the
|
|
10
|
+
* other's contract. The interactive clusters are carved back out with
|
|
11
|
+
* `app-region: no-drag`, or the buttons in the bar would only ever move the
|
|
12
|
+
* window instead of firing.
|
|
13
|
+
*/
|
|
14
|
+
platformDrag?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Centre slot: the document name. Absolutely centred on the *bar*, not
|
|
17
|
+
* between the two clusters, so it does not shift sideways when a button
|
|
18
|
+
* appears on one side. `pointer-events-none`, so the dead space around a
|
|
19
|
+
* short title stays draggable.
|
|
20
|
+
*/
|
|
21
|
+
center?: React.ReactNode;
|
|
22
|
+
/** Trailing slot: window controls, connection state, an overflow menu. */
|
|
23
|
+
actions?: React.ReactNode;
|
|
24
|
+
/** Leading slot: the app mark, a back button, the file menu. */
|
|
25
|
+
children?: React.ReactNode;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The window's own bar: app mark left, document name centred, controls right.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* <TitleBar platformDrag center="untitled.cue" actions={<WindowControls />}>
|
|
32
|
+
* <Eyebrow>CUE++</Eyebrow>
|
|
33
|
+
* </TitleBar>
|
|
34
|
+
*/
|
|
35
|
+
declare const TitleBar: React.ForwardRefExoticComponent<TitleBarProps & React.RefAttributes<HTMLDivElement>>;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { TitleBar, TitleBarProps };
|