@ponchia/ui 0.6.9 → 0.6.10

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
@@ -5,6 +5,26 @@
5
5
  |> `^0` / `*` wildcard does **not** protect you. See README → Versioning, and
6
6
  |> the deprecation policy in CONTRIBUTING.md.
7
7
 
8
+ ## 0.6.10 — 2026-06-23
9
+
10
+ ### Added
11
+
12
+ - **Workbench toolstrip primitives.** `workbench.css`, the generated class
13
+ registry, and the workbench docs now cover floating toolstrips, compact
14
+ grouped actions, segmented button groups, contextual labels, and search/action
15
+ slots for dense canvas or editor-style tools.
16
+ - **Annotation composition guidance.** The annotation docs now show how the
17
+ dependency-free `@ponchia/ui` annotation surface composes with richer
18
+ annotation engines in a workbench-style consumer, while keeping runtime
19
+ package boundaries explicit.
20
+
21
+ ### Verified
22
+
23
+ - **Release evidence.** PR CI passed for the workbench expansion, including the
24
+ aggregate `check` gate, Chromium e2e, CodeQL, and the packed examples matrix.
25
+ This release adds opt-in workbench CSS and generated class/docs artifacts; it
26
+ does not move the default bundle contract.
27
+
8
28
  ## 0.6.9 — 2026-06-20
9
29
 
10
30
  ### Changed
package/README.md CHANGED
@@ -67,7 +67,7 @@ npm i @ponchia/ui
67
67
  Or drop it in with no build step, straight from a CDN:
68
68
 
69
69
  ```html
70
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.9/dist/bronto.css">
70
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.10/dist/bronto.css">
71
71
  ```
72
72
 
73
73
  ## Quick start
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$comment": "@ponchia/ui class vocabulary as language-neutral data — validate emitted markup without executing the ESM cls map or parsing the .d.ts. Generated from classes/index.js — do not edit by hand; run `npm run classes:json:build`. Drift-checked in CI. `groups[].base` is null for a parts-only namespace (no standalone base class — do NOT emit it). A modifier whose name contains `__` (e.g. `ui-spark__bar--pos`) attaches to THAT part, not the base host. `states` is the author-applied `is-*` hooks (runtime/behavior-managed hooks are excluded); `behaviorAttributes` are the `data-bronto-*` wiring hooks the optional behaviors delegate on; `requiredAria` is the role/aria a generator must emit per component. `states` + `customProperties` are documented in docs/reference.md and ship outside `cls` by design.",
3
3
  "counts": {
4
- "classes": 634,
5
- "groups": 177
4
+ "classes": 644,
5
+ "groups": 179
6
6
  },
7
7
  "groups": {
8
8
  "ui-accordion": {
@@ -1081,6 +1081,13 @@
1081
1081
  "ui-segmented__option"
1082
1082
  ]
1083
1083
  },
1084
+ "ui-segmented-buttons": {
1085
+ "base": "ui-segmented-buttons",
1086
+ "modifiers": [],
1087
+ "parts": [
1088
+ "ui-segmented-buttons__button"
1089
+ ]
1090
+ },
1084
1091
  "ui-sel": {
1085
1092
  "base": "ui-sel",
1086
1093
  "modifiers": [
@@ -1437,6 +1444,20 @@
1437
1444
  "modifiers": [],
1438
1445
  "parts": []
1439
1446
  },
1447
+ "ui-toolstrip": {
1448
+ "base": "ui-toolstrip",
1449
+ "modifiers": [
1450
+ "ui-toolstrip--compact",
1451
+ "ui-toolstrip--floating"
1452
+ ],
1453
+ "parts": [
1454
+ "ui-toolstrip__actions",
1455
+ "ui-toolstrip__brand",
1456
+ "ui-toolstrip__context",
1457
+ "ui-toolstrip__group",
1458
+ "ui-toolstrip__search"
1459
+ ]
1460
+ },
1440
1461
  "ui-tooltip": {
1441
1462
  "base": "ui-tooltip",
1442
1463
  "modifiers": [],
@@ -1964,6 +1985,8 @@
1964
1985
  "ui-scroll-reveal",
1965
1986
  "ui-search",
1966
1987
  "ui-segmented",
1988
+ "ui-segmented-buttons",
1989
+ "ui-segmented-buttons__button",
1967
1990
  "ui-segmented__option",
1968
1991
  "ui-sel",
1969
1992
  "ui-sel--maybe",
@@ -2100,6 +2123,14 @@
2100
2123
  "ui-tool-call__name",
2101
2124
  "ui-tool-call__status",
2102
2125
  "ui-tool-log",
2126
+ "ui-toolstrip",
2127
+ "ui-toolstrip--compact",
2128
+ "ui-toolstrip--floating",
2129
+ "ui-toolstrip__actions",
2130
+ "ui-toolstrip__brand",
2131
+ "ui-toolstrip__context",
2132
+ "ui-toolstrip__group",
2133
+ "ui-toolstrip__search",
2103
2134
  "ui-tooltip",
2104
2135
  "ui-tooltip__bubble",
2105
2136
  "ui-tour-note",
@@ -574,6 +574,16 @@ export declare const cls: {
574
574
  readonly inspector: 'ui-inspector';
575
575
  readonly inspectorHead: 'ui-inspector__head';
576
576
  readonly inspectorBody: 'ui-inspector__body';
577
+ readonly toolstrip: 'ui-toolstrip';
578
+ readonly toolstripFloating: 'ui-toolstrip--floating';
579
+ readonly toolstripCompact: 'ui-toolstrip--compact';
580
+ readonly toolstripBrand: 'ui-toolstrip__brand';
581
+ readonly toolstripContext: 'ui-toolstrip__context';
582
+ readonly toolstripGroup: 'ui-toolstrip__group';
583
+ readonly toolstripActions: 'ui-toolstrip__actions';
584
+ readonly toolstripSearch: 'ui-toolstrip__search';
585
+ readonly segmentedButtons: 'ui-segmented-buttons';
586
+ readonly segmentedButtonsButton: 'ui-segmented-buttons__button';
577
587
  readonly property: 'ui-property';
578
588
  readonly propertyLabel: 'ui-property__label';
579
589
  readonly propertyValue: 'ui-property__value';
package/classes/index.js CHANGED
@@ -609,10 +609,20 @@ export const cls = Object.freeze({
609
609
  toolCallName: 'ui-tool-call__name',
610
610
  toolCallStatus: 'ui-tool-call__status',
611
611
  toolCallBody: 'ui-tool-call__body',
612
- // workbench — inspector / property / selection bar / splitter (css/workbench.css)
612
+ // workbench — inspector / property / toolstrip / selection bar / splitter (css/workbench.css)
613
613
  inspector: 'ui-inspector',
614
614
  inspectorHead: 'ui-inspector__head',
615
615
  inspectorBody: 'ui-inspector__body',
616
+ toolstrip: 'ui-toolstrip',
617
+ toolstripFloating: 'ui-toolstrip--floating',
618
+ toolstripCompact: 'ui-toolstrip--compact',
619
+ toolstripBrand: 'ui-toolstrip__brand',
620
+ toolstripContext: 'ui-toolstrip__context',
621
+ toolstripGroup: 'ui-toolstrip__group',
622
+ toolstripActions: 'ui-toolstrip__actions',
623
+ toolstripSearch: 'ui-toolstrip__search',
624
+ segmentedButtons: 'ui-segmented-buttons',
625
+ segmentedButtonsButton: 'ui-segmented-buttons__button',
616
626
  property: 'ui-property',
617
627
  propertyLabel: 'ui-property__label',
618
628
  propertyValue: 'ui-property__value',
package/css/workbench.css CHANGED
@@ -32,6 +32,119 @@
32
32
  gap: var(--space-2xs);
33
33
  }
34
34
 
35
+ /* --- Toolstrip — compact workbench controls, optionally floating over a
36
+ viewport. The host owns commands, search behavior, active mode, and
37
+ responsive hiding policy. --- */
38
+ .ui-toolstrip {
39
+ align-items: center;
40
+ background: var(--panel-strong);
41
+ border: 1px solid var(--line-strong);
42
+ border-radius: var(--radius-md);
43
+ display: flex;
44
+ flex-wrap: wrap;
45
+ gap: var(--space-xs);
46
+ min-inline-size: 0;
47
+ padding: 0.35rem;
48
+ }
49
+
50
+ .ui-toolstrip--floating {
51
+ box-shadow: var(--shadow-raised);
52
+ }
53
+
54
+ .ui-toolstrip--compact {
55
+ gap: var(--space-2xs);
56
+ padding: 0.25rem;
57
+ }
58
+
59
+ .ui-toolstrip__brand {
60
+ align-items: baseline;
61
+ display: inline-flex;
62
+ flex: 0 1 auto;
63
+ gap: var(--space-xs);
64
+ min-inline-size: 0;
65
+ padding-inline: var(--space-xs);
66
+ }
67
+
68
+ .ui-toolstrip__brand strong {
69
+ color: var(--text);
70
+ font-size: var(--text-sm);
71
+ }
72
+
73
+ .ui-toolstrip__context {
74
+ color: var(--text-dim);
75
+ font-size: var(--text-xs);
76
+ min-inline-size: 0;
77
+ overflow: hidden;
78
+ text-overflow: ellipsis;
79
+ white-space: nowrap;
80
+ }
81
+
82
+ .ui-toolstrip__group,
83
+ .ui-toolstrip__actions {
84
+ align-items: center;
85
+ display: inline-flex;
86
+ flex-wrap: wrap;
87
+ gap: var(--space-2xs);
88
+ }
89
+
90
+ .ui-toolstrip__group {
91
+ background: var(--panel-soft);
92
+ border: 1px solid var(--line);
93
+ border-radius: var(--radius-md);
94
+ padding: 0.16rem;
95
+ }
96
+
97
+ .ui-toolstrip__search {
98
+ flex: 1 1 14rem;
99
+ min-inline-size: min(100%, 11rem);
100
+ }
101
+
102
+ .ui-toolstrip__actions {
103
+ margin-inline-start: auto;
104
+ }
105
+
106
+ /* --- Button segmented control — command buttons that expose one active
107
+ mode. For actual form values, keep using `.ui-segmented` with radio inputs. --- */
108
+ .ui-segmented-buttons {
109
+ align-items: center;
110
+ background: var(--panel-soft);
111
+ border: 1px solid var(--line);
112
+ border-radius: var(--radius-md);
113
+ display: inline-flex;
114
+ flex-wrap: wrap;
115
+ gap: 0.16rem;
116
+ padding: 0.16rem;
117
+ }
118
+
119
+ .ui-segmented-buttons__button {
120
+ background: transparent;
121
+ border: 1px solid transparent;
122
+ border-radius: var(--radius-sm);
123
+ color: var(--text-soft);
124
+ cursor: pointer;
125
+ font-family: var(--mono);
126
+ font-size: var(--text-xs);
127
+ font-weight: 700;
128
+ letter-spacing: var(--tracking-wide);
129
+ line-height: 1;
130
+ min-block-size: 1.9rem;
131
+ padding: 0.48rem 0.7rem;
132
+ text-transform: uppercase;
133
+ }
134
+
135
+ .ui-segmented-buttons__button[aria-pressed='true'],
136
+ .ui-segmented-buttons__button.is-active {
137
+ background: var(--accent);
138
+ border-color: var(--accent);
139
+ color: var(--button-text);
140
+ }
141
+
142
+ .ui-segmented-buttons__button:disabled,
143
+ .ui-segmented-buttons__button[aria-disabled='true'] {
144
+ cursor: not-allowed;
145
+ opacity: 0.45;
146
+ }
147
+
35
148
  /* --- Property row — a label/value pair, denser than ui-key-value and tuned
36
149
  for an inspector (the value can hold an input or a static read-out). --- */
37
150
  .ui-property {
@@ -81,6 +194,14 @@
81
194
  gap: var(--space-xs);
82
195
  }
83
196
 
197
+ @media (hover: hover) {
198
+ .ui-segmented-buttons__button:hover:not(:disabled, [aria-disabled='true'], [aria-pressed='true'], .is-active) {
199
+ background: var(--panel);
200
+ border-color: var(--line-strong);
201
+ color: var(--text);
202
+ }
203
+ }
204
+
84
205
  /* --- Splitter — two panes separated by a focusable ARIA separator handle. --- */
85
206
  .ui-splitter {
86
207
  --splitter-pos: 50%;
@@ -166,6 +287,13 @@
166
287
  }
167
288
 
168
289
  @media (forced-colors: active) {
290
+ .ui-segmented-buttons__button[aria-pressed='true'],
291
+ .ui-segmented-buttons__button.is-active {
292
+ background: Highlight;
293
+ border-color: Highlight;
294
+ color: HighlightText;
295
+ }
296
+
169
297
  .ui-splitter__handle {
170
298
  border-color: CanvasText;
171
299
  }
@@ -1 +1 @@
1
- @layer bronto{.ui-inspector{background: var(--panel);border: 1px solid var(--line);border-radius: var(--radius-md);display: grid;gap: var(--space-sm);padding: var(--space-md)}.ui-inspector__head{align-items: baseline;border-block-end: 1px solid var(--line);display: flex;gap: var(--space-sm);justify-content: space-between;padding-block-end: var(--space-xs)}.ui-inspector__body{display: grid;gap: var(--space-2xs)}.ui-property{align-items: baseline;display: grid;gap: var(--space-sm);grid-template-columns: minmax(6rem,38%) 1fr}.ui-property__label{color: var(--text-dim);font-family: var(--mono);font-size: var(--text-2xs);letter-spacing: var(--tracking-wide);text-transform: uppercase}.ui-property__value{color: var(--text);font-size: var(--text-sm);min-inline-size: 0}.ui-selectionbar{align-items: center;background: var(--panel-strong);border: 1px solid var(--line-strong);border-radius: var(--radius-md);box-shadow: var(--shadow-raised);display: flex;flex-wrap: wrap;gap: var(--space-sm) var(--space-md);justify-content: space-between;padding: 0.5rem 0.85rem}.ui-selectionbar__count{color: var(--text);font-family: var(--mono);font-size: var(--text-sm)}.ui-selectionbar__actions{display: flex;flex-wrap: wrap;gap: var(--space-xs)}.ui-splitter{--splitter-pos: 50%;--splitter-handle: 0.75rem;--splitter-pane-min: 0px;background: var(--panel);border: 1px solid var(--line);border-radius: var(--radius-md);display: grid;grid-template-columns: minmax(var(--splitter-pane-min),var(--splitter-pos)) var(--splitter-handle) minmax(0,1fr);min-block-size: 18rem;overflow: hidden}.ui-splitter--vertical{grid-template-columns: minmax(var(--splitter-pane-min),var(--splitter-pos)) var(--splitter-handle) minmax(0,1fr)}.ui-splitter--horizontal{grid-template-columns: 1fr;grid-template-rows: minmax(var(--splitter-pane-min),var(--splitter-pos)) var(--splitter-handle) minmax(0,1fr)}.ui-splitter__pane{min-block-size: 0;min-inline-size: 0;overflow: auto;padding: var(--space-md)}.ui-splitter__handle{align-self: stretch;background: var(--panel-strong);border-block: 0;border-inline: 1px solid var(--line);cursor: col-resize;display: grid;min-inline-size: var(--splitter-handle);place-items: center;touch-action: none}.ui-splitter__handle::before{background: var(--line-strong);border-radius: var(--radius-pill);block-size: 2.5rem;content: "";inline-size: 2px}.ui-splitter__handle:hover::before,.ui-splitter__handle.is-active::before,.ui-splitter__handle[aria-valuenow]:focus-visible::before{background: var(--accent)}.ui-splitter__handle:focus-visible{outline: 2px solid var(--focus-ring);outline-offset: -2px}.ui-splitter--horizontal .ui-splitter__handle{border-block: 1px solid var(--line);border-inline: 0;cursor: row-resize;min-block-size: var(--splitter-handle);min-inline-size: 0}.ui-splitter--horizontal .ui-splitter__handle::before{block-size: 2px;inline-size: 2.5rem}@media (forced-colors: active){.ui-splitter__handle{border-color: CanvasText}.ui-splitter__handle::before{background: CanvasText}}}
1
+ @layer bronto{.ui-inspector{background: var(--panel);border: 1px solid var(--line);border-radius: var(--radius-md);display: grid;gap: var(--space-sm);padding: var(--space-md)}.ui-inspector__head{align-items: baseline;border-block-end: 1px solid var(--line);display: flex;gap: var(--space-sm);justify-content: space-between;padding-block-end: var(--space-xs)}.ui-inspector__body{display: grid;gap: var(--space-2xs)}.ui-toolstrip{align-items: center;background: var(--panel-strong);border: 1px solid var(--line-strong);border-radius: var(--radius-md);display: flex;flex-wrap: wrap;gap: var(--space-xs);min-inline-size: 0;padding: 0.35rem}.ui-toolstrip--floating{box-shadow: var(--shadow-raised)}.ui-toolstrip--compact{gap: var(--space-2xs);padding: 0.25rem}.ui-toolstrip__brand{align-items: baseline;display: inline-flex;flex: 0 1 auto;gap: var(--space-xs);min-inline-size: 0;padding-inline: var(--space-xs)}.ui-toolstrip__brand strong{color: var(--text);font-size: var(--text-sm)}.ui-toolstrip__context{color: var(--text-dim);font-size: var(--text-xs);min-inline-size: 0;overflow: hidden;text-overflow: ellipsis;white-space: nowrap}.ui-toolstrip__group,.ui-toolstrip__actions{align-items: center;display: inline-flex;flex-wrap: wrap;gap: var(--space-2xs)}.ui-toolstrip__group{background: var(--panel-soft);border: 1px solid var(--line);border-radius: var(--radius-md);padding: 0.16rem}.ui-toolstrip__search{flex: 1 1 14rem;min-inline-size: min(100%,11rem)}.ui-toolstrip__actions{margin-inline-start: auto}.ui-segmented-buttons{align-items: center;background: var(--panel-soft);border: 1px solid var(--line);border-radius: var(--radius-md);display: inline-flex;flex-wrap: wrap;gap: 0.16rem;padding: 0.16rem}.ui-segmented-buttons__button{background: transparent;border: 1px solid transparent;border-radius: var(--radius-sm);color: var(--text-soft);cursor: pointer;font-family: var(--mono);font-size: var(--text-xs);font-weight: 700;letter-spacing: var(--tracking-wide);line-height: 1;min-block-size: 1.9rem;padding: 0.48rem 0.7rem;text-transform: uppercase}.ui-segmented-buttons__button[aria-pressed='true'],.ui-segmented-buttons__button.is-active{background: var(--accent);border-color: var(--accent);color: var(--button-text)}.ui-segmented-buttons__button:disabled,.ui-segmented-buttons__button[aria-disabled='true']{cursor: not-allowed;opacity: 0.45}.ui-property{align-items: baseline;display: grid;gap: var(--space-sm);grid-template-columns: minmax(6rem,38%) 1fr}.ui-property__label{color: var(--text-dim);font-family: var(--mono);font-size: var(--text-2xs);letter-spacing: var(--tracking-wide);text-transform: uppercase}.ui-property__value{color: var(--text);font-size: var(--text-sm);min-inline-size: 0}.ui-selectionbar{align-items: center;background: var(--panel-strong);border: 1px solid var(--line-strong);border-radius: var(--radius-md);box-shadow: var(--shadow-raised);display: flex;flex-wrap: wrap;gap: var(--space-sm) var(--space-md);justify-content: space-between;padding: 0.5rem 0.85rem}.ui-selectionbar__count{color: var(--text);font-family: var(--mono);font-size: var(--text-sm)}.ui-selectionbar__actions{display: flex;flex-wrap: wrap;gap: var(--space-xs)}@media (hover: hover){.ui-segmented-buttons__button:hover:not(:disabled,[aria-disabled='true'],[aria-pressed='true'],.is-active){background: var(--panel);border-color: var(--line-strong);color: var(--text)}}.ui-splitter{--splitter-pos: 50%;--splitter-handle: 0.75rem;--splitter-pane-min: 0px;background: var(--panel);border: 1px solid var(--line);border-radius: var(--radius-md);display: grid;grid-template-columns: minmax(var(--splitter-pane-min),var(--splitter-pos)) var(--splitter-handle) minmax(0,1fr);min-block-size: 18rem;overflow: hidden}.ui-splitter--vertical{grid-template-columns: minmax(var(--splitter-pane-min),var(--splitter-pos)) var(--splitter-handle) minmax(0,1fr)}.ui-splitter--horizontal{grid-template-columns: 1fr;grid-template-rows: minmax(var(--splitter-pane-min),var(--splitter-pos)) var(--splitter-handle) minmax(0,1fr)}.ui-splitter__pane{min-block-size: 0;min-inline-size: 0;overflow: auto;padding: var(--space-md)}.ui-splitter__handle{align-self: stretch;background: var(--panel-strong);border-block: 0;border-inline: 1px solid var(--line);cursor: col-resize;display: grid;min-inline-size: var(--splitter-handle);place-items: center;touch-action: none}.ui-splitter__handle::before{background: var(--line-strong);border-radius: var(--radius-pill);block-size: 2.5rem;content: "";inline-size: 2px}.ui-splitter__handle:hover::before,.ui-splitter__handle.is-active::before,.ui-splitter__handle[aria-valuenow]:focus-visible::before{background: var(--accent)}.ui-splitter__handle:focus-visible{outline: 2px solid var(--focus-ring);outline-offset: -2px}.ui-splitter--horizontal .ui-splitter__handle{border-block: 1px solid var(--line);border-inline: 0;cursor: row-resize;min-block-size: var(--splitter-handle);min-inline-size: 0}.ui-splitter--horizontal .ui-splitter__handle::before{block-size: 2px;inline-size: 2.5rem}@media (forced-colors: active){.ui-segmented-buttons__button[aria-pressed='true'],.ui-segmented-buttons__button.is-active{background: Highlight;border-color: Highlight;color: HighlightText}.ui-splitter__handle{border-color: CanvasText}.ui-splitter__handle::before{background: CanvasText}}}
@@ -22,6 +22,33 @@ declarations never type-reference it. Combine the two by using Bronto's
22
22
  `css/annotations.css` for the visual grammar, or the annotation package's Bronto
23
23
  CSS bridge when the engine emits its own layer.
24
24
 
25
+ When an annotation engine overlays a rendered chart, screenshot, canvas, or
26
+ diagram, put the rendered media in `.ui-figure__media` and the emitted annotation
27
+ layer in `.ui-figure__overlay`. The figure stage supplies the stable positioning
28
+ context; the annotation package owns anchors, placement, collision handling, and
29
+ SVG/React rendering. Keep the same annotation text available through a caption,
30
+ `<desc>`, fallback table, or surrounding prose when it carries data.
31
+
32
+ For inspector-driven selection, keep selection state in the host application:
33
+ the selected item can render details in `.ui-inspector`, while the annotation
34
+ engine receives the focused anchor and emits the matching overlay. Bronto UI
35
+ styles the inspector, figure stage, and annotation visual grammar; it does not
36
+ own hit-testing, selected IDs, camera/chart state, or focus policy.
37
+
38
+ ```html
39
+ <figure class="ui-figure" role="group" aria-labelledby="annotated-title">
40
+ <figcaption id="annotated-title" class="ui-figure__caption">
41
+ Annotated service latency
42
+ </figcaption>
43
+ <div class="ui-figure__stage">
44
+ <canvas class="ui-figure__media" aria-label="Latency chart"></canvas>
45
+ <svg class="ui-figure__overlay pa-annotation-layer" viewBox="0 0 640 360">
46
+ <!-- emitted by @ponchia/annotations -->
47
+ </svg>
48
+ </div>
49
+ </figure>
50
+ ```
51
+
25
52
  ```js
26
53
  import {
27
54
  annotationParts,
package/docs/reference.md CHANGED
@@ -9,7 +9,7 @@ rendering of every class is the kitchen-sink demo:
9
9
  **<https://ponchia.github.io/bronto-ui/>**. Theming knobs and the token
10
10
  contract: [docs/theming.md](theming.md).
11
11
 
12
- - 634 classes across 177 component groups
12
+ - 644 classes across 179 component groups
13
13
  - Import the typed registry: `import { cls, ui, cx } from '@ponchia/ui/classes'`
14
14
  - Validate markup as data (no JS/TS): `@ponchia/ui/classes.json` — the same
15
15
  vocabulary as language-neutral JSON (`groups`, `classes`, `states`,
@@ -1131,6 +1131,13 @@ each one matches a real selector in the stylesheet.
1131
1131
  | `cls.segmented` | `ui-segmented` | base |
1132
1132
  | `cls.segmentedOption` | `ui-segmented__option` | part |
1133
1133
 
1134
+ ### `.ui-segmented-buttons`
1135
+
1136
+ | Registry key | Class | Kind |
1137
+ | --- | --- | --- |
1138
+ | `cls.segmentedButtons` | `ui-segmented-buttons` | base |
1139
+ | `cls.segmentedButtonsButton` | `ui-segmented-buttons__button` | part |
1140
+
1134
1141
  ### `.ui-sel`
1135
1142
 
1136
1143
  | Registry key | Class | Kind |
@@ -1496,6 +1503,19 @@ each one matches a real selector in the stylesheet.
1496
1503
  | --- | --- | --- |
1497
1504
  | `cls.toolLog` | `ui-tool-log` | base |
1498
1505
 
1506
+ ### `.ui-toolstrip`
1507
+
1508
+ | Registry key | Class | Kind |
1509
+ | --- | --- | --- |
1510
+ | `cls.toolstrip` | `ui-toolstrip` | base |
1511
+ | `cls.toolstripActions` | `ui-toolstrip__actions` | part |
1512
+ | `cls.toolstripBrand` | `ui-toolstrip__brand` | part |
1513
+ | `cls.toolstripContext` | `ui-toolstrip__context` | part |
1514
+ | `cls.toolstripGroup` | `ui-toolstrip__group` | part |
1515
+ | `cls.toolstripSearch` | `ui-toolstrip__search` | part |
1516
+ | `cls.toolstripCompact` | `ui-toolstrip--compact` | modifier |
1517
+ | `cls.toolstripFloating` | `ui-toolstrip--floating` | modifier |
1518
+
1499
1519
  ### `.ui-tooltip`
1500
1520
 
1501
1521
  | Registry key | Class | Kind |
package/docs/reporting.md CHANGED
@@ -54,18 +54,18 @@ No install? Link the same files from a CDN. Pin the version — pre-1.0, breakin
54
54
  changes ship in the minor (see [stability.md](./stability.md)):
55
55
 
56
56
  ```html
57
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.9/dist/bronto.css" />
58
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.9/dist/css/report-kit.css" />
57
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.10/dist/bronto.css" />
58
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.10/dist/css/report-kit.css" />
59
59
  ```
60
60
 
61
61
  Leaf-by-leaf CDN imports use the same `dist/css/` paths:
62
62
 
63
63
  ```html
64
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.9/dist/bronto.css" />
65
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.9/dist/css/report.css" />
66
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.9/dist/css/dataviz.css" />
67
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.9/dist/css/annotations.css" />
68
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.9/dist/css/legend.css" />
64
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.10/dist/bronto.css" />
65
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.10/dist/css/report.css" />
66
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.10/dist/css/dataviz.css" />
67
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.10/dist/css/annotations.css" />
68
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.10/dist/css/legend.css" />
69
69
  ```
70
70
 
71
71
  The CDN serves the package's own `fonts/` next to the CSS, so font URLs resolve
@@ -879,7 +879,7 @@ or validation runtime.
879
879
 
880
880
  ```json
881
881
  {
882
- "$schema": "https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.9/schemas/report-claims.v1.schema.json",
882
+ "$schema": "https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.10/schemas/report-claims.v1.schema.json",
883
883
  "schemaVersion": "bronto-report-claims.v1",
884
884
  "report": { "title": "Decision readiness", "type": "decision" },
885
885
  "claims": [
package/docs/workbench.md CHANGED
@@ -1,10 +1,11 @@
1
- # Workbench — split panes, inspector, properties, selection bar
1
+ # Workbench — split panes, toolstrips, inspector, properties, selection bar
2
2
 
3
3
  `@ponchia/ui/css/workbench.css` is an opt-in set of primitives for **real
4
- tools**: resizable split panes, an inspector panel, property rows for a selected
5
- object, and a bar of actions on the current selection. Generic kits stop at
6
- cards/tables/forms, so every app builds its own half-consistent workbench. This
7
- is the low-risk core — layout, resize affordance, and ARIA value sync.
4
+ tools**: resizable split panes, compact toolstrips, button-mode segmented
5
+ controls, an inspector panel, property rows for a selected object, and a bar of
6
+ actions on the current selection. Generic kits stop at cards/tables/forms, so
7
+ every app builds its own half-consistent workbench. This is the low-risk core —
8
+ layout, dense controls, resize affordance, and ARIA value sync.
8
9
 
9
10
  ```css
10
11
  @import '@ponchia/ui';
@@ -20,6 +21,51 @@ initSplitter();
20
21
  Not in the core bundle. Import the CSS leaf where the workbench appears and run
21
22
  `initSplitter()` only if the page includes `[data-bronto-splitter]`.
22
23
 
24
+ ## Toolstrip — `.ui-toolstrip`
25
+
26
+ A compact row of controls for a tool surface or viewport. Use
27
+ `.ui-toolstrip--floating` when the strip sits over a canvas, chart, map, media
28
+ stage, or preview. The CSS owns density, wrapping, grouping, and raised/floating
29
+ treatment; the host owns commands, search behavior, active mode, responsive
30
+ hiding, and placement.
31
+
32
+ ```html
33
+ <header class="ui-toolstrip ui-toolstrip--floating" aria-label="View controls">
34
+ <div class="ui-toolstrip__brand">
35
+ <strong>Repository</strong>
36
+ <span class="ui-toolstrip__context">main branch</span>
37
+ </div>
38
+ <div class="ui-toolstrip__group" aria-label="Mode">
39
+ <button class="ui-segmented-buttons__button" type="button" aria-pressed="true">Map</button>
40
+ <button class="ui-segmented-buttons__button" type="button" aria-pressed="false">Flow</button>
41
+ <button class="ui-segmented-buttons__button" type="button" aria-pressed="false">Risk</button>
42
+ </div>
43
+ <label class="ui-toolstrip__search">
44
+ <span class="ui-visually-hidden">Filter items</span>
45
+ <input class="ui-input" type="search" placeholder="Filter by path, owner, or tag" />
46
+ </label>
47
+ <div class="ui-toolstrip__actions" aria-label="Viewport actions">
48
+ <button class="ui-button ui-button--ghost ui-button--icon ui-button--sm" type="button">
49
+ Fit
50
+ </button>
51
+ </div>
52
+ </header>
53
+ ```
54
+
55
+ ## Button segmented control — `.ui-segmented-buttons`
56
+
57
+ Use `.ui-segmented-buttons` when each option is a real command button and the
58
+ current mode is exposed with `aria-pressed`. For form values submitted with the
59
+ page, keep using the core `.ui-segmented` radio-input pattern.
60
+
61
+ ```html
62
+ <div class="ui-segmented-buttons" aria-label="Density">
63
+ <button class="ui-segmented-buttons__button" type="button" aria-pressed="true">Dense</button>
64
+ <button class="ui-segmented-buttons__button" type="button" aria-pressed="false">Comfort</button>
65
+ <button class="ui-segmented-buttons__button" type="button" aria-pressed="false">Wide</button>
66
+ </div>
67
+ ```
68
+
23
69
  ## Splitter — `.ui-splitter`
24
70
 
25
71
  Two panes separated by a focusable ARIA separator handle. The CSS owns the grid
@@ -113,7 +159,8 @@ A raised bar of actions on the current selection: a `__count` on one side,
113
159
  ## Scope
114
160
 
115
161
  No recipes — these are structural containers and rows; apply the classes
116
- directly (or read them from `cls.splitter`, `cls.inspector`, `cls.property`, …).
117
- Pair the selection bar with the cross-cutting [`ui-sel`](./selection.md) states
118
- on the selected items themselves. Bronto styles both and wires the splitter
119
- affordance; the host owns hit-testing, persistence, pane contents, and commands.
162
+ directly (or read them from `cls.toolstrip`, `cls.splitter`, `cls.inspector`,
163
+ `cls.property`, …). Pair the selection bar with the cross-cutting
164
+ [`ui-sel`](./selection.md) states on the selected items themselves. Bronto styles
165
+ the chrome and wires the splitter affordance; the host owns hit-testing,
166
+ persistence, pane contents, viewport semantics, and commands.
package/llms.txt CHANGED
@@ -44,7 +44,7 @@ the path changes from source `css/` to built `dist/css/`:
44
44
  <!-- installed locally -->
45
45
  <link rel="stylesheet" href="./node_modules/@ponchia/ui/dist/css/<leaf>.css" />
46
46
  <!-- or from a CDN; pin the version (pre-1.0, breaking changes ship in the minor) -->
47
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.9/dist/css/<leaf>.css" />
47
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.6.10/dist/css/<leaf>.css" />
48
48
  ```
49
49
 
50
50
  The flattened default bundle is `dist/bronto.css` (bundler shorthand
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ponchia/ui",
3
- "version": "0.6.9",
3
+ "version": "0.6.10",
4
4
  "type": "module",
5
5
  "description": "CSS-first identity and UI layer for services, tools, sites, and reports — works in HTML, every framework, and PDF, no component runtime. Shared app shell, forms, tables, workflow chrome, plus opt-in analytical/report primitives. Monochrome with one rationed accent. Zero runtime dependencies.",
6
6
  "keywords": [