@ponchia/ui 0.4.0 → 0.5.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.
Files changed (123) hide show
  1. package/CHANGELOG.md +352 -12
  2. package/MIGRATIONS.json +92 -0
  3. package/README.md +27 -17
  4. package/annotations/index.d.ts +280 -0
  5. package/annotations/index.js +522 -0
  6. package/behaviors/carousel.js +197 -0
  7. package/behaviors/combobox.js +195 -0
  8. package/behaviors/command.js +187 -0
  9. package/behaviors/connectors.js +96 -0
  10. package/behaviors/crosshair.js +58 -0
  11. package/behaviors/dialog.js +73 -0
  12. package/behaviors/disclosure.js +25 -0
  13. package/behaviors/dismissible.js +24 -0
  14. package/behaviors/forms.js +158 -0
  15. package/behaviors/glyph.js +109 -0
  16. package/behaviors/index.d.ts +82 -1
  17. package/behaviors/index.js +18 -1336
  18. package/behaviors/internal.js +50 -0
  19. package/behaviors/legend.js +46 -0
  20. package/behaviors/menu.js +46 -0
  21. package/behaviors/popover.js +108 -0
  22. package/behaviors/spotlight.js +53 -0
  23. package/behaviors/table.js +109 -0
  24. package/behaviors/tabs.js +103 -0
  25. package/behaviors/theme.js +82 -0
  26. package/behaviors/toast.js +152 -0
  27. package/classes/index.d.ts +318 -0
  28. package/classes/index.js +352 -0
  29. package/classes/vscode.css-custom-data.json +18 -14
  30. package/connectors/index.d.ts +71 -0
  31. package/connectors/index.js +179 -0
  32. package/css/analytical.css +21 -0
  33. package/css/annotations.css +292 -0
  34. package/css/command.css +97 -0
  35. package/css/connectors.css +93 -0
  36. package/css/crosshair.css +100 -0
  37. package/css/disclosure.css +29 -0
  38. package/css/dots.css +2 -0
  39. package/css/feedback.css +104 -0
  40. package/css/fonts.css +11 -7
  41. package/css/generated.css +117 -0
  42. package/css/legend.css +268 -0
  43. package/css/marks.css +144 -0
  44. package/css/motion.css +88 -0
  45. package/css/overlay.css +52 -1
  46. package/css/primitives.css +18 -0
  47. package/css/report.css +363 -0
  48. package/css/selection.css +46 -0
  49. package/css/sources.css +179 -0
  50. package/css/spotlight.css +104 -0
  51. package/css/state.css +121 -0
  52. package/css/tokens.css +78 -60
  53. package/css/workbench.css +83 -0
  54. package/dist/bronto.css +1 -1
  55. package/dist/css/analytical.css +1 -0
  56. package/dist/css/annotations.css +1 -0
  57. package/dist/css/command.css +1 -0
  58. package/dist/css/connectors.css +1 -0
  59. package/dist/css/crosshair.css +1 -0
  60. package/dist/css/disclosure.css +1 -1
  61. package/dist/css/dots.css +1 -1
  62. package/dist/css/feedback.css +1 -1
  63. package/dist/css/fonts.css +1 -1
  64. package/dist/css/generated.css +1 -0
  65. package/dist/css/legend.css +1 -0
  66. package/dist/css/marks.css +1 -0
  67. package/dist/css/motion.css +1 -1
  68. package/dist/css/overlay.css +1 -1
  69. package/dist/css/primitives.css +1 -1
  70. package/dist/css/report.css +1 -0
  71. package/dist/css/selection.css +1 -0
  72. package/dist/css/sources.css +1 -0
  73. package/dist/css/spotlight.css +1 -0
  74. package/dist/css/state.css +1 -0
  75. package/dist/css/tokens.css +1 -1
  76. package/dist/css/workbench.css +1 -0
  77. package/docs/adr/0001-color-system.md +26 -27
  78. package/docs/adr/0002-scope-and-2026-baseline.md +104 -0
  79. package/docs/adr/0003-theme-model.md +97 -0
  80. package/docs/annotations.md +345 -0
  81. package/docs/architecture.md +202 -0
  82. package/docs/command.md +95 -0
  83. package/docs/connectors.md +91 -0
  84. package/docs/contrast.md +42 -42
  85. package/docs/crosshair.md +63 -0
  86. package/docs/generated.md +91 -0
  87. package/docs/legends.md +168 -0
  88. package/docs/marks.md +86 -0
  89. package/docs/reference.md +418 -15
  90. package/docs/reporting.md +305 -0
  91. package/docs/selection.md +40 -0
  92. package/docs/sources.md +110 -0
  93. package/docs/spotlight.md +78 -0
  94. package/docs/stability.md +52 -0
  95. package/docs/state.md +85 -0
  96. package/docs/theming.md +18 -6
  97. package/docs/usage.md +43 -3
  98. package/docs/workbench.md +72 -0
  99. package/fonts/doto-400.woff2 +0 -0
  100. package/fonts/doto-500.woff2 +0 -0
  101. package/fonts/doto-600.woff2 +0 -0
  102. package/fonts/doto-700.woff2 +0 -0
  103. package/fonts/doto-800.woff2 +0 -0
  104. package/fonts/doto-900.woff2 +0 -0
  105. package/llms.txt +288 -8
  106. package/package.json +95 -5
  107. package/qwik/index.d.ts +60 -0
  108. package/qwik/index.js +149 -0
  109. package/react/index.d.ts +40 -14
  110. package/react/index.js +32 -5
  111. package/solid/index.d.ts +40 -14
  112. package/solid/index.js +31 -3
  113. package/tokens/index.d.ts +3 -3
  114. package/tokens/index.js +25 -19
  115. package/tokens/index.json +32 -28
  116. package/tokens/resolved.json +34 -32
  117. package/tokens/tokens.dtcg.json +22 -14
  118. package/fonts/doto-400.ttf +0 -0
  119. package/fonts/doto-500.ttf +0 -0
  120. package/fonts/doto-600.ttf +0 -0
  121. package/fonts/doto-700.ttf +0 -0
  122. package/fonts/doto-800.ttf +0 -0
  123. package/fonts/doto-900.ttf +0 -0
@@ -0,0 +1,179 @@
1
+ /**
2
+ * @ponchia/ui/connectors — dependency-free SVG geometry for connecting two
3
+ * elements (or two points) with a leader line.
4
+ *
5
+ * Pure functions only: they take points/rects and return SVG path strings (or
6
+ * resolved coordinates). They own no DOM, no scales, and no live tracking —
7
+ * that optional glue lives in `@ponchia/ui/behaviors` (`initConnectors`). This
8
+ * is the page-coordinate, element-to-element cousin of the figure-coordinate
9
+ * `@ponchia/ui/annotations` helpers.
10
+ *
11
+ * import { connectRects } from '@ponchia/ui/connectors';
12
+ * const { d } = connectRects({ fromRect: a, toRect: b, shape: 'elbow' });
13
+ */
14
+
15
+ const PRECISION = 1000;
16
+
17
+ function finite(name, value, fallback) {
18
+ const v = value ?? fallback;
19
+ if (!Number.isFinite(v)) throw new TypeError(`${name} must be a finite number`);
20
+ return v;
21
+ }
22
+
23
+ function dimension(name, value, fallback) {
24
+ const v = finite(name, value, fallback);
25
+ if (v < 0) throw new RangeError(`${name} must be greater than or equal to 0`);
26
+ return v;
27
+ }
28
+
29
+ function fmt(value) {
30
+ const rounded = Math.round((Object.is(value, -0) ? 0 : value) * PRECISION) / PRECISION;
31
+ return String(Object.is(rounded, -0) ? 0 : rounded);
32
+ }
33
+
34
+ function point(x, y) {
35
+ return `${fmt(x)},${fmt(y)}`;
36
+ }
37
+
38
+ function clamp(value, min, max) {
39
+ return Math.min(max, Math.max(min, value));
40
+ }
41
+
42
+ /** A point on a rect's edge (or centre). `rect` is `{ x, y, width, height }`. */
43
+ export function anchorPoint(rect, side = 'center') {
44
+ const x = finite('rect.x', rect?.x, 0);
45
+ const y = finite('rect.y', rect?.y, 0);
46
+ const w = dimension('rect.width', rect?.width, 0);
47
+ const h = dimension('rect.height', rect?.height, 0);
48
+ switch (side) {
49
+ case 'top':
50
+ return { x: x + w / 2, y };
51
+ case 'bottom':
52
+ return { x: x + w / 2, y: y + h };
53
+ case 'left':
54
+ return { x, y: y + h / 2 };
55
+ case 'right':
56
+ return { x: x + w, y: y + h / 2 };
57
+ case 'center':
58
+ default:
59
+ return { x: x + w / 2, y: y + h / 2 };
60
+ }
61
+ }
62
+
63
+ /** Angle (radians) from `from` to `to`. */
64
+ export function angleBetween(from, to) {
65
+ return Math.atan2(
66
+ finite('to.y', to?.y) - finite('from.y', from?.y),
67
+ finite('to.x', to?.x) - finite('from.x', from?.x),
68
+ );
69
+ }
70
+
71
+ export function straightPath(from, to) {
72
+ return `M${point(finite('from.x', from?.x), finite('from.y', from?.y))}L${point(
73
+ finite('to.x', to?.x),
74
+ finite('to.y', to?.y),
75
+ )}`;
76
+ }
77
+
78
+ /** Right-angle dogleg. Turns on the dominant axis at `mid` (0..1) of the span. */
79
+ export function elbowPath(from, to, opts = {}) {
80
+ const fx = finite('from.x', from?.x);
81
+ const fy = finite('from.y', from?.y);
82
+ const tx = finite('to.x', to?.x);
83
+ const ty = finite('to.y', to?.y);
84
+ const mid = clamp(finite('mid', opts.mid, 0.5), 0, 1);
85
+ const dx = tx - fx;
86
+ const dy = ty - fy;
87
+ if (Math.abs(dx) >= Math.abs(dy)) {
88
+ const mx = fx + dx * mid;
89
+ return `M${point(fx, fy)}H${fmt(mx)}V${fmt(ty)}H${fmt(tx)}`;
90
+ }
91
+ const my = fy + dy * mid;
92
+ return `M${point(fx, fy)}V${fmt(my)}H${fmt(tx)}V${fmt(ty)}`;
93
+ }
94
+
95
+ /** Cubic curve; control points extend along the dominant axis by `curvature`. */
96
+ export function curvePath(from, to, opts = {}) {
97
+ const fx = finite('from.x', from?.x);
98
+ const fy = finite('from.y', from?.y);
99
+ const tx = finite('to.x', to?.x);
100
+ const ty = finite('to.y', to?.y);
101
+ const k = finite('curvature', opts.curvature, 0.5);
102
+ const dx = tx - fx;
103
+ const dy = ty - fy;
104
+ const horizontal = Math.abs(dx) >= Math.abs(dy);
105
+ const c1 = horizontal ? { x: fx + dx * k, y: fy } : { x: fx, y: fy + dy * k };
106
+ const c2 = horizontal ? { x: tx - dx * k, y: ty } : { x: tx, y: ty - dy * k };
107
+ return `M${point(fx, fy)}C${point(c1.x, c1.y)} ${point(c2.x, c2.y)} ${point(tx, ty)}`;
108
+ }
109
+
110
+ /** Build a path between two points by `shape` (`straight` | `elbow` | `curve`). */
111
+ export function connectorPath(opts = {}) {
112
+ const { from, to, shape = 'straight' } = opts;
113
+ if (shape === 'elbow') return elbowPath(from, to, opts);
114
+ if (shape === 'curve') return curvePath(from, to, opts);
115
+ return straightPath(from, to);
116
+ }
117
+
118
+ /** A filled triangle arrowhead at `p`, pointing along `angle` (radians). */
119
+ export function arrowHead(p, angle, size = 8) {
120
+ const px = finite('p.x', p?.x);
121
+ const py = finite('p.y', p?.y);
122
+ const a = finite('angle', angle, 0);
123
+ const s = dimension('size', size, 8);
124
+ const back = a + Math.PI;
125
+ const spread = 0.45;
126
+ const p1 = { x: px + Math.cos(back - spread) * s, y: py + Math.sin(back - spread) * s };
127
+ const p2 = { x: px + Math.cos(back + spread) * s, y: py + Math.sin(back + spread) * s };
128
+ return `M${point(px, py)}L${point(p1.x, p1.y)}L${point(p2.x, p2.y)}Z`;
129
+ }
130
+
131
+ /** A filled dot at `p`. */
132
+ export function dotMark(p, radius = 3) {
133
+ const px = finite('p.x', p?.x);
134
+ const py = finite('p.y', p?.y);
135
+ const r = dimension('radius', radius, 3);
136
+ if (r === 0) return '';
137
+ return `M${point(px, py - r)}A${fmt(r)},${fmt(r)} 0 1 1 ${point(px, py + r)}A${fmt(r)},${fmt(
138
+ r,
139
+ )} 0 1 1 ${point(px, py - r)}Z`;
140
+ }
141
+
142
+ /** Pick facing edges from the rects' relative centres. */
143
+ export function autoSides(fromRect, toRect) {
144
+ const fc = anchorPoint(fromRect, 'center');
145
+ const tc = anchorPoint(toRect, 'center');
146
+ const dx = tc.x - fc.x;
147
+ const dy = tc.y - fc.y;
148
+ if (Math.abs(dx) >= Math.abs(dy)) {
149
+ return dx >= 0 ? { from: 'right', to: 'left' } : { from: 'left', to: 'right' };
150
+ }
151
+ return dy >= 0 ? { from: 'bottom', to: 'top' } : { from: 'top', to: 'bottom' };
152
+ }
153
+
154
+ /**
155
+ * Connect two rects. Resolves anchor points (explicit `fromSide`/`toSide`, else
156
+ * auto), builds the path, and returns `{ d, from, to, angle }` so the caller can
157
+ * place an arrowhead/dot at `to` rotated by `angle`.
158
+ */
159
+ /** Angle (radians) at which a `shape` path *arrives* at `to` — straight is the
160
+ * chord; elbow/curve arrive axis-aligned along the dominant axis. Rotate an
161
+ * end marker by this so it points along the path, not the chord. */
162
+ export function endTangentAngle(from, to, shape = 'straight') {
163
+ if (shape === 'straight') return angleBetween(from, to);
164
+ const dx = finite('to.x', to?.x) - finite('from.x', from?.x);
165
+ const dy = finite('to.y', to?.y) - finite('from.y', from?.y);
166
+ if (Math.abs(dx) >= Math.abs(dy)) return dx >= 0 ? 0 : Math.PI;
167
+ return dy >= 0 ? Math.PI / 2 : -Math.PI / 2;
168
+ }
169
+
170
+ export function connectRects(opts = {}) {
171
+ const { fromRect, toRect, shape = 'straight', curvature, mid } = opts;
172
+ // Honor each side override independently; auto-pick whichever is unset.
173
+ const auto = autoSides(fromRect, toRect);
174
+ const sides = { from: opts.fromSide || auto.from, to: opts.toSide || auto.to };
175
+ const from = anchorPoint(fromRect, sides.from);
176
+ const to = anchorPoint(toRect, sides.to);
177
+ const d = connectorPath({ from, to, shape, curvature, mid });
178
+ return { d, from, to, angle: endTangentAngle(from, to, shape) };
179
+ }
@@ -0,0 +1,21 @@
1
+ /* ==========================================================================
2
+ analytical — convenience roll-up of the opt-in analytical-primitive layers.
3
+
4
+ Import this one file instead of the seven leaves when you're building
5
+ analytical / generated-report UI:
6
+
7
+ @import '@ponchia/ui';
8
+ @import '@ponchia/ui/css/analytical.css';
9
+
10
+ Add @ponchia/ui/css/dataviz.css for the chart colour palette (legend swatches
11
+ fall back to the accent without it) and @ponchia/ui/css/report.css for the
12
+ document grammar as needed — those are separate concerns, kept opt-in.
13
+ ========================================================================== */
14
+
15
+ @import url('./annotations.css') layer(bronto);
16
+ @import url('./legend.css') layer(bronto);
17
+ @import url('./marks.css') layer(bronto);
18
+ @import url('./connectors.css') layer(bronto);
19
+ @import url('./spotlight.css') layer(bronto);
20
+ @import url('./crosshair.css') layer(bronto);
21
+ @import url('./selection.css') layer(bronto);
@@ -0,0 +1,292 @@
1
+ /* ==========================================================================
2
+ annotations — opt-in SVG callouts for analytical figures.
3
+
4
+ Bronto-native take on the subject / connector / note grammar: SVG-first,
5
+ no runtime dependency, no authoring handles. Import only beside charts,
6
+ reports, or generated figures that need explicit callouts.
7
+ ========================================================================== */
8
+
9
+ .ui-annotation {
10
+ --annotation-color: var(--accent);
11
+ --annotation-line: var(--line-strong);
12
+ --annotation-note-bg: var(--panel);
13
+ --annotation-subject-fill: color-mix(in srgb, var(--annotation-color) 8%, transparent);
14
+ --annotation-stroke-width: 1.5;
15
+
16
+ color: var(--annotation-color);
17
+ font-family: var(--mono);
18
+ font-size: var(--text-xs);
19
+ overflow: visible;
20
+ }
21
+
22
+ .ui-annotation--muted {
23
+ --annotation-color: var(--text-dim);
24
+ --annotation-line: var(--line);
25
+ }
26
+
27
+ .ui-annotation--accent {
28
+ --annotation-color: var(--accent);
29
+ --annotation-line: var(--line-strong);
30
+ }
31
+
32
+ .ui-annotation--success {
33
+ --annotation-color: var(--success);
34
+ }
35
+
36
+ .ui-annotation--warning {
37
+ --annotation-color: var(--warning);
38
+ }
39
+
40
+ .ui-annotation--danger {
41
+ --annotation-color: var(--danger);
42
+ }
43
+
44
+ .ui-annotation--info {
45
+ --annotation-color: var(--info);
46
+ }
47
+
48
+ .ui-annotation__subject,
49
+ .ui-annotation__connector,
50
+ .ui-annotation__connector-end,
51
+ .ui-annotation__note-line,
52
+ .ui-annotation__badge {
53
+ vector-effect: non-scaling-stroke;
54
+ }
55
+
56
+ .ui-annotation__subject {
57
+ fill: var(--annotation-subject-fill);
58
+ stroke: var(--annotation-color);
59
+ stroke-linejoin: miter;
60
+ stroke-width: var(--annotation-stroke-width);
61
+ }
62
+
63
+ .ui-annotation__connector,
64
+ .ui-annotation__note-line {
65
+ fill: none;
66
+ stroke: var(--annotation-line);
67
+ stroke-linecap: square;
68
+ stroke-linejoin: miter;
69
+ stroke-opacity: 0.86;
70
+ stroke-width: var(--annotation-stroke-width);
71
+ }
72
+
73
+ .ui-annotation__connector-end {
74
+ fill: var(--annotation-line);
75
+ stroke: none;
76
+ }
77
+
78
+ .ui-annotation__note {
79
+ color: var(--text-soft);
80
+ fill: currentColor;
81
+ }
82
+
83
+ .ui-annotation__note > rect {
84
+ fill: var(--annotation-note-bg);
85
+ stroke: var(--line);
86
+ stroke-width: 1;
87
+ vector-effect: non-scaling-stroke;
88
+ }
89
+
90
+ .ui-annotation__title {
91
+ fill: var(--text);
92
+ font-size: var(--text-xs);
93
+ font-weight: 700;
94
+ letter-spacing: 0;
95
+ paint-order: stroke fill;
96
+ stroke: var(--annotation-note-bg);
97
+ stroke-linejoin: round;
98
+ stroke-width: 3;
99
+ text-transform: uppercase;
100
+ }
101
+
102
+ .ui-annotation__label {
103
+ fill: var(--text-soft);
104
+ font-size: var(--text-xs);
105
+ letter-spacing: 0;
106
+ paint-order: stroke fill;
107
+ stroke: var(--annotation-note-bg);
108
+ stroke-linejoin: round;
109
+ stroke-width: 3;
110
+ }
111
+
112
+ .ui-annotation__badge {
113
+ fill: var(--annotation-note-bg);
114
+ stroke: var(--annotation-color);
115
+ stroke-width: var(--annotation-stroke-width);
116
+ }
117
+
118
+ .ui-annotation--label .ui-annotation__subject,
119
+ .ui-annotation--badge .ui-annotation__connector,
120
+ .ui-annotation--badge .ui-annotation__note-line {
121
+ display: none;
122
+ }
123
+
124
+ .ui-annotation--callout .ui-annotation__note-line,
125
+ .ui-annotation--elbow .ui-annotation__note-line,
126
+ .ui-annotation--curve .ui-annotation__note-line {
127
+ stroke: var(--annotation-color);
128
+ }
129
+
130
+ .ui-annotation--elbow .ui-annotation__connector {
131
+ stroke-linejoin: bevel;
132
+ }
133
+
134
+ .ui-annotation--curve .ui-annotation__connector {
135
+ stroke-linecap: round;
136
+ }
137
+
138
+ .ui-annotation--circle .ui-annotation__subject {
139
+ stroke-dasharray: 0.01 4;
140
+ stroke-linecap: round;
141
+ }
142
+
143
+ .ui-annotation--rect .ui-annotation__subject {
144
+ stroke-dasharray: 5 3;
145
+ }
146
+
147
+ .ui-annotation--threshold .ui-annotation__subject {
148
+ fill: none;
149
+ stroke: var(--annotation-color);
150
+ stroke-dasharray: 6 4;
151
+ }
152
+
153
+ .ui-annotation--badge .ui-annotation__subject {
154
+ fill: var(--annotation-color);
155
+ }
156
+
157
+ .ui-annotation--badge .ui-annotation__badge {
158
+ fill: var(--annotation-color);
159
+ }
160
+
161
+ .ui-annotation--badge .ui-annotation__title,
162
+ .ui-annotation--badge .ui-annotation__label {
163
+ fill: var(--button-text);
164
+ stroke: none;
165
+ }
166
+
167
+ .ui-annotation--bracket .ui-annotation__subject,
168
+ .ui-annotation--compare .ui-annotation__subject,
169
+ .ui-annotation--axis .ui-annotation__subject,
170
+ .ui-annotation--timeline .ui-annotation__subject {
171
+ fill: none;
172
+ stroke: var(--annotation-color);
173
+ stroke-linecap: square;
174
+ }
175
+
176
+ .ui-annotation--band .ui-annotation__subject {
177
+ fill: var(--annotation-subject-fill);
178
+ stroke: var(--annotation-color);
179
+ stroke-dasharray: 5 3;
180
+ }
181
+
182
+ .ui-annotation--slope .ui-annotation__subject {
183
+ fill: none;
184
+ stroke: var(--annotation-color);
185
+ stroke-linecap: round;
186
+ }
187
+
188
+ .ui-annotation--cluster .ui-annotation__subject {
189
+ fill: var(--annotation-subject-fill);
190
+ stroke: var(--annotation-color);
191
+ stroke-dasharray: 0.01 5;
192
+ stroke-linecap: round;
193
+ }
194
+
195
+ .ui-annotation--evidence .ui-annotation__badge {
196
+ fill: var(--annotation-note-bg);
197
+ stroke: var(--annotation-color);
198
+ }
199
+
200
+ .ui-annotation--evidence .ui-annotation__title {
201
+ fill: var(--annotation-color);
202
+ stroke: none;
203
+ }
204
+
205
+ .ui-annotation--focus {
206
+ --annotation-stroke-width: 2;
207
+ --annotation-subject-fill: color-mix(in srgb, var(--annotation-color) 14%, transparent);
208
+ }
209
+
210
+ @media (prefers-reduced-motion: no-preference) {
211
+ .ui-annotation--draw .ui-annotation__connector,
212
+ .ui-annotation--draw .ui-annotation__note-line {
213
+ animation: uiAnnotationDraw var(--duration-slow, 600ms) var(--ease-out, ease-out) both;
214
+ animation-delay: var(--annotation-delay, 0ms);
215
+ stroke-dasharray: var(--annotation-dash, 360);
216
+ stroke-dashoffset: var(--annotation-dash, 360);
217
+ }
218
+
219
+ .ui-annotation--draw .ui-annotation__subject,
220
+ .ui-annotation--draw .ui-annotation__badge {
221
+ animation: uiAnnotationSubjectReveal var(--duration-slow, 600ms) var(--ease-out, ease-out) both;
222
+ animation-delay: var(--annotation-delay, 0ms);
223
+ }
224
+
225
+ .ui-annotation--reveal .ui-annotation__note {
226
+ animation: uiAnnotationReveal var(--duration-slow, 600ms) var(--ease-out, ease-out) both;
227
+ animation-delay: var(--annotation-delay, 0ms);
228
+ }
229
+
230
+ .ui-annotation--pulse .ui-annotation__subject,
231
+ .ui-annotation--pulse .ui-annotation__badge {
232
+ animation: uiAnnotationPulse 1.6s var(--ease-out, ease-out) infinite;
233
+ animation-delay: var(--annotation-delay, 0ms);
234
+ transform-box: fill-box;
235
+ transform-origin: center;
236
+ }
237
+ }
238
+
239
+ @keyframes uiAnnotationDraw {
240
+ to {
241
+ stroke-dashoffset: 0;
242
+ }
243
+ }
244
+
245
+ @keyframes uiAnnotationSubjectReveal {
246
+ from {
247
+ opacity: 0;
248
+ }
249
+
250
+ to {
251
+ opacity: 1;
252
+ }
253
+ }
254
+
255
+ @keyframes uiAnnotationReveal {
256
+ from {
257
+ opacity: 0;
258
+ }
259
+
260
+ to {
261
+ opacity: 1;
262
+ }
263
+ }
264
+
265
+ @keyframes uiAnnotationPulse {
266
+ 50% {
267
+ opacity: 0.62;
268
+ transform: scale(1.06);
269
+ }
270
+ }
271
+
272
+ @media print {
273
+ .ui-annotation__subject,
274
+ .ui-annotation__connector,
275
+ .ui-annotation__note,
276
+ .ui-annotation__note-line,
277
+ .ui-annotation__badge {
278
+ animation: none !important;
279
+ opacity: 1;
280
+ stroke-dashoffset: 0;
281
+ transform: none;
282
+ }
283
+ }
284
+
285
+ @media (forced-colors: active) {
286
+ .ui-annotation {
287
+ --annotation-color: CanvasText;
288
+ --annotation-line: CanvasText;
289
+ --annotation-note-bg: Canvas;
290
+ --annotation-subject-fill: Canvas;
291
+ }
292
+ }
@@ -0,0 +1,97 @@
1
+ /* ==========================================================================
2
+ command — opt-in command-palette shell (the command-first tier).
3
+
4
+ A filter input over a listbox of commands, grouped, with shortcut hints. The
5
+ CSS shell only; `initCommand` (behaviors) does the filtering + roving focus +
6
+ selection event. Bronto navigates a DOM-authored list; the HOST owns the
7
+ action registry, routing, and execution. Open it yourself (e.g. inside a
8
+ native <dialog> via initDialog) — there is no global Cmd/Ctrl+K. Pairs with
9
+ the `.ui-shortcut` hint. Not imported by core.css.
10
+ ========================================================================== */
11
+
12
+ .ui-command {
13
+ background: var(--panel-strong);
14
+ border: 1px solid var(--line-strong);
15
+ border-radius: var(--radius-md);
16
+ display: grid;
17
+ grid-template-rows: auto 1fr auto;
18
+ max-block-size: min(28rem, 70vh);
19
+ overflow: hidden;
20
+ }
21
+
22
+ .ui-command__input {
23
+ background: transparent;
24
+ border: 0;
25
+ border-block-end: 1px solid var(--line);
26
+ color: var(--text);
27
+ font-family: inherit;
28
+ font-size: var(--text-base);
29
+ inline-size: 100%;
30
+ padding: 0.85rem 1rem;
31
+ }
32
+
33
+ .ui-command__input::placeholder {
34
+ color: var(--text-dim);
35
+ }
36
+
37
+ .ui-command__list {
38
+ list-style: none;
39
+ margin: 0;
40
+ overflow-y: auto;
41
+ padding: var(--space-2xs);
42
+ }
43
+
44
+ .ui-command__group {
45
+ color: var(--text-dim);
46
+ font-family: var(--mono);
47
+ font-size: var(--text-2xs);
48
+ letter-spacing: var(--tracking-wide);
49
+ padding: 0.5rem 0.6rem 0.25rem;
50
+ text-transform: uppercase;
51
+ }
52
+
53
+ .ui-command__item {
54
+ align-items: center;
55
+ border-radius: var(--radius-sm);
56
+ color: var(--text-soft);
57
+ cursor: pointer;
58
+ display: flex;
59
+ gap: 0.6rem;
60
+ padding: 0.5rem 0.6rem;
61
+ }
62
+
63
+ /* `display: flex` would otherwise beat the UA `[hidden]` rule, so a
64
+ filtered-out item stays visible — re-assert none for hidden items/groups. */
65
+ .ui-command__item[hidden],
66
+ .ui-command__group[hidden] {
67
+ display: none;
68
+ }
69
+
70
+ .ui-command__item.is-active {
71
+ background: color-mix(in srgb, var(--accent) 14%, transparent);
72
+ color: var(--text);
73
+ }
74
+
75
+ .ui-command__shortcut {
76
+ color: var(--text-dim);
77
+ margin-inline-start: auto;
78
+ }
79
+
80
+ .ui-command__meta {
81
+ color: var(--text-dim);
82
+ font-family: var(--mono);
83
+ font-size: var(--text-2xs);
84
+ margin-inline-start: auto;
85
+ }
86
+
87
+ .ui-command__empty {
88
+ color: var(--text-dim);
89
+ padding: 0.85rem 1rem;
90
+ }
91
+
92
+ @media (forced-colors: active) {
93
+ .ui-command__item.is-active {
94
+ background: Highlight;
95
+ color: HighlightText;
96
+ }
97
+ }
@@ -0,0 +1,93 @@
1
+ /* ==========================================================================
2
+ connectors — opt-in leader lines between two DOM elements.
3
+
4
+ An overlay SVG (`.ui-connector`) sits inside a positioned container and draws
5
+ a line from one element to another — connect a note to a card, a card to a
6
+ chart point, two related regions. Bronto styles and (optionally, via
7
+ `initConnectors`) draws/tracks the line; the geometry helpers in
8
+ `@ponchia/ui/connectors` compute the path. Not imported by core.css.
9
+
10
+ Monochrome by default; the rationed accent and status tones are opt-in.
11
+ ========================================================================== */
12
+
13
+ .ui-connector {
14
+ --connector-color: var(--line-strong);
15
+
16
+ color: var(--connector-color);
17
+ inset: 0;
18
+ overflow: visible;
19
+ pointer-events: none;
20
+ position: absolute;
21
+ }
22
+
23
+ .ui-connector__path {
24
+ fill: none;
25
+ stroke: var(--connector-color);
26
+ stroke-linecap: round;
27
+ stroke-linejoin: round;
28
+ stroke-width: var(--connector-width, 1.5);
29
+ vector-effect: non-scaling-stroke;
30
+ }
31
+
32
+ .ui-connector__end {
33
+ fill: var(--connector-color);
34
+ stroke: none;
35
+ }
36
+
37
+ .ui-connector--dashed .ui-connector__path {
38
+ stroke-dasharray: 4 3;
39
+ }
40
+
41
+ .ui-connector--accent {
42
+ --connector-color: var(--accent);
43
+ }
44
+
45
+ .ui-connector--muted {
46
+ --connector-color: var(--line);
47
+ }
48
+
49
+ .ui-connector--success {
50
+ --connector-color: var(--success);
51
+ }
52
+
53
+ .ui-connector--warning {
54
+ --connector-color: var(--warning);
55
+ }
56
+
57
+ .ui-connector--danger {
58
+ --connector-color: var(--danger);
59
+ }
60
+
61
+ .ui-connector--info {
62
+ --connector-color: var(--info);
63
+ }
64
+
65
+ /* Draw-on: the path strokes in once. Requires pathLength="1" on the path
66
+ (initConnectors sets it); reduced motion shows the finished line. */
67
+ @media (prefers-reduced-motion: no-preference) {
68
+ .ui-connector--draw .ui-connector__path {
69
+ animation: ui-connector-draw 0.6s ease both;
70
+ stroke-dasharray: 1;
71
+ }
72
+ }
73
+
74
+ @keyframes ui-connector-draw {
75
+ from {
76
+ stroke-dashoffset: 1;
77
+ }
78
+
79
+ to {
80
+ stroke-dashoffset: 0;
81
+ }
82
+ }
83
+
84
+ /* Forced colours: keep the line visible as a system colour. */
85
+ @media (forced-colors: active) {
86
+ .ui-connector__path {
87
+ stroke: CanvasText;
88
+ }
89
+
90
+ .ui-connector__end {
91
+ fill: CanvasText;
92
+ }
93
+ }