@ponchia/ui 0.6.8 → 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 +79 -4
- package/README.md +2 -2
- package/annotations/index.d.ts.map +1 -1
- package/annotations/index.js +5 -6
- package/behaviors/carousel.d.ts.map +1 -1
- package/behaviors/carousel.js +100 -60
- package/behaviors/combobox.d.ts.map +1 -1
- package/behaviors/combobox.js +167 -113
- package/behaviors/connectors.d.ts.map +1 -1
- package/behaviors/connectors.js +39 -23
- package/behaviors/forms.d.ts.map +1 -1
- package/behaviors/forms.js +211 -207
- package/behaviors/glyph.d.ts.map +1 -1
- package/behaviors/glyph.js +157 -132
- package/behaviors/inert.d.ts +1 -1
- package/behaviors/inert.d.ts.map +1 -1
- package/behaviors/inert.js +1 -1
- package/behaviors/internal.js +2 -2
- package/behaviors/modal.js +1 -1
- package/behaviors/popover.js +5 -5
- package/behaviors/table.d.ts +1 -1
- package/behaviors/table.d.ts.map +1 -1
- package/behaviors/table.js +7 -8
- package/behaviors/tabs.js +2 -2
- package/behaviors/toast.js +5 -5
- package/classes/classes.json +33 -2
- package/classes/index.d.ts +10 -0
- package/classes/index.js +59 -35
- package/connectors/index.d.ts +2 -2
- package/connectors/index.d.ts.map +1 -1
- package/connectors/index.js +7 -10
- package/css/app.css +3 -4
- package/css/base.css +1 -1
- package/css/content.css +3 -3
- package/css/disclosure.css +3 -3
- package/css/dots.css +4 -4
- package/css/feedback.css +6 -7
- package/css/forms.css +9 -12
- package/css/legend.css +1 -1
- package/css/marks.css +1 -1
- package/css/motion.css +6 -6
- package/css/overlay.css +5 -7
- package/css/primitives.css +14 -16
- package/css/sidenote.css +2 -2
- package/css/table.css +2 -2
- package/css/workbench.css +128 -0
- package/dist/css/workbench.css +1 -1
- package/docs/annotations.md +36 -0
- package/docs/architecture.md +28 -0
- package/docs/interop/react-flow.md +89 -0
- package/docs/package-contract.md +2 -0
- package/docs/reference.md +21 -1
- package/docs/reporting.md +8 -8
- package/docs/stability.md +67 -7
- package/docs/workbench.md +56 -9
- package/glyphs/glyphs.js +43 -33
- package/llms.txt +10 -4
- package/package.json +5 -2
- package/schemas/report-claims.v1.schema.json +1 -1
- package/tokens/index.js +2 -2
package/classes/index.js
CHANGED
|
@@ -212,7 +212,7 @@ export const cls = Object.freeze({
|
|
|
212
212
|
tableLined: 'ui-table--lined',
|
|
213
213
|
tableBreakAnywhere: 'ui-table--break-anywhere',
|
|
214
214
|
tableWrap: 'ui-table-wrap',
|
|
215
|
-
// Loading state goes on the
|
|
215
|
+
// Loading state goes on the wrap, so the modifier is named for the wrap.
|
|
216
216
|
tableLoading: 'ui-table-wrap--loading',
|
|
217
217
|
tableEmpty: 'ui-table__empty',
|
|
218
218
|
tableSort: 'ui-table__sort',
|
|
@@ -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',
|
|
@@ -739,14 +749,14 @@ const srcTone = (state) =>
|
|
|
739
749
|
})[state] || '';
|
|
740
750
|
|
|
741
751
|
// Component tone → modifier class. Same object-literal idiom as srcTone/stateTone
|
|
742
|
-
//
|
|
752
|
+
// while keeping modifier classes grep-friendly.
|
|
743
753
|
//
|
|
744
754
|
// The set differs PER COMPONENT on purpose — `muted` is a badge/num tone, not an
|
|
745
755
|
// alert/toast/meter/dot one — so a caller extrapolating a universal tone (e.g.
|
|
746
756
|
// `ui.alert({ tone: 'muted' })`) used to get a silent no-op: a bare, untoned
|
|
747
757
|
// element with no signal that the tone was dropped. Warn at dev time instead, so
|
|
748
758
|
// that "validates-but-no-ops" trap is loud rather than invisible. An omitted tone
|
|
749
|
-
// is fine
|
|
759
|
+
// is fine and returns no modifier.
|
|
750
760
|
const toneClass = (component, map, tone) => {
|
|
751
761
|
if (tone == null) return '';
|
|
752
762
|
const hit = map[tone];
|
|
@@ -852,6 +862,43 @@ const claimStatus = (status) =>
|
|
|
852
862
|
status,
|
|
853
863
|
);
|
|
854
864
|
|
|
865
|
+
const valueClass = (map, value) => (value == null ? '' : map[value] || '');
|
|
866
|
+
|
|
867
|
+
const annotationVariants = Object.freeze({
|
|
868
|
+
label: cls.annotationLabelVariant,
|
|
869
|
+
callout: cls.annotationCallout,
|
|
870
|
+
elbow: cls.annotationElbow,
|
|
871
|
+
curve: cls.annotationCurve,
|
|
872
|
+
circle: cls.annotationCircle,
|
|
873
|
+
rect: cls.annotationRect,
|
|
874
|
+
threshold: cls.annotationThreshold,
|
|
875
|
+
badge: cls.annotationBadgeVariant,
|
|
876
|
+
bracket: cls.annotationBracket,
|
|
877
|
+
band: cls.annotationBand,
|
|
878
|
+
slope: cls.annotationSlope,
|
|
879
|
+
compare: cls.annotationCompare,
|
|
880
|
+
cluster: cls.annotationCluster,
|
|
881
|
+
axis: cls.annotationAxis,
|
|
882
|
+
timeline: cls.annotationTimeline,
|
|
883
|
+
evidence: cls.annotationEvidence,
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
const annotationTones = Object.freeze({
|
|
887
|
+
accent: cls.annotationAccent,
|
|
888
|
+
muted: cls.annotationMuted,
|
|
889
|
+
success: cls.annotationSuccess,
|
|
890
|
+
warning: cls.annotationWarning,
|
|
891
|
+
danger: cls.annotationDanger,
|
|
892
|
+
info: cls.annotationInfo,
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
const annotationMotions = Object.freeze({
|
|
896
|
+
draw: cls.annotationDraw,
|
|
897
|
+
pulse: cls.annotationPulse,
|
|
898
|
+
reveal: cls.annotationReveal,
|
|
899
|
+
focus: cls.annotationFocus,
|
|
900
|
+
});
|
|
901
|
+
|
|
855
902
|
export const ui = {
|
|
856
903
|
button: ({ variant, icon, size } = {}) =>
|
|
857
904
|
j(
|
|
@@ -927,7 +974,7 @@ export const ui = {
|
|
|
927
974
|
j(
|
|
928
975
|
cls.legendSwatch,
|
|
929
976
|
// Series 1–8 map to ui-legend__swatch--N; the explicit bounds-check keeps a
|
|
930
|
-
// 0/9/non-integer from coining a class the stylesheet never defines.
|
|
977
|
+
// 0/9/non-integer from coining a class the stylesheet never defines.
|
|
931
978
|
Number.isInteger(series) && series >= 1 && series <= 8 && cls[`legendSwatch${series}`],
|
|
932
979
|
shape === 'circle' && cls.legendSwatchCircle,
|
|
933
980
|
shape === 'line' && cls.legendSwatchLine,
|
|
@@ -935,32 +982,9 @@ export const ui = {
|
|
|
935
982
|
annotation: ({ variant = 'callout', tone = 'accent', motion } = {}) =>
|
|
936
983
|
j(
|
|
937
984
|
cls.annotation,
|
|
938
|
-
variant
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
variant === 'curve' && cls.annotationCurve,
|
|
942
|
-
variant === 'circle' && cls.annotationCircle,
|
|
943
|
-
variant === 'rect' && cls.annotationRect,
|
|
944
|
-
variant === 'threshold' && cls.annotationThreshold,
|
|
945
|
-
variant === 'badge' && cls.annotationBadgeVariant,
|
|
946
|
-
variant === 'bracket' && cls.annotationBracket,
|
|
947
|
-
variant === 'band' && cls.annotationBand,
|
|
948
|
-
variant === 'slope' && cls.annotationSlope,
|
|
949
|
-
variant === 'compare' && cls.annotationCompare,
|
|
950
|
-
variant === 'cluster' && cls.annotationCluster,
|
|
951
|
-
variant === 'axis' && cls.annotationAxis,
|
|
952
|
-
variant === 'timeline' && cls.annotationTimeline,
|
|
953
|
-
variant === 'evidence' && cls.annotationEvidence,
|
|
954
|
-
tone === 'accent' && cls.annotationAccent,
|
|
955
|
-
tone === 'muted' && cls.annotationMuted,
|
|
956
|
-
tone === 'success' && cls.annotationSuccess,
|
|
957
|
-
tone === 'warning' && cls.annotationWarning,
|
|
958
|
-
tone === 'danger' && cls.annotationDanger,
|
|
959
|
-
tone === 'info' && cls.annotationInfo,
|
|
960
|
-
motion === 'draw' && cls.annotationDraw,
|
|
961
|
-
motion === 'pulse' && cls.annotationPulse,
|
|
962
|
-
motion === 'reveal' && cls.annotationReveal,
|
|
963
|
-
motion === 'focus' && cls.annotationFocus,
|
|
985
|
+
valueClass(annotationVariants, variant),
|
|
986
|
+
valueClass(annotationTones, tone),
|
|
987
|
+
valueClass(annotationMotions, motion),
|
|
964
988
|
),
|
|
965
989
|
mark: ({ style, tone, motion } = {}) =>
|
|
966
990
|
j(
|
|
@@ -1049,7 +1073,7 @@ export const ui = {
|
|
|
1049
1073
|
// UNITLESS `--value` (0–100) and AT needs role + aria-valuenow/min/max. This sets
|
|
1050
1074
|
// the painted value and its announced value together so they can't drift, and
|
|
1051
1075
|
// normalizes an arbitrary {min,max} to the 0–100 `--value` the CSS expects while
|
|
1052
|
-
// keeping aria-valuenow in the caller's real units.
|
|
1076
|
+
// keeping aria-valuenow in the caller's real units.
|
|
1053
1077
|
// `busyWhenIndeterminate` — a progressbar advertises aria-busy when its value is
|
|
1054
1078
|
// unknown; a meter is never indeterminate so it passes false. (Kept a boolean
|
|
1055
1079
|
// flag rather than testing the role string, so check:recipe-types doesn't read it
|
|
@@ -1064,7 +1088,7 @@ const valueAttrs = (role, value, min, max, busyWhenIndeterminate) => {
|
|
|
1064
1088
|
// advertises aria-busy; a meter has no indeterminate state, so a non-finite
|
|
1065
1089
|
// value there is a caller error we still fail safe on by omitting the
|
|
1066
1090
|
// misleading 0. Pair with `ui.progress({ indeterminate: true })` for the CSS
|
|
1067
|
-
// sweep.
|
|
1091
|
+
// sweep.
|
|
1068
1092
|
if (!Number.isFinite(raw)) {
|
|
1069
1093
|
return busyWhenIndeterminate ? { role, 'aria-busy': 'true' } : { role };
|
|
1070
1094
|
}
|
|
@@ -1086,13 +1110,13 @@ const valueAttrs = (role, value, min, max, busyWhenIndeterminate) => {
|
|
|
1086
1110
|
* </div>
|
|
1087
1111
|
* `value` is in your own units; pass `{ min, max }` (default 0–100) and the
|
|
1088
1112
|
* `--value` width is normalized for you. Call `attrs.progress()` with no value
|
|
1089
|
-
* for an indeterminate bar (omits aria-valuenow, sets aria-busy).
|
|
1113
|
+
* for an indeterminate bar (omits aria-valuenow, sets aria-busy).
|
|
1090
1114
|
*
|
|
1091
1115
|
* `attrs.dotbar(value)` is the segmented analogue of `attrs.progress`: a
|
|
1092
1116
|
* determinate `.ui-dotbar` carries the same progress data as `.ui-progress` but,
|
|
1093
1117
|
* without this, was eight empty `<span>`s to AT (the segments are decorative —
|
|
1094
1118
|
* mark them `aria-hidden`). Same progressbar role + aria-valuenow/min/max;
|
|
1095
|
-
* call with no value for the indeterminate sweep.
|
|
1119
|
+
* call with no value for the indeterminate sweep.
|
|
1096
1120
|
*/
|
|
1097
1121
|
export const attrs = Object.freeze({
|
|
1098
1122
|
meter: (value, { min = 0, max = 100 } = {}) => valueAttrs('meter', value, min, max, false),
|
package/connectors/index.d.ts
CHANGED
|
@@ -103,8 +103,8 @@ export function arrowHead(p: Point, angle: number, size?: number, spread?: numbe
|
|
|
103
103
|
export function dotMark(p: Point, radius?: number): string;
|
|
104
104
|
/**
|
|
105
105
|
* An axis-aligned rectangle path from its corners (callers derive the corners
|
|
106
|
-
* from a centre or a top-left as they need). Shared by
|
|
107
|
-
*
|
|
106
|
+
* from a centre or a top-left as they need). Shared by annotation rect/band
|
|
107
|
+
* and evidence-marker subjects.
|
|
108
108
|
* @param {number} left
|
|
109
109
|
* @param {number} top
|
|
110
110
|
* @param {number} right
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.js"],"names":[],"mappings":"AAiDA;;;;;;GAMG;AACH,6BALW,MAAM,SACN,MAAM,GAAG,IAAI,GAAG,SAAS,aACzB,MAAM,GAAG,IAAI,GAAG,SAAS,GACvB,MAAM,CAMlB;AAED;;;;;;GAMG;AACH,gCALW,MAAM,SACN,MAAM,GAAG,IAAI,GAAG,SAAS,aACzB,MAAM,GAAG,IAAI,GAAG,SAAS,GACvB,MAAM,CAMlB;AAID;;;GAGG;AACH,mCAHW,MAAM,GACJ,MAAM,CAKlB;AAED;;;GAGG;AACH,2BAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;GAIG;AACH,yBAJW,MAAM,KACN,MAAM,GACJ,MAAM,CAIlB;AAGD;;;;;GAKG;AACH,6BALW,MAAM,OACN,MAAM,OACN,MAAM,GACJ,MAAM,CAKlB;AAqBD;;;;;GAKG;AACH,kCAJW,IAAI,SACJ,IAAI,GACF,KAAK,CAoBjB;AAED;;;;;GAKG;AACH,mCAJW,KAAK,MACL,KAAK,GACH,MAAM,CAOlB;AAED;;;;;GAKG;AACH,mCAJW,KAAK,MACL,KAAK,GACH,MAAM,CAOlB;AAED;;;;;;GAMG;AACH,gCALW,KAAK,MACL,KAAK,SACL;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACd,MAAM,CAgBlB;AAED;;;;;;GAMG;AACH,gCALW,KAAK,MACL,KAAK,SACL;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACpB,MAAM,CAclB;AAED;;;;GAIG;AACH,qCAHW,oBAAoB,GAClB,MAAM,CAQlB;AAED;;;;;;;;GAQG;AACH,6BAPW,KAAK,SACL,MAAM,SACN,MAAM,WACN,MAAM,GAEJ,MAAM,CAalB;AAED;;;;;GAKG;AACH,2BAJW,KAAK,WACL,MAAM,GACJ,MAAM,CAUlB;AAED;;;;;;;;;GASG;AACH,+BANW,MAAM,OACN,MAAM,SACN,MAAM,UACN,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;GAKG;AACH,oCAJW,IAAI,UACJ,IAAI,GACF;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,IAAI,CAAA;CAAE,CAWpC;AAED;;;;;;;;GAQG;AACH,sCALW,KAAK,MACL,KAAK,UACL,cAAc,GACZ,MAAM,CASlB;AAED;;;;;;GAMG;AACH,oCAHW,mBAAmB,GACjB,kBAAkB,CAe9B;AA9VD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAKH,wBAAyB,IAAI,CAAC;oBA/BjB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE;mBACxB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;mBACvD,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ;6BAC9C,UAAU,GAAG,OAAO,GAAG,OAAO;;UAG7B,KAAK;QACL,KAAK;;;;;;;;;;;;cAML,IAAI;YACJ,IAAI;;;;;;;;;;;;;;OAQJ,MAAM;UACN,KAAK;QACL,KAAK;;;;WACL,MAAM"}
|
package/connectors/index.js
CHANGED
|
@@ -43,9 +43,8 @@
|
|
|
43
43
|
*/
|
|
44
44
|
|
|
45
45
|
// Shared scalar/geometry primitives. Exported so the annotations layer composes
|
|
46
|
-
// on the
|
|
47
|
-
//
|
|
48
|
-
// builders below.
|
|
46
|
+
// on the same kernel as the connector path builders. Low-level helpers; the
|
|
47
|
+
// documented API is the path builders below.
|
|
49
48
|
export const PRECISION = 1000;
|
|
50
49
|
|
|
51
50
|
/**
|
|
@@ -74,9 +73,8 @@ export function dimension(name, value, fallback) {
|
|
|
74
73
|
return v;
|
|
75
74
|
}
|
|
76
75
|
|
|
77
|
-
// Round to PRECISION, normalising -0 → 0, and return the NUMBER
|
|
78
|
-
//
|
|
79
|
-
// coordinates it echoes back to the host. (code-quality audit Q5.)
|
|
76
|
+
// Round to PRECISION, normalising -0 → 0, and return the NUMBER. `fmt`
|
|
77
|
+
// stringifies the numeric core; annotations use the same rounded coordinates.
|
|
80
78
|
/**
|
|
81
79
|
* @param {number} value
|
|
82
80
|
* @returns {number}
|
|
@@ -103,8 +101,7 @@ export function point(x, y) {
|
|
|
103
101
|
return `${fmt(x)},${fmt(y)}`;
|
|
104
102
|
}
|
|
105
103
|
|
|
106
|
-
// Guarded form
|
|
107
|
-
// connectors only ever calls clamp(v, 0, 1) so this is output-identical here.
|
|
104
|
+
// Guarded form: an inverted range resolves to `min`.
|
|
108
105
|
/**
|
|
109
106
|
* @param {number} value
|
|
110
107
|
* @param {number} min
|
|
@@ -284,8 +281,8 @@ export function dotMark(p, radius = 3) {
|
|
|
284
281
|
|
|
285
282
|
/**
|
|
286
283
|
* An axis-aligned rectangle path from its corners (callers derive the corners
|
|
287
|
-
* from a centre or a top-left as they need). Shared by
|
|
288
|
-
*
|
|
284
|
+
* from a centre or a top-left as they need). Shared by annotation rect/band
|
|
285
|
+
* and evidence-marker subjects.
|
|
289
286
|
* @param {number} left
|
|
290
287
|
* @param {number} top
|
|
291
288
|
* @param {number} right
|
package/css/app.css
CHANGED
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
near-imperceptible tint/dot opacity delta survives, and current-page becomes
|
|
124
124
|
invisible to HCM users. Re-assert "current" on channels HCM preserves: a
|
|
125
125
|
Highlight start-border and marker dot, plus a NON-colour bold weight so the
|
|
126
|
-
cue does not rely on colour alone (WCAG 1.4.1).
|
|
126
|
+
cue does not rely on colour alone (WCAG 1.4.1). */
|
|
127
127
|
@media (forced-colors: active) {
|
|
128
128
|
.ui-app-nav a.is-active,
|
|
129
129
|
.ui-app-nav a[aria-current]:not([aria-current='false']) {
|
|
@@ -276,7 +276,7 @@
|
|
|
276
276
|
/* The shell keeps `min-block-size: 100dvh`, so with two auto rows the default
|
|
277
277
|
`align-content: stretch` distributes the leftover viewport across BOTH
|
|
278
278
|
tracks — ballooning the horizontal rail to ~half the screen. Pin tracks to
|
|
279
|
-
their content and let the content row absorb the slack.
|
|
279
|
+
their content and let the content row absorb the slack. */
|
|
280
280
|
align-content: start;
|
|
281
281
|
grid-template-rows: auto 1fr;
|
|
282
282
|
}
|
|
@@ -296,8 +296,7 @@
|
|
|
296
296
|
|
|
297
297
|
/* The rail is flex-row here, so the base `margin-block-start: auto` (which
|
|
298
298
|
pushed account to the bottom in the column layout) is inert and account can
|
|
299
|
-
scroll off. Push it to the inline end instead so sign-out stays reachable.
|
|
300
|
-
(layout review C21.) */
|
|
299
|
+
scroll off. Push it to the inline end instead so sign-out stays reachable. */
|
|
301
300
|
.ui-app-rail__account {
|
|
302
301
|
margin-block-start: 0;
|
|
303
302
|
margin-inline-start: auto;
|
package/css/base.css
CHANGED
|
@@ -230,7 +230,7 @@ textarea:focus-visible,
|
|
|
230
230
|
/* NB: the active-tab forced-colors re-assert lives in disclosure.css, right
|
|
231
231
|
after the `.ui-tab.is-active` default — placing it here (an earlier bundle
|
|
232
232
|
leaf) let the later default win even in forced-colors mode, since @media
|
|
233
|
-
adds no specificity.
|
|
233
|
+
adds no specificity. */
|
|
234
234
|
|
|
235
235
|
/* Keyboard focus must never depend on a colour that gets overridden. */
|
|
236
236
|
a:focus-visible,
|
package/css/content.css
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
/* Machine-generated Markdown carries long unbreakable tokens (URLs, hashes,
|
|
17
17
|
code) that otherwise force horizontal page scroll on the prose surface
|
|
18
|
-
itself. Break them
|
|
18
|
+
itself. Break them; table cells already do this locally. */
|
|
19
19
|
overflow-wrap: break-word;
|
|
20
20
|
|
|
21
21
|
/* Readable measure; the container can still be wider for tables/media. */
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
is the opt-in marks leaf (marks.css) and must win: this rule is higher-specificity
|
|
109
109
|
(0,1,1) than `.ui-mark` (0,1,0) and sits in the same `bronto` layer, so without the
|
|
110
110
|
`:not(.ui-mark)` it silently overrides every `.ui-mark` tone/draw modifier in prose —
|
|
111
|
-
the most-documented mark usage.
|
|
111
|
+
the most-documented mark usage. */
|
|
112
112
|
.ui-prose mark:not(.ui-mark) {
|
|
113
113
|
background: var(--accent-soft);
|
|
114
114
|
color: var(--text);
|
|
@@ -255,7 +255,7 @@
|
|
|
255
255
|
because `.ui-prose` is generated prose, not a data grid — but for a table whose
|
|
256
256
|
semantics MUST survive on WebKit, author the `.ui-table` component inside a
|
|
257
257
|
`.ui-table-wrap` instead (the wrap scrolls, the <table> keeps `display: table`),
|
|
258
|
-
or add `role="table"` to the markdown output.
|
|
258
|
+
or add `role="table"` to the markdown output. */
|
|
259
259
|
|
|
260
260
|
.ui-prose table {
|
|
261
261
|
border: 1px solid var(--line);
|
package/css/disclosure.css
CHANGED
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
|
|
60
60
|
/* Forced-colors re-assert MUST sit after the default above (same specificity,
|
|
61
61
|
@media adds none) or the accent default wins and the selected tab loses its
|
|
62
|
-
only cue. Moved here from base.css, an earlier bundle leaf.
|
|
62
|
+
only cue. Moved here from base.css, an earlier bundle leaf. */
|
|
63
63
|
@media (forced-colors: active) {
|
|
64
64
|
.ui-tab.is-active {
|
|
65
65
|
border-block-end-color: Highlight;
|
|
@@ -306,7 +306,7 @@
|
|
|
306
306
|
/* Active page keys on BOTH `.is-active` and `[aria-current]` — usage.md calls
|
|
307
307
|
aria-current "the framework rule", and every nav sibling (breadcrumb, sitenav,
|
|
308
308
|
app-nav) highlights on it, so a pagination author who sets only aria-current
|
|
309
|
-
must still get the highlight.
|
|
309
|
+
must still get the highlight. */
|
|
310
310
|
.ui-pagination__item.is-active,
|
|
311
311
|
.ui-pagination__item[aria-current]:not([aria-current='false']) {
|
|
312
312
|
border-color: var(--accent);
|
|
@@ -319,7 +319,7 @@
|
|
|
319
319
|
(CSS can't intercept keys). For a fully-inert control prefer native
|
|
320
320
|
`<button disabled>`, run `initDisabledGuard()` (intercepts Enter/Space), or
|
|
321
321
|
pair aria-disabled with `tabindex="-1"`. See docs/usage.md "Disabled vs
|
|
322
|
-
aria-disabled".
|
|
322
|
+
aria-disabled". */
|
|
323
323
|
.ui-pagination__item[aria-disabled='true'],
|
|
324
324
|
.ui-pagination__item:disabled {
|
|
325
325
|
cursor: not-allowed;
|
package/css/dots.css
CHANGED
|
@@ -283,7 +283,7 @@
|
|
|
283
283
|
|
|
284
284
|
/* The comet expects exactly 8 `<i>`; a 9th+ child has no rotation rule and
|
|
285
285
|
would pile up dead-centre. Hide the overflow so extra children fail safe
|
|
286
|
-
rather than rendering a stray static dot
|
|
286
|
+
rather than rendering a stray static dot. */
|
|
287
287
|
.ui-dotspinner i:nth-child(n + 9) {
|
|
288
288
|
display: none;
|
|
289
289
|
}
|
|
@@ -523,7 +523,7 @@
|
|
|
523
523
|
clipped from-state on `scripting: enabled`: with JS off, `.is-in` is never
|
|
524
524
|
toggled, so without the gate the content stays permanently clipped away and
|
|
525
525
|
invisible to every no-JS/static/print reader. Same graceful default as
|
|
526
|
-
`.ui-reveal`.
|
|
526
|
+
`.ui-reveal`. */
|
|
527
527
|
@media (scripting: enabled) {
|
|
528
528
|
.ui-matrix {
|
|
529
529
|
clip-path: inset(0 100% 0 0);
|
|
@@ -583,7 +583,7 @@
|
|
|
583
583
|
|
|
584
584
|
/* Brand/live dots aren't status tones, but they still encode meaning via
|
|
585
585
|
background-color alone, which HCM flattens. Keep them on a distinct,
|
|
586
|
-
opted-out system colour for completeness.
|
|
586
|
+
opted-out system colour for completeness. */
|
|
587
587
|
.ui-dot--accent,
|
|
588
588
|
.ui-dot--live {
|
|
589
589
|
forced-color-adjust: none;
|
|
@@ -599,7 +599,7 @@
|
|
|
599
599
|
glyph vanishes (white-on-white) — yet .ui-icon is the recommended
|
|
600
600
|
icon-at-scale path AND backs .ui-legend__symbol, and the print block
|
|
601
601
|
already special-cases it. Opt out and pin the fill to the system text
|
|
602
|
-
colour so the glyph stays visible.
|
|
602
|
+
colour so the glyph stays visible. */
|
|
603
603
|
.ui-icon {
|
|
604
604
|
forced-color-adjust: none;
|
|
605
605
|
background: CanvasText;
|
package/css/feedback.css
CHANGED
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
a stray `--value: 50%` is invalid against the typed syntax and falls back to
|
|
10
10
|
the initial `0` (empty bar) instead of poisoning the `clamp()` and painting a
|
|
11
11
|
FULL bar (the old failure mode). It inherits so the value set on the host
|
|
12
|
-
`.ui-meter` / `.ui-progress` cascades to the inner `__fill`/`__bar`.
|
|
13
|
-
(component audit C8.) */
|
|
12
|
+
`.ui-meter` / `.ui-progress` cascades to the inner `__fill`/`__bar`. */
|
|
14
13
|
@property --value {
|
|
15
14
|
syntax: '<number>';
|
|
16
15
|
inherits: true;
|
|
@@ -442,7 +441,7 @@
|
|
|
442
441
|
/* A still, solid, full-width bar reads as "100% complete" — the opposite of
|
|
443
442
|
indeterminate. Fall back to a static diagonal hatch that fills the track
|
|
444
443
|
(so it's clearly active) but doesn't read as done. AT is covered via
|
|
445
|
-
aria-busy.
|
|
444
|
+
aria-busy. */
|
|
446
445
|
background: repeating-linear-gradient(
|
|
447
446
|
-45deg,
|
|
448
447
|
var(--accent) 0,
|
|
@@ -466,7 +465,7 @@
|
|
|
466
465
|
Drive the fill with the same --value knob as progress; tone the fill by
|
|
467
466
|
threshold. Author role="meter" + aria-valuenow/min/max for AT — but role=meter
|
|
468
467
|
has uneven AT support, so keep the visible .ui-meter__label/__value (they are
|
|
469
|
-
the real channel, not just decoration).
|
|
468
|
+
the real channel, not just decoration). --- */
|
|
470
469
|
|
|
471
470
|
.ui-meter {
|
|
472
471
|
background: var(--panel-soft);
|
|
@@ -537,7 +536,7 @@
|
|
|
537
536
|
/* Prefer the natural one-line width, but never wider than the container: a
|
|
538
537
|
long step label at `max-content` couldn't shrink and overflowed the page on
|
|
539
538
|
narrow viewports (tabs scroll; steps didn't). Capping at 100% lets an
|
|
540
|
-
over-long label wrap instead of overflowing.
|
|
539
|
+
over-long label wrap instead of overflowing. */
|
|
541
540
|
min-inline-size: min(100%, max-content);
|
|
542
541
|
text-transform: uppercase;
|
|
543
542
|
}
|
|
@@ -597,10 +596,10 @@
|
|
|
597
596
|
/* Forced-colors flattens the fill's tone to the system palette and can erase it
|
|
598
597
|
against the track, dropping the only visual cue of the measured proportion.
|
|
599
598
|
Re-assert a system colour so the bar stays visible; the tone's *semantic* is
|
|
600
|
-
carried by the author-written label beside it, not the colour.
|
|
599
|
+
carried by the author-written label beside it, not the colour.
|
|
601
600
|
The toned `.ui-meter--TONE .ui-meter__fill` rules are (0,2,0); the bare
|
|
602
601
|
`.ui-meter__fill` reset is only (0,1,0), so it lost — a toned fill stayed
|
|
603
|
-
`var(--TONE)` and was forced to black-on-black
|
|
602
|
+
`var(--TONE)` and was forced to black-on-black. Match the
|
|
604
603
|
tone specificity here (and set `forced-color-adjust: none`) so every meter,
|
|
605
604
|
toned or not, paints `Highlight`, mirroring the `.ui-dot` precedent. */
|
|
606
605
|
@media (forced-colors: active) {
|
package/css/forms.css
CHANGED
|
@@ -79,8 +79,7 @@
|
|
|
79
79
|
|
|
80
80
|
/* Read-only is editable-looking but not editable; give it a distinct, quieter
|
|
81
81
|
cue (muted fill + default cursor) so it doesn't read as a live field. Not
|
|
82
|
-
disabled — value still submits and the field stays focusable/selectable.
|
|
83
|
-
(component audit C28.) */
|
|
82
|
+
disabled — value still submits and the field stays focusable/selectable. */
|
|
84
83
|
.ui-input:read-only:not(:disabled),
|
|
85
84
|
.ui-textarea:read-only:not(:disabled) {
|
|
86
85
|
background: var(--panel-soft);
|
|
@@ -91,7 +90,7 @@
|
|
|
91
90
|
the controls that WRAP a native input (switch/check/segmented) showed no
|
|
92
91
|
disabled cue and their label kept cursor:pointer — a lie. Mirror the cue via
|
|
93
92
|
:has(input:disabled); the native-element controls (range/file) take :disabled
|
|
94
|
-
directly.
|
|
93
|
+
directly. */
|
|
95
94
|
.ui-range:disabled,
|
|
96
95
|
.ui-file:disabled,
|
|
97
96
|
.ui-switch:has(input:disabled),
|
|
@@ -102,7 +101,7 @@
|
|
|
102
101
|
}
|
|
103
102
|
|
|
104
103
|
/* Keep autofilled fields on-theme — the UA's yellow fill otherwise paints over
|
|
105
|
-
the monochrome surface and breaks the contrast story.
|
|
104
|
+
the monochrome surface and breaks the contrast story. */
|
|
106
105
|
.ui-input:autofill,
|
|
107
106
|
.ui-select:autofill,
|
|
108
107
|
.ui-textarea:autofill,
|
|
@@ -121,8 +120,7 @@
|
|
|
121
120
|
/* Wrapper controls (switch / check / segmented) hide their native <input>, so
|
|
122
121
|
the `[aria-invalid]` the validator sets on it paints nothing — a sighted,
|
|
123
122
|
non-AT user couldn't see the error (WCAG 1.4.1). Mirror the invalid cue onto
|
|
124
|
-
the visible surface via :has(), the same way the disabled cue is mirrored.
|
|
125
|
-
(component audit C7.) */
|
|
123
|
+
the visible surface via :has(), the same way the disabled cue is mirrored. */
|
|
126
124
|
.ui-check:has(input[aria-invalid='true']) input {
|
|
127
125
|
outline: 2px solid var(--danger);
|
|
128
126
|
outline-offset: 1px;
|
|
@@ -141,8 +139,7 @@
|
|
|
141
139
|
one and sighted HCM users lose the only error cue (WCAG 1.4.1). The switch got
|
|
142
140
|
a forced-colors block; the error family did not. Re-assert the state on a
|
|
143
141
|
NON-colour channel — a thicker, doubled border — that survives HCM, and prefix
|
|
144
|
-
the error hint with a glyph so the message itself carries the error.
|
|
145
|
-
(component audit C5.) */
|
|
142
|
+
the error hint with a glyph so the message itself carries the error. */
|
|
146
143
|
@media (forced-colors: active) {
|
|
147
144
|
.ui-input[aria-invalid='true'],
|
|
148
145
|
.ui-select[aria-invalid='true'],
|
|
@@ -151,7 +148,7 @@
|
|
|
151
148
|
border-width: 3px;
|
|
152
149
|
}
|
|
153
150
|
|
|
154
|
-
/* Same NON-colour re-assertion for the wrapper controls
|
|
151
|
+
/* Same NON-colour re-assertion for the wrapper controls: a thicker,
|
|
155
152
|
doubled outline/border survives the HCM colour flattening. */
|
|
156
153
|
.ui-check:has(input[aria-invalid='true']) input {
|
|
157
154
|
outline-width: 3px;
|
|
@@ -205,7 +202,7 @@
|
|
|
205
202
|
|
|
206
203
|
.ui-input-group > .ui-input:focus-visible,
|
|
207
204
|
.ui-input-group > .ui-select:focus-visible {
|
|
208
|
-
z-index: 1; /* keep the focus ring above the adjacent addon border
|
|
205
|
+
z-index: 1; /* keep the focus ring above the adjacent addon border */
|
|
209
206
|
}
|
|
210
207
|
|
|
211
208
|
.ui-input-group__addon {
|
|
@@ -213,7 +210,7 @@
|
|
|
213
210
|
background: var(--panel-soft);
|
|
214
211
|
|
|
215
212
|
/* Match the wrapped control's `--line-strong` border so the prefix/suffix seam
|
|
216
|
-
isn't a fainter cap than the field it abuts.
|
|
213
|
+
isn't a fainter cap than the field it abuts. */
|
|
217
214
|
border: 1px solid var(--line-strong);
|
|
218
215
|
color: var(--text-dim);
|
|
219
216
|
display: flex;
|
|
@@ -358,7 +355,7 @@
|
|
|
358
355
|
|
|
359
356
|
/* Keyboard focus ring to match every sibling input (which use a 2px ring); the
|
|
360
357
|
border-colour shift alone read markedly fainter on this one control. Keyed to
|
|
361
|
-
:focus-visible on the inner input so it stays keyboard-only.
|
|
358
|
+
:focus-visible on the inner input so it stays keyboard-only. */
|
|
362
359
|
.ui-search:has(input:focus-visible) {
|
|
363
360
|
outline: 2px solid var(--focus-ring);
|
|
364
361
|
outline-offset: 1px;
|
package/css/legend.css
CHANGED
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
/* Glyph/symbol swatch — fill an `.ui-icon` mask with the series colour. Match the
|
|
94
94
|
__swatch fallback chain exactly (--chart-color → --chart-1 → --accent): without
|
|
95
95
|
the --chart-1 layer, a symbol and a swatch for the SAME series diverge to two
|
|
96
|
-
colours whenever a theme overrides --chart-1.
|
|
96
|
+
colours whenever a theme overrides --chart-1. */
|
|
97
97
|
.ui-legend__symbol {
|
|
98
98
|
block-size: 0.95rem;
|
|
99
99
|
color: var(--chart-color, var(--chart-1, var(--accent)));
|
package/css/marks.css
CHANGED
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
@media (prefers-reduced-motion: no-preference) {
|
|
92
92
|
/* The sweep animates `background-size`, i.e. the highlight FILL — so it is
|
|
93
93
|
inert on the no-fill styles (underline/box/strike). Scope it out rather
|
|
94
|
-
than let `--draw` look applied but do nothing.
|
|
94
|
+
than let `--draw` look applied but do nothing. */
|
|
95
95
|
.ui-mark--draw:not(.ui-mark--underline, .ui-mark--box, .ui-mark--strike) {
|
|
96
96
|
animation: ui-mark-draw 0.6s var(--ease, ease) both;
|
|
97
97
|
}
|
package/css/motion.css
CHANGED
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
scroll far enough to finish its range, so a fade-to-opacity-1 would strand the
|
|
58
58
|
content permanently transparent. Reach full opacity early (35%) and hold it,
|
|
59
59
|
so even a partially-driven reveal is fully legible — only the last few px of
|
|
60
|
-
the rise are left unfinished.
|
|
60
|
+
the rise are left unfinished. */
|
|
61
61
|
@keyframes uiScrollReveal {
|
|
62
62
|
0% {
|
|
63
63
|
opacity: 0;
|
|
@@ -183,7 +183,7 @@
|
|
|
183
183
|
/* Stagger children: set --i on each child (or use nth-child cap). Cap the manual
|
|
184
184
|
--i path at index 6 (360ms) to match the .ui-stagger--auto ceiling — a long
|
|
185
185
|
list with --i:30 would otherwise hold the last child at opacity:0 for 1.8s
|
|
186
|
-
before popping in.
|
|
186
|
+
before popping in. */
|
|
187
187
|
.ui-stagger > * {
|
|
188
188
|
animation: uiRise var(--duration-slow) var(--ease-spring) both;
|
|
189
189
|
animation-delay: calc(min(var(--i, 0), 6) * 60ms);
|
|
@@ -307,7 +307,7 @@
|
|
|
307
307
|
rest to one system colour, so the ring looks uniform with no visible sweep,
|
|
308
308
|
and the scroll-progress bar can vanish into the canvas. Re-assert distinct
|
|
309
309
|
system colours so each keeps a visible channel; AT is already covered via
|
|
310
|
-
aria-busy / role="status" / role="progressbar".
|
|
310
|
+
aria-busy / role="status" / role="progressbar". */
|
|
311
311
|
@media (forced-colors: active) {
|
|
312
312
|
.ui-spinner {
|
|
313
313
|
border-color: CanvasText;
|
|
@@ -321,7 +321,7 @@
|
|
|
321
321
|
/* HCM strips the shimmer gradient, leaving an invisible box where a loading
|
|
322
322
|
placeholder should be. Give it a system-colour border so the skeleton
|
|
323
323
|
still reads as present. Same decorative-loading family as the spinner +
|
|
324
|
-
scroll-progress above.
|
|
324
|
+
scroll-progress above. */
|
|
325
325
|
.ui-skeleton {
|
|
326
326
|
border: 1px solid CanvasText;
|
|
327
327
|
}
|
|
@@ -346,7 +346,7 @@
|
|
|
346
346
|
The range is `entry 0% entry 100%`, NOT the old `cover 40%`: `cover` only
|
|
347
347
|
completes once the element has scrolled most of the way THROUGH the viewport,
|
|
348
348
|
which an element near the document bottom can never do — it froze part-way,
|
|
349
|
-
leaving a conclusion section permanently semi-transparent
|
|
349
|
+
leaving a conclusion section permanently semi-transparent. `entry`
|
|
350
350
|
completes the moment the element is fully in view, which any scroll-to-bottom
|
|
351
351
|
reaches. Paired with the early-opacity uiScrollReveal keyframe, an element
|
|
352
352
|
taller than the viewport is legible even if its range never fully completes. */
|
|
@@ -405,7 +405,7 @@
|
|
|
405
405
|
/* Zero the delay too: `.ui-stagger` children animate `uiRise` with
|
|
406
406
|
`fill-mode: both`, so a non-zero `animation-delay` holds them at the
|
|
407
407
|
`opacity: 0` from-state for the full delay and then pops them in — the
|
|
408
|
-
exact late flash a reduced-motion user asked to avoid
|
|
408
|
+
exact late flash a reduced-motion user asked to avoid. */
|
|
409
409
|
animation-delay: 0s !important;
|
|
410
410
|
transition-duration: 0.01ms !important;
|
|
411
411
|
}
|
package/css/overlay.css
CHANGED
|
@@ -91,7 +91,7 @@ dialog.ui-modal[open]::backdrop {
|
|
|
91
91
|
/* Background scroll-lock. A native <dialog> top layer does NOT stop the page
|
|
92
92
|
behind it scrolling, and the no-JS native path can't lock it in script — so
|
|
93
93
|
lock it in CSS, for both the native [open] dialog and the controlled .is-open
|
|
94
|
-
overlay (incl. the drawer modifier, same base).
|
|
94
|
+
overlay (incl. the drawer modifier, same base). */
|
|
95
95
|
html:has(dialog.ui-modal[open]),
|
|
96
96
|
html:has(.ui-modal.is-open) {
|
|
97
97
|
overflow: hidden;
|
|
@@ -164,8 +164,7 @@ html:has(.ui-modal.is-open) {
|
|
|
164
164
|
/* Comfortable hit target on coarse pointers — this bespoke close button measured
|
|
165
165
|
~26px on touch, below the 2.9rem floor the rest of the button family meets
|
|
166
166
|
(WCAG 2.5.8). Scoped to coarse so the fine-pointer (mouse) rendering, which
|
|
167
|
-
already clears 24×24, is unchanged; centre the glyph in the enlarged box.
|
|
168
|
-
(audit C3.) */
|
|
167
|
+
already clears 24×24, is unchanged; centre the glyph in the enlarged box. */
|
|
169
168
|
@media (pointer: coarse) {
|
|
170
169
|
.ui-modal__close {
|
|
171
170
|
align-items: center;
|
|
@@ -313,7 +312,7 @@ html:has(.ui-modal.is-open) {
|
|
|
313
312
|
/* Menu hover/focus paints var(--bg-accent), which HCM strips, so the hovered row
|
|
314
313
|
is indistinguishable from its siblings (focus keeps the UA ring; hover has no
|
|
315
314
|
such fallback). Re-assert a system Highlight like the combobox/command rows,
|
|
316
|
-
for parity with those sibling surfaces.
|
|
315
|
+
for parity with those sibling surfaces. */
|
|
317
316
|
@media (forced-colors: active) {
|
|
318
317
|
.ui-menu__item:hover,
|
|
319
318
|
.ui-menu__item:focus-visible {
|
|
@@ -384,7 +383,7 @@ html:has(.ui-modal.is-open) {
|
|
|
384
383
|
|
|
385
384
|
/* The active option is tracked by aria-activedescendant — it is NEVER DOM-focused,
|
|
386
385
|
so it gets no UA focus ring under HCM, and its only cue (--bg-accent) is stripped.
|
|
387
|
-
Re-assert a system Highlight like the command palette does.
|
|
386
|
+
Re-assert a system Highlight like the command palette does. */
|
|
388
387
|
@media (forced-colors: active) {
|
|
389
388
|
.ui-combobox__option.is-active,
|
|
390
389
|
.ui-combobox__option[aria-selected='true'] {
|
|
@@ -454,8 +453,7 @@ html:has(.ui-modal.is-open) {
|
|
|
454
453
|
/* Forced-colors drops both `backdrop-filter: blur()` and the `color-mix()`
|
|
455
454
|
scrim, so the dialog/lightbox would float over an undimmed page with no
|
|
456
455
|
separation. Re-assert a translucent scrim with `forced-color-adjust: none`
|
|
457
|
-
so the layering reads in High Contrast, matching the meter/dot precedent
|
|
458
|
-
(C28). */
|
|
456
|
+
so the layering reads in High Contrast, matching the meter/dot precedent. */
|
|
459
457
|
@media (forced-colors: active) {
|
|
460
458
|
.ui-modal::backdrop,
|
|
461
459
|
.ui-lightbox::backdrop {
|