@cueplusplus/ui 0.18.2 → 0.20.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/CHANGELOG.md +100 -0
- package/dist/brand/_motif-seed.js +20 -0
- package/dist/brand/gloss-object.d.ts +23 -0
- package/dist/brand/gloss-object.js +108 -0
- package/dist/brand/halftone.d.ts +23 -0
- package/dist/brand/halftone.js +54 -0
- package/dist/brand/index.d.ts +8 -1
- package/dist/brand/motif.d.ts +32 -0
- package/dist/brand/motif.js +71 -0
- package/dist/brand/particle-logo.d.ts +50 -0
- package/dist/brand/particle-logo.js +437 -0
- package/dist/brand/particle-mark.d.ts +29 -0
- package/dist/brand/particle-mark.js +137 -0
- package/dist/brand/ribbon.d.ts +20 -0
- package/dist/brand/ribbon.js +54 -0
- package/dist/brand/text-scramble.d.ts +42 -0
- package/dist/brand/text-scramble.js +160 -0
- package/dist/chat/delegation-card.js +2 -1
- package/dist/chat/message.js +12 -13
- package/dist/chrome/announcement-bar.d.ts +30 -0
- package/dist/chrome/announcement-bar.js +38 -0
- package/dist/chrome/app-bar.d.ts +4 -1
- package/dist/chrome/app-bar.js +7 -2
- package/dist/chrome/app-shell.js +8 -1
- package/dist/chrome/band.d.ts +3 -1
- package/dist/chrome/band.js +4 -3
- package/dist/chrome/hero.d.ts +61 -0
- package/dist/chrome/hero.js +108 -0
- package/dist/chrome/index.d.ts +6 -1
- package/dist/chrome/index.js +6 -1
- package/dist/chrome/keyword.d.ts +22 -0
- package/dist/chrome/keyword.js +28 -0
- package/dist/chrome/logo-strip.d.ts +23 -0
- package/dist/chrome/logo-strip.js +43 -0
- package/dist/chrome/page-shell.js +13 -1
- package/dist/chrome/stat-band.d.ts +32 -0
- package/dist/chrome/stat-band.js +39 -0
- package/dist/color/color-area.js +2 -1
- package/dist/dmx/channel-matrix.js +5 -3
- package/dist/dmx/dmx-strip.js +5 -3
- package/dist/elements/animated-number.js +4 -1
- package/dist/elements/replay.d.ts +1 -1
- package/dist/elements/replay.js +5 -2
- package/dist/elements/scroll-anchor.js +4 -1
- package/dist/forms/_chassis.d.ts +1 -1
- package/dist/forms/_chassis.js +2 -2
- package/dist/forms/env-var-input.js +2 -1
- package/dist/forms/file-upload.js +2 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +18 -2
- package/dist/instruments/data-table.js +3 -2
- package/dist/instruments/index.js +1 -1
- package/dist/instruments/stat.js +1 -1
- package/dist/instruments/table.js +1 -1
- package/dist/instruments/terminal-frame.js +5 -2
- package/dist/layout/grid.js +4 -2
- package/dist/layout/index.d.ts +2 -1
- package/dist/layout/index.js +2 -1
- package/dist/layout/preview.js +4 -188
- package/dist/layout/reveal.d.ts +44 -0
- package/dist/layout/reveal.js +106 -0
- package/dist/layout/sidebar.js +88 -52
- package/dist/lib/cn.js +23 -5
- package/dist/lib/particle-field-shaders.js +236 -0
- package/dist/lib/particle-field.js +210 -0
- package/dist/midi/spectrum-visualizer.js +2 -1
- package/dist/overlays/_surface.d.ts +2 -2
- package/dist/primitives/button.js +22 -3
- package/dist/primitives/chip.d.ts +1 -1
- package/dist/primitives/chip.js +63 -6
- package/dist/styles.css +26 -0
- package/dist/system/_scoped-pairing.js +18 -0
- package/dist/system/_stage-scope.js +199 -0
- package/dist/system/_style-check.js +1 -1
- package/dist/system/_style-chip.js +1 -1
- package/dist/system/_style-field-chassis.js +14 -1
- package/dist/system/_style-group-label.js +7 -3
- package/dist/system/_style-hero-title.js +41 -0
- package/dist/system/_style-kbd.js +1 -1
- package/dist/system/_style-label-ink.js +12 -5
- package/dist/system/_style-menu.js +1 -1
- package/dist/system/_style-page-title.js +1 -1
- package/dist/system/_style-segmented-control.js +1 -1
- package/dist/system/_style-skeleton.js +1 -1
- package/dist/system/_style-tab.js +1 -1
- package/dist/system/font-scope.d.ts +38 -0
- package/dist/system/font-scope.js +69 -0
- package/dist/system/frame-clock.d.ts +33 -0
- package/dist/system/frame-clock.js +55 -0
- package/dist/system/index.d.ts +4 -1
- package/dist/system/index.js +4 -1
- package/dist/system/portal.js +7 -1
- package/dist/system/still.d.ts +32 -0
- package/dist/system/still.js +60 -0
- package/manifest/components/alert-dialog.json +1 -1
- package/manifest/components/announcement-bar.json +82 -0
- package/manifest/components/app-bar.json +3 -2
- package/manifest/components/app-shell.json +3 -0
- package/manifest/components/autocomplete.json +2 -0
- package/manifest/components/band.json +2 -1
- package/manifest/components/bento.json +13 -13
- package/manifest/components/button.json +1 -0
- package/manifest/components/channel-matrix.json +1 -0
- package/manifest/components/chart-tooltip-content.json +1 -0
- package/manifest/components/checkbox-group.json +1 -1
- package/manifest/components/checkbox.json +1 -1
- package/manifest/components/chip.json +1 -0
- package/manifest/components/color-area.json +10 -0
- package/manifest/components/color-field.json +3 -0
- package/manifest/components/color-picker.json +3 -0
- package/manifest/components/combobox.json +2 -0
- package/manifest/components/command-palette.json +1 -0
- package/manifest/components/composer.json +3 -0
- package/manifest/components/context-menu.json +1 -1
- package/manifest/components/data-table-pagination.json +3 -0
- package/manifest/components/data-table-toolbar.json +3 -0
- package/manifest/components/date-field.json +3 -0
- package/manifest/components/date-picker.json +3 -0
- package/manifest/components/date-range-picker.json +3 -0
- package/manifest/components/delegation-card.json +6 -0
- package/manifest/components/density.json +6 -2
- package/manifest/components/dialog.json +1 -1
- package/manifest/components/dmx-bar.json +1 -1
- package/manifest/components/dmx-strip.json +1 -1
- package/manifest/components/drawer.json +1 -1
- package/manifest/components/dropdown-menu.json +1 -0
- package/manifest/components/env-var-input.json +3 -0
- package/manifest/components/file-upload.json +5 -0
- package/manifest/components/font-scope.json +82 -0
- package/manifest/components/footer.json +0 -1
- package/manifest/components/gloss-object.json +81 -0
- package/manifest/components/grid.json +6 -6
- package/manifest/components/halftone.json +79 -0
- package/manifest/components/hero.json +204 -0
- package/manifest/components/hover-card.json +1 -1
- package/manifest/components/input-group.json +3 -0
- package/manifest/components/input.json +3 -0
- package/manifest/components/kbd.json +1 -0
- package/manifest/components/keyword.json +67 -0
- package/manifest/components/ledger.json +5 -5
- package/manifest/components/logo-strip.json +93 -0
- package/manifest/components/markdown-text.json +3 -3
- package/manifest/components/menubar.json +1 -1
- package/manifest/components/message.json +8 -0
- package/manifest/components/motif.json +90 -0
- package/manifest/components/multi-select.json +2 -0
- package/manifest/components/musical-time-input.json +3 -0
- package/manifest/components/navigation-menu.json +1 -0
- package/manifest/components/number-field.json +3 -0
- package/manifest/components/otp-field.json +3 -0
- package/manifest/components/page-shell.json +5 -0
- package/manifest/components/particle-logo.json +140 -0
- package/manifest/components/particle-mark.json +75 -0
- package/manifest/components/password-input.json +3 -0
- package/manifest/components/popover.json +1 -1
- package/manifest/components/preview.json +10 -4
- package/manifest/components/radio-group.json +0 -1
- package/manifest/components/radio.json +0 -1
- package/manifest/components/reveal.json +106 -0
- package/manifest/components/ribbon.json +65 -0
- package/manifest/components/scrollable-tabs-list.json +1 -0
- package/manifest/components/scrub-input.json +3 -0
- package/manifest/components/search-input.json +3 -0
- package/manifest/components/segmented-control.json +1 -0
- package/manifest/components/select.json +3 -0
- package/manifest/components/sheet.json +1 -1
- package/manifest/components/sidebar.json +1 -0
- package/manifest/components/skeleton.json +1 -0
- package/manifest/components/spectrum-visualizer.json +10 -0
- package/manifest/components/stack.json +4 -4
- package/manifest/components/stat-band.json +68 -0
- package/manifest/components/stat.json +1 -1
- package/manifest/components/still-provider.json +60 -0
- package/manifest/components/switch.json +0 -1
- package/manifest/components/table.json +2 -2
- package/manifest/components/tabs.json +1 -0
- package/manifest/components/tags-input.json +2 -0
- package/manifest/components/text-scramble.json +90 -0
- package/manifest/components/textarea.json +3 -0
- package/manifest/components/theme-configurator.json +1 -0
- package/manifest/components/theme-provider.json +10 -4
- package/manifest/components/time-field.json +3 -0
- package/manifest/components/toast.json +1 -0
- package/manifest/components/tooltip.json +1 -1
- package/manifest/fixtures.json +18 -0
- package/manifest/manifest.json +368 -80
- package/manifest/tokens.json +93 -3
- package/package.json +6 -6
- package/dist/system/_paint-ground-pattern.js +0 -30
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Stat } from "./stat.js";
|
|
1
2
|
import { activateRowFromClick, activateRowFromKeyDown } from "./_data-row.js";
|
|
2
3
|
import { AppWindowFrame } from "./app-window-frame.js";
|
|
3
4
|
import { CopyButton } from "./copy-button.js";
|
|
@@ -10,7 +11,6 @@ import { Meter } from "./meter.js";
|
|
|
10
11
|
import { Progress } from "./progress.js";
|
|
11
12
|
import { SeamCell, SeamGrid } from "./seam-grid.js";
|
|
12
13
|
import { Sparkline } from "./sparkline.js";
|
|
13
|
-
import { Stat } from "./stat.js";
|
|
14
14
|
import { Table, TableScrollRegion } from "./table.js";
|
|
15
15
|
import { TerminalFrame } from "./terminal-frame.js";
|
|
16
16
|
import { TwoStepButton } from "./two-step-button.js";
|
package/dist/instruments/stat.js
CHANGED
|
@@ -12,7 +12,7 @@ import * as React from "react";
|
|
|
12
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
13
|
//#region src/instruments/stat.tsx
|
|
14
14
|
const VALUE_TONE_CLASSES = {
|
|
15
|
-
neutral: "text-fg",
|
|
15
|
+
neutral: "text-[color:var(--cue-style-stat-numeral-ink,var(--cue-fg))]",
|
|
16
16
|
accent: "text-accent",
|
|
17
17
|
ok: "text-ok",
|
|
18
18
|
busy: "text-busy",
|
|
@@ -247,7 +247,7 @@ const Table = {
|
|
|
247
247
|
return /* @__PURE__ */ jsx("caption", {
|
|
248
248
|
ref,
|
|
249
249
|
"data-slot": "table-caption",
|
|
250
|
-
className: cn(`caption-bottom pt-(--cue-space-3) text-left ${BODY_SIZE_LABEL} ${HELP_INK}`, LABEL_FACE, className),
|
|
250
|
+
className: cn(`caption-bottom pt-(--cue-space-3) ${CELL_PAD} text-left ${BODY_SIZE_LABEL} ${HELP_INK}`, LABEL_FACE, className),
|
|
251
251
|
...elementProps
|
|
252
252
|
});
|
|
253
253
|
})
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { mulberry32, usePrefersReducedMotion } from "./_motion.js";
|
|
4
|
+
import { useStill } from "../system/still.js";
|
|
3
5
|
import { LABEL_INK_SUBTLE } from "../system/_style-label-ink.js";
|
|
4
6
|
import { LABEL_SIZE } from "../system/_style-label-size.js";
|
|
5
7
|
import { CopyButton } from "./copy-button.js";
|
|
6
8
|
import { toRem } from "./_rem.js";
|
|
7
|
-
import { mulberry32, usePrefersReducedMotion } from "./_motion.js";
|
|
8
9
|
import * as React from "react";
|
|
9
10
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
11
|
//#region src/instruments/terminal-frame.tsx
|
|
@@ -76,7 +77,9 @@ function finalLines(script) {
|
|
|
76
77
|
* <TerminalFrame simulate={SCRIPT} />
|
|
77
78
|
*/
|
|
78
79
|
const TerminalFrame = React.forwardRef(function TerminalFrame({ className, title, lines, prompt = "$", copy = false, copyValue, simulate, height, children, ...elementProps }, ref) {
|
|
79
|
-
const
|
|
80
|
+
const prefersReduced = usePrefersReducedMotion();
|
|
81
|
+
const held = useStill();
|
|
82
|
+
const reduced = prefersReduced || held;
|
|
80
83
|
const [transcript, setTranscript] = React.useState(IDLE);
|
|
81
84
|
React.useEffect(() => {
|
|
82
85
|
if (simulate === void 0) {
|
package/dist/layout/grid.js
CHANGED
|
@@ -15,9 +15,11 @@ const COLUMN_CLASSES = {
|
|
|
15
15
|
/**
|
|
16
16
|
* The auto-filling track. The measure travels as a custom property rather than
|
|
17
17
|
* as an arbitrary value, so the track definition is one static class the
|
|
18
|
-
* scanner always sees instead of a fresh one per call site.
|
|
18
|
+
* scanner always sees instead of a fresh one per call site. The minimum is
|
|
19
|
+
* capped at the grid's own width, so a column narrower than `minItemWidth` (a
|
|
20
|
+
* phone) gets one full-width track instead of one that overflows it.
|
|
19
21
|
*/
|
|
20
|
-
const AUTO_FILL_CLASS = "grid-cols-[repeat(auto-fill,minmax(var(--cue-grid-min),1fr))]";
|
|
22
|
+
const AUTO_FILL_CLASS = "grid-cols-[repeat(auto-fill,minmax(min(var(--cue-grid-min),100%),1fr))]";
|
|
21
23
|
/**
|
|
22
24
|
* Two-dimensional layout: equal columns, or as many as fit.
|
|
23
25
|
*
|
package/dist/layout/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { Accordion, AccordionHeaderProps, AccordionItemProps, AccordionPanelProp
|
|
|
5
5
|
import { SpaceStep, Stack, StackAlign, StackJustify, StackProps } from "./stack.js";
|
|
6
6
|
import { Bento, BentoColumns, BentoMinHeight, BentoRootProps, BentoRowSpan, BentoRows, BentoSpan, BentoTileProps } from "./bento.js";
|
|
7
7
|
import { Breadcrumb, BreadcrumbItem, BreadcrumbProps } from "./breadcrumb.js";
|
|
8
|
+
import { Reveal, RevealProps } from "./reveal.js";
|
|
8
9
|
import { Card, CardContentProps, CardDescriptionProps, CardFooterProps, CardHeaderProps, CardRootProps, CardTitleProps } from "./card.js";
|
|
9
10
|
import { Collapsible, CollapsiblePanelProps, CollapsibleRootProps, CollapsibleTriggerProps, Disclosure, DisclosureProps } from "./collapsible.js";
|
|
10
11
|
import { DescriptionList, DescriptionListDetailProps, DescriptionListLayout, DescriptionListRootProps, DescriptionListTermProps } from "./description-list.js";
|
|
@@ -16,4 +17,4 @@ import { Pagination, PaginationEntry, PaginationProps, paginationRange } from ".
|
|
|
16
17
|
import { Preview, PreviewAxis, PreviewPresentation, PreviewProps, PreviewResizeOptions } from "./preview.js";
|
|
17
18
|
import { Stepper, StepperProps, StepperState, StepperStep } from "./stepper.js";
|
|
18
19
|
import { Timeline, TimelineContentProps, TimelineItemProps, TimelineMarkerProps, TimelineRootProps } from "./timeline.js";
|
|
19
|
-
export { Accordion, type AccordionHeaderProps, type AccordionItemProps, type AccordionPanelProps, type AccordionRootProps, type AccordionTriggerProps, Bento, type BentoColumns, type BentoMinHeight, type BentoRootProps, type BentoRowSpan, type BentoRows, type BentoSpan, type BentoTileProps, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Card, type CardContentProps, type CardDescriptionProps, type CardFooterProps, type CardHeaderProps, type CardRootProps, type CardTitleProps, Collapsible, type CollapsiblePanelProps, type CollapsibleRootProps, type CollapsibleTriggerProps, Container, type ContainerProps, type ContainerWidth, DescriptionList, type DescriptionListDetailProps, type DescriptionListLayout, type DescriptionListRootProps, type DescriptionListTermProps, Disclosure, type DisclosureProps, Frames, type FramesHeight, type FramesItemProps, type FramesLayout, type FramesRootProps, Grid, type GridColumns, type GridProps, Item, type ItemProps, Link, type LinkProps, Pagination, type PaginationEntry, type PaginationProps, Preview, type PreviewAxis, type PreviewGround, type PreviewPresentation, type PreviewProps, type PreviewResizeOptions, Sidebar, type SidebarItemProps, type SidebarRailProps, type SidebarRootProps, type SidebarSectionProps, type SpaceStep, Stack, type StackAlign, type StackJustify, type StackProps, Stepper, type StepperProps, type StepperState, type StepperStep, Timeline, type TimelineContentProps, type TimelineItemProps, type TimelineMarkerProps, type TimelineRootProps, itemVariants, linkVariants, paginationRange, useSidebar };
|
|
20
|
+
export { Accordion, type AccordionHeaderProps, type AccordionItemProps, type AccordionPanelProps, type AccordionRootProps, type AccordionTriggerProps, Bento, type BentoColumns, type BentoMinHeight, type BentoRootProps, type BentoRowSpan, type BentoRows, type BentoSpan, type BentoTileProps, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Card, type CardContentProps, type CardDescriptionProps, type CardFooterProps, type CardHeaderProps, type CardRootProps, type CardTitleProps, Collapsible, type CollapsiblePanelProps, type CollapsibleRootProps, type CollapsibleTriggerProps, Container, type ContainerProps, type ContainerWidth, DescriptionList, type DescriptionListDetailProps, type DescriptionListLayout, type DescriptionListRootProps, type DescriptionListTermProps, Disclosure, type DisclosureProps, Frames, type FramesHeight, type FramesItemProps, type FramesLayout, type FramesRootProps, Grid, type GridColumns, type GridProps, Item, type ItemProps, Link, type LinkProps, Pagination, type PaginationEntry, type PaginationProps, Preview, type PreviewAxis, type PreviewGround, type PreviewPresentation, type PreviewProps, type PreviewResizeOptions, Reveal, type RevealProps, Sidebar, type SidebarItemProps, type SidebarRailProps, type SidebarRootProps, type SidebarSectionProps, type SpaceStep, Stack, type StackAlign, type StackJustify, type StackProps, Stepper, type StepperProps, type StepperState, type StepperStep, Timeline, type TimelineContentProps, type TimelineItemProps, type TimelineMarkerProps, type TimelineRootProps, itemVariants, linkVariants, paginationRange, useSidebar };
|
package/dist/layout/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { Accordion } from "./accordion.js";
|
|
|
5
5
|
import { Stack } from "./stack.js";
|
|
6
6
|
import { Bento } from "./bento.js";
|
|
7
7
|
import { Breadcrumb } from "./breadcrumb.js";
|
|
8
|
+
import { Reveal } from "./reveal.js";
|
|
8
9
|
import { Card } from "./card.js";
|
|
9
10
|
import { Collapsible, Disclosure } from "./collapsible.js";
|
|
10
11
|
import { DescriptionList } from "./description-list.js";
|
|
@@ -15,4 +16,4 @@ import { Pagination, paginationRange } from "./pagination.js";
|
|
|
15
16
|
import { Preview } from "./preview.js";
|
|
16
17
|
import { Stepper } from "./stepper.js";
|
|
17
18
|
import { Timeline } from "./timeline.js";
|
|
18
|
-
export { Accordion, Bento, Breadcrumb, Card, Collapsible, Container, DescriptionList, Disclosure, Frames, Grid, Item, Link, Pagination, Preview, Sidebar, Stack, Stepper, Timeline, itemVariants, linkVariants, paginationRange, useSidebar };
|
|
19
|
+
export { Accordion, Bento, Breadcrumb, Card, Collapsible, Container, DescriptionList, Disclosure, Frames, Grid, Item, Link, Pagination, Preview, Reveal, Sidebar, Stack, Stepper, Timeline, itemVariants, linkVariants, paginationRange, useSidebar };
|
package/dist/layout/preview.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.js";
|
|
3
3
|
import { useIsomorphicLayoutEffect } from "../system/use-isomorphic-layout-effect.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { NO_PAIRING_SEED, PairingSeedContext, ThemeContext } from "../system/theme-provider.js";
|
|
4
|
+
import { useRead } from "../system/published.js";
|
|
5
|
+
import { DensityContext, PaintContext, StyleSetContext, useFollowedAxes, useRestateReady } from "../system/density.js";
|
|
6
|
+
import { ThemeContext } from "../system/theme-provider.js";
|
|
8
7
|
import { GROUND_CLASSES } from "./_ground.js";
|
|
9
8
|
import { STAGE_MARKS } from "../system/_style-stage-marks.js";
|
|
9
|
+
import { StageScope, stageAttributes } from "../system/_stage-scope.js";
|
|
10
10
|
import * as React from "react";
|
|
11
11
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
12
12
|
//#region src/layout/preview.tsx
|
|
@@ -212,190 +212,6 @@ function effectiveBounds(options, available) {
|
|
|
212
212
|
};
|
|
213
213
|
}
|
|
214
214
|
/**
|
|
215
|
-
* The attributes the stage carries — and, when nothing is asked, none at all.
|
|
216
|
-
*
|
|
217
|
-
* Inheriting is the *absence* of attributes, which is why every branch below
|
|
218
|
-
* is conditional. Three branches add a second attribute, each for a reason in
|
|
219
|
-
* the stylesheets rather than in taste.
|
|
220
|
-
*
|
|
221
|
-
* A theme's light block is the compound selector
|
|
222
|
-
* `[data-theme="t"][data-mode="light"]`, so a mode with no theme restates the
|
|
223
|
-
* page's theme on the same element. Read the other way, a theme with no mode
|
|
224
|
-
* repeats the page's mode. Otherwise the stage would match the theme's dark
|
|
225
|
-
* block under a light page, while every popup opened on it came up light:
|
|
226
|
-
* popups are stamped from the context `StageScope` publishes, which carries
|
|
227
|
-
* the page's mode.
|
|
228
|
-
*
|
|
229
|
-
* A theme's density overrides are addressed through `data-cue-theme`, the
|
|
230
|
-
* stamp `<Density>` writes, so a density names the nearest theme the same way.
|
|
231
|
-
*
|
|
232
|
-
* A stage that ends up naming a theme and no rung — its own theme, or the
|
|
233
|
-
* page's restated beside a mode (`scoped`, below) — restates the rung in force
|
|
234
|
-
* around it, as `data-density` with the theme as `data-cue-theme` (spec
|
|
235
|
-
* 2026-09-26-looks-fidelity §4.1.1). A theme's rung retunes are keyed on the
|
|
236
|
-
* theme and the rung on one element, or a rung below the theme, so a stage that
|
|
237
|
-
* re-themes with no `data-density` of its own inherits the rung already
|
|
238
|
-
* resolved against the PAGE's theme, and its own theme's retune of that rung
|
|
239
|
-
* never applies. `/looks` opens every stage this way: a theme and no rung. It
|
|
240
|
-
* is what a nested `ThemeProvider` that names a theme already does — theme,
|
|
241
|
-
* rung and mode together. The rung is the one `DensityContext` carries: `null`
|
|
242
|
-
* outside every provider, where nothing is restated, and never `useDensity()`'s
|
|
243
|
-
* `compact` fallback, which would invent one.
|
|
244
|
-
*
|
|
245
|
-
* The style set adds no second attribute, and that is the difference worth
|
|
246
|
-
* writing down beside the three that do: a `[data-style]` block is a single
|
|
247
|
-
* attribute selector naming no other axis, so a set stamped alone matches on
|
|
248
|
-
* its own.
|
|
249
|
-
*
|
|
250
|
-
* But a stage that re-themes, re-modes or re-faces restates the set and the pack
|
|
251
|
-
* in force around it (`around`), for a reason in custom properties rather than
|
|
252
|
-
* in selectors. Their blocks declare names whose values read those axes — a
|
|
253
|
-
* pack's stroke stops are the theme's borders, a set's band rule and ground are
|
|
254
|
-
* the theme's border and surface — and a custom property's `var()`s are
|
|
255
|
-
* substituted where it is declared. Declared only on the page, they arrive at
|
|
256
|
-
* the stage already resolved against the page's theme and pairing; restated on
|
|
257
|
-
* the stage, beside its own `data-theme` or `data-font`, they resolve against
|
|
258
|
-
* those. A rung alone changes no ink and restates nothing. `around` is `null`
|
|
259
|
-
* until the stage may restate: under a root that persists, not before the stage
|
|
260
|
-
* has mounted, when the set and pack in force are the root's props rather than
|
|
261
|
-
* the visitor's (see `useRestateReady`).
|
|
262
|
-
*
|
|
263
|
-
* The page's mode and rung, restated beside a stage theme — and the page's
|
|
264
|
-
* theme, restated beside a stage mode or as a stage rung's `data-cue-theme` —
|
|
265
|
-
* wait for the same mount on the same terms (tracking plan F13): under a
|
|
266
|
-
* persisting root each is the root's, whose value on the server is its prop
|
|
267
|
-
* while `<html>` carries the visitor's. So until then `followed` holds it back,
|
|
268
|
-
* and `data-cue-follows` names it instead — the theme stylesheets' blocks each
|
|
269
|
-
* have a twin keyed on `<html>`'s value and that marker (a followed rung
|
|
270
|
-
* included: the base rung's twin in `axes.css`, and each theme's retune of it
|
|
271
|
-
* keyed on the stage's own `data-theme`), and a rung node with no
|
|
272
|
-
* `data-cue-theme` is reached by the rung rules' structural form, so the stage
|
|
273
|
-
* paints the visitor's theme, mode and rung from the first frame (see
|
|
274
|
-
* `useFollowedAxes`). A theme, mode or rung the stage names, or one named
|
|
275
|
-
* between it and the root, is stamped as it always was. A followed rung takes
|
|
276
|
-
* its `data-cue-theme` with it: the stamp addresses a `data-density` on the
|
|
277
|
-
* same element, and there is none to address until the rung is stamped.
|
|
278
|
-
*/
|
|
279
|
-
function stageAttributes(asked, page, around, aroundDensity, followed) {
|
|
280
|
-
const attributes = {};
|
|
281
|
-
const scoped = asked.theme ?? (asked.mode === void 0 ? null : page?.theme ?? null);
|
|
282
|
-
if (scoped !== null && (asked.theme !== void 0 || !followed.theme)) attributes["data-theme"] = scoped;
|
|
283
|
-
const moded = asked.mode ?? (asked.theme === void 0 ? void 0 : page?.mode);
|
|
284
|
-
if (moded !== void 0 && !followed.mode) attributes["data-mode"] = moded;
|
|
285
|
-
if (asked.density !== void 0) {
|
|
286
|
-
attributes["data-density"] = asked.density;
|
|
287
|
-
const nearest = asked.theme ?? page?.theme ?? null;
|
|
288
|
-
if (nearest !== null && (asked.theme !== void 0 || !followed.theme)) attributes["data-cue-theme"] = nearest;
|
|
289
|
-
} else if (scoped !== null && aroundDensity !== null && !followed.density) {
|
|
290
|
-
attributes["data-density"] = aroundDensity;
|
|
291
|
-
if (asked.theme !== void 0 || !followed.theme) attributes["data-cue-theme"] = scoped;
|
|
292
|
-
}
|
|
293
|
-
if (followed.marker !== null) attributes["data-cue-follows"] = followed.marker;
|
|
294
|
-
if (asked.font !== void 0) attributes["data-font"] = asked.font;
|
|
295
|
-
if (asked.styleSet !== void 0) attributes["data-style"] = asked.styleSet;
|
|
296
|
-
if (asked.paint !== void 0) attributes["data-paint"] = asked.paint;
|
|
297
|
-
const restates = around !== null && (scoped !== null || moded !== void 0 || asked.font !== void 0);
|
|
298
|
-
if (restates && asked.styleSet === void 0 && around.styleSet !== null) attributes["data-style"] = around.styleSet;
|
|
299
|
-
if (restates && asked.paint === void 0 && around.paint !== null) attributes["data-paint"] = around.paint;
|
|
300
|
-
return attributes;
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* The contexts the stage republishes, so an overlay opened on it follows it.
|
|
304
|
-
*
|
|
305
|
-
* `useCuePortalProps()` stamps a portal container from `ThemeContext` and
|
|
306
|
-
* `DensityContext`; a popup mounts on `<body>` and inherits nothing from the
|
|
307
|
-
* stage's DOM. So the stage's subtree reads a theme context with the stage's
|
|
308
|
-
* theme and mode, and a density context with the stage's rung. The tools and
|
|
309
|
-
* footer are outside this subtree, so what they open follows the page. A theme
|
|
310
|
-
* the provider did not register leaves `manifest` null, which is what
|
|
311
|
-
* `useTheme()` already reports for a name nobody registered.
|
|
312
|
-
*
|
|
313
|
-
* The style set travels with the density for the same reason and by the same
|
|
314
|
-
* route: `useCuePortalProps()` stamps a portal container from `StyleSetContext`,
|
|
315
|
-
* and a popup opened on the stage inherits nothing from the stage's DOM.
|
|
316
|
-
*
|
|
317
|
-
* And the pairing travels in the theme context, because that is where the
|
|
318
|
-
* portal stamp reads `data-font` from (`theme?.font`). It used not to: the
|
|
319
|
-
* stage stamped `data-font` on its own element and republished nothing, so a
|
|
320
|
-
* popover opened on a `plex` stage came up in the root's pairing — a limit the
|
|
321
|
-
* `font` prop's docblock stated rather than a rule anybody chose. A pairing on
|
|
322
|
-
* the stage is the stage's, exactly as its theme is; `setFont` read here still
|
|
323
|
-
* drives the root, because the pairing's setter has no island form.
|
|
324
|
-
*/
|
|
325
|
-
function StageScope({ theme, mode, density, font, styleSet, paint, children }) {
|
|
326
|
-
const outer = useRead(ThemeContext);
|
|
327
|
-
const outerOverrides = useRead(OverridesContext);
|
|
328
|
-
const outerDensity = useRead(DensityContext);
|
|
329
|
-
const outerAmbient = useRead(AmbientThemeContext);
|
|
330
|
-
const outerStyleSet = useRead(StyleSetContext);
|
|
331
|
-
const outerPaint = useRead(PaintContext);
|
|
332
|
-
const value = React.useMemo(() => {
|
|
333
|
-
if (outer === null || theme === void 0 && mode === void 0 && font === void 0) return outer;
|
|
334
|
-
const scoped = theme ?? outer.theme;
|
|
335
|
-
return {
|
|
336
|
-
...outer,
|
|
337
|
-
theme: scoped,
|
|
338
|
-
manifest: scoped === outer.theme ? outer.manifest : null,
|
|
339
|
-
mode: mode ?? outer.mode,
|
|
340
|
-
font: font ?? outer.font,
|
|
341
|
-
resolvedMode: mode === "dark" || mode === "light" ? mode : outer.resolvedMode
|
|
342
|
-
};
|
|
343
|
-
}, [
|
|
344
|
-
outer,
|
|
345
|
-
theme,
|
|
346
|
-
mode,
|
|
347
|
-
font
|
|
348
|
-
]);
|
|
349
|
-
const stamped = theme !== void 0 || mode !== void 0;
|
|
350
|
-
const inputs = [
|
|
351
|
-
theme,
|
|
352
|
-
mode,
|
|
353
|
-
density,
|
|
354
|
-
font,
|
|
355
|
-
styleSet,
|
|
356
|
-
paint,
|
|
357
|
-
React.useContext(ThemeContext),
|
|
358
|
-
React.useContext(OverridesContext),
|
|
359
|
-
React.useContext(DensityContext),
|
|
360
|
-
React.useContext(AmbientThemeContext),
|
|
361
|
-
React.useContext(StyleSetContext),
|
|
362
|
-
React.useContext(PaintContext)
|
|
363
|
-
];
|
|
364
|
-
const publishedAmbient = usePublish(theme ?? outerAmbient, inputs);
|
|
365
|
-
const publishedDensity = usePublish(density ?? outerDensity, inputs);
|
|
366
|
-
const publishedStyleSet = usePublish(styleSet ?? outerStyleSet, inputs);
|
|
367
|
-
const publishedPaint = usePublish(paint ?? outerPaint, inputs);
|
|
368
|
-
const publishedOverrides = usePublish(stamped ? null : outerOverrides, inputs);
|
|
369
|
-
const publishedValue = usePublish(value, inputs);
|
|
370
|
-
const outerPairingSeed = React.useContext(PairingSeedContext);
|
|
371
|
-
const outerRootAxes = React.useContext(RootAxesContext);
|
|
372
|
-
return /* @__PURE__ */ jsx(RootAxesContext.Provider, {
|
|
373
|
-
value: rootAxes(outerRootAxes.theme && theme === void 0, outerRootAxes.mode && mode === void 0, outerRootAxes.density && density === void 0),
|
|
374
|
-
children: /* @__PURE__ */ jsx(AmbientThemeContext.Provider, {
|
|
375
|
-
value: publishedAmbient,
|
|
376
|
-
children: /* @__PURE__ */ jsx(DensityContext.Provider, {
|
|
377
|
-
value: publishedDensity,
|
|
378
|
-
children: /* @__PURE__ */ jsx(StyleSetContext.Provider, {
|
|
379
|
-
value: publishedStyleSet,
|
|
380
|
-
children: /* @__PURE__ */ jsx(PaintContext.Provider, {
|
|
381
|
-
value: publishedPaint,
|
|
382
|
-
children: /* @__PURE__ */ jsx(OverridesContext.Provider, {
|
|
383
|
-
value: publishedOverrides,
|
|
384
|
-
children: /* @__PURE__ */ jsx(PairingSeedContext.Provider, {
|
|
385
|
-
value: font === void 0 ? outerPairingSeed : NO_PAIRING_SEED,
|
|
386
|
-
children: /* @__PURE__ */ jsx(ThemeContext.Provider, {
|
|
387
|
-
value: publishedValue,
|
|
388
|
-
children
|
|
389
|
-
})
|
|
390
|
-
})
|
|
391
|
-
})
|
|
392
|
-
})
|
|
393
|
-
})
|
|
394
|
-
})
|
|
395
|
-
})
|
|
396
|
-
});
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
215
|
* The stage's size: explicit per axis once a reader has moved it, and the size
|
|
400
216
|
* the layout gives it before that — `null` on an axis, which is also what a
|
|
401
217
|
* double-click returns an axis to.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
//#region src/layout/reveal.d.ts
|
|
3
|
+
interface RevealProps extends React.ComponentPropsWithoutRef<"div"> {
|
|
4
|
+
/** How far below its resting place the content starts, in px. Defaults to `28`, the site's services blocks. */
|
|
5
|
+
distance?: number;
|
|
6
|
+
/**
|
|
7
|
+
* How far inside the viewport the entry line sits, as an `IntersectionObserver`
|
|
8
|
+
* root margin. Defaults to `"-12% 0px"`, the site's services blocks; its
|
|
9
|
+
* beliefs use `"-15% 0px"`.
|
|
10
|
+
*/
|
|
11
|
+
rootMargin?: string;
|
|
12
|
+
/** How long the entrance takes, in ms. Defaults to `500`. */
|
|
13
|
+
duration?: number;
|
|
14
|
+
/**
|
|
15
|
+
* The delay between items, in ms. `0` (the default) moves the whole block as
|
|
16
|
+
* one. Anything else leaves the block still and moves only the descendants
|
|
17
|
+
* marked `data-reveal-item`, this many ms apart, in document order — the
|
|
18
|
+
* site's beliefs stagger their two columns 80ms apart, and nothing inside
|
|
19
|
+
* them.
|
|
20
|
+
*/
|
|
21
|
+
stagger?: number;
|
|
22
|
+
/** What rises into place: the block itself, or the items in it marked `data-reveal-item`. */
|
|
23
|
+
children?: React.ReactNode;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Content that rises into place the first time it scrolls into view —
|
|
27
|
+
* cueplusplus.com's section entrance, ported (spec 2026-10-04-cue-site-verbatim
|
|
28
|
+
* §4.3): framer-motion's `whileInView` with `viewport: { once: true }`, from
|
|
29
|
+
* `opacity: 0` and `distance` px down, over `duration` ms `easeOut`.
|
|
30
|
+
*
|
|
31
|
+
* No motion library: an `IntersectionObserver` and two inline styles. It
|
|
32
|
+
* watches once and lets go. Held still, or for a reader who prefers reduced
|
|
33
|
+
* motion, the content is simply there and nothing is observed — as the site's
|
|
34
|
+
* `initial={reduce ? false : …}` does.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* <Reveal distance={22} rootMargin="-15% 0px" stagger={80}>
|
|
38
|
+
* <div data-reveal-item>Stance</div>
|
|
39
|
+
* <div data-reveal-item>Reason</div>
|
|
40
|
+
* </Reveal>
|
|
41
|
+
*/
|
|
42
|
+
declare const Reveal: React.ForwardRefExoticComponent<RevealProps & React.RefAttributes<HTMLDivElement>>;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { Reveal, RevealProps };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { useStill } from "../system/still.js";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
//#region src/layout/reveal.tsx
|
|
7
|
+
/** framer-motion's `easeOut`, the curve cueplusplus.com's entrances use. */
|
|
8
|
+
const EASE_OUT = "cubic-bezier(0, 0, 0.58, 1)";
|
|
9
|
+
/**
|
|
10
|
+
* Content that rises into place the first time it scrolls into view —
|
|
11
|
+
* cueplusplus.com's section entrance, ported (spec 2026-10-04-cue-site-verbatim
|
|
12
|
+
* §4.3): framer-motion's `whileInView` with `viewport: { once: true }`, from
|
|
13
|
+
* `opacity: 0` and `distance` px down, over `duration` ms `easeOut`.
|
|
14
|
+
*
|
|
15
|
+
* No motion library: an `IntersectionObserver` and two inline styles. It
|
|
16
|
+
* watches once and lets go. Held still, or for a reader who prefers reduced
|
|
17
|
+
* motion, the content is simply there and nothing is observed — as the site's
|
|
18
|
+
* `initial={reduce ? false : …}` does.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* <Reveal distance={22} rootMargin="-15% 0px" stagger={80}>
|
|
22
|
+
* <div data-reveal-item>Stance</div>
|
|
23
|
+
* <div data-reveal-item>Reason</div>
|
|
24
|
+
* </Reveal>
|
|
25
|
+
*/
|
|
26
|
+
const Reveal = React.forwardRef(function Reveal({ distance = 28, rootMargin = "-12% 0px", duration = 500, stagger = 0, className, children, ...props }, ref) {
|
|
27
|
+
const box = React.useRef(null);
|
|
28
|
+
const still = useStill();
|
|
29
|
+
const entered = React.useRef(false);
|
|
30
|
+
const targets = React.useCallback(() => {
|
|
31
|
+
const element = box.current;
|
|
32
|
+
if (element === null) return [];
|
|
33
|
+
return stagger > 0 ? [...element.querySelectorAll("[data-reveal-item]")] : [element];
|
|
34
|
+
}, [stagger]);
|
|
35
|
+
React.useLayoutEffect(() => {
|
|
36
|
+
if (still || entered.current) return;
|
|
37
|
+
for (const target of targets()) {
|
|
38
|
+
target.style.opacity = "0";
|
|
39
|
+
target.style.transform = `translateY(${distance}px)`;
|
|
40
|
+
}
|
|
41
|
+
}, [
|
|
42
|
+
still,
|
|
43
|
+
distance,
|
|
44
|
+
targets
|
|
45
|
+
]);
|
|
46
|
+
React.useEffect(() => {
|
|
47
|
+
if (still) {
|
|
48
|
+
for (const target of targets()) {
|
|
49
|
+
target.style.opacity = "";
|
|
50
|
+
target.style.transform = "";
|
|
51
|
+
}
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (entered.current) return;
|
|
55
|
+
const reveal = () => {
|
|
56
|
+
entered.current = true;
|
|
57
|
+
targets().forEach((target, index) => {
|
|
58
|
+
target.style.transition = `opacity ${duration}ms ${EASE_OUT}, transform ${duration}ms ${EASE_OUT}`;
|
|
59
|
+
if (stagger > 0) target.style.transitionDelay = `${index * stagger}ms`;
|
|
60
|
+
target.style.opacity = "1";
|
|
61
|
+
target.style.transform = "none";
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
const element = box.current;
|
|
65
|
+
if (element === null || typeof IntersectionObserver === "undefined") {
|
|
66
|
+
reveal();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const stop = () => {
|
|
70
|
+
line.disconnect();
|
|
71
|
+
whole.disconnect();
|
|
72
|
+
};
|
|
73
|
+
const line = new IntersectionObserver((entries) => {
|
|
74
|
+
if (!entries.some((entry) => entry.isIntersecting)) return;
|
|
75
|
+
reveal();
|
|
76
|
+
stop();
|
|
77
|
+
}, { rootMargin });
|
|
78
|
+
const whole = new IntersectionObserver((entries) => {
|
|
79
|
+
if (!entries.some((entry) => entry.isIntersecting && entry.intersectionRatio >= .99)) return;
|
|
80
|
+
reveal();
|
|
81
|
+
stop();
|
|
82
|
+
}, { threshold: 1 });
|
|
83
|
+
line.observe(element);
|
|
84
|
+
whole.observe(element);
|
|
85
|
+
return stop;
|
|
86
|
+
}, [
|
|
87
|
+
still,
|
|
88
|
+
rootMargin,
|
|
89
|
+
duration,
|
|
90
|
+
stagger,
|
|
91
|
+
targets
|
|
92
|
+
]);
|
|
93
|
+
return /* @__PURE__ */ jsx("div", {
|
|
94
|
+
ref: (node) => {
|
|
95
|
+
box.current = node;
|
|
96
|
+
if (typeof ref === "function") ref(node);
|
|
97
|
+
else if (ref !== null) ref.current = node;
|
|
98
|
+
},
|
|
99
|
+
"data-slot": "reveal",
|
|
100
|
+
className: cn(className),
|
|
101
|
+
...props,
|
|
102
|
+
children
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
//#endregion
|
|
106
|
+
export { Reveal };
|
package/dist/layout/sidebar.js
CHANGED
|
@@ -51,6 +51,91 @@ const LANDMARK_ELEMENTS = {
|
|
|
51
51
|
complementary: "aside"
|
|
52
52
|
};
|
|
53
53
|
/**
|
|
54
|
+
* The navigation column: a `<nav>` on a hairline, with a collapse valve and a
|
|
55
|
+
* scroller of its own.
|
|
56
|
+
*
|
|
57
|
+
* Width is an inline length rather than a class, because it is the one piece of
|
|
58
|
+
* console geometry a user is expected to change and persist; the transition
|
|
59
|
+
* between the two widths is CSS and switches off under `prefers-reduced-motion`.
|
|
60
|
+
*
|
|
61
|
+
* **The column scrolls, the rail does not.** Thirty rows of navigation is an
|
|
62
|
+
* ordinary amount for a documentation site or a settings screen, and a column
|
|
63
|
+
* that cannot scroll simply loses the last of them off the bottom of the frame.
|
|
64
|
+
* So the sections go in an inner scroller and the root keeps the height — which
|
|
65
|
+
* is also what saves {@link SidebarRail}: it is `absolute inset-y-0`, its
|
|
66
|
+
* containing block is the root rather than the scroller, and an absolutely
|
|
67
|
+
* positioned box whose containing block is outside a scroll container neither
|
|
68
|
+
* scrolls with it nor is clipped by it. Put the scroller on the root instead
|
|
69
|
+
* and the collapse rail slides away with the third screenful.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* <Sidebar.Root aria-label="Main">
|
|
73
|
+
* <Sidebar.Section label="Console">
|
|
74
|
+
* <Sidebar.Item icon={Sliders} active>Patch</Sidebar.Item>
|
|
75
|
+
* <Sidebar.Item icon={List}>Cues</Sidebar.Item>
|
|
76
|
+
* </Sidebar.Section>
|
|
77
|
+
* <Sidebar.Rail />
|
|
78
|
+
* </Sidebar.Root>
|
|
79
|
+
*/
|
|
80
|
+
const SidebarRoot = React.forwardRef(function SidebarRoot({ className, landmark = "navigation", collapsed: collapsedProp, defaultCollapsed = false, onCollapsedChange, width = "14rem", collapsedWidth = "3rem", style, children, ...elementProps }, ref) {
|
|
81
|
+
const Element = LANDMARK_ELEMENTS[landmark];
|
|
82
|
+
const [uncontrolled, setUncontrolled] = React.useState(defaultCollapsed);
|
|
83
|
+
const collapsed = collapsedProp ?? uncontrolled;
|
|
84
|
+
const toggle = React.useCallback(() => {
|
|
85
|
+
const next = !(collapsedProp ?? uncontrolled);
|
|
86
|
+
if (collapsedProp === void 0) setUncontrolled(next);
|
|
87
|
+
onCollapsedChange?.(next);
|
|
88
|
+
}, [
|
|
89
|
+
collapsedProp,
|
|
90
|
+
uncontrolled,
|
|
91
|
+
onCollapsedChange
|
|
92
|
+
]);
|
|
93
|
+
const context = React.useMemo(() => ({
|
|
94
|
+
collapsed,
|
|
95
|
+
toggle
|
|
96
|
+
}), [collapsed, toggle]);
|
|
97
|
+
return /* @__PURE__ */ jsx(SidebarContext.Provider, {
|
|
98
|
+
value: context,
|
|
99
|
+
children: /* @__PURE__ */ jsx(Element, {
|
|
100
|
+
ref,
|
|
101
|
+
"data-slot": "sidebar",
|
|
102
|
+
"data-collapsed": collapsed ? "" : void 0,
|
|
103
|
+
className: cn("group/sidebar relative flex h-full min-h-0 shrink-0 flex-col border-r border-border bg-surface-1 transition-[width] duration-150 ease-out motion-reduce:transition-none", "[counter-reset:cue-rail]", className),
|
|
104
|
+
style: {
|
|
105
|
+
width: collapsed ? collapsedWidth : width,
|
|
106
|
+
...style
|
|
107
|
+
},
|
|
108
|
+
...elementProps,
|
|
109
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
110
|
+
"data-slot": "sidebar-scroller",
|
|
111
|
+
className: "flex min-h-0 flex-1 flex-col gap-(--cue-space-4) overflow-y-auto py-(--cue-space-4)",
|
|
112
|
+
children
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
/** One group of items, under an optional caption. */
|
|
118
|
+
const SidebarSection = React.forwardRef(function SidebarSection({ className, label, children, ...elementProps }, ref) {
|
|
119
|
+
const { collapsed } = useSidebar();
|
|
120
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
121
|
+
ref,
|
|
122
|
+
"data-slot": "sidebar-section",
|
|
123
|
+
className: cn("flex flex-col gap-(--cue-space-1) px-(--cue-space-2)", className),
|
|
124
|
+
...elementProps,
|
|
125
|
+
children: [label === void 0 || collapsed ? null : /* @__PURE__ */ jsx("div", {
|
|
126
|
+
"data-slot": "sidebar-section-label",
|
|
127
|
+
className: cn("flex h-control-sm items-center px-(--cue-space-2)", LABEL_SIZE, LABEL_INK_SUBTLE, LABEL_WEIGHT, LABEL_FACE, LABEL_TRACKING, LABEL_CASE),
|
|
128
|
+
children: label
|
|
129
|
+
}), children]
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
/**
|
|
133
|
+
* A style set's numbered rail (structural Looks, spec 2026-10-02 §3.5): every item
|
|
134
|
+
* counts, and draws its number before the icon only when the set derives
|
|
135
|
+
* `style-rail-counter-content` — `none` unset, which generates no box at all.
|
|
136
|
+
*/
|
|
137
|
+
const RAIL_COUNTER = "[counter-increment:cue-rail] before:content-[var(--cue-style-rail-counter-content,none)] before:shrink-0 before:font-mono before:text-(length:--cue-text-label) before:text-fg-subtle";
|
|
138
|
+
/**
|
|
54
139
|
* The console's navigation column: sections of items, a scroller of its own,
|
|
55
140
|
* and a rail that collapses the whole thing to icons.
|
|
56
141
|
*
|
|
@@ -63,57 +148,8 @@ const LANDMARK_ELEMENTS = {
|
|
|
63
148
|
* </Sidebar.Root>
|
|
64
149
|
*/
|
|
65
150
|
const Sidebar = {
|
|
66
|
-
Root:
|
|
67
|
-
|
|
68
|
-
const [uncontrolled, setUncontrolled] = React.useState(defaultCollapsed);
|
|
69
|
-
const collapsed = collapsedProp ?? uncontrolled;
|
|
70
|
-
const toggle = React.useCallback(() => {
|
|
71
|
-
const next = !(collapsedProp ?? uncontrolled);
|
|
72
|
-
if (collapsedProp === void 0) setUncontrolled(next);
|
|
73
|
-
onCollapsedChange?.(next);
|
|
74
|
-
}, [
|
|
75
|
-
collapsedProp,
|
|
76
|
-
uncontrolled,
|
|
77
|
-
onCollapsedChange
|
|
78
|
-
]);
|
|
79
|
-
const context = React.useMemo(() => ({
|
|
80
|
-
collapsed,
|
|
81
|
-
toggle
|
|
82
|
-
}), [collapsed, toggle]);
|
|
83
|
-
return /* @__PURE__ */ jsx(SidebarContext.Provider, {
|
|
84
|
-
value: context,
|
|
85
|
-
children: /* @__PURE__ */ jsx(Element, {
|
|
86
|
-
ref,
|
|
87
|
-
"data-slot": "sidebar",
|
|
88
|
-
"data-collapsed": collapsed ? "" : void 0,
|
|
89
|
-
className: cn("group/sidebar relative flex h-full min-h-0 shrink-0 flex-col border-r border-border bg-surface-1 transition-[width] duration-150 ease-out motion-reduce:transition-none", className),
|
|
90
|
-
style: {
|
|
91
|
-
width: collapsed ? collapsedWidth : width,
|
|
92
|
-
...style
|
|
93
|
-
},
|
|
94
|
-
...elementProps,
|
|
95
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
96
|
-
"data-slot": "sidebar-scroller",
|
|
97
|
-
className: "flex min-h-0 flex-1 flex-col gap-(--cue-space-4) overflow-y-auto py-(--cue-space-4)",
|
|
98
|
-
children
|
|
99
|
-
})
|
|
100
|
-
})
|
|
101
|
-
});
|
|
102
|
-
}),
|
|
103
|
-
Section: React.forwardRef(function SidebarSection({ className, label, children, ...elementProps }, ref) {
|
|
104
|
-
const { collapsed } = useSidebar();
|
|
105
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
106
|
-
ref,
|
|
107
|
-
"data-slot": "sidebar-section",
|
|
108
|
-
className: cn("flex flex-col gap-(--cue-space-1) px-(--cue-space-2)", className),
|
|
109
|
-
...elementProps,
|
|
110
|
-
children: [label === void 0 || collapsed ? null : /* @__PURE__ */ jsx("div", {
|
|
111
|
-
"data-slot": "sidebar-section-label",
|
|
112
|
-
className: cn("flex h-control-sm items-center px-(--cue-space-2)", LABEL_SIZE, LABEL_INK_SUBTLE, LABEL_WEIGHT, LABEL_FACE, LABEL_TRACKING, LABEL_CASE),
|
|
113
|
-
children: label
|
|
114
|
-
}), children]
|
|
115
|
-
});
|
|
116
|
-
}),
|
|
151
|
+
Root: SidebarRoot,
|
|
152
|
+
Section: SidebarSection,
|
|
117
153
|
Item: React.forwardRef(function SidebarItem({ className, icon: Icon, active = false, badge, render, type, children, ...elementProps }, ref) {
|
|
118
154
|
return useRender({
|
|
119
155
|
render,
|
|
@@ -125,7 +161,7 @@ const Sidebar = {
|
|
|
125
161
|
"data-slot": "sidebar-item",
|
|
126
162
|
"data-active": active ? "" : void 0,
|
|
127
163
|
"aria-current": active ? "page" : void 0,
|
|
128
|
-
className: cn(`relative flex h-control-md w-full cursor-pointer items-center gap-(--cue-space-3) rounded-control border-0 bg-transparent px-(--cue-space-3) text-left font-mono text-(length:--cue-text-ui) no-underline transition-colors duration-150 outline-none select-none hover:bg-surface-2 hover:text-fg ${FOCUS_RING_INSET} ${NAV_ITEM} disabled:pointer-events-none disabled:opacity-40`, className),
|
|
164
|
+
className: cn(`relative flex h-control-md w-full cursor-pointer items-center gap-(--cue-space-3) rounded-control border-0 bg-transparent px-(--cue-space-3) text-left font-mono text-(length:--cue-text-ui) no-underline transition-colors duration-150 outline-none select-none hover:bg-surface-2 hover:text-fg ${FOCUS_RING_INSET} ${NAV_ITEM} ${RAIL_COUNTER} disabled:pointer-events-none disabled:opacity-40`, className),
|
|
129
165
|
children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
130
166
|
Icon === void 0 ? null : /* @__PURE__ */ jsx(Icon, {
|
|
131
167
|
"aria-hidden": "true",
|
package/dist/lib/cn.js
CHANGED
|
@@ -22,12 +22,30 @@ import { extendTailwindMerge } from "tailwind-merge";
|
|
|
22
22
|
* own `radius` theme scale, which is also what makes `rounded-t-control`,
|
|
23
23
|
* `rounded-br-overlay` and the rest of the per-corner rungs resolve against
|
|
24
24
|
* the same conflict group as their bare form and each other.
|
|
25
|
+
*
|
|
26
|
+
* The bridge's spacing names are the same defect on another axis:
|
|
27
|
+
* `h-control-md`, `size-icon-sm`, `min-h-control-lg` and their kin read as
|
|
28
|
+
* unknown classes, so a Button's size height and a caller's `h-auto` both
|
|
29
|
+
* stayed on the element and the bridge utility won by CSS order — the CUE++
|
|
30
|
+
* site's hero actions drew 34px tall against the site's 48px (2026-10-04).
|
|
31
|
+
* They are members of Tailwind's `spacing` scale, which every sizing and
|
|
32
|
+
* spacing utility reads, so that is where they are taught.
|
|
25
33
|
*/
|
|
26
|
-
const twMergeCue = extendTailwindMerge({ extend: { theme: {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
const twMergeCue = extendTailwindMerge({ extend: { theme: {
|
|
35
|
+
radius: [
|
|
36
|
+
"control",
|
|
37
|
+
"surface",
|
|
38
|
+
"overlay"
|
|
39
|
+
],
|
|
40
|
+
spacing: [
|
|
41
|
+
"control-sm",
|
|
42
|
+
"control-md",
|
|
43
|
+
"control-lg",
|
|
44
|
+
"chip",
|
|
45
|
+
"icon-sm",
|
|
46
|
+
"icon-md"
|
|
47
|
+
]
|
|
48
|
+
} } });
|
|
31
49
|
/**
|
|
32
50
|
* Join class names and resolve conflicting Tailwind utilities, last one wins.
|
|
33
51
|
*
|