@ponchia/ui 0.13.0 → 0.14.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 +40 -0
- package/README.md +4 -4
- package/behaviors/command.d.ts +34 -13
- package/behaviors/command.d.ts.map +1 -1
- package/behaviors/command.js +195 -129
- package/classes/classes.json +15 -2
- package/classes/index.d.ts +10 -0
- package/classes/index.js +11 -1
- package/css/content.css +34 -1
- package/css/feedback.css +95 -3
- package/css/fonts-inter.css +35 -0
- package/css/fonts-jetbrains-mono.css +49 -0
- package/css/site.css +0 -31
- package/css/tool.css +29 -0
- package/dist/bronto.css +1 -1
- package/dist/css/content.css +1 -1
- package/dist/css/feedback.css +1 -1
- package/dist/css/fonts-inter.css +1 -0
- package/dist/css/fonts-jetbrains-mono.css +1 -0
- package/dist/css/site.css +1 -1
- package/dist/css/tool.css +1 -0
- package/docs/command.md +47 -7
- package/docs/compositions.md +2 -2
- package/docs/package-contract.md +6 -1
- package/docs/reference.md +10 -1
- package/docs/reporting.md +8 -8
- package/docs/stability.md +4 -2
- package/docs/theming.md +8 -1
- package/docs/usage.md +55 -0
- package/fonts/OFL-Inter.txt +92 -0
- package/fonts/OFL-JetBrainsMono.txt +93 -0
- package/fonts/inter-variable-italic.woff2 +0 -0
- package/fonts/inter-variable.woff2 +0 -0
- package/fonts/jetbrains-mono-400-italic.woff2 +0 -0
- package/fonts/jetbrains-mono-400.woff2 +0 -0
- package/fonts/jetbrains-mono-700-italic.woff2 +0 -0
- package/fonts/jetbrains-mono-700.woff2 +0 -0
- package/llms.txt +1 -1
- package/package.json +6 -1
package/classes/index.js
CHANGED
|
@@ -141,6 +141,10 @@ export const cls = Object.freeze({
|
|
|
141
141
|
alertWarning: 'ui-alert--warning',
|
|
142
142
|
alertDanger: 'ui-alert--danger',
|
|
143
143
|
alertInfo: 'ui-alert--info',
|
|
144
|
+
alertBand: 'ui-alert--band',
|
|
145
|
+
bodyState: 'ui-body-state',
|
|
146
|
+
bodyStateError: 'ui-body-state--error',
|
|
147
|
+
bodyStateStale: 'ui-body-state--stale',
|
|
144
148
|
toastStack: 'ui-toast-stack',
|
|
145
149
|
toastStackAssertive: 'ui-toast-stack--assertive',
|
|
146
150
|
toast: 'ui-toast',
|
|
@@ -875,6 +879,11 @@ const dotTone = (tone) =>
|
|
|
875
879
|
tone,
|
|
876
880
|
);
|
|
877
881
|
|
|
882
|
+
// A body state's tone. Empty and loading are the plain state (no option); a
|
|
883
|
+
// loading region says so with aria-busy, not a class.
|
|
884
|
+
const bodyStateTone = (state) =>
|
|
885
|
+
valueClass({ error: cls.bodyStateError, stale: cls.bodyStateStale }, state);
|
|
886
|
+
|
|
878
887
|
const alertTone = (tone) =>
|
|
879
888
|
toneClass(
|
|
880
889
|
'alert',
|
|
@@ -1026,7 +1035,7 @@ export const ui = {
|
|
|
1026
1035
|
hint: ({ error } = {}) => j(cls.hint, error && cls.hintError),
|
|
1027
1036
|
cluster: ({ between } = {}) => j(cls.cluster, between && cls.clusterBetween),
|
|
1028
1037
|
stagger: ({ auto } = {}) => j(cls.stagger, auto && cls.staggerAuto),
|
|
1029
|
-
alert: ({ tone } = {}) => j(cls.alert, alertTone(tone)),
|
|
1038
|
+
alert: ({ tone, band } = {}) => j(cls.alert, alertTone(tone), band && cls.alertBand),
|
|
1030
1039
|
toast: ({ tone } = {}) => j(cls.toast, toastTone(tone)),
|
|
1031
1040
|
progress: ({ indeterminate } = {}) => j(cls.progress, indeterminate && cls.progressIndeterminate),
|
|
1032
1041
|
meter: ({ tone } = {}) => j(cls.meter, meterTone(tone)),
|
|
@@ -1152,6 +1161,7 @@ export const ui = {
|
|
|
1152
1161
|
job: ({ state, compact } = {}) => j(cls.job, jobTone(state), compact && cls.jobCompact),
|
|
1153
1162
|
originLabel: ({ ai } = {}) => j(cls.originLabel, ai && cls.originLabelAi),
|
|
1154
1163
|
emptyState: ({ invite } = {}) => j(cls.emptyState, invite && cls.emptyStateInvite),
|
|
1164
|
+
bodyState: ({ state } = {}) => j(cls.bodyState, bodyStateTone(state)),
|
|
1155
1165
|
toolstrip: ({ variant, anchor } = {}) =>
|
|
1156
1166
|
j(
|
|
1157
1167
|
cls.toolstrip,
|
package/css/content.css
CHANGED
|
@@ -5,9 +5,42 @@
|
|
|
5
5
|
and the document is styled in the Nothing aesthetic while the markup
|
|
6
6
|
stays semantic and machine-readable (no class-soup). Everything here
|
|
7
7
|
is an element selector scoped under `.ui-prose`, so it never leaks
|
|
8
|
-
into app UI.
|
|
8
|
+
into app UI. The one exception is `.ui-meta`, the date · author line
|
|
9
|
+
that sits beside long-form text, a tool's remarks included (it lived in
|
|
10
|
+
site.css until 0.14, so css/tool.css can keep it without the site shell).
|
|
9
11
|
========================================================================== */
|
|
10
12
|
|
|
13
|
+
/* --- Meta row — date · author · read-time, dot-separated --- */
|
|
14
|
+
|
|
15
|
+
.ui-meta {
|
|
16
|
+
align-items: center;
|
|
17
|
+
color: var(--text-dim);
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-wrap: wrap;
|
|
20
|
+
font-family: var(--mono);
|
|
21
|
+
font-size: var(--text-2xs);
|
|
22
|
+
gap: 0.55rem;
|
|
23
|
+
letter-spacing: var(--tracking-wide);
|
|
24
|
+
list-style: none;
|
|
25
|
+
margin: 0;
|
|
26
|
+
padding: 0;
|
|
27
|
+
text-transform: uppercase;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.ui-meta__item {
|
|
31
|
+
align-items: center;
|
|
32
|
+
display: inline-flex;
|
|
33
|
+
gap: 0.55rem;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.ui-meta__item:not(:last-child)::after {
|
|
37
|
+
background: var(--line-strong);
|
|
38
|
+
border-radius: 50%;
|
|
39
|
+
block-size: 0.22rem;
|
|
40
|
+
content: '';
|
|
41
|
+
inline-size: 0.22rem;
|
|
42
|
+
}
|
|
43
|
+
|
|
11
44
|
.ui-prose {
|
|
12
45
|
/* A prose block must shrink as a grid/flex item; its pre blocks scroll locally. */
|
|
13
46
|
min-inline-size: 0;
|
package/css/feedback.css
CHANGED
|
@@ -79,6 +79,8 @@
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
.ui-alert--accent {
|
|
82
|
+
--alert-tone: var(--accent);
|
|
83
|
+
|
|
82
84
|
border-inline-start-color: var(--accent);
|
|
83
85
|
}
|
|
84
86
|
|
|
@@ -87,6 +89,8 @@
|
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
.ui-alert--success {
|
|
92
|
+
--alert-tone: var(--success);
|
|
93
|
+
|
|
90
94
|
border-inline-start-color: var(--success);
|
|
91
95
|
}
|
|
92
96
|
|
|
@@ -95,6 +99,8 @@
|
|
|
95
99
|
}
|
|
96
100
|
|
|
97
101
|
.ui-alert--warning {
|
|
102
|
+
--alert-tone: var(--warning);
|
|
103
|
+
|
|
98
104
|
border-inline-start-color: var(--warning);
|
|
99
105
|
}
|
|
100
106
|
|
|
@@ -103,6 +109,8 @@
|
|
|
103
109
|
}
|
|
104
110
|
|
|
105
111
|
.ui-alert--danger {
|
|
112
|
+
--alert-tone: var(--danger);
|
|
113
|
+
|
|
106
114
|
border-inline-start-color: var(--danger);
|
|
107
115
|
}
|
|
108
116
|
|
|
@@ -111,6 +119,8 @@
|
|
|
111
119
|
}
|
|
112
120
|
|
|
113
121
|
.ui-alert--info {
|
|
122
|
+
--alert-tone: var(--info);
|
|
123
|
+
|
|
114
124
|
border-inline-start-color: var(--info);
|
|
115
125
|
}
|
|
116
126
|
|
|
@@ -118,6 +128,84 @@
|
|
|
118
128
|
background: var(--info);
|
|
119
129
|
}
|
|
120
130
|
|
|
131
|
+
/* --- Band: an alert across the edge of a small surface ---
|
|
132
|
+
A node, panel or card body that must say "this failed" or "this is out of
|
|
133
|
+
date" above content it still shows. Full-bleed, one line of small type, the
|
|
134
|
+
tone as a tint: at 200–400px a boxed alert spends a third of the body on its
|
|
135
|
+
frame. Put it first in the body; the tone modifiers work as on any alert. */
|
|
136
|
+
.ui-alert--band {
|
|
137
|
+
background: color-mix(in oklch, var(--alert-tone, var(--text-dim)) 10%, var(--panel));
|
|
138
|
+
border: 0;
|
|
139
|
+
border-block-end: 1px solid var(--line);
|
|
140
|
+
border-radius: 0;
|
|
141
|
+
font-size: var(--text-2xs);
|
|
142
|
+
gap: var(--space-1-5);
|
|
143
|
+
padding: var(--space-1-5) var(--space-sm);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.ui-alert--band::before {
|
|
147
|
+
block-size: 0.4rem;
|
|
148
|
+
inline-size: 0.4rem;
|
|
149
|
+
margin-block-start: 0.3em;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* --- Body state: what a small surface shows instead of its content ---
|
|
153
|
+
Empty, loading, failed or out of date, for a node, panel or card body of
|
|
154
|
+
200–400px. It fills the body and centres one short sentence (with an
|
|
155
|
+
optional `ui-empty-state__hint` or an action), without the dashed frame a
|
|
156
|
+
page-level `ui-empty-state` draws. Error and stale lead with a tone dot;
|
|
157
|
+
loading takes `aria-busy="true"` on the region and an optional
|
|
158
|
+
`ui-dotspinner` or `ui-skeleton` inside. In a `ui-cq` body narrower than
|
|
159
|
+
15rem the state tightens to the smallest type. */
|
|
160
|
+
.ui-body-state {
|
|
161
|
+
align-items: center;
|
|
162
|
+
box-sizing: border-box;
|
|
163
|
+
color: var(--text-dim);
|
|
164
|
+
display: flex;
|
|
165
|
+
flex: 1 1 auto;
|
|
166
|
+
flex-direction: column;
|
|
167
|
+
font-size: var(--text-xs);
|
|
168
|
+
gap: var(--space-2xs);
|
|
169
|
+
justify-content: center;
|
|
170
|
+
margin: 0;
|
|
171
|
+
min-block-size: 100%;
|
|
172
|
+
padding: var(--space-md);
|
|
173
|
+
text-align: center;
|
|
174
|
+
text-wrap: balance;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.ui-body-state > * {
|
|
178
|
+
margin: 0;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.ui-body-state--error,
|
|
182
|
+
.ui-body-state--stale {
|
|
183
|
+
--body-state-tone: var(--danger);
|
|
184
|
+
|
|
185
|
+
color: var(--text-soft);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.ui-body-state--stale {
|
|
189
|
+
--body-state-tone: var(--warning);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.ui-body-state--error::before,
|
|
193
|
+
.ui-body-state--stale::before {
|
|
194
|
+
background: var(--body-state-tone);
|
|
195
|
+
border-radius: 50%;
|
|
196
|
+
block-size: 0.5rem;
|
|
197
|
+
content: '';
|
|
198
|
+
inline-size: 0.5rem;
|
|
199
|
+
print-color-adjust: exact;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
@container bronto (max-inline-size: 15rem) {
|
|
203
|
+
.ui-body-state {
|
|
204
|
+
font-size: var(--text-2xs);
|
|
205
|
+
padding: var(--space-xs);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
121
209
|
@media (hover: hover) {
|
|
122
210
|
.ui-alert__close:hover {
|
|
123
211
|
color: var(--text);
|
|
@@ -277,7 +365,9 @@
|
|
|
277
365
|
inherited via --tone-glyph so one rule covers both alert and toast. */
|
|
278
366
|
@media (forced-colors: active) {
|
|
279
367
|
.ui-alert::before,
|
|
280
|
-
.ui-toast::before
|
|
368
|
+
.ui-toast::before,
|
|
369
|
+
.ui-body-state--error::before,
|
|
370
|
+
.ui-body-state--stale::before {
|
|
281
371
|
background: none;
|
|
282
372
|
border-radius: 0;
|
|
283
373
|
content: var(--tone-glyph, '\2022'); /* • neutral default */
|
|
@@ -300,12 +390,14 @@
|
|
|
300
390
|
}
|
|
301
391
|
|
|
302
392
|
.ui-alert--warning,
|
|
303
|
-
.ui-toast--warning
|
|
393
|
+
.ui-toast--warning,
|
|
394
|
+
.ui-body-state--stale {
|
|
304
395
|
--tone-glyph: '\0021'; /* ! */
|
|
305
396
|
}
|
|
306
397
|
|
|
307
398
|
.ui-alert--danger,
|
|
308
|
-
.ui-toast--danger
|
|
399
|
+
.ui-toast--danger,
|
|
400
|
+
.ui-body-state--error {
|
|
309
401
|
--tone-glyph: '\2715'; /* ✕ */
|
|
310
402
|
}
|
|
311
403
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
fonts-inter — Inter, the face `--sans` names first.
|
|
3
|
+
|
|
4
|
+
OPT-IN LEAF. Since 0.10 ordinary text is `--sans`, and the stack names
|
|
5
|
+
Inter first, but nothing shipped it: each OS fell through to its own
|
|
6
|
+
system face, so the same screen set differently on every device. Import
|
|
7
|
+
this leaf and Inter is what renders everywhere.
|
|
8
|
+
|
|
9
|
+
@import '@ponchia/ui/css/fonts-inter.css';
|
|
10
|
+
|
|
11
|
+
One variable face per style covers every weight the tokens use (400 to 700,
|
|
12
|
+
and the in-between ones a heading or a readout asks for). A browser
|
|
13
|
+
downloads a face only when text on the page needs it, so the italic costs
|
|
14
|
+
nothing until something is italic.
|
|
15
|
+
|
|
16
|
+
Inter 4.1 (rsms/inter, web/InterVariable*.woff2), unmodified. License: SIL
|
|
17
|
+
OFL 1.1, fonts/OFL-Inter.txt. URLs are relative to this file; a bundler
|
|
18
|
+
rewrites them and emits the files.
|
|
19
|
+
========================================================================== */
|
|
20
|
+
|
|
21
|
+
@font-face {
|
|
22
|
+
font-family: Inter;
|
|
23
|
+
font-style: normal;
|
|
24
|
+
font-weight: 100 900;
|
|
25
|
+
font-display: swap;
|
|
26
|
+
src: url('../fonts/inter-variable.woff2') format('woff2');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@font-face {
|
|
30
|
+
font-family: Inter;
|
|
31
|
+
font-style: italic;
|
|
32
|
+
font-weight: 100 900;
|
|
33
|
+
font-display: swap;
|
|
34
|
+
src: url('../fonts/inter-variable-italic.woff2') format('woff2');
|
|
35
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
fonts-jetbrains-mono — JetBrains Mono, the face `--mono` names first.
|
|
3
|
+
|
|
4
|
+
OPT-IN LEAF. Code, terminals, numbers in tables and readouts are `--mono`,
|
|
5
|
+
and a terminal measures its cells in it, so a fallback monospace changes
|
|
6
|
+
layout as well as looks. Import this leaf and JetBrains Mono is what
|
|
7
|
+
renders everywhere.
|
|
8
|
+
|
|
9
|
+
@import '@ponchia/ui/css/fonts-jetbrains-mono.css';
|
|
10
|
+
|
|
11
|
+
Four faces: regular and bold, upright and italic, the ones terminal output
|
|
12
|
+
uses. A browser downloads a face only when text on the page needs it.
|
|
13
|
+
|
|
14
|
+
JetBrains Mono 2.304 (JetBrains/JetBrainsMono, fonts/webfonts), unmodified.
|
|
15
|
+
License: SIL OFL 1.1, fonts/OFL-JetBrainsMono.txt. URLs are relative to
|
|
16
|
+
this file; a bundler rewrites them and emits the files.
|
|
17
|
+
========================================================================== */
|
|
18
|
+
|
|
19
|
+
@font-face {
|
|
20
|
+
font-family: 'JetBrains Mono';
|
|
21
|
+
font-style: normal;
|
|
22
|
+
font-weight: 400;
|
|
23
|
+
font-display: swap;
|
|
24
|
+
src: url('../fonts/jetbrains-mono-400.woff2') format('woff2');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@font-face {
|
|
28
|
+
font-family: 'JetBrains Mono';
|
|
29
|
+
font-style: normal;
|
|
30
|
+
font-weight: 700;
|
|
31
|
+
font-display: swap;
|
|
32
|
+
src: url('../fonts/jetbrains-mono-700.woff2') format('woff2');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@font-face {
|
|
36
|
+
font-family: 'JetBrains Mono';
|
|
37
|
+
font-style: italic;
|
|
38
|
+
font-weight: 400;
|
|
39
|
+
font-display: swap;
|
|
40
|
+
src: url('../fonts/jetbrains-mono-400-italic.woff2') format('woff2');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@font-face {
|
|
44
|
+
font-family: 'JetBrains Mono';
|
|
45
|
+
font-style: italic;
|
|
46
|
+
font-weight: 700;
|
|
47
|
+
font-display: swap;
|
|
48
|
+
src: url('../fonts/jetbrains-mono-700-italic.woff2') format('woff2');
|
|
49
|
+
}
|
package/css/site.css
CHANGED
|
@@ -340,34 +340,3 @@
|
|
|
340
340
|
border-color: color-mix(in srgb, var(--accent) 42%, var(--line));
|
|
341
341
|
color: var(--text-soft);
|
|
342
342
|
}
|
|
343
|
-
|
|
344
|
-
/* --- Meta row — date · author · read-time, dot-separated --- */
|
|
345
|
-
|
|
346
|
-
.ui-meta {
|
|
347
|
-
align-items: center;
|
|
348
|
-
color: var(--text-dim);
|
|
349
|
-
display: flex;
|
|
350
|
-
flex-wrap: wrap;
|
|
351
|
-
font-family: var(--mono);
|
|
352
|
-
font-size: var(--text-2xs);
|
|
353
|
-
gap: 0.55rem;
|
|
354
|
-
letter-spacing: var(--tracking-wide);
|
|
355
|
-
list-style: none;
|
|
356
|
-
margin: 0;
|
|
357
|
-
padding: 0;
|
|
358
|
-
text-transform: uppercase;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
.ui-meta__item {
|
|
362
|
-
align-items: center;
|
|
363
|
-
display: inline-flex;
|
|
364
|
-
gap: 0.55rem;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
.ui-meta__item:not(:last-child)::after {
|
|
368
|
-
background: var(--line-strong);
|
|
369
|
-
border-radius: 50%;
|
|
370
|
-
block-size: 0.22rem;
|
|
371
|
-
content: '';
|
|
372
|
-
inline-size: 0.22rem;
|
|
373
|
-
}
|
package/css/tool.css
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
tool — the default bundle for a tool, without site and app chrome.
|
|
3
|
+
|
|
4
|
+
Import it INSTEAD of the default bundle, not after it:
|
|
5
|
+
|
|
6
|
+
@import '@ponchia/ui/css/tool.css';
|
|
7
|
+
|
|
8
|
+
Everything in the default bundle except four leaves a tool on its own
|
|
9
|
+
canvas never renders: navigation (the theme toggle), site (the
|
|
10
|
+
marketing/content shell), table (data tables) and app (the admin service
|
|
11
|
+
shell). Tokens, fonts, base, motion, the dot-matrix and glyph primitives,
|
|
12
|
+
content, primitives, rows, forms, feedback, overlay and disclosure stay, in
|
|
13
|
+
the default bundle's cascade order. Need one of the four after all? Import
|
|
14
|
+
its leaf as well (`@ponchia/ui/css/table.css`).
|
|
15
|
+
========================================================================== */
|
|
16
|
+
@layer bronto;
|
|
17
|
+
|
|
18
|
+
@import url('./tokens.css') layer(bronto);
|
|
19
|
+
@import url('./fonts.css') layer(bronto);
|
|
20
|
+
@import url('./base.css') layer(bronto);
|
|
21
|
+
@import url('./motion.css') layer(bronto);
|
|
22
|
+
@import url('./dots.css') layer(bronto);
|
|
23
|
+
@import url('./content.css') layer(bronto);
|
|
24
|
+
@import url('./primitives.css') layer(bronto);
|
|
25
|
+
@import url('./row.css') layer(bronto);
|
|
26
|
+
@import url('./forms.css') layer(bronto);
|
|
27
|
+
@import url('./feedback.css') layer(bronto);
|
|
28
|
+
@import url('./overlay.css') layer(bronto);
|
|
29
|
+
@import url('./disclosure.css') layer(bronto);
|