@ponchia/ui 0.4.1 → 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 (105) hide show
  1. package/CHANGELOG.md +230 -8
  2. package/MIGRATIONS.json +92 -0
  3. package/README.md +9 -6
  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 +79 -0
  17. package/behaviors/index.js +18 -1409
  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 +280 -2
  28. package/classes/index.js +313 -2
  29. package/connectors/index.d.ts +71 -0
  30. package/connectors/index.js +179 -0
  31. package/css/analytical.css +21 -0
  32. package/css/annotations.css +292 -0
  33. package/css/command.css +97 -0
  34. package/css/connectors.css +93 -0
  35. package/css/crosshair.css +100 -0
  36. package/css/feedback.css +51 -0
  37. package/css/fonts.css +11 -7
  38. package/css/generated.css +117 -0
  39. package/css/legend.css +268 -0
  40. package/css/marks.css +144 -0
  41. package/css/primitives.css +18 -0
  42. package/css/report.css +12 -31
  43. package/css/selection.css +46 -0
  44. package/css/sources.css +179 -0
  45. package/css/spotlight.css +104 -0
  46. package/css/state.css +121 -0
  47. package/css/tokens.css +25 -37
  48. package/css/workbench.css +83 -0
  49. package/dist/bronto.css +1 -1
  50. package/dist/css/analytical.css +1 -0
  51. package/dist/css/annotations.css +1 -0
  52. package/dist/css/command.css +1 -0
  53. package/dist/css/connectors.css +1 -0
  54. package/dist/css/crosshair.css +1 -0
  55. package/dist/css/feedback.css +1 -1
  56. package/dist/css/fonts.css +1 -1
  57. package/dist/css/generated.css +1 -0
  58. package/dist/css/legend.css +1 -0
  59. package/dist/css/marks.css +1 -0
  60. package/dist/css/primitives.css +1 -1
  61. package/dist/css/report.css +1 -1
  62. package/dist/css/selection.css +1 -0
  63. package/dist/css/sources.css +1 -0
  64. package/dist/css/spotlight.css +1 -0
  65. package/dist/css/state.css +1 -0
  66. package/dist/css/workbench.css +1 -0
  67. package/docs/adr/0003-theme-model.md +7 -4
  68. package/docs/annotations.md +345 -0
  69. package/docs/architecture.md +202 -0
  70. package/docs/command.md +95 -0
  71. package/docs/connectors.md +91 -0
  72. package/docs/crosshair.md +63 -0
  73. package/docs/generated.md +91 -0
  74. package/docs/legends.md +168 -0
  75. package/docs/marks.md +86 -0
  76. package/docs/reference.md +309 -3
  77. package/docs/reporting.md +49 -14
  78. package/docs/selection.md +40 -0
  79. package/docs/sources.md +110 -0
  80. package/docs/spotlight.md +78 -0
  81. package/docs/stability.md +16 -1
  82. package/docs/state.md +85 -0
  83. package/docs/usage.md +22 -0
  84. package/docs/workbench.md +72 -0
  85. package/fonts/doto-400.woff2 +0 -0
  86. package/fonts/doto-500.woff2 +0 -0
  87. package/fonts/doto-600.woff2 +0 -0
  88. package/fonts/doto-700.woff2 +0 -0
  89. package/fonts/doto-800.woff2 +0 -0
  90. package/fonts/doto-900.woff2 +0 -0
  91. package/llms.txt +229 -6
  92. package/package.json +69 -4
  93. package/qwik/index.d.ts +5 -0
  94. package/qwik/index.js +20 -0
  95. package/react/index.d.ts +5 -0
  96. package/react/index.js +10 -0
  97. package/solid/index.d.ts +5 -0
  98. package/solid/index.js +10 -0
  99. package/tokens/index.js +9 -5
  100. package/fonts/doto-400.ttf +0 -0
  101. package/fonts/doto-500.ttf +0 -0
  102. package/fonts/doto-600.ttf +0 -0
  103. package/fonts/doto-700.ttf +0 -0
  104. package/fonts/doto-800.ttf +0 -0
  105. package/fonts/doto-900.ttf +0 -0
@@ -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
+ }
@@ -0,0 +1,100 @@
1
+ /* ==========================================================================
2
+ crosshair — opt-in ruler + readout for reading a value off a plot.
3
+
4
+ A pointer-tracking crosshair (vertical/horizontal rules), axis value badges,
5
+ and a pinned readout chip — the *visual* language of precise reading. Bronto
6
+ draws the rules and (via `initCrosshair`) tracks the pointer, setting
7
+ `--crosshair-x/y` (pixels within the plot) and emitting the pointer position
8
+ as a fraction. It does NOT find the nearest data point or map pixels to data
9
+ — that needs the host's scales. Not imported by core.css.
10
+ ========================================================================== */
11
+
12
+ .ui-crosshair {
13
+ --crosshair-x: 0;
14
+ --crosshair-y: 0;
15
+ --crosshair-color: var(--accent);
16
+
17
+ inset: 0;
18
+ opacity: 0;
19
+ pointer-events: none;
20
+ position: absolute;
21
+ transition: opacity 0.12s ease;
22
+ }
23
+
24
+ .ui-crosshair.is-active {
25
+ opacity: 1;
26
+ }
27
+
28
+ @media (prefers-reduced-motion: reduce) {
29
+ .ui-crosshair {
30
+ transition: none;
31
+ }
32
+ }
33
+
34
+ .ui-crosshair--muted {
35
+ --crosshair-color: var(--line-strong);
36
+ }
37
+
38
+ .ui-crosshair__line {
39
+ background: var(--crosshair-color);
40
+ position: absolute;
41
+ }
42
+
43
+ .ui-crosshair__line--x {
44
+ inline-size: 1px;
45
+ inset-block: 0;
46
+ inset-inline-start: 0;
47
+ transform: translateX(var(--crosshair-x));
48
+ }
49
+
50
+ .ui-crosshair__line--y {
51
+ block-size: 1px;
52
+ inset-block-start: 0;
53
+ inset-inline: 0;
54
+ transform: translateY(var(--crosshair-y));
55
+ }
56
+
57
+ /* An axis value chip (host sets its text + which edge it sits on). On the
58
+ accent fill it uses the tested on-accent text (same as buttons). */
59
+ .ui-crosshair__badge {
60
+ background: var(--crosshair-color);
61
+ border-radius: var(--radius-sm);
62
+ color: var(--button-text);
63
+ font-family: var(--mono);
64
+ font-size: var(--text-2xs);
65
+ padding-block: 0.05rem;
66
+ padding-inline: 0.3rem;
67
+ position: absolute;
68
+ white-space: nowrap;
69
+ }
70
+
71
+ /* The muted crosshair's grey fill can't carry on-accent text — use a neutral chip. */
72
+ .ui-crosshair--muted .ui-crosshair__badge {
73
+ background: var(--panel);
74
+ border: 1px solid var(--line-strong);
75
+ color: var(--text);
76
+ }
77
+
78
+ /* A pinned readout chip — host fills the content; it follows the crosshair. */
79
+ .ui-readout {
80
+ background: var(--panel);
81
+ border: 1px solid var(--line);
82
+ border-radius: var(--radius-sm);
83
+ box-shadow: var(--shadow-raised);
84
+ color: var(--text);
85
+ font-family: var(--mono);
86
+ font-size: var(--text-xs);
87
+ inset-block-start: 0;
88
+ inset-inline-start: 0;
89
+ padding-block: 0.2rem;
90
+ padding-inline: 0.4rem;
91
+ pointer-events: none;
92
+ position: absolute;
93
+ transform: translate(var(--crosshair-x), var(--crosshair-y));
94
+ }
95
+
96
+ @media (forced-colors: active) {
97
+ .ui-crosshair__line {
98
+ background: CanvasText;
99
+ }
100
+ }
package/css/feedback.css CHANGED
@@ -27,6 +27,9 @@
27
27
  block-size: 0.5rem;
28
28
  margin-block-start: 0.32rem;
29
29
  inline-size: 0.5rem;
30
+
31
+ /* Keep the tone dot when printing (matches the legend swatch). */
32
+ print-color-adjust: exact;
30
33
  }
31
34
 
32
35
  .ui-alert > * {
@@ -174,6 +177,9 @@
174
177
  block-size: 0.5rem;
175
178
  margin-block-start: 0.3rem;
176
179
  inline-size: 0.5rem;
180
+
181
+ /* Keep the tone dot when printing (matches the legend swatch). */
182
+ print-color-adjust: exact;
177
183
  }
178
184
 
179
185
  .ui-toast__title {
@@ -230,6 +236,51 @@
230
236
  background: var(--info);
231
237
  }
232
238
 
239
+ /* Forced-colors (Windows HCM): system colours override the rationed tone
240
+ colour on the dot + border, so all tones would collapse to one appearance
241
+ (WCAG 1.4.1 — colour as the sole channel). Carry the tone as a distinct
242
+ glyph instead; rendered as text it survives HCM as CanvasText. The glyph is
243
+ inherited via --tone-glyph so one rule covers both alert and toast. */
244
+ @media (forced-colors: active) {
245
+ .ui-alert::before,
246
+ .ui-toast::before {
247
+ background: none;
248
+ border-radius: 0;
249
+ content: var(--tone-glyph, '\2022'); /* • neutral default */
250
+ block-size: auto;
251
+ inline-size: auto;
252
+ margin-block-start: 0;
253
+ font-family: var(--mono);
254
+ font-weight: 700;
255
+ line-height: 1.1;
256
+ }
257
+
258
+ .ui-alert--accent,
259
+ .ui-toast--accent {
260
+ --tone-glyph: '\25C6'; /* ◆ */
261
+ }
262
+
263
+ .ui-alert--success,
264
+ .ui-toast--success {
265
+ --tone-glyph: '\2713'; /* ✓ */
266
+ }
267
+
268
+ .ui-alert--warning,
269
+ .ui-toast--warning {
270
+ --tone-glyph: '\0021'; /* ! */
271
+ }
272
+
273
+ .ui-alert--danger,
274
+ .ui-toast--danger {
275
+ --tone-glyph: '\2715'; /* ✕ */
276
+ }
277
+
278
+ .ui-alert--info,
279
+ .ui-toast--info {
280
+ --tone-glyph: '\69'; /* i */
281
+ }
282
+ }
283
+
233
284
  /* --- Tooltip — CSS-only, hover/focus, no JS --- */
234
285
 
235
286
  .ui-tooltip {
package/css/fonts.css CHANGED
@@ -2,10 +2,14 @@
2
2
  @ponchia/ui — Doto webfont (dot-matrix display face)
3
3
 
4
4
  URLs are relative to this file. When the package is consumed through a
5
- bundler (Vite/astro/webpack) the `../fonts/*.ttf` references are rewritten
5
+ bundler (Vite/astro/webpack) the `../fonts/*.woff2` references are rewritten
6
6
  and the files emitted automatically. When served statically, ship the
7
7
  package's `fonts/` directory next to `css/` and it resolves as-is.
8
8
 
9
+ Shipped as woff2 only (Brotli-compressed) — ~5.7 kB per weight vs ~137 kB
10
+ uncompressed TTF. woff2 is supported by the whole browser floor (ADR-0002:
11
+ Chrome 125 / Safari 18 / Firefox 129), so no TTF fallback is carried.
12
+
9
13
  This file is optional: it is bundled into core.css/index.css, but a
10
14
  consumer that hosts Doto itself (or overrides `--display` / `--dot-font`)
11
15
  can import the rest of the framework without it.
@@ -16,7 +20,7 @@
16
20
  font-style: normal;
17
21
  font-weight: 400;
18
22
  font-display: swap;
19
- src: url('../fonts/doto-400.ttf') format('truetype');
23
+ src: url('../fonts/doto-400.woff2') format('woff2');
20
24
  }
21
25
 
22
26
  @font-face {
@@ -24,7 +28,7 @@
24
28
  font-style: normal;
25
29
  font-weight: 500;
26
30
  font-display: swap;
27
- src: url('../fonts/doto-500.ttf') format('truetype');
31
+ src: url('../fonts/doto-500.woff2') format('woff2');
28
32
  }
29
33
 
30
34
  @font-face {
@@ -32,7 +36,7 @@
32
36
  font-style: normal;
33
37
  font-weight: 600;
34
38
  font-display: swap;
35
- src: url('../fonts/doto-600.ttf') format('truetype');
39
+ src: url('../fonts/doto-600.woff2') format('woff2');
36
40
  }
37
41
 
38
42
  @font-face {
@@ -40,7 +44,7 @@
40
44
  font-style: normal;
41
45
  font-weight: 700;
42
46
  font-display: swap;
43
- src: url('../fonts/doto-700.ttf') format('truetype');
47
+ src: url('../fonts/doto-700.woff2') format('woff2');
44
48
  }
45
49
 
46
50
  @font-face {
@@ -48,7 +52,7 @@
48
52
  font-style: normal;
49
53
  font-weight: 800;
50
54
  font-display: swap;
51
- src: url('../fonts/doto-800.ttf') format('truetype');
55
+ src: url('../fonts/doto-800.woff2') format('woff2');
52
56
  }
53
57
 
54
58
  @font-face {
@@ -56,7 +60,7 @@
56
60
  font-style: normal;
57
61
  font-weight: 900;
58
62
  font-display: swap;
59
- src: url('../fonts/doto-900.ttf') format('truetype');
63
+ src: url('../fonts/doto-900.woff2') format('woff2');
60
64
  }
61
65
 
62
66
  /* Data-saver: never *use* Doto, so the browser never fetches it. The