@0001-labs/design-system-1 0.3.0 → 0.3.2
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/DS1/0-face/constraint-panel.ts +27 -6
- package/DS1/0-face/constraint-site.ts +3 -2
- package/DS1/0-face/constraints.ts +27 -0
- package/DS1/0-face/define.ts +1 -1
- package/DS1/0-face/fault-lines.ts +159 -0
- package/DS1/0-face/generated/toast-assets.ts +1 -1
- package/DS1/1-root/card.css +2 -2
- package/DS1/1-root/cjk.css +1 -1
- package/DS1/1-root/component-tokens.css +12 -0
- package/DS1/1-root/context.css +1 -1
- package/DS1/1-root/controls.css +8 -8
- package/DS1/1-root/document.css +2 -2
- package/DS1/1-root/empty.css +2 -2
- package/DS1/1-root/figures.css +2 -2
- package/DS1/1-root/fonts/Inter-LICENSE.md +91 -2
- package/DS1/1-root/fonts.css +5 -4
- package/DS1/1-root/footer.css +2 -2
- package/DS1/1-root/header.css +5 -4
- package/DS1/1-root/inter-arrows.css +11 -0
- package/DS1/1-root/notice.css +2 -2
- package/DS1/1-root/one.css +5 -4
- package/DS1/1-root/progress.css +3 -3
- package/DS1/1-root/prose.css +5 -5
- package/DS1/1-root/row.css +1 -1
- package/DS1/1-root/table.css +1 -1
- package/DS1/1-root/text.css +5 -5
- package/DS1/2-core/chart/chart.css +1 -1
- package/DS1/2-core/ds-avatar.ts +47 -8
- package/DS1/2-core/styles/ds-activity.css +1 -1
- package/DS1/2-core/styles/ds-avatar.css +1 -1
- package/DS1/2-core/styles/ds-badge.css +1 -1
- package/DS1/2-core/styles/ds-button-host.css +3 -2
- package/DS1/2-core/styles/ds-button-split.css +1 -1
- package/DS1/2-core/styles/ds-button.css +5 -4
- package/DS1/2-core/styles/ds-composer.css +1 -1
- package/DS1/2-core/styles/ds-image.css +1 -1
- package/DS1/2-core/styles/ds-input.css +3 -3
- package/DS1/2-core/styles/ds-number.css +1 -1
- package/DS1/2-core/styles/ds-radio.css +1 -1
- package/DS1/2-core/styles/ds-tag.css +3 -2
- package/DS1/2-core/styles/ds-text.css +5 -5
- package/DS1/2-core/styles/ds-toast.css +1 -1
- package/DS1/2-core/styles/ds-token.css +1 -1
- package/DS1/2-core/styles/ds-tooltip.css +1 -1
- package/DS1/3-unit/context-trigger.ts +29 -2
- package/DS1/3-unit/ds-form.ts +2 -1
- package/DS1/3-unit/ds-table.ts +2 -1
- package/DS1/3-unit/styles/ds-calendar.css +4 -4
- package/DS1/3-unit/styles/ds-list.css +1 -1
- package/DS1/3-unit/styles/ds-matrix.css +2 -2
- package/DS1/3-unit/styles/ds-menu.css +1 -1
- package/DS1/3-unit/styles/ds-select.css +1 -1
- package/DS1/3-unit/styles/ds-sidebar.css +1 -1
- package/DS1/3-unit/styles/ds-table-of-contents.css +1 -1
- package/DS1/3-unit/styles/ds-token-field.css +1 -1
- package/DS1/4-page/ds-container.ts +2 -1
- package/DS1/4-page/styles/ds-overlay.css +1 -1
- package/DS1/4-page/styles/ds-page.css +1 -1
- package/DS1/4-page/styles/ds-panel.css +1 -1
- package/dist/0-face/constraint-panel.d.ts.map +1 -1
- package/dist/0-face/constraint-panel.js +28 -6
- package/dist/0-face/constraint-site.d.ts +1 -0
- package/dist/0-face/constraint-site.d.ts.map +1 -1
- package/dist/0-face/constraint-site.js +3 -2
- package/dist/0-face/constraints.d.ts.map +1 -1
- package/dist/0-face/constraints.js +27 -0
- package/dist/0-face/define.js +1 -1
- package/dist/0-face/fault-lines.d.ts +20 -0
- package/dist/0-face/fault-lines.d.ts.map +1 -0
- package/dist/0-face/fault-lines.js +172 -0
- package/dist/0-face/generated/toast-assets.d.ts.map +1 -1
- package/dist/0-face/generated/toast-assets.js +1 -1
- package/dist/2-core/ds-avatar.d.ts +5 -0
- package/dist/2-core/ds-avatar.d.ts.map +1 -1
- package/dist/2-core/ds-avatar.js +53 -9
- package/dist/3-unit/context-trigger.d.ts.map +1 -1
- package/dist/3-unit/context-trigger.js +32 -2
- package/dist/3-unit/ds-form.d.ts.map +1 -1
- package/dist/3-unit/ds-form.js +2 -1
- package/dist/3-unit/ds-table.d.ts.map +1 -1
- package/dist/3-unit/ds-table.js +2 -1
- package/dist/4-page/ds-container.d.ts.map +1 -1
- package/dist/4-page/ds-container.js +2 -1
- package/dist/design-system-1.bundle.js +406 -66
- package/dist/design-system-1.bundle.js.map +1 -1
- package/dist/design-system-1.bundle.min.js +3388 -3136
- package/dist/design-system-1.bundle.min.js.map +1 -1
- package/dist/design-system-1.css +1 -1
- package/dist/feedback.js +1 -1
- package/dist/feedback.js.map +1 -1
- package/package.json +6 -4
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { paintFaultLines } from './fault-lines';
|
|
1
2
|
import { measureConstraints, type Constraint, type Finding } from './constraints';
|
|
2
|
-
import {
|
|
3
|
+
import { VIEWPORT_WIDTHS, checkSite, findSitePages, inspectInFrame, ruleLine, summarizePages, summarizeRules, type PageResult } from './constraint-site';
|
|
3
4
|
|
|
4
5
|
// appendChild, not append: a Worker project's types redefine append for its HTML rewriter.
|
|
5
6
|
|
|
@@ -38,7 +39,8 @@ export function createConstraintPanel() {
|
|
|
38
39
|
--danger: var(--ds-danger-color, light-dark(#de0331, #ff5f5f));
|
|
39
40
|
}
|
|
40
41
|
:host([hidden]) { display: none !important; }
|
|
41
|
-
.
|
|
42
|
+
.fault-lines { z-index: 0 !important; }
|
|
43
|
+
.rings { z-index: 1; position: absolute; inset: 0; overflow: hidden; }
|
|
42
44
|
.frames { position: absolute; width: 0; height: 0; overflow: hidden; }
|
|
43
45
|
.ring {
|
|
44
46
|
position: absolute;
|
|
@@ -60,6 +62,7 @@ export function createConstraintPanel() {
|
|
|
60
62
|
text-align: center;
|
|
61
63
|
}
|
|
62
64
|
aside {
|
|
65
|
+
z-index: 2;
|
|
63
66
|
position: absolute;
|
|
64
67
|
inset-block: 0;
|
|
65
68
|
inset-inline-end: 0;
|
|
@@ -106,14 +109,18 @@ export function createConstraintPanel() {
|
|
|
106
109
|
.code b { color: var(--danger); font-weight: 400; }
|
|
107
110
|
.rule { color: var(--muted); }
|
|
108
111
|
p { margin: 0; }
|
|
112
|
+
:host([data-lines-only]) aside { inset-block: 0 auto; width: auto; padding: calc(var(--u) / 2); }
|
|
113
|
+
:host([data-lines-only]) aside > :not(header), :host([data-lines-only]) header > :not([data-lines], [data-close]) { display: none; }
|
|
114
|
+
:host([data-lines-only]) header { margin: 0; }
|
|
109
115
|
@media print { :host { display: none !important; } }
|
|
110
|
-
</style><div class="rings"></div><div class="frames"></div><aside aria-label="Constraints">
|
|
111
|
-
<header><strong>Constraints</strong><button type="button" data-run>Page</button><button type="button" data-site>Site</button><button type="button" data-close aria-label="Close">Close</button></header>
|
|
112
|
-
<p data-status aria-live="polite"></p>
|
|
116
|
+
</style><svg class="fault-lines" aria-hidden="true"></svg><div class="rings"></div><div class="frames"></div><aside aria-label="Constraints">
|
|
117
|
+
<header><strong>Constraints</strong><button type="button" data-run>Page</button><button type="button" data-site>Site</button><button type="button" data-lines>Lines</button><button type="button" data-close aria-label="Close">Close</button></header>
|
|
118
|
+
<p data-status aria-live="polite"></p><p class="rule">Fault lines: dashed reference · red drift</p>
|
|
113
119
|
<ol data-findings></ol>
|
|
114
120
|
<section data-rules hidden><h3>Rules</h3><ol></ol></section>
|
|
115
121
|
<section data-pages hidden><h3>Pages</h3><ol></ol></section>
|
|
116
122
|
</aside>`;
|
|
123
|
+
const faultLines = shadow.querySelector<SVGSVGElement>('.fault-lines')!;
|
|
117
124
|
const rings = shadow.querySelector<HTMLDivElement>('.rings')!;
|
|
118
125
|
const list = shadow.querySelector<HTMLOListElement>('[data-findings]')!;
|
|
119
126
|
const rulesSection = shadow.querySelector<HTMLElement>('[data-rules]')!;
|
|
@@ -123,6 +130,9 @@ export function createConstraintPanel() {
|
|
|
123
130
|
const status = shadow.querySelector<HTMLElement>('[data-status]')!;
|
|
124
131
|
const title = shadow.querySelector('strong')!;
|
|
125
132
|
const frames = shadow.querySelector<HTMLDivElement>('.frames')!;
|
|
133
|
+
const linesButton = shadow.querySelector<HTMLButtonElement>('[data-lines]')!;
|
|
134
|
+
const setLinesOnly = (enabled: boolean) => { panel.toggleAttribute('data-lines-only', enabled); linesButton.textContent = enabled ? 'Results' : 'Lines'; };
|
|
135
|
+
linesButton.addEventListener('click', () => setLinesOnly(!panel.hasAttribute('data-lines-only')));
|
|
126
136
|
const siteButton = shadow.querySelector<HTMLButtonElement>('[data-site]')!;
|
|
127
137
|
let site: AbortController | null = null;
|
|
128
138
|
let findings: (Finding & { constraint: Constraint })[] = [];
|
|
@@ -131,6 +141,7 @@ export function createConstraintPanel() {
|
|
|
131
141
|
|
|
132
142
|
const place = () => {
|
|
133
143
|
frame = 0;
|
|
144
|
+
paintFaultLines(document, faultLines);
|
|
134
145
|
rings.replaceChildren(...findings.map(({ element }, index) => {
|
|
135
146
|
const rect = element.getBoundingClientRect();
|
|
136
147
|
const ring = document.createElement('div');
|
|
@@ -144,6 +155,8 @@ export function createConstraintPanel() {
|
|
|
144
155
|
}));
|
|
145
156
|
};
|
|
146
157
|
const schedule = () => { if (!frame) frame = requestAnimationFrame(place); };
|
|
158
|
+
const layoutChanges = new MutationObserver(schedule);
|
|
159
|
+
const sizeChanges = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(schedule);
|
|
147
160
|
|
|
148
161
|
const stopSite = () => {
|
|
149
162
|
site?.abort();
|
|
@@ -276,7 +289,7 @@ export function createConstraintPanel() {
|
|
|
276
289
|
title.textContent = 'Constraints';
|
|
277
290
|
status.textContent = 'Finding the pages…';
|
|
278
291
|
const pages = await findSitePages();
|
|
279
|
-
const widths = `${
|
|
292
|
+
const widths = `${VIEWPORT_WIDTHS.slice(0, -1).join(', ')} and ${VIEWPORT_WIDTHS[VIEWPORT_WIDTHS.length - 1]}px`;
|
|
280
293
|
let broken = 0;
|
|
281
294
|
const results = await checkSite({
|
|
282
295
|
pages,
|
|
@@ -302,13 +315,21 @@ export function createConstraintPanel() {
|
|
|
302
315
|
const show = (mode: 'page' | 'site' = 'page') => {
|
|
303
316
|
if (!panel.isConnected) document.body.appendChild(panel);
|
|
304
317
|
panel.hidden = false;
|
|
318
|
+
setLinesOnly(window.innerWidth < 640);
|
|
305
319
|
if (mode === 'site') void runSite(); else run();
|
|
320
|
+
layoutChanges.observe(document.body, {subtree:true, childList:true, attributes:true, attributeFilter:['style','class','hidden','data-ds-fault-lines','data-ds-fault-axis']});
|
|
321
|
+
sizeChanges?.observe(document.body);
|
|
306
322
|
window.addEventListener('scroll', schedule, { passive: true, capture: true });
|
|
307
323
|
window.addEventListener('resize', schedule);
|
|
308
324
|
};
|
|
309
325
|
const hide = () => {
|
|
310
326
|
stopSite();
|
|
311
327
|
panel.hidden = true;
|
|
328
|
+
if (frame) cancelAnimationFrame(frame);
|
|
329
|
+
frame = 0;
|
|
330
|
+
faultLines.replaceChildren();
|
|
331
|
+
layoutChanges.disconnect();
|
|
332
|
+
sizeChanges?.disconnect();
|
|
312
333
|
window.removeEventListener('scroll', schedule, { capture: true });
|
|
313
334
|
window.removeEventListener('resize', schedule);
|
|
314
335
|
};
|
|
@@ -8,6 +8,7 @@ import { calculateScalingFactor, defaultScalingConfig } from './scaling';
|
|
|
8
8
|
|
|
9
9
|
/** The narrowest phone still sold, the common ones and the widest. */
|
|
10
10
|
export const PHONE_WIDTHS = [320, 375, 393, 430];
|
|
11
|
+
export const VIEWPORT_WIDTHS = [...PHONE_WIDTHS, 768, 1024, 1440];
|
|
11
12
|
/** Pages checked side by side, each in its own frame. */
|
|
12
13
|
export const PAGES_AT_ONCE = 3;
|
|
13
14
|
|
|
@@ -61,7 +62,7 @@ const wait = (ms: number) => new Promise(done => setTimeout(done, ms));
|
|
|
61
62
|
* order of `widths`. The page reflows at each width without loading again. The address carries `ph=out`,
|
|
62
63
|
* the analytics opt-out most trackers honour, so the check counts no visits.
|
|
63
64
|
*/
|
|
64
|
-
export async function inspectInFrame(host: Element | ShadowRoot, url: string, widths: number[] =
|
|
65
|
+
export async function inspectInFrame(host: Element | ShadowRoot, url: string, widths: number[] = VIEWPORT_WIDTHS, height = 844): Promise<PageCheck[]> {
|
|
65
66
|
const frame = document.createElement('iframe');
|
|
66
67
|
frame.setAttribute('aria-hidden', 'true');
|
|
67
68
|
frame.tabIndex = -1;
|
|
@@ -114,7 +115,7 @@ export function checkPage(page: ParentNode): PageCheck {
|
|
|
114
115
|
* each width as it comes. Stops starting pages when `signal` aborts. Whatever the pages store in this
|
|
115
116
|
* browser while they are checked is put back afterwards.
|
|
116
117
|
*/
|
|
117
|
-
export async function checkSite({ pages, widths =
|
|
118
|
+
export async function checkSite({ pages, widths = VIEWPORT_WIDTHS, inspect, onResult, signal, atOnce = PAGES_AT_ONCE }: {
|
|
118
119
|
pages: string[];
|
|
119
120
|
widths?: number[];
|
|
120
121
|
/** One page at every width, in the order of `widths`. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { faultLineGrids, inspectFaultLines } from './fault-lines';
|
|
1
2
|
import { labelledButtons, inspectButtonLabels } from './button-label';
|
|
2
3
|
import { inspectTextContrast, measureTextContrast } from "./text-contrast";
|
|
3
4
|
import { inspectWordWrap, wordHeaders } from './word-wrap';
|
|
@@ -35,6 +36,14 @@ export type Constraint = {
|
|
|
35
36
|
count: (root: ParentNode) => number;
|
|
36
37
|
};
|
|
37
38
|
|
|
39
|
+
/** The actual initial, including a component nested in another open shadow root. */
|
|
40
|
+
function isAvatarInitial(element: Element): boolean {
|
|
41
|
+
for (let parent: Element | null = element; parent; parent = parent.assignedSlot ?? parent.parentElement ?? (parent.getRootNode() as ShadowRoot).host ?? null) {
|
|
42
|
+
if (parent.matches('ds-avatar, .ds-avatar')) return true;
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
38
47
|
/** A pixel either way is the same place. */
|
|
39
48
|
const near = (a: number, b: number) => Math.abs(a - b) <= 1;
|
|
40
49
|
const px = (n: number) => `${Math.round(n)}px`;
|
|
@@ -103,6 +112,14 @@ function rows(found: ReturnType<typeof cards>) {
|
|
|
103
112
|
}
|
|
104
113
|
|
|
105
114
|
export const constraints: Constraint[] = [
|
|
115
|
+
{
|
|
116
|
+
code: 'page.fault-lines',
|
|
117
|
+
rule: 'Fault lines keep related card and control grids aligned across the whole page, with matching track edges and gaps at every checked viewport width.',
|
|
118
|
+
why: 'Compare separate sections in the same alignment family; responsive layouts may change together, while unrelated groups and intentional exceptions remain independent.',
|
|
119
|
+
components: ['ds-page'],
|
|
120
|
+
check: { file: 'tests/fault-lines.test.ts', test: 'fault lines catch shifted tracks and unequal gaps across sections at each viewport' },
|
|
121
|
+
measures: ['alignment group', 'alignment groups'], count: root => faultLineGrids(root).length, inspect: inspectFaultLines,
|
|
122
|
+
},
|
|
106
123
|
{
|
|
107
124
|
code: 'select.hug',
|
|
108
125
|
rule: 'Select and date-picker triggers use hug sizing, never fill sizing or growing to occupy the available row.',
|
|
@@ -146,6 +163,16 @@ export const constraints: Constraint[] = [
|
|
|
146
163
|
count: root => measureTextContrast(root).length,
|
|
147
164
|
inspect: inspectTextContrast,
|
|
148
165
|
},
|
|
166
|
+
{
|
|
167
|
+
code: 'avatar.initial-contrast',
|
|
168
|
+
rule: 'Avatar initials have at least 4.5:1 contrast against their rendered fill, including after a theme or identity colour changes.',
|
|
169
|
+
why: 'Check each initial inside the avatar’s shadow root and in overlapping groups; decorative initials still need to be readable. Explicit ink overrides must pass too.',
|
|
170
|
+
components: ['ds-avatar'],
|
|
171
|
+
check: { file: 'tests/avatar-contrast.test.ts', test: 'avatar initials stay readable after theme and CSS-variable changes, and the avatar constraint catches overrides' },
|
|
172
|
+
measures: ['avatar initial', 'avatar initials'],
|
|
173
|
+
count: root => measureTextContrast(root).filter(result => isAvatarInitial(result.element)).length,
|
|
174
|
+
inspect: root => inspectTextContrast(root).filter(finding => isAvatarInitial(finding.element)),
|
|
175
|
+
},
|
|
149
176
|
{
|
|
150
177
|
code: 'card.media-level',
|
|
151
178
|
rule: "A card's picture stands on the card's foot, a square below the words at least, so the pictures of cards side by side stand on one level whatever the words above them.",
|
package/DS1/0-face/define.ts
CHANGED
|
@@ -13,7 +13,7 @@ export function define(name: string, element: CustomElementConstructor): void {
|
|
|
13
13
|
const type = element as StyledConstructor;
|
|
14
14
|
const prototype = element.prototype as StyledElement;
|
|
15
15
|
const original = prototype.createRenderRoot;
|
|
16
|
-
if (original) {
|
|
16
|
+
if (original && typeof document !== 'undefined') {
|
|
17
17
|
const definingDocument = document;
|
|
18
18
|
prototype.createRenderRoot = function (this: StyledElement) {
|
|
19
19
|
if (this.ownerDocument === definingDocument || !type.elementStyles?.length) return original.call(this);
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type { Finding } from './constraints';
|
|
2
|
+
|
|
3
|
+
const tolerance = 1;
|
|
4
|
+
const near = (a: number, b: number) => Math.abs(a - b) <= tolerance;
|
|
5
|
+
const style = (el: Element) => el.ownerDocument.defaultView!.getComputedStyle(el);
|
|
6
|
+
const visible = (el: Element) => {
|
|
7
|
+
const box = el.getBoundingClientRect();
|
|
8
|
+
return box.width > 0 && box.height > 0 && style(el).visibility !== 'hidden' && style(el).display !== 'none';
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/** Walk each open shadow tree once; slotted children already occur in the light tree. */
|
|
12
|
+
function elements(root: ParentNode): Element[] {
|
|
13
|
+
return Array.from(root.querySelectorAll('*')).flatMap(el => [el, ...(el.shadowRoot ? elements(el.shadowRoot) : [])]);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type Grid = { element: Element; family: string | null; axis: 'x' | 'y'; lines: number[]; gaps: number[]; crossGap?: number; internalDrift: boolean; start: number; end: number };
|
|
17
|
+
|
|
18
|
+
/** Related grids opt in by name; unlabelled card grids are candidates for human review. */
|
|
19
|
+
export function faultLineGrids(root: ParentNode): Grid[] {
|
|
20
|
+
return elements(root).flatMap(element => {
|
|
21
|
+
const family = element.getAttribute('data-ds-fault-lines');
|
|
22
|
+
if (family === 'off' || !visible(element)) return [];
|
|
23
|
+
const children = Array.from(element.children).filter(visible);
|
|
24
|
+
if (!children.length) return [];
|
|
25
|
+
if (family === null && (!/grid/.test(style(element).display) || children.length < 2 ||
|
|
26
|
+
!children.every(child => child.matches('ds-card, .ds-card, ds-button, button')))) return [];
|
|
27
|
+
const axis = element.getAttribute('data-ds-fault-axis') === 'y' ? 'y' : 'x';
|
|
28
|
+
const boxes = children.map(child => child.getBoundingClientRect());
|
|
29
|
+
const crossStart = (box: DOMRect) => axis === 'x' ? box.top : box.left;
|
|
30
|
+
const crossEnd = (box: DOMRect) => axis === 'x' ? box.bottom : box.right;
|
|
31
|
+
const start = (box: DOMRect) => axis === 'x' ? box.left : box.top;
|
|
32
|
+
const end = (box: DOMRect) => axis === 'x' ? box.right : box.bottom;
|
|
33
|
+
const bands: DOMRect[][] = [];
|
|
34
|
+
for (const box of boxes.sort((a,b) => crossStart(a)-crossStart(b))) {
|
|
35
|
+
const band = bands.find(row => near(crossStart(row[0]!), crossStart(box)));
|
|
36
|
+
if (band) band.push(box); else bands.push([box]);
|
|
37
|
+
}
|
|
38
|
+
// The fullest band defines the tracks; an incomplete final row is valid.
|
|
39
|
+
const band = [...bands].sort((a,b) => b.length-a.length)[0]!.sort((a,b) => start(a)-start(b));
|
|
40
|
+
const lines = band.flatMap(box => [start(box), end(box)]);
|
|
41
|
+
const gaps = band.slice(1).map((box,index) => start(box)-end(band[index]!));
|
|
42
|
+
const crossGaps = bands.slice(1).map((row,index) => Math.min(...row.map(crossStart))-Math.max(...bands[index]!.map(crossEnd)));
|
|
43
|
+
const internalDrift = bands.some(row => row.length === band.length && row.slice().sort((a,b)=>start(a)-start(b)).some((box,index)=>!near(start(box),lines[index*2]!) || !near(end(box),lines[index*2+1]!))) || crossGaps.some(gap=>!near(gap,crossGaps[0]!));
|
|
44
|
+
return [{element, family, axis, lines, gaps, crossGap: crossGaps[0], internalDrift, start: lines[0]!, end: lines[lines.length - 1]!}];
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function referenceFor(grids: Grid[], i: number) {
|
|
49
|
+
const current = grids[i]!;
|
|
50
|
+
return grids.slice(0,i).find(other => {
|
|
51
|
+
if (other.axis !== current.axis || other.lines.length !== current.lines.length) return false;
|
|
52
|
+
if (current.family !== null || other.family !== null) return current.family !== null && current.family === other.family;
|
|
53
|
+
return near(current.start,other.start) && near(current.end,other.end);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Fault lines compare rendered tracks across separate sections, in the current viewport. */
|
|
58
|
+
export function inspectFaultLines(root: ParentNode): Finding[] {
|
|
59
|
+
const grids = faultLineGrids(root);
|
|
60
|
+
const findings: Finding[] = [];
|
|
61
|
+
for (let i = 0; i < grids.length; i++) {
|
|
62
|
+
const current = grids[i]!;
|
|
63
|
+
if (current.internalDrift) findings.push({element:current.element, ...(current.family === null ? {review:true} : {}), message:`Fault lines at ${current.element.ownerDocument.documentElement.clientWidth}px: tracks or repeated gaps drift inside ${current.family || 'this card grid'}. Align its complete rows and repeated spacing.`});
|
|
64
|
+
const reference = referenceFor(grids, i);
|
|
65
|
+
if (!reference) continue;
|
|
66
|
+
const drift = current.lines.map((line,index) => Math.abs(line-reference.lines[index]!));
|
|
67
|
+
const gapDrift = current.gaps.some((gap,index) => !near(gap,reference.gaps[index]!));
|
|
68
|
+
const rowDrift = current.crossGap !== undefined && reference.crossGap !== undefined && !near(current.crossGap,reference.crossGap);
|
|
69
|
+
if (!drift.some(value => value > tolerance) && !gapDrift && !rowDrift) continue;
|
|
70
|
+
const width = current.element.ownerDocument.documentElement.clientWidth;
|
|
71
|
+
const review = current.family === null;
|
|
72
|
+
findings.push({element: current.element, ...(review ? {review:true} : {}), message:
|
|
73
|
+
`Fault lines at ${width}px: ${current.family || 'these card grids'} ${review ? 'may be related but have' : 'have'} misaligned ${current.axis === 'x' ? 'column' : 'row'} edges or unequal gaps (edge drift ${Math.round(Math.max(...drift))}px; gaps ${current.gaps.map(Math.round).join('/')}px versus ${reference.gaps.map(Math.round).join('/')}px${rowDrift ? `; cross-axis gap ${Math.round(current.crossGap!)}px versus ${Math.round(reference.crossGap!)}px` : ''}). ${review ? 'Name the related groups with data-ds-fault-lines to enforce alignment, or mark an intentional exception off.' : 'Use the same tracks and gap for this family at this viewport.'}`});
|
|
74
|
+
}
|
|
75
|
+
return findings;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
/** The same rendered geometry as the checker, painted without affecting layout or hit testing. */
|
|
80
|
+
export function paintFaultLines(root: ParentNode, layer: SVGSVGElement): void {
|
|
81
|
+
const doc = layer.ownerDocument;
|
|
82
|
+
const width = doc.documentElement.clientWidth;
|
|
83
|
+
const height = doc.defaultView!.innerHeight;
|
|
84
|
+
layer.setAttribute('viewBox', `0 0 ${width} ${height}`);
|
|
85
|
+
layer.setAttribute('width', String(width));
|
|
86
|
+
layer.setAttribute('height', String(height));
|
|
87
|
+
layer.setAttribute('aria-hidden', 'true');
|
|
88
|
+
layer.style.cssText = 'position:fixed;inset:0;pointer-events:none;overflow:hidden;z-index:2147483644';
|
|
89
|
+
layer.replaceChildren();
|
|
90
|
+
const grids = faultLineGrids(root);
|
|
91
|
+
const failed = new Set(inspectFaultLines(root).map(finding => finding.element));
|
|
92
|
+
const drawn = new Set<string>();
|
|
93
|
+
const referenceInk = '#087ba8';
|
|
94
|
+
const faultInk = '#de0331';
|
|
95
|
+
function mark(tag: string, attributes: Record<string, string | number>, title?: string) {
|
|
96
|
+
const node = doc.createElementNS('http://www.w3.org/2000/svg', tag);
|
|
97
|
+
for (const [key, value] of Object.entries(attributes)) node.setAttribute(key, String(value));
|
|
98
|
+
if (title) {const tip = doc.createElementNS(node.namespaceURI, 'title');tip.textContent = title;node.appendChild(tip);}
|
|
99
|
+
layer.appendChild(node);
|
|
100
|
+
return node;
|
|
101
|
+
}
|
|
102
|
+
for (let index = 0; index < grids.length; index++) {
|
|
103
|
+
const grid = grids[index]!;
|
|
104
|
+
const reference = referenceFor(grids, index) ?? grid;
|
|
105
|
+
for (const edge of reference.lines) {
|
|
106
|
+
const key = `${grid.axis}:${edge}`;
|
|
107
|
+
if (drawn.has(key)) continue;
|
|
108
|
+
drawn.add(key);
|
|
109
|
+
mark('line', { 'data-fault-reference': '', x1: grid.axis === 'x' ? edge : 0, y1: grid.axis === 'y' ? edge : 0,
|
|
110
|
+
x2: grid.axis === 'x' ? edge : width, y2: grid.axis === 'y' ? edge : height,
|
|
111
|
+
stroke: referenceInk, 'stroke-width': 1, 'stroke-dasharray': '4 4' }, 'Reference edge');
|
|
112
|
+
}
|
|
113
|
+
const broken = failed.has(grid.element);
|
|
114
|
+
if (!broken) continue;
|
|
115
|
+
// Draw each actual child so drift inside a later row is visible too.
|
|
116
|
+
for (const child of Array.from(grid.element.children).filter(visible)) {
|
|
117
|
+
const box = child.getBoundingClientRect();
|
|
118
|
+
const edges = grid.axis === 'x' ? [box.left, box.right] : [box.top, box.bottom];
|
|
119
|
+
for (const edge of edges) {
|
|
120
|
+
if (reference.lines.some(expected => near(edge, expected))) continue;
|
|
121
|
+
mark('line', { 'data-fault-actual': '', x1: grid.axis === 'x' ? edge : box.left, y1: grid.axis === 'y' ? edge : box.top,
|
|
122
|
+
x2: grid.axis === 'x' ? edge : box.right, y2: grid.axis === 'y' ? edge : box.bottom,
|
|
123
|
+
stroke: faultInk, 'stroke-width': 2 }, 'Actual edge differs from the dashed reference');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Row spacing can drift even when every column edge still aligns.
|
|
127
|
+
const rows: DOMRect[][] = [];
|
|
128
|
+
for (const child of Array.from(grid.element.children).filter(visible)) {
|
|
129
|
+
const box = child.getBoundingClientRect();
|
|
130
|
+
const start = grid.axis === 'x' ? box.top : box.left;
|
|
131
|
+
const row = rows.find(row => near(grid.axis === 'x' ? row[0]!.top : row[0]!.left, start));
|
|
132
|
+
if (row) row.push(box); else rows.push([box]);
|
|
133
|
+
}
|
|
134
|
+
rows.sort((a,b) => grid.axis === 'x' ? a[0]!.top-b[0]!.top : a[0]!.left-b[0]!.left);
|
|
135
|
+
const bounds = grid.element.getBoundingClientRect();
|
|
136
|
+
const crossGap = reference.crossGap ?? grid.crossGap;
|
|
137
|
+
if (crossGap !== undefined) for (let row = 1; row < rows.length; row++) {
|
|
138
|
+
const previousEnd = Math.max(...rows[row-1]!.map(box => grid.axis === 'x' ? box.bottom : box.right));
|
|
139
|
+
const actual = Math.min(...rows[row]!.map(box => grid.axis === 'x' ? box.top : box.left));
|
|
140
|
+
const expected = previousEnd+crossGap;
|
|
141
|
+
if (near(actual,expected)) continue;
|
|
142
|
+
for (const [edge,kind] of [[expected,'reference'],[actual,'actual']] as const) {
|
|
143
|
+
mark('line', {[`data-fault-${kind}`]: '', x1:grid.axis === 'x' ? bounds.left : edge, y1:grid.axis === 'x' ? edge : bounds.top,
|
|
144
|
+
x2:grid.axis === 'x' ? bounds.right : edge, y2:grid.axis === 'x' ? edge : bounds.bottom,
|
|
145
|
+
stroke:kind === 'reference' ? referenceInk : faultInk, 'stroke-width':kind === 'reference' ? 1 : 2,
|
|
146
|
+
'stroke-dasharray':kind === 'reference' ? '4 4' : ''}, `Row gap ${Math.round(actual-previousEnd)}px; reference ${Math.round(crossGap)}px`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const box = grid.element.getBoundingClientRect();
|
|
150
|
+
const label = mark('text', { 'data-fault-gap': '', x: Math.max(4,box.left), y: Math.max(16,Math.min(height-4,box.top+16)),
|
|
151
|
+
fill: faultInk, stroke: 'var(--ds-background-color, white)', 'stroke-width': 3, 'paint-order': 'stroke',
|
|
152
|
+
'font-family': 'var(--ds-typeface-regular, sans-serif)', 'font-size': 12 });
|
|
153
|
+
const gaps = grid.gaps.map(gap => Math.round(gap)).join('/');
|
|
154
|
+
const expected = reference.gaps.map(gap => Math.round(gap)).join('/');
|
|
155
|
+
label.textContent = `Gap ${gaps || '—'}px · reference ${expected || '—'}px` +
|
|
156
|
+
(grid.crossGap !== undefined && reference.crossGap !== undefined && !near(grid.crossGap,reference.crossGap)
|
|
157
|
+
? ` · row gap ${Math.round(grid.crossGap)}px / ${Math.round(reference.crossGap)}px` : '');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/** The toast's stylesheet, the same one `<ds-toast>` imports. */
|
|
8
|
-
export const toastStyles: string = "[data-ds-shape=\"square\"], :host([data-ds-shape=\"square\"]){--ds-corner-size: 0px;--ds-corner-shape: round;--ds-button-inset: 0.5px}[data-ds-shape=\"rounded\"], :host([data-ds-shape=\"rounded\"]){--ds-corner-size: 4px;--ds-corner-shape: round;--ds-button-inset: 2.5px}[data-ds-shape=\"circular\"], :host([data-ds-shape=\"circular\"]){--ds-corner-size: 999px;--ds-corner-shape: round;--ds-button-inset: 5px}@supports (corner-shape: squircle){[data-ds-shape=\"rounded\"], :host([data-ds-shape=\"rounded\"]){--ds-corner-size: 8px;--ds-corner-shape: squircle}}:root, :host, :where([data-ds-surface]){--ds-unit: calc(var(--ds-1, 20px) * var(--ds-sf, 1));--ds-control-height: calc(var(--ds-control-size, var(--ds-08, 16px)) * var(--ds-sf, 1));--ds-row-height: calc(var(--ds-row-size, var(--ds-1, 20px)) * var(--ds-sf, 1));--ds-type-size-default: calc(var(--ds-text-size, 14px) * var(--ds-sf, 1));--ds-type-size-small: calc(var(--ds-small-text-size, 10px) * var(--ds-sf, 1));--ds-type-size-heading: calc(var(--ds-heading-text-size, 13px) * var(--ds-sf, 1));--ds-type-size-display: calc(var(--ds-display-text-size, 20px) * var(--ds-sf, 1));--ds-type-lineheight-default: calc(var(--ds-text-leading, 16px) * var(--ds-sf, 1));--ds-type-letterspacing-default: calc(var(--ds-text-tracking, -0.3px) * var(--ds-sf, 1));--ds-radius: calc(var(--ds-corner-size, 4px) * var(--ds-sf, 1));--ds-radius-card: calc(var(--ds-card-corner-size, 4px) * var(--ds-sf, 1))}:host{--ds-toast-width: calc(16 * var(--ds-unit));--ds-toast-offset: var(--ds-unit);--ds-toast-gap: calc(var(--ds-unit) - var(--ds-control-height));--ds-toast-background: var(--ds-tooltip-background, light-dark(var(--ds-black, #2a2a2a), var(--ds-white, #ffffff)));--ds-toast-color: var(--ds-tooltip-color, light-dark(var(--ds-white, #ffffff), var(--ds-black, #2a2a2a)));display: contents}section{display: contents}ol{--lift: -1;position: fixed;z-index: 2147483000;inset: auto;overflow: visible;border: 0;background: transparent;color: inherit;box-sizing: border-box;width: min(var(--ds-toast-width), calc(100% - 2 * var(--ds-toast-offset)));height: calc(var(--height) + var(--gaps) * var(--ds-toast-gap));margin: 0;padding: 0;list-style: none;outline: none;pointer-events: none}ol[data-y=\"top\"]{--lift: 1;top: calc(var(--ds-toast-offset) + env(safe-area-inset-top, 0px))}ol[data-y=\"bottom\"]{bottom: calc(var(--ds-toast-offset) + env(safe-area-inset-bottom, 0px))}ol[data-x=\"left\"]{left: var(--ds-toast-offset)}ol[data-x=\"right\"]{right: var(--ds-toast-offset)}ol[data-x=\"center\"]{left: 50%;transform: translateX(-50%)}:host([contained]) ol{position: absolute;z-index: var(--ds-toast-z-index, 60)}:host([contained]) ol[data-y=\"top\"]{top: var(--ds-toast-offset)}:host([contained]) ol[data-y=\"bottom\"]{bottom: var(--ds-toast-offset)}.toast{--swipe: 0px;position: absolute;left: 0;right: 0;box-sizing: border-box;width: max-content;max-width: 100%;overflow: hidden;border-radius: var(--ds-radius);background: var(--ds-toast-background);color: var(--ds-toast-color);font-family: var(--ds-typeface-regular);font-feature-settings: var(--ds-font-features);font-size: var(--ds-type-size-default);line-height: var(--ds-control-height);letter-spacing: var(--ds-type-letterspacing-default);outline: none;touch-action: none;user-select: none;pointer-events: auto;opacity: 0;transition: transform 400ms ease, opacity 400ms ease}ol[data-y=\"bottom\"] .toast{bottom: 0}ol[data-y=\"top\"] .toast{top: 0}ol[data-x=\"center\"] .toast{margin-inline: auto}ol[data-x=\"left\"] .toast{margin-right: auto}ol[data-x=\"right\"] .toast{margin-left: auto}.toast:focus-visible{outline: 2px solid var(--ds-focus-ring);outline-offset: 1px}.toast[data-mounted=\"false\"]{transform: translateY(calc(var(--lift) * -100%))}.toast[data-mounted=\"true\"]{opacity: 1}ol[data-expanded=\"false\"] .toast[data-mounted=\"true\"]{transform: translateY(calc(var(--lift) * var(--index) * var(--ds-toast-gap) + var(--swipe))) scale(calc(1 - var(--index) * 0.05))}ol[data-expanded=\"false\"] .toast[data-front=\"false\"]{height: var(--front-height)}ol[data-expanded=\"false\"] .toast[data-front=\"false\"] .body{opacity: 0}ol[data-expanded=\"true\"] .toast[data-mounted=\"true\"]{transform: translateY(calc(var(--lift) * (var(--offset) + var(--index) * var(--ds-toast-gap)) + var(--swipe)))}.toast[data-visible=\"false\"]{opacity: 0;pointer-events: none}.toast[data-swiping=\"true\"]{transition: none}.toast[data-removed=\"true\"]{opacity: 0;pointer-events: none}.toast[data-removed=\"true\"][data-front=\"true\"]{transform: translateY(calc(var(--lift) * -100%))}.toast[data-swipe-out=\"true\"]{transform: translateY(calc(var(--swipe) + var(--lift) * -100%))}.body{display: flex;align-items: flex-start;gap: calc(4px * var(--ds-sf));box-sizing: border-box;min-height: var(--ds-control-height);padding-inline: calc(4px * var(--ds-sf));transition: opacity 400ms ease}.icon{display: inline-flex;flex: 0 0 auto;align-items: center;justify-content: center;width: var(--ds-control-height);height: var(--ds-control-height);--ds-icon-color: currentColor}.icon:first-child{margin-left: calc(-4px * var(--ds-sf))}.icon > svg, .close > svg{width: calc(14px * var(--ds-sf));height: calc(14px * var(--ds-sf))}.content{flex: 1 1 auto;min-width: 0}.title, .description{white-space: normal;overflow-wrap: anywhere}.description{opacity: 0.7}.button{flex: 0 0 auto;margin: 0 0 0 calc(4px * var(--ds-sf));padding: 0;border: 0;background: none;color: inherit;font: inherit;letter-spacing: inherit;text-decoration: underline;text-underline-offset: 2px;cursor: pointer}a.button{display: inline-block}.button.cancel{opacity: 0.7}.button:focus-visible, .close:focus-visible{outline: 1px solid currentColor;outline-offset: 1px;border-radius: 1px}.close{display: inline-flex;flex: 0 0 auto;align-items: center;justify-content: center;width: var(--ds-control-height);height: var(--ds-control-height);margin: 0 calc(-4px * var(--ds-sf)) 0 0;padding: 0;border: 0;background: none;color: inherit;cursor: pointer;--ds-icon-color: currentColor}.spinner{width: calc(10px * var(--ds-sf));height: calc(10px * var(--ds-sf));box-sizing: border-box;border: 1px solid color-mix(in srgb, currentColor 25%, transparent);border-top-color: currentColor;border-radius: 50%;animation: ds-toast-spin 720ms linear infinite}@keyframes ds-toast-spin{to{transform: rotate(360deg)}}:host([rich-colors]) .toast[data-type=\"success\"]{--ds-toast-background: var(--ds-apple-green)}:host([rich-colors]) .toast[data-type=\"info\"]{--ds-toast-background: var(--ds-zenith-blue)}:host([rich-colors]) .toast[data-type=\"warning\"]{--ds-toast-background: var(--ds-orange)}:host([rich-colors]) .toast[data-type=\"error\"]{--ds-toast-background: var(--ds-tuned-red)}:host([rich-colors]) .toast:is([data-type=\"success\"], [data-type=\"info\"], [data-type=\"warning\"], [data-type=\"error\"]){--ds-toast-color: var(--ds-black)}@media (prefers-reduced-motion: reduce){.toast, .body{transition: none}.spinner{animation: none}}";
|
|
8
|
+
export const toastStyles: string = "[data-ds-shape=\"square\"], :host([data-ds-shape=\"square\"]){--ds-corner-size: 0px;--ds-corner-shape: round;--ds-button-inset: 0.5px}[data-ds-shape=\"rounded\"], :host([data-ds-shape=\"rounded\"]){--ds-corner-size: 4px;--ds-corner-shape: round;--ds-button-inset: 2.5px}[data-ds-shape=\"circular\"], :host([data-ds-shape=\"circular\"]){--ds-corner-size: 999px;--ds-corner-shape: round;--ds-button-inset: 5px}@supports (corner-shape: squircle){[data-ds-shape=\"rounded\"], :host([data-ds-shape=\"rounded\"]){--ds-corner-size: 8px;--ds-corner-shape: squircle}}:root, :host, :where([data-ds-surface]){--ds-unit: calc(var(--ds-1, 20px) * var(--ds-sf, 1));--ds-control-height: calc(var(--ds-control-size, var(--ds-08, 16px)) * var(--ds-sf, 1));--ds-row-height: calc(var(--ds-row-size, var(--ds-1, 20px)) * var(--ds-sf, 1));--ds-type-size-default: calc(var(--ds-text-size, 14px) * var(--ds-sf, 1));--ds-type-size-small: calc(var(--ds-small-text-size, 10px) * var(--ds-sf, 1));--ds-type-size-heading: calc(var(--ds-heading-text-size, 13px) * var(--ds-sf, 1));--ds-type-size-display: calc(var(--ds-display-text-size, 20px) * var(--ds-sf, 1));--ds-type-lineheight-default: calc(var(--ds-text-leading, 16px) * var(--ds-sf, 1));--ds-type-letterspacing-default: calc(var(--ds-text-tracking, -0.3px) * var(--ds-sf, 1));--ds-radius: calc(var(--ds-corner-size, 4px) * var(--ds-sf, 1));--ds-radius-card: calc(var(--ds-card-corner-size, 4px) * var(--ds-sf, 1))}:host{--ds-toast-width: calc(16 * var(--ds-unit));--ds-toast-offset: var(--ds-unit);--ds-toast-gap: calc(var(--ds-unit) - var(--ds-control-height));--ds-toast-background: var(--ds-tooltip-background, light-dark(var(--ds-black, #2a2a2a), var(--ds-white, #ffffff)));--ds-toast-color: var(--ds-tooltip-color, light-dark(var(--ds-white, #ffffff), var(--ds-black, #2a2a2a)));display: contents}section{display: contents}ol{--lift: -1;position: fixed;z-index: 2147483000;inset: auto;overflow: visible;border: 0;background: transparent;color: inherit;box-sizing: border-box;width: min(var(--ds-toast-width), calc(100% - 2 * var(--ds-toast-offset)));height: calc(var(--height) + var(--gaps) * var(--ds-toast-gap));margin: 0;padding: 0;list-style: none;outline: none;pointer-events: none}ol[data-y=\"top\"]{--lift: 1;top: calc(var(--ds-toast-offset) + env(safe-area-inset-top, 0px))}ol[data-y=\"bottom\"]{bottom: calc(var(--ds-toast-offset) + env(safe-area-inset-bottom, 0px))}ol[data-x=\"left\"]{left: var(--ds-toast-offset)}ol[data-x=\"right\"]{right: var(--ds-toast-offset)}ol[data-x=\"center\"]{left: 50%;transform: translateX(-50%)}:host([contained]) ol{position: absolute;z-index: var(--ds-toast-z-index, 60)}:host([contained]) ol[data-y=\"top\"]{top: var(--ds-toast-offset)}:host([contained]) ol[data-y=\"bottom\"]{bottom: var(--ds-toast-offset)}.toast{--swipe: 0px;position: absolute;left: 0;right: 0;box-sizing: border-box;width: max-content;max-width: 100%;overflow: hidden;border-radius: var(--ds-radius);background: var(--ds-toast-background);color: var(--ds-toast-color);font-family: \"Inter Arrows\", var(--ds-typeface-regular);font-feature-settings: var(--ds-font-features);font-size: var(--ds-type-size-default);line-height: var(--ds-control-height);letter-spacing: var(--ds-type-letterspacing-default);outline: none;touch-action: none;user-select: none;pointer-events: auto;opacity: 0;transition: transform 400ms ease, opacity 400ms ease}ol[data-y=\"bottom\"] .toast{bottom: 0}ol[data-y=\"top\"] .toast{top: 0}ol[data-x=\"center\"] .toast{margin-inline: auto}ol[data-x=\"left\"] .toast{margin-right: auto}ol[data-x=\"right\"] .toast{margin-left: auto}.toast:focus-visible{outline: 2px solid var(--ds-focus-ring);outline-offset: 1px}.toast[data-mounted=\"false\"]{transform: translateY(calc(var(--lift) * -100%))}.toast[data-mounted=\"true\"]{opacity: 1}ol[data-expanded=\"false\"] .toast[data-mounted=\"true\"]{transform: translateY(calc(var(--lift) * var(--index) * var(--ds-toast-gap) + var(--swipe))) scale(calc(1 - var(--index) * 0.05))}ol[data-expanded=\"false\"] .toast[data-front=\"false\"]{height: var(--front-height)}ol[data-expanded=\"false\"] .toast[data-front=\"false\"] .body{opacity: 0}ol[data-expanded=\"true\"] .toast[data-mounted=\"true\"]{transform: translateY(calc(var(--lift) * (var(--offset) + var(--index) * var(--ds-toast-gap)) + var(--swipe)))}.toast[data-visible=\"false\"]{opacity: 0;pointer-events: none}.toast[data-swiping=\"true\"]{transition: none}.toast[data-removed=\"true\"]{opacity: 0;pointer-events: none}.toast[data-removed=\"true\"][data-front=\"true\"]{transform: translateY(calc(var(--lift) * -100%))}.toast[data-swipe-out=\"true\"]{transform: translateY(calc(var(--swipe) + var(--lift) * -100%))}.body{display: flex;align-items: flex-start;gap: calc(4px * var(--ds-sf));box-sizing: border-box;min-height: var(--ds-control-height);padding-inline: calc(4px * var(--ds-sf));transition: opacity 400ms ease}.icon{display: inline-flex;flex: 0 0 auto;align-items: center;justify-content: center;width: var(--ds-control-height);height: var(--ds-control-height);--ds-icon-color: currentColor}.icon:first-child{margin-left: calc(-4px * var(--ds-sf))}.icon > svg, .close > svg{width: calc(14px * var(--ds-sf));height: calc(14px * var(--ds-sf))}.content{flex: 1 1 auto;min-width: 0}.title, .description{white-space: normal;overflow-wrap: anywhere}.description{opacity: 0.7}.button{flex: 0 0 auto;margin: 0 0 0 calc(4px * var(--ds-sf));padding: 0;border: 0;background: none;color: inherit;font: inherit;letter-spacing: inherit;text-decoration: underline;text-underline-offset: 2px;cursor: pointer}a.button{display: inline-block}.button.cancel{opacity: 0.7}.button:focus-visible, .close:focus-visible{outline: 1px solid currentColor;outline-offset: 1px;border-radius: 1px}.close{display: inline-flex;flex: 0 0 auto;align-items: center;justify-content: center;width: var(--ds-control-height);height: var(--ds-control-height);margin: 0 calc(-4px * var(--ds-sf)) 0 0;padding: 0;border: 0;background: none;color: inherit;cursor: pointer;--ds-icon-color: currentColor}.spinner{width: calc(10px * var(--ds-sf));height: calc(10px * var(--ds-sf));box-sizing: border-box;border: 1px solid color-mix(in srgb, currentColor 25%, transparent);border-top-color: currentColor;border-radius: 50%;animation: ds-toast-spin 720ms linear infinite}@keyframes ds-toast-spin{to{transform: rotate(360deg)}}:host([rich-colors]) .toast[data-type=\"success\"]{--ds-toast-background: var(--ds-apple-green)}:host([rich-colors]) .toast[data-type=\"info\"]{--ds-toast-background: var(--ds-zenith-blue)}:host([rich-colors]) .toast[data-type=\"warning\"]{--ds-toast-background: var(--ds-orange)}:host([rich-colors]) .toast[data-type=\"error\"]{--ds-toast-background: var(--ds-tuned-red)}:host([rich-colors]) .toast:is([data-type=\"success\"], [data-type=\"info\"], [data-type=\"warning\"], [data-type=\"error\"]){--ds-toast-color: var(--ds-black)}@media (prefers-reduced-motion: reduce){.toast, .body{transition: none}.spinner{animation: none}}";
|
|
9
9
|
|
|
10
10
|
export type ToastIconName = "check" | "close" | "notifications" | "warning";
|
|
11
11
|
|
package/DS1/1-root/card.css
CHANGED
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
border-radius: var(--ds-radius-card);
|
|
58
58
|
background: var(--ds-card-fill);
|
|
59
59
|
color: var(--ds-card-ink);
|
|
60
|
-
font-family: var(--ds-typeface-regular);
|
|
60
|
+
font-family: "Inter Arrows", var(--ds-typeface-regular);
|
|
61
61
|
font-size: var(--ds-type-size-default);
|
|
62
62
|
text-decoration: none;
|
|
63
63
|
-webkit-tap-highlight-color: transparent;
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
.ds-card__title {
|
|
128
128
|
margin: 0 0 var(--ds-card-title-gap, 0px);
|
|
129
129
|
color: var(--ds-card-ink);
|
|
130
|
-
font-family: var(--ds-typeface-medium);
|
|
130
|
+
font-family: "Inter Arrows", var(--ds-typeface-medium);
|
|
131
131
|
font-size: var(--ds-type-size-display);
|
|
132
132
|
font-weight: var(--ds-type-weight-bold);
|
|
133
133
|
/* A title that wraps keeps its lines together: a square and a half each. */
|
package/DS1/1-root/cjk.css
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
@import "./component-metrics.css";
|
|
2
2
|
|
|
3
|
+
/* inter-arrows:start — generated by scripts/fonts/embed-arrows.mjs */
|
|
4
|
+
/* Inter 4.1, SIL Open Font License 1.1; see fonts/Inter-LICENSE.md. */
|
|
5
|
+
@font-face {
|
|
6
|
+
font-family: "Inter Arrows";
|
|
7
|
+
src: url("data:font/woff2;base64,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") format("woff2");
|
|
8
|
+
unicode-range: U+2190-21FF, U+27F0-27FF, U+2900-297F, U+2B00-2BFF;
|
|
9
|
+
font-weight: 100 900;
|
|
10
|
+
font-style: normal;
|
|
11
|
+
font-display: swap;
|
|
12
|
+
}
|
|
13
|
+
/* inter-arrows:end */
|
|
14
|
+
|
|
3
15
|
/* Shared component tokens. Scoped names keep embedded documents independent.
|
|
4
16
|
* Products may set tokens at their surface; component implementations stay shared.
|
|
5
17
|
*/
|
package/DS1/1-root/context.css
CHANGED
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
box-shadow: none;
|
|
57
57
|
clip-path: inset(0 round var(--ds-context-radius, var(--ds-radius, 4px)));
|
|
58
58
|
color: var(--ds-context-ink);
|
|
59
|
-
font-family: var(--ds-typeface-regular);
|
|
59
|
+
font-family: "Inter Arrows", var(--ds-typeface-regular);
|
|
60
60
|
font-feature-settings: var(--ds-font-features);
|
|
61
61
|
font-size: var(--ds-type-size-default);
|
|
62
62
|
font-weight: var(--ds-type-weight-default);
|
package/DS1/1-root/controls.css
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
border-radius: var(--ds-radius);
|
|
49
49
|
background: var(--ds-button-background, transparent);
|
|
50
50
|
color: var(--ds-button-color, var(--ds-button-text-color));
|
|
51
|
-
font-family: var(--ds-typeface-regular);
|
|
51
|
+
font-family: "Inter Arrows", var(--ds-typeface-regular);
|
|
52
52
|
font-feature-settings: var(--ds-font-features);
|
|
53
53
|
font-size: var(--ds-type-size-default);
|
|
54
54
|
line-height: var(--ds-type-lineheight-default);
|
|
@@ -168,7 +168,7 @@ a.ds-button[aria-disabled="true"] {
|
|
|
168
168
|
border-radius: var(--ds-radius);
|
|
169
169
|
background: var(--ds-fill);
|
|
170
170
|
color: var(--ds-text-color);
|
|
171
|
-
font-family: var(--ds-typeface-regular);
|
|
171
|
+
font-family: "Inter Arrows", var(--ds-typeface-regular);
|
|
172
172
|
font-feature-settings: var(--ds-font-features);
|
|
173
173
|
font-size: var(--ds-type-size-default);
|
|
174
174
|
line-height: var(--ds-type-lineheight-default);
|
|
@@ -498,7 +498,7 @@ dialog.ds-overlay {
|
|
|
498
498
|
box-shadow: none;
|
|
499
499
|
overflow: auto;
|
|
500
500
|
overscroll-behavior: contain;
|
|
501
|
-
font-family: var(--ds-typeface-regular);
|
|
501
|
+
font-family: "Inter Arrows", var(--ds-typeface-regular);
|
|
502
502
|
font-feature-settings: var(--ds-font-features);
|
|
503
503
|
font-size: var(--ds-type-size-default);
|
|
504
504
|
font-weight: var(--ds-type-weight-default);
|
|
@@ -669,7 +669,7 @@ dialog.ds-overlay:has(> [data-ds-overlay="close"]) [data-ds-overlay="header"] {
|
|
|
669
669
|
background: var(--ds-paper);
|
|
670
670
|
color: var(--ds-text-color);
|
|
671
671
|
box-shadow: none;
|
|
672
|
-
font-family: var(--ds-typeface-regular);
|
|
672
|
+
font-family: "Inter Arrows", var(--ds-typeface-regular);
|
|
673
673
|
font-feature-settings: var(--ds-font-features);
|
|
674
674
|
font-size: var(--ds-type-size-default);
|
|
675
675
|
font-weight: var(--ds-type-weight-default);
|
|
@@ -825,7 +825,7 @@ dialog.ds-overlay:has(> [data-ds-overlay="close"]) [data-ds-overlay="header"] {
|
|
|
825
825
|
min-width: 0;
|
|
826
826
|
margin: 0;
|
|
827
827
|
color: var(--ds-text-color);
|
|
828
|
-
font-family: var(--ds-typeface-regular);
|
|
828
|
+
font-family: "Inter Arrows", var(--ds-typeface-regular);
|
|
829
829
|
font-feature-settings: var(--ds-font-features);
|
|
830
830
|
font-size: var(--ds-type-size-default);
|
|
831
831
|
font-weight: var(--ds-type-weight-default);
|
|
@@ -908,7 +908,7 @@ dialog.ds-overlay:has(> [data-ds-overlay="close"]) [data-ds-overlay="header"] {
|
|
|
908
908
|
corner-shape: round;
|
|
909
909
|
background: var(--ds-avatar-background, var(--ds-fill));
|
|
910
910
|
color: var(--ds-avatar-color, var(--ds-text-color));
|
|
911
|
-
font: var(--ds-type-weight-default) var(--ds-type-size-small) / 1 var(--ds-typeface-regular);
|
|
911
|
+
font: var(--ds-type-weight-default) var(--ds-type-size-small) / 1 "Inter Arrows", var(--ds-typeface-regular);
|
|
912
912
|
letter-spacing: normal;
|
|
913
913
|
text-align: center;
|
|
914
914
|
white-space: nowrap;
|
|
@@ -986,7 +986,7 @@ dialog.ds-overlay:has(> [data-ds-overlay="close"]) [data-ds-overlay="header"] {
|
|
|
986
986
|
overflow: hidden;
|
|
987
987
|
background: var(--ds-badge-background, var(--ds-fill));
|
|
988
988
|
color: var(--ds-badge-color, var(--ds-text-color));
|
|
989
|
-
font-family: var(--ds-typeface-regular);
|
|
989
|
+
font-family: "Inter Arrows", var(--ds-typeface-regular);
|
|
990
990
|
font-feature-settings: var(--ds-font-features);
|
|
991
991
|
font-size: var(--ds-type-size-default);
|
|
992
992
|
font-weight: var(--ds-type-weight-default);
|
|
@@ -1163,7 +1163,7 @@ dialog.ds-overlay:has(> [data-ds-overlay="close"]) [data-ds-overlay="header"] {
|
|
|
1163
1163
|
corner-shape: var(--ds-corner-shape, round);
|
|
1164
1164
|
background: var(--ds-button-background-color-secondary);
|
|
1165
1165
|
color: var(--ds-button-text-color);
|
|
1166
|
-
font-family: var(--ds-typeface-regular);
|
|
1166
|
+
font-family: "Inter Arrows", var(--ds-typeface-regular);
|
|
1167
1167
|
font-feature-settings: var(--ds-font-features);
|
|
1168
1168
|
font-size: var(--ds-type-size-default);
|
|
1169
1169
|
font-weight: var(--ds-type-weight-default);
|
package/DS1/1-root/document.css
CHANGED
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
gap: var(--ds-unit) calc(2 * var(--ds-unit));
|
|
42
42
|
min-width: 0;
|
|
43
43
|
color: var(--ds-text-color);
|
|
44
|
-
font-family: var(--ds-typeface-regular);
|
|
44
|
+
font-family: "Inter Arrows", var(--ds-typeface-regular);
|
|
45
45
|
font-feature-settings: var(--ds-font-features);
|
|
46
46
|
font-size: var(--ds-type-size-default);
|
|
47
47
|
font-weight: var(--ds-type-weight-default);
|
|
@@ -141,7 +141,7 @@
|
|
|
141
141
|
margin: 0;
|
|
142
142
|
padding: 0;
|
|
143
143
|
color: var(--ds-text-color);
|
|
144
|
-
font-family: var(--ds-typeface-regular);
|
|
144
|
+
font-family: "Inter Arrows", var(--ds-typeface-regular);
|
|
145
145
|
font-size: var(--ds-type-size-default);
|
|
146
146
|
line-height: var(--ds-unit);
|
|
147
147
|
letter-spacing: var(--ds-type-letterspacing-default);
|
package/DS1/1-root/empty.css
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
text-align: center;
|
|
35
35
|
padding-block: var(--ds-empty-padding, 0);
|
|
36
36
|
color: var(--ds-text-color);
|
|
37
|
-
font-family: var(--ds-typeface-regular);
|
|
37
|
+
font-family: "Inter Arrows", var(--ds-typeface-regular);
|
|
38
38
|
font-feature-settings: var(--ds-font-features);
|
|
39
39
|
font-size: var(--ds-type-size-default);
|
|
40
40
|
font-weight: var(--ds-type-weight-default);
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
min-width: 0;
|
|
74
74
|
padding-top: calc(var(--ds-unit) - var(--ds-control-height));
|
|
75
75
|
line-height: var(--ds-control-height);
|
|
76
|
-
font-family: var(--ds-typeface-medium);
|
|
76
|
+
font-family: "Inter Arrows", var(--ds-typeface-medium);
|
|
77
77
|
font-weight: var(--ds-type-weight-bold);
|
|
78
78
|
}
|
|
79
79
|
|
package/DS1/1-root/figures.css
CHANGED
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
min-width: 0;
|
|
47
47
|
margin: 0;
|
|
48
48
|
color: var(--ds-text-color);
|
|
49
|
-
font-family: var(--ds-typeface-regular);
|
|
49
|
+
font-family: "Inter Arrows", var(--ds-typeface-regular);
|
|
50
50
|
font-feature-settings: var(--ds-font-features);
|
|
51
51
|
font-size: var(--ds-type-size-default);
|
|
52
52
|
font-weight: var(--ds-type-weight-default);
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
.ds-stat__figure {
|
|
91
91
|
display: block;
|
|
92
92
|
overflow: hidden;
|
|
93
|
-
font-family: var(--ds-stat-typeface, var(--ds-typeface-medium));
|
|
93
|
+
font-family: "Inter Arrows", var(--ds-stat-typeface, var(--ds-typeface-medium));
|
|
94
94
|
font-size: calc(var(--ds-stat-size, var(--ds-display-text-size, 20px)) * var(--ds-sf, 1));
|
|
95
95
|
font-weight: var(--ds-type-weight-bold);
|
|
96
96
|
font-variant-numeric: tabular-nums;
|