@cueplusplus/ui 0.7.0 → 0.8.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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # @cueplusplus/ui
2
2
 
3
+ ## 0.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 4c7b963: `Ledger.Tier` and `Ledger.Group` take `collapsible`: the heading stays the `h2`/`h3` element it always was and gains a real `button[aria-expanded aria-controls]` inside it, which folds the run of rows below away. The heading outline is untouched, so a page that offers the same dataset folded and unfolded does not move a screen-reader user's heading list. Expansion is controlled or uncontrolled — `expanded`, `defaultExpanded`, `onExpandedChange` — and the library stores nothing: which places a reader folded is the caller's to keep. A folded run of rows is hidden rather than unmounted, so a group holding its own fold inside a tier still holds it after the tier above has been shut and opened again. A ledger nobody asks to fold renders exactly as before, with no client boundary.
8
+
9
+ ### Patch Changes
10
+
11
+ - @cueplusplus/tokens@0.8.0
12
+
3
13
  ## 0.7.0
4
14
 
5
15
  ### Minor Changes
@@ -0,0 +1,103 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { ChevronRightGlyph } from "../chrome/_glyphs.js";
4
+ import { headingTag } from "./_ledger.js";
5
+ import * as React from "react";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/instruments/_ledger-disclosure.tsx
8
+ /**
9
+ * A heading that folds the rows beneath it: the accordion pattern, once, for
10
+ * both of the ledger's headings.
11
+ *
12
+ * ## Why the button is inside the heading rather than instead of it
13
+ *
14
+ * This is the disclosure shape the APG calls an accordion, and the one
15
+ * `Table.GroupRow`'s own note already points at — *"a real
16
+ * `<button aria-expanded aria-controls>` inside this cell, never the row
17
+ * itself"*. The heading element survives, so the page's `h2`/`h3` outline is
18
+ * unchanged whether a tier folds or not, and a screen-reader user who navigates
19
+ * a two-hundred-row ledger by heading — which is what the outline is *for* —
20
+ * finds the same places in the same order either way. Making the heading the
21
+ * button, or replacing it with one, would trade that outline for a control, and
22
+ * the outline is the more valuable of the two.
23
+ *
24
+ * The glyph is `aria-hidden`, so the button's accessible name is the heading's
25
+ * own words. A reader hears "Ours, 13, collapsed button", not "button".
26
+ *
27
+ * ## Why the folded rows are hidden rather than unmounted
28
+ *
29
+ * A folded run of rows stays mounted inside a panel that carries `hidden`. The
30
+ * obvious alternative — dropping the children while the run is shut, so that
31
+ * folding something away costs nothing to have folded — is wrong here, and the
32
+ * reason is that **the rows are not always inert**. A `Ledger.Group` inside a
33
+ * tier is itself a disclosure holding its own uncontrolled state: unmount it
34
+ * and that state goes with it, so a reader who folds three groups, folds the
35
+ * tier over them and opens it again finds all three sprung back open. A control
36
+ * that says nothing about touching them had quietly undone their work. React
37
+ * state below a fold is the caller's too, and this component is not entitled to
38
+ * throw it away.
39
+ *
40
+ * Nothing is given up in exchange. A `hidden` subtree is out of the
41
+ * accessibility tree exactly as an absent one is — no heading in it reaches the
42
+ * outline, no row in it answers `getByRole`, and a screen reader walks past all
43
+ * of it — so the two forms are indistinguishable to the reader this component
44
+ * is built for. What differs is only that the caller's state survives.
45
+ *
46
+ * The panel element itself would have to stay in any case: `aria-controls` must
47
+ * name an element that exists, and pointed at a node that leaves with its
48
+ * contents it becomes a dangling reference and an `aria-valid-attr-value`
49
+ * failure — the very trap `DataRowDisclosure.controls` documents.
50
+ *
51
+ * ## Why the folded panel wears no classes at all
52
+ *
53
+ * `hidden` is a UA rule, `[hidden] { display: none }`, and **any author
54
+ * `display` beats it**: a panel that keeps `flex` while it is `hidden` is a
55
+ * panel that is not hidden. Rather than fight that with a `display` utility
56
+ * whose win depends on Tailwind's emission order, the folded panel is given no
57
+ * class list at all, and the layout classes come back when it opens.
58
+ *
59
+ * Keeping the rows mounted is what makes this load-bearing rather than tidy.
60
+ * When the panel was emptied on folding there was nothing inside to leak; now
61
+ * the panel's own `display: none` is the only thing standing between a folded
62
+ * run of rows and a visible one. It is enough — a `display: none` element
63
+ * generates no boxes for any of its descendants, whatever `display` each of
64
+ * them asks for — but it has to actually apply, and jsdom cannot see whether it
65
+ * does, which is why `tests/browser/data-surfaces.spec.ts` reads the computed
66
+ * `display` on both real engines.
67
+ */
68
+ function LedgerDisclosure({ headingLevel, headingSlot, headingClassName, toggleSlot, toggleClassName, panelSlot, panelClassName, label, expanded: expandedProp, defaultExpanded = true, onExpandedChange, children }) {
69
+ const [selfExpanded, setSelfExpanded] = React.useState(defaultExpanded);
70
+ const expanded = expandedProp ?? selfExpanded;
71
+ const panelId = React.useId();
72
+ const Heading = headingTag(headingLevel);
73
+ const toggle = () => {
74
+ const next = !expanded;
75
+ if (expandedProp === void 0) setSelfExpanded(next);
76
+ onExpandedChange?.(next);
77
+ };
78
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Heading, {
79
+ "data-slot": headingSlot,
80
+ className: headingClassName,
81
+ children: /* @__PURE__ */ jsxs("button", {
82
+ type: "button",
83
+ "data-slot": toggleSlot,
84
+ "aria-expanded": expanded,
85
+ "aria-controls": panelId,
86
+ onClick: toggle,
87
+ className: toggleClassName,
88
+ children: [/* @__PURE__ */ jsx(ChevronRightGlyph, {
89
+ "aria-hidden": "true",
90
+ "data-slot": `${toggleSlot}-glyph`,
91
+ className: cn("size-icon-sm shrink-0 self-center transition-transform duration-150 motion-reduce:transition-none", expanded ? "rotate-90" : null)
92
+ }), label]
93
+ })
94
+ }), /* @__PURE__ */ jsx("div", {
95
+ id: panelId,
96
+ "data-slot": panelSlot,
97
+ hidden: !expanded,
98
+ className: expanded ? panelClassName : void 0,
99
+ children
100
+ })] });
101
+ }
102
+ //#endregion
103
+ export { LedgerDisclosure };
@@ -0,0 +1,21 @@
1
+ //#region src/instruments/_ledger.d.ts
2
+ /**
3
+ * The outline half of the ledger, in a module carrying no runtime directive.
4
+ *
5
+ * `ledger.tsx` renders on the server and has to keep doing so — a document of
6
+ * two hundred rows that ships its own JavaScript in order to be *read* is
7
+ * exactly what the static form exists to avoid — while the disclosure in
8
+ * `_ledger-disclosure.tsx` holds React state and is therefore `"use client"`.
9
+ *
10
+ * A server module may **render** a client one, but it may not **call into** it:
11
+ * every value imported from a `"use client"` file is a client reference, and
12
+ * invoking one during a server render throws rather than returning a tag name.
13
+ * So the two symbols both halves need — what a heading level is, and which
14
+ * element it names — live here, in a plain module either graph can compile,
15
+ * instead of being copied into both and drifting the day one of them learns
16
+ * about `h5`.
17
+ */
18
+ /** The heading elements a tier or a group may be given. */
19
+ type LedgerHeadingLevel = 2 | 3 | 4;
20
+ //#endregion
21
+ export { LedgerHeadingLevel };
@@ -0,0 +1,5 @@
1
+ //#region src/instruments/_ledger.ts
2
+ /** `headingLevel` as a tag name, so the outline is real elements, not roles. */
3
+ const headingTag = (level) => level === 2 ? "h2" : level === 3 ? "h3" : "h4";
4
+ //#endregion
5
+ export { headingTag };
@@ -1,7 +1,6 @@
1
+ import { LedgerHeadingLevel } from "./_ledger.js";
1
2
  import * as React from "react";
2
3
  //#region src/instruments/ledger.d.ts
3
- /** The heading elements a tier or a group may be given. */
4
- type LedgerHeadingLevel = 2 | 3 | 4;
5
4
  interface LedgerRootProps extends React.ComponentPropsWithoutRef<"div"> {
6
5
  /**
7
6
  * Make the ledger a size container, so a caller's `@container` rules shed
@@ -40,6 +39,48 @@ interface LedgerTierProps extends React.ComponentPropsWithoutRef<"section"> {
40
39
  headingLevel?: LedgerHeadingLevel;
41
40
  /** A qualifier printed after the name — a date, a source, a state. */
42
41
  note?: React.ReactNode;
42
+ /**
43
+ * Put a disclosure in the tier's heading that folds its rows away. Defaults
44
+ * to `false`, and a tier with no `heading` has nothing to fold from, so it
45
+ * ignores this and renders as it always has.
46
+ *
47
+ * **This is the accordion pattern, not the tree pattern.** What folds is the
48
+ * heading — a *place* — and the `<h2>` stays exactly where it was with a real
49
+ * `<button aria-expanded aria-controls>` inside it. The rows below are hidden
50
+ * while it is shut, which takes them out of the accessibility tree and out of
51
+ * the layout but keeps whatever state they hold. If what you are folding is a
52
+ * *row*, and the thing under it is that row's children rather than that
53
+ * place's contents, you want `DataTree` and its `treeitem` semantics instead.
54
+ */
55
+ collapsible?: boolean;
56
+ /**
57
+ * Whether the tier is open, when the caller owns the state.
58
+ *
59
+ * **Persistence is the caller's.** Which places a reader has folded is a fact
60
+ * about the reader, not about the list, and it belongs wherever that consumer
61
+ * keeps the rest of them — `localStorage`, a URL, a profile. This library
62
+ * stores nothing. Pass this with {@link LedgerTierProps.onExpandedChange};
63
+ * omit both and the tier keeps its own state from
64
+ * {@link LedgerTierProps.defaultExpanded}. Ignored unless `collapsible`.
65
+ */
66
+ expanded?: boolean;
67
+ /**
68
+ * Whether an uncontrolled tier starts open. Defaults to `true`.
69
+ *
70
+ * Open, because a ledger whose content is folded away on first paint has
71
+ * hidden the thing the reader came for; the reader folds what they are done
72
+ * with. Ignored unless `collapsible`, and ignored entirely once
73
+ * {@link LedgerTierProps.expanded} is passed.
74
+ */
75
+ defaultExpanded?: boolean;
76
+ /**
77
+ * Called with the tier's next state each time the reader presses the
78
+ * disclosure — `true` when it is being opened, `false` when it is being shut.
79
+ *
80
+ * Fires in both the controlled and the uncontrolled form, so a consumer can
81
+ * record what was folded without also having to own the state.
82
+ */
83
+ onExpandedChange?: (expanded: boolean) => void;
43
84
  }
44
85
  interface LedgerGroupProps extends React.ComponentPropsWithoutRef<"div"> {
45
86
  /**
@@ -64,24 +105,70 @@ interface LedgerGroupProps extends React.ComponentPropsWithoutRef<"div"> {
64
105
  * rather than measuring at runtime.
65
106
  */
66
107
  sticky?: boolean;
108
+ /**
109
+ * Put a disclosure in the group's slug that folds its rows away. Defaults to
110
+ * `false`, and an unlabelled group has no slug to fold from, so it ignores
111
+ * this. The same accordion pattern the tier takes — see
112
+ * {@link LedgerTierProps.collapsible} for why it is not the tree pattern.
113
+ */
114
+ collapsible?: boolean;
115
+ /**
116
+ * Whether the group is open, when the caller owns the state. Persistence is
117
+ * the caller's; see {@link LedgerTierProps.expanded}.
118
+ */
119
+ expanded?: boolean;
120
+ /** Whether an uncontrolled group starts open. Defaults to `true`. */
121
+ defaultExpanded?: boolean;
122
+ /** Called with the group's next state each time the reader presses the slug. */
123
+ onExpandedChange?: (expanded: boolean) => void;
67
124
  }
68
125
  interface LedgerEmptyProps extends React.ComponentPropsWithoutRef<"p"> {}
69
126
  /**
70
127
  * A grouped run of dense rows under sticky headings: the ledger idiom.
71
128
  *
72
- * The flattest of the three surfaces this package ships over one row model, and
73
- * the one that does the least: headings, slugs, rows. **Nothing here collapses.**
74
- * A ledger with a disclosure on it would be a tree with worse semantics, so the
75
- * component emits no `aria-expanded` anywhere, and a test holds it to that —
76
- * collapse belongs to `DataTree`, and grouping-with-columns belongs to a
77
- * grouped `Table`.
129
+ * The flattest of the three surfaces this package ships over one row model:
130
+ * headings, slugs, rows. What it owns above all is the document outline. Tiers
131
+ * and groups are real `<h2>` / `<h3>` elements at caller-chosen levels, because
132
+ * in a list of two hundred rows the heading list *is* how a screen-reader user
133
+ * navigates.
134
+ *
135
+ * ## Folding: the accordion pattern, opt-in, and why it lives here
78
136
  *
79
- * What it does own is the document outline. Tiers and groups are real `<h2>` /
80
- * `<h3>` elements at caller-chosen levels, because in a list of two hundred
81
- * rows the heading list *is* how a screen-reader user navigates.
137
+ * This component used to refuse disclosure outright, on the grounds that *a
138
+ * ledger which folds is a tree with worse semantics*. That ruling was right
139
+ * about rows and wrong about places, and the distinction is the whole of
140
+ * {@link LedgerTierProps.collapsible}:
82
141
  *
83
- * Static markup — no `"use client"`. The rows inside it may be anything;
84
- * `DataRow` is the intended tenant.
142
+ * - **`DataTree` folds a row.** Its `role="treeitem"` rows carry their own
143
+ * `aria-expanded`, its chevron is `role="presentation"` because in tree
144
+ * semantics the row owns its expansion, and a tier and a subgroup drawn
145
+ * through it stop being places and become rows. A consumer who measured this
146
+ * exact shape through `DataTree` counted **zero** `h2`/`h3` elements and zero
147
+ * `button[aria-expanded]`, which is `DataTree` working correctly and still
148
+ * not being what a grouped document needs.
149
+ * - **`Ledger` folds a place.** A tier is already an `<h2>`, which is already
150
+ * the right element for it, so the disclosure goes *inside* the heading as a
151
+ * real `<button aria-expanded aria-controls>` — the accordion pattern, and
152
+ * the same one `Table.GroupRow`'s note has always pointed at for a table that
153
+ * genuinely needs to fold. The outline is untouched: the heading list of a
154
+ * folding ledger and a plain one are identical, which is what lets a page
155
+ * offer both idioms over one dataset without the outline moving under a
156
+ * reader who switches.
157
+ *
158
+ * So it is one component with two forms rather than a `DisclosureLedger` beside
159
+ * it: everything a folding ledger needs — the gutter track, the sticky offsets,
160
+ * the label recipe, the type contract — is this component, and a sibling would
161
+ * have been a copy of all of it wrapped around one `<button>`.
162
+ *
163
+ * Expansion is controllable and stores nothing. *Which* places a reader has
164
+ * folded is a fact about the reader; consumers keep that set themselves and
165
+ * pass it back in. A folded run of rows is hidden rather than unmounted, so a
166
+ * group that keeps its own fold inside a tier still keeps it after the tier has
167
+ * been shut and opened over it.
168
+ *
169
+ * Static markup — no `"use client"` — **until a heading is asked to fold**, at
170
+ * which point that heading and its rows become a small client island and the
171
+ * rest of the ledger keeps rendering on the server.
85
172
  *
86
173
  * @example
87
174
  * <Ledger.Root className="[--cue-data-row-cols:1fr_8rem_auto]">
@@ -94,6 +181,18 @@ interface LedgerEmptyProps extends React.ComponentPropsWithoutRef<"p"> {}
94
181
  * </Ledger.Group>
95
182
  * </Ledger.Tier>
96
183
  * </Ledger.Root>
184
+ *
185
+ * @example
186
+ * // Folded places are the reader's, so the reader's storage holds them.
187
+ * <Ledger.Tier
188
+ * heading="Ours"
189
+ * count={13}
190
+ * collapsible
191
+ * expanded={!folded.includes("ours")}
192
+ * onExpandedChange={(open) => remember("ours", open)}
193
+ * >
194
+ * <Ledger.Group label="released">…</Ledger.Group>
195
+ * </Ledger.Tier>
97
196
  */
98
197
  declare const Ledger: {
99
198
  Root: React.ForwardRefExoticComponent<LedgerRootProps & React.RefAttributes<HTMLDivElement>>;
@@ -1,4 +1,6 @@
1
1
  import { cn } from "../lib/cn.js";
2
+ import { headingTag } from "./_ledger.js";
3
+ import { LedgerDisclosure } from "./_ledger-disclosure.js";
2
4
  import * as React from "react";
3
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
6
  //#region src/instruments/ledger.tsx
@@ -12,24 +14,68 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
14
  * micro-label in a dense list reads as a second kind of emphasis.
13
15
  */
14
16
  const LEDGER_LABEL = "font-mono text-(length:--cue-text-label) font-normal tracking-[0.15em] text-fg-subtle uppercase";
15
- /** `headingLevel` as a tag name, so the outline is real elements, not roles. */
16
- const headingTag = (level) => level === 2 ? "h2" : level === 3 ? "h3" : "h4";
17
+ /**
18
+ * The disclosure button a collapsible heading holds.
19
+ *
20
+ * Worn *with* {@link LEDGER_LABEL}, which the heading around it is already
21
+ * wearing. The repetition is deliberate: a `<button>` carries the UA's own font
22
+ * rather than its parent's, and while Tailwind's preflight resets that to
23
+ * `font: inherit`, a component whose micro-label silently becomes 13px Arial if
24
+ * a consumer drops preflight is a component with a very confusing bug report.
25
+ * One constant applied twice cannot drift; two recipes can.
26
+ *
27
+ * `w-full` so the whole width of the heading is the hit area rather than the
28
+ * word itself, and the focus ring is inset (`-outline-offset-2`) for the same
29
+ * reason `_data-row.ts` gives: these headings dock at the top of clipped panes,
30
+ * where an outset ring on the first one is cut off by the pane's own rim.
31
+ */
32
+ const LEDGER_TOGGLE = "flex w-full min-w-0 cursor-pointer items-baseline gap-(--cue-space-2) text-left outline-none focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-2 focus-visible:outline-accent";
17
33
  /**
18
34
  * A grouped run of dense rows under sticky headings: the ledger idiom.
19
35
  *
20
- * The flattest of the three surfaces this package ships over one row model, and
21
- * the one that does the least: headings, slugs, rows. **Nothing here collapses.**
22
- * A ledger with a disclosure on it would be a tree with worse semantics, so the
23
- * component emits no `aria-expanded` anywhere, and a test holds it to that —
24
- * collapse belongs to `DataTree`, and grouping-with-columns belongs to a
25
- * grouped `Table`.
36
+ * The flattest of the three surfaces this package ships over one row model:
37
+ * headings, slugs, rows. What it owns above all is the document outline. Tiers
38
+ * and groups are real `<h2>` / `<h3>` elements at caller-chosen levels, because
39
+ * in a list of two hundred rows the heading list *is* how a screen-reader user
40
+ * navigates.
41
+ *
42
+ * ## Folding: the accordion pattern, opt-in, and why it lives here
43
+ *
44
+ * This component used to refuse disclosure outright, on the grounds that *a
45
+ * ledger which folds is a tree with worse semantics*. That ruling was right
46
+ * about rows and wrong about places, and the distinction is the whole of
47
+ * {@link LedgerTierProps.collapsible}:
26
48
  *
27
- * What it does own is the document outline. Tiers and groups are real `<h2>` /
28
- * `<h3>` elements at caller-chosen levels, because in a list of two hundred
29
- * rows the heading list *is* how a screen-reader user navigates.
49
+ * - **`DataTree` folds a row.** Its `role="treeitem"` rows carry their own
50
+ * `aria-expanded`, its chevron is `role="presentation"` because in tree
51
+ * semantics the row owns its expansion, and a tier and a subgroup drawn
52
+ * through it stop being places and become rows. A consumer who measured this
53
+ * exact shape through `DataTree` counted **zero** `h2`/`h3` elements and zero
54
+ * `button[aria-expanded]`, which is `DataTree` working correctly and still
55
+ * not being what a grouped document needs.
56
+ * - **`Ledger` folds a place.** A tier is already an `<h2>`, which is already
57
+ * the right element for it, so the disclosure goes *inside* the heading as a
58
+ * real `<button aria-expanded aria-controls>` — the accordion pattern, and
59
+ * the same one `Table.GroupRow`'s note has always pointed at for a table that
60
+ * genuinely needs to fold. The outline is untouched: the heading list of a
61
+ * folding ledger and a plain one are identical, which is what lets a page
62
+ * offer both idioms over one dataset without the outline moving under a
63
+ * reader who switches.
30
64
  *
31
- * Static markup — no `"use client"`. The rows inside it may be anything;
32
- * `DataRow` is the intended tenant.
65
+ * So it is one component with two forms rather than a `DisclosureLedger` beside
66
+ * it: everything a folding ledger needs — the gutter track, the sticky offsets,
67
+ * the label recipe, the type contract — is this component, and a sibling would
68
+ * have been a copy of all of it wrapped around one `<button>`.
69
+ *
70
+ * Expansion is controllable and stores nothing. *Which* places a reader has
71
+ * folded is a fact about the reader; consumers keep that set themselves and
72
+ * pass it back in. A folded run of rows is hidden rather than unmounted, so a
73
+ * group that keeps its own fold inside a tier still keeps it after the tier has
74
+ * been shut and opened over it.
75
+ *
76
+ * Static markup — no `"use client"` — **until a heading is asked to fold**, at
77
+ * which point that heading and its rows become a small client island and the
78
+ * rest of the ledger keeps rendering on the server.
33
79
  *
34
80
  * @example
35
81
  * <Ledger.Root className="[--cue-data-row-cols:1fr_8rem_auto]">
@@ -42,6 +88,18 @@ const headingTag = (level) => level === 2 ? "h2" : level === 3 ? "h3" : "h4";
42
88
  * </Ledger.Group>
43
89
  * </Ledger.Tier>
44
90
  * </Ledger.Root>
91
+ *
92
+ * @example
93
+ * // Folded places are the reader's, so the reader's storage holds them.
94
+ * <Ledger.Tier
95
+ * heading="Ours"
96
+ * count={13}
97
+ * collapsible
98
+ * expanded={!folded.includes("ours")}
99
+ * onExpandedChange={(open) => remember("ours", open)}
100
+ * >
101
+ * <Ledger.Group label="released">…</Ledger.Group>
102
+ * </Ledger.Tier>
45
103
  */
46
104
  const Ledger = {
47
105
  Root: React.forwardRef(function LedgerRoot({ className, containment = true, ...elementProps }, ref) {
@@ -52,53 +110,85 @@ const Ledger = {
52
110
  ...elementProps
53
111
  });
54
112
  }),
55
- Tier: React.forwardRef(function LedgerTier({ className, heading, count, sticky = true, headingLevel = 2, note, children, ...elementProps }, ref) {
113
+ Tier: React.forwardRef(function LedgerTier({ className, heading, count, sticky = true, headingLevel = 2, note, collapsible = false, expanded, defaultExpanded = true, onExpandedChange, children, ...elementProps }, ref) {
56
114
  const Heading = headingTag(headingLevel);
57
- return /* @__PURE__ */ jsxs("section", {
115
+ const words = /* @__PURE__ */ jsxs(Fragment, { children: [
116
+ /* @__PURE__ */ jsx("span", {
117
+ "data-slot": "ledger-tier-label",
118
+ children: heading
119
+ }),
120
+ count === void 0 ? null : /* @__PURE__ */ jsx("span", {
121
+ "data-slot": "ledger-tier-count",
122
+ className: "tabular-nums",
123
+ children: count
124
+ }),
125
+ note === void 0 ? null : /* @__PURE__ */ jsx("span", {
126
+ "data-slot": "ledger-tier-note",
127
+ className: "tracking-normal normal-case",
128
+ children: note
129
+ })
130
+ ] });
131
+ const ground = sticky ? "sticky top-0 z-2 bg-bg" : null;
132
+ return /* @__PURE__ */ jsx("section", {
58
133
  ref,
59
134
  "data-slot": "ledger-tier",
60
135
  className: cn("flex flex-col", className),
61
136
  ...elementProps,
62
- children: [heading === void 0 ? null : /* @__PURE__ */ jsxs(Heading, {
137
+ children: heading === void 0 ? children : collapsible ? /* @__PURE__ */ jsx(LedgerDisclosure, {
138
+ headingLevel,
139
+ headingSlot: "ledger-tier-heading",
140
+ headingClassName: cn(LEDGER_LABEL, "py-(--cue-pad-row-y)", ground),
141
+ toggleSlot: "ledger-tier-toggle",
142
+ toggleClassName: cn(LEDGER_LABEL, LEDGER_TOGGLE),
143
+ panelSlot: "ledger-tier-rows",
144
+ panelClassName: "flex flex-col",
145
+ label: words,
146
+ expanded,
147
+ defaultExpanded,
148
+ onExpandedChange,
149
+ children
150
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Heading, {
63
151
  "data-slot": "ledger-tier-heading",
64
- className: cn(LEDGER_LABEL, "flex items-baseline gap-(--cue-space-2) py-(--cue-pad-row-y)", sticky ? "sticky top-0 z-2 bg-bg" : null),
65
- children: [
66
- /* @__PURE__ */ jsx("span", {
67
- "data-slot": "ledger-tier-label",
68
- children: heading
69
- }),
70
- count === void 0 ? null : /* @__PURE__ */ jsx("span", {
71
- "data-slot": "ledger-tier-count",
72
- className: "tabular-nums",
73
- children: count
74
- }),
75
- note === void 0 ? null : /* @__PURE__ */ jsx("span", {
76
- "data-slot": "ledger-tier-note",
77
- className: "tracking-normal normal-case",
78
- children: note
79
- })
80
- ]
81
- }), children]
152
+ className: cn(LEDGER_LABEL, "flex items-baseline gap-(--cue-space-2) py-(--cue-pad-row-y)", ground),
153
+ children: words
154
+ }), children] })
82
155
  });
83
156
  }),
84
- Group: React.forwardRef(function LedgerGroup({ className, label, headingLevel = 3, sticky = true, children, ...elementProps }, ref) {
157
+ Group: React.forwardRef(function LedgerGroup({ className, label, headingLevel = 3, sticky = true, collapsible = false, expanded, defaultExpanded = true, onExpandedChange, children, ...elementProps }, ref) {
85
158
  const Heading = headingTag(headingLevel);
86
159
  const labelled = label !== void 0;
160
+ const ground = sticky ? "sticky self-start [top:var(--cue-ledger-slug-top,2.5rem)] bg-bg" : null;
87
161
  return /* @__PURE__ */ jsx("div", {
88
162
  ref,
89
163
  "data-slot": "ledger-group",
90
164
  "data-labelled": labelled ? "" : void 0,
91
165
  className: cn(labelled ? "grid [grid-template-columns:var(--cue-ledger-gutter,7rem)_minmax(0,1fr)]" : "flex flex-col", className),
92
166
  ...elementProps,
93
- children: labelled ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Heading, {
167
+ children: !labelled ? children : collapsible ? /* @__PURE__ */ jsx(LedgerDisclosure, {
168
+ headingLevel,
169
+ headingSlot: "ledger-group-label",
170
+ headingClassName: cn(LEDGER_LABEL, "min-w-0 py-(--cue-pad-row-y) pr-(--cue-space-3)", ground),
171
+ toggleSlot: "ledger-group-toggle",
172
+ toggleClassName: cn(LEDGER_LABEL, LEDGER_TOGGLE),
173
+ panelSlot: "ledger-group-rows",
174
+ panelClassName: "flex min-w-0 flex-col",
175
+ label: /* @__PURE__ */ jsx("span", {
176
+ className: "min-w-0 truncate",
177
+ children: label
178
+ }),
179
+ expanded,
180
+ defaultExpanded,
181
+ onExpandedChange,
182
+ children
183
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Heading, {
94
184
  "data-slot": "ledger-group-label",
95
- className: cn(LEDGER_LABEL, "min-w-0 truncate py-(--cue-pad-row-y) pr-(--cue-space-3)", sticky ? "sticky self-start [top:var(--cue-ledger-slug-top,2.5rem)] bg-bg" : null),
185
+ className: cn(LEDGER_LABEL, "min-w-0 truncate py-(--cue-pad-row-y) pr-(--cue-space-3)", ground),
96
186
  children: label
97
187
  }), /* @__PURE__ */ jsx("div", {
98
188
  "data-slot": "ledger-group-rows",
99
189
  className: "flex min-w-0 flex-col",
100
190
  children
101
- })] }) : children
191
+ })] })
102
192
  });
103
193
  }),
104
194
  Empty: React.forwardRef(function LedgerEmpty({ className, ...elementProps }, ref) {
@@ -128,6 +128,7 @@
128
128
  "whenNotToUse": [
129
129
  "A single-column outline of labels with a glyph gutter. Use `Tree`, which is that component.",
130
130
  "A grouped list nobody folds. Use `Ledger` or a grouped `Table`; disclosure semantics you never use are a promise you never keep.",
131
+ "A grouped document whose *headings* fold, where the `h2`/`h3` outline has to survive. Use `Ledger` with `collapsible`: a tree makes every tier and subgroup a `treeitem` row and leaves no headings behind.",
131
132
  "A grid whose cells are individually editable. That needs a real `treegrid` from a library that maintains one — this component trades cell navigation away on purpose."
132
133
  ],
133
134
  "commonMistakes": [
@@ -5,7 +5,7 @@
5
5
  "importPath": "@cueplusplus/ui",
6
6
  "peerDependencies": [],
7
7
  "clientOnly": false,
8
- "description": "A grouped run of dense rows under sticky headings: the ledger idiom.\n\nThe flattest of the three surfaces this package ships over one row model, and\nthe one that does the least: headings, slugs, rows. **Nothing here collapses.**\nA ledger with a disclosure on it would be a tree with worse semantics, so the\ncomponent emits no `aria-expanded` anywhere, and a test holds it to that —\ncollapse belongs to `DataTree`, and grouping-with-columns belongs to a\ngrouped `Table`.\n\nWhat it does own is the document outline. Tiers and groups are real `<h2>` /\n`<h3>` elements at caller-chosen levels, because in a list of two hundred\nrows the heading list *is* how a screen-reader user navigates.\n\nStatic markup — no `\"use client\"`. The rows inside it may be anything;\n`DataRow` is the intended tenant.",
8
+ "description": "A grouped run of dense rows under sticky headings: the ledger idiom.\n\nThe flattest of the three surfaces this package ships over one row model:\nheadings, slugs, rows. What it owns above all is the document outline. Tiers\nand groups are real `<h2>` / `<h3>` elements at caller-chosen levels, because\nin a list of two hundred rows the heading list *is* how a screen-reader user\nnavigates.\n\n## Folding: the accordion pattern, opt-in, and why it lives here\n\nThis component used to refuse disclosure outright, on the grounds that *a\nledger which folds is a tree with worse semantics*. That ruling was right\nabout rows and wrong about places, and the distinction is the whole of\n{@link LedgerTierProps.collapsible}:\n\n- **`DataTree` folds a row.** Its `role=\"treeitem\"` rows carry their own\n `aria-expanded`, its chevron is `role=\"presentation\"` because in tree\n semantics the row owns its expansion, and a tier and a subgroup drawn\n through it stop being places and become rows. A consumer who measured this\n exact shape through `DataTree` counted **zero** `h2`/`h3` elements and zero\n `button[aria-expanded]`, which is `DataTree` working correctly and still\n not being what a grouped document needs.\n- **`Ledger` folds a place.** A tier is already an `<h2>`, which is already\n the right element for it, so the disclosure goes *inside* the heading as a\n real `<button aria-expanded aria-controls>` — the accordion pattern, and\n the same one `Table.GroupRow`'s note has always pointed at for a table that\n genuinely needs to fold. The outline is untouched: the heading list of a\n folding ledger and a plain one are identical, which is what lets a page\n offer both idioms over one dataset without the outline moving under a\n reader who switches.\n\nSo it is one component with two forms rather than a `DisclosureLedger` beside\nit: everything a folding ledger needs — the gutter track, the sticky offsets,\nthe label recipe, the type contract — is this component, and a sibling would\nhave been a copy of all of it wrapped around one `<button>`.\n\nExpansion is controllable and stores nothing. *Which* places a reader has\nfolded is a fact about the reader; consumers keep that set themselves and\npass it back in. A folded run of rows is hidden rather than unmounted, so a\ngroup that keeps its own fold inside a tier still keeps it after the tier has\nbeen shut and opened over it.\n\nStatic markup — no `\"use client\"` — **until a heading is asked to fold**, at\nwhich point that heading and its rows become a small client island and the\nrest of the ledger keeps rendering on the server.",
9
9
  "props": [],
10
10
  "typeReferences": [],
11
11
  "subcomponents": [
@@ -71,6 +71,34 @@
71
71
  "required": false,
72
72
  "defaultValue": null,
73
73
  "description": "A qualifier printed after the name — a date, a source, a state."
74
+ },
75
+ {
76
+ "name": "collapsible",
77
+ "type": "boolean",
78
+ "required": false,
79
+ "defaultValue": "false",
80
+ "description": "Put a disclosure in the tier's heading that folds its rows away. Defaults\nto `false`, and a tier with no `heading` has nothing to fold from, so it\nignores this and renders as it always has.\n\n**This is the accordion pattern, not the tree pattern.** What folds is the\nheading — a *place* — and the `<h2>` stays exactly where it was with a real\n`<button aria-expanded aria-controls>` inside it. The rows below are hidden\nwhile it is shut, which takes them out of the accessibility tree and out of\nthe layout but keeps whatever state they hold. If what you are folding is a\n*row*, and the thing under it is that row's children rather than that\nplace's contents, you want `DataTree` and its `treeitem` semantics instead."
81
+ },
82
+ {
83
+ "name": "expanded",
84
+ "type": "boolean",
85
+ "required": false,
86
+ "defaultValue": null,
87
+ "description": "Whether the tier is open, when the caller owns the state.\n\n**Persistence is the caller's.** Which places a reader has folded is a fact\nabout the reader, not about the list, and it belongs wherever that consumer\nkeeps the rest of them — `localStorage`, a URL, a profile. This library\nstores nothing. Pass this with {@link LedgerTierProps.onExpandedChange};\nomit both and the tier keeps its own state from\n{@link LedgerTierProps.defaultExpanded}. Ignored unless `collapsible`."
88
+ },
89
+ {
90
+ "name": "defaultExpanded",
91
+ "type": "boolean",
92
+ "required": false,
93
+ "defaultValue": "true",
94
+ "description": "Whether an uncontrolled tier starts open. Defaults to `true`.\n\nOpen, because a ledger whose content is folded away on first paint has\nhidden the thing the reader came for; the reader folds what they are done\nwith. Ignored unless `collapsible`, and ignored entirely once\n{@link LedgerTierProps.expanded} is passed."
95
+ },
96
+ {
97
+ "name": "onExpandedChange",
98
+ "type": "((expanded: boolean) => void)",
99
+ "required": false,
100
+ "defaultValue": null,
101
+ "description": "Called with the tier's next state each time the reader presses the\ndisclosure — `true` when it is being opened, `false` when it is being shut.\n\nFires in both the controlled and the uncontrolled form, so a consumer can\nrecord what was folded without also having to own the state."
74
102
  }
75
103
  ],
76
104
  "typeReferences": [
@@ -102,6 +130,34 @@
102
130
  "required": false,
103
131
  "defaultValue": "true",
104
132
  "description": "Dock the slug under the tier heading while the group's rows scroll past.\nDefaults to `true`.\n\nThe offset is a custom property, `--cue-ledger-slug-top` (default `2.5rem`):\nhow far down the slug docks depends on how tall the tier heading above it\nrenders, which is a function of the density and the type the *caller*\nconfigured. Set it on the ledger — `className=\"[--cue-ledger-slug-top:2rem]\"` —\nrather than measuring at runtime."
133
+ },
134
+ {
135
+ "name": "collapsible",
136
+ "type": "boolean",
137
+ "required": false,
138
+ "defaultValue": "false",
139
+ "description": "Put a disclosure in the group's slug that folds its rows away. Defaults to\n`false`, and an unlabelled group has no slug to fold from, so it ignores\nthis. The same accordion pattern the tier takes — see\n{@link LedgerTierProps.collapsible} for why it is not the tree pattern."
140
+ },
141
+ {
142
+ "name": "expanded",
143
+ "type": "boolean",
144
+ "required": false,
145
+ "defaultValue": null,
146
+ "description": "Whether the group is open, when the caller owns the state. Persistence is\nthe caller's; see {@link LedgerTierProps.expanded}."
147
+ },
148
+ {
149
+ "name": "defaultExpanded",
150
+ "type": "boolean",
151
+ "required": false,
152
+ "defaultValue": "true",
153
+ "description": "Whether an uncontrolled group starts open. Defaults to `true`."
154
+ },
155
+ {
156
+ "name": "onExpandedChange",
157
+ "type": "((expanded: boolean) => void)",
158
+ "required": false,
159
+ "defaultValue": null,
160
+ "description": "Called with the group's next state each time the reader presses the slug."
105
161
  }
106
162
  ],
107
163
  "typeReferences": [
@@ -121,11 +177,13 @@
121
177
  "variants": {},
122
178
  "defaultVariants": {},
123
179
  "tokensUsed": [
180
+ "--cue-accent",
124
181
  "--cue-bg",
125
182
  "--cue-data-row-cols",
126
183
  "--cue-fg",
127
184
  "--cue-fg-subtle",
128
185
  "--cue-font-mono",
186
+ "--cue-icon-sm",
129
187
  "--cue-ledger-gutter",
130
188
  "--cue-ledger-slug-top",
131
189
  "--cue-pad-row-x",
@@ -135,7 +193,7 @@
135
193
  "--cue-text-label",
136
194
  "--cue-text-ui"
137
195
  ],
138
- "summary": "Grouped dense rows under sticky tier headings and gutter slugs, with no disclosure anywhere.",
196
+ "summary": "Grouped dense rows under sticky tier headings and gutter slugs, with an opt-in disclosure that folds a heading without leaving the outline.",
139
197
  "examples": [
140
198
  {
141
199
  "title": "Tiers, groups, rows",
@@ -147,9 +205,14 @@
147
205
  "code": "<Ledger.Tier>\n <Ledger.Group>\n <DataRow.Root>…</DataRow.Root>\n </Ledger.Group>\n</Ledger.Tier>",
148
206
  "language": "tsx"
149
207
  },
208
+ {
209
+ "title": "Folded places, persisted by the caller",
210
+ "code": "<Ledger.Tier\n heading=\"Ours\"\n count={13}\n collapsible\n expanded={!folded.includes(\"ours\")}\n onExpandedChange={(open) => remember(\"ours\", open)}\n>\n <Ledger.Group label=\"released\" collapsible defaultExpanded={false}>\n <DataRow.Root>…</DataRow.Root>\n </Ledger.Group>\n</Ledger.Tier>",
211
+ "language": "tsx"
212
+ },
150
213
  {
151
214
  "title": "Usage",
152
- "code": "<Ledger.Root className=\"[--cue-data-row-cols:1fr_8rem_auto]\">\n <Ledger.Tier heading=\"Ours\" count={12}>\n <Ledger.Group label=\"released\">\n <DataRow.Root interactive onActivate={open}>…</DataRow.Root>\n </Ledger.Group>\n <Ledger.Group label=\"lab\">\n <Ledger.Empty>Nothing yet.</Ledger.Empty>\n </Ledger.Group>\n </Ledger.Tier>\n</Ledger.Root>",
215
+ "code": "<Ledger.Root className=\"[--cue-data-row-cols:1fr_8rem_auto]\">\n <Ledger.Tier heading=\"Ours\" count={12}>\n <Ledger.Group label=\"released\">\n <DataRow.Root interactive onActivate={open}>…</DataRow.Root>\n </Ledger.Group>\n <Ledger.Group label=\"lab\">\n <Ledger.Empty>Nothing yet.</Ledger.Empty>\n </Ledger.Group>\n </Ledger.Tier>\n</Ledger.Root>\n// Folded places are the reader's, so the reader's storage holds them.\n<Ledger.Tier\n heading=\"Ours\"\n count={13}\n collapsible\n expanded={!folded.includes(\"ours\")}\n onExpandedChange={(open) => remember(\"ours\", open)}\n>\n <Ledger.Group label=\"released\">…</Ledger.Group>\n</Ledger.Tier>",
153
216
  "language": "tsx"
154
217
  }
155
218
  ],
@@ -158,16 +221,18 @@
158
221
  "mdUrl": "/docs/components/ledger.md",
159
222
  "jsonUrl": "/r/components/ledger.json",
160
223
  "whenToUse": [
161
- "A long list that is grouped but never folded: a corpus by source, a patch by direction, a run log by day.",
162
- "A surface whose groups should be reachable by heading, since the tiers and slugs are real `h2`/`h3` elements."
224
+ "A long grouped list: a corpus by source, a patch by direction, a run log by day.",
225
+ "A surface whose groups should be reachable by heading, since the tiers and slugs are real `h2`/`h3` elements.",
226
+ "A grouped list the reader folds *by place* — `collapsible` puts a real `button[aria-expanded]` inside the heading and leaves the `h2`/`h3` outline exactly as it was."
163
227
  ],
164
228
  "whenNotToUse": [
165
- "A hierarchy the reader folds. Use `DataTree`, which owns collapse and the tree semantics that go with it.",
229
+ "A hierarchy whose *rows* fold into their own children. Use `DataTree`, where the row is the treeitem and owns its expansion.",
166
230
  "Rows meant to be compared down a named column. Use a grouped `Table`, where the columns are named once in a `thead`.",
167
231
  "A handful of rows in a panel. Use `Row` inside `Panel`; a tier heading over three rows is furniture with nothing to organise."
168
232
  ],
169
233
  "commonMistakes": [
170
- "Adding a toggle to a tier. A ledger that folds is a tree with worse semantics — the component emits no `aria-expanded`, and a test holds it to that.",
234
+ "Reaching for `DataTree` to fold a grouped list. A tree turns every tier and subgroup into a `treeitem` row and leaves zero headings behind — if the thing folding is a *place*, `collapsible` is the prop.",
235
+ "Storing the folded set inside the component. Which places a reader folded is a fact about the reader: pass `expanded` and `onExpandedChange` and keep it wherever the rest of that reader's preferences live.",
171
236
  "Framing each group in a `Panel`. A card per group turns one list into a stack of little tables and breaks the top-to-bottom scan.",
172
237
  "Leaving `--cue-ledger-slug-top` at its default after changing the density or the heading type, which docks the slug over the tier heading instead of under it.",
173
238
  "Passing an `empty` string as a prop. `Ledger.Empty` takes the words because \"this place is empty\" and \"your filter emptied it\" are different sentences."
@@ -182,6 +247,16 @@
182
247
  "code": "<Panel className=\"w-full\">\n <div className=\"max-h-[18rem] overflow-y-auto\">\n <Ledger.Root className={PATCH_TRACKS}>\n <Ledger.Tier heading=\"Patch\" count={PATCH_DEVICES.length} note=\"polled 18:04\">\n {PATCH_GROUPS.map((group) => (\n <Ledger.Group key={group.id} label={group.label}>\n {group.rows.map((device) => (\n <DataRow.Root key={device.id} interactive>\n <PatchRowSlots device={device} />\n </DataRow.Root>\n ))}\n </Ledger.Group>\n ))}\n <Ledger.Group label=\"spare\">\n <Ledger.Empty>Nothing yet.</Ledger.Empty>\n </Ledger.Group>\n </Ledger.Tier>\n </Ledger.Root>\n </div>\n</Panel>",
183
248
  "note": "The same rows as tiers and slugs: sticky headings, a gutter for the group name, and no disclosure anywhere — the ledger does not collapse.",
184
249
  "interaction": "the tier heading and the group slug dock as the rows scroll under them; scroll the pane to see it."
250
+ },
251
+ {
252
+ "title": "Ledger — collapsible",
253
+ "group": "instruments",
254
+ "components": [
255
+ "Ledger"
256
+ ],
257
+ "code": "<Panel className=\"w-full\">\n <div className=\"max-h-[18rem] overflow-y-auto\">\n <Ledger.Root className={PATCH_TRACKS}>\n <Ledger.Tier\n heading=\"Patch\"\n count={PATCH_DEVICES.length}\n collapsible\n expanded={patchOpen}\n onExpandedChange={setPatchOpen}\n >\n {PATCH_GROUPS.map((group, index) => (\n <Ledger.Group\n key={group.id}\n label={group.label}\n collapsible\n defaultExpanded={index === 0}\n >\n {group.rows.map((device) => (\n <DataRow.Root key={device.id} interactive>\n <PatchRowSlots device={device} />\n </DataRow.Root>\n ))}\n </Ledger.Group>\n ))}\n </Ledger.Tier>\n </Ledger.Root>\n </div>\n</Panel>",
258
+ "note": "The same ledger with `collapsible` on the tier and on one group. The disclosure is a real `button[aria-expanded aria-controls]` *inside* the `h2`/`h3`, so the heading outline is identical to the bench above it. A folded run of rows is hidden rather than unmounted — out of the layout and out of the accessibility tree, but still holding its state, which is what lets a group keep its own fold while the tier above it is shut and reopened. Which places are folded is the caller's to keep; this bench keeps it in React state and nothing is stored by the library.",
259
+ "interaction": "press a tier heading or a group slug to fold it; the chevron turns, the sibling group stays open, and Tab reaches each disclosure as a real button with Enter and Space. Fold the first group, then fold and reopen the tier over it: the group is still folded."
185
260
  }
186
261
  ]
187
262
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "library": "@cueplusplus/ui",
4
- "version": "0.7.0",
4
+ "version": "0.8.0",
5
5
  "generatedAt": "1970-01-01T00:00:00.000Z",
6
6
  "themes": [
7
7
  "cue",
@@ -29,7 +29,7 @@
29
29
  ],
30
30
  "tokens": {
31
31
  "path": "./tokens.json",
32
- "sha256": "6672f3007cb48503b465985501b881b7d5144816bc716d4350e7d9bd7b7c566e"
32
+ "sha256": "6d7c8411b968edd7c1d6dca18d845ec52370da8f6364cc28454b48122fb3ead0"
33
33
  },
34
34
  "systemApis": [
35
35
  {
@@ -3501,7 +3501,7 @@
3501
3501
  "mdUrl": "/docs/components/data-tree.md",
3502
3502
  "jsonUrl": "/r/components/data-tree.json",
3503
3503
  "path": "./components/data-tree.json",
3504
- "sha256": "33244c5faf277716152a605c28726b0be0fb110f1bafa8b0b84f8a00a9315b55"
3504
+ "sha256": "3e68587c9fde809009a4a9661636a7b64dbe72b519cde4d6093bd36996106bdf"
3505
3505
  },
3506
3506
  {
3507
3507
  "name": "GroupBar",
@@ -3521,13 +3521,13 @@
3521
3521
  "slug": "ledger",
3522
3522
  "group": "instruments",
3523
3523
  "importPath": "@cueplusplus/ui",
3524
- "summary": "Grouped dense rows under sticky tier headings and gutter slugs, with no disclosure anywhere.",
3524
+ "summary": "Grouped dense rows under sticky tier headings and gutter slugs, with an opt-in disclosure that folds a heading without leaving the outline.",
3525
3525
  "status": "stable",
3526
3526
  "url": "/docs/components/ledger",
3527
3527
  "mdUrl": "/docs/components/ledger.md",
3528
3528
  "jsonUrl": "/r/components/ledger.json",
3529
3529
  "path": "./components/ledger.json",
3530
- "sha256": "129b47da8898b856d150ae7c6901e1e5340cabacd15457b860aa03e80139c388"
3530
+ "sha256": "52cc7f45dbf809e5be6eb04fc2420038143ee199d4f8bef29033d78197c20da6"
3531
3531
  },
3532
3532
  {
3533
3533
  "name": "LogViewer",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "library": "@cueplusplus/tokens",
4
- "version": "0.7.0",
4
+ "version": "0.8.0",
5
5
  "themes": [
6
6
  "cue",
7
7
  "terminal",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cueplusplus/ui",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "CUE++ design system components: Tailwind v4 styled wrappers over Base UI, driven by @cueplusplus/tokens.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -140,7 +140,7 @@
140
140
  "clsx": "^2.1.1",
141
141
  "culori": "^4.0.2",
142
142
  "tailwind-merge": "^3.6.0",
143
- "@cueplusplus/tokens": "0.7.0"
143
+ "@cueplusplus/tokens": "0.8.0"
144
144
  },
145
145
  "peerDependencies": {
146
146
  "@assistant-ui/react": "^0.15.16",
@@ -253,8 +253,8 @@
253
253
  "tsdown": "0.22.14",
254
254
  "typescript": "^5.7.0",
255
255
  "vitest": "^4.1.10",
256
- "@repo/typescript-config": "0.0.0",
257
- "@repo/docgen": "0.0.0"
256
+ "@repo/docgen": "0.0.0",
257
+ "@repo/typescript-config": "0.0.0"
258
258
  },
259
259
  "scripts": {
260
260
  "build": "pnpm run check:manifest && tsdown",