@lifecorner/angular-ui-kit 3.22.4 → 3.23.1
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/fesm2022/lifecorner-angular-ui-kit-accordion.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-accordion.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-dependency-viewer.mjs +6 -6
- package/fesm2022/lifecorner-angular-ui-kit-dependency-viewer.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-description-list.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-description-list.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-log-viewer.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-log-viewer.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-notification-center.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-notification-center.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-progress-bar.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-progress-bar.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-progress-ring.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-progress-ring.mjs.map +1 -1
- package/package.json +1 -1
- package/src/styles/_theme-dark.scss +4 -0
- package/src/styles/_theme-light.scss +4 -0
- package/src/styles/theme-contrast.spec.ts +291 -8
- package/types/lifecorner-angular-ui-kit-accordion.d.ts +12 -2
|
@@ -743,11 +743,13 @@ describe('Component pairings of 3.21.1 (request 029)', () => {
|
|
|
743
743
|
);
|
|
744
744
|
});
|
|
745
745
|
|
|
746
|
-
it('AC-10: the progress track is unchanged; primary
|
|
746
|
+
it('AC-10: the progress track is unchanged; primary stays raw (secondary: request 036)', () => {
|
|
747
747
|
// The base rule (the forced-colours block repeats the selector with an outline).
|
|
748
748
|
expect(sheets.progress).toMatch(/\n\.progress-bar__track \{\s*flex: 1;\s*background-color: var\(--color-surface-hover\);/);
|
|
749
749
|
expect(fills('progress', '.progress-bar--primary .progress-bar__fill')['background-color']).toMatch(/^#[0-9a-f]{6}$/i);
|
|
750
|
-
|
|
750
|
+
// 036 (F-11): the raw secondary-500 was 2.83:1 against the light track;
|
|
751
|
+
// secondary now reads the data-mark token (4.19 light, 4.05 dark).
|
|
752
|
+
expect(fills('progress', '.progress-bar--secondary .progress-bar__fill')['background-color']).toBe('var(--color-secondary-graphic)');
|
|
751
753
|
});
|
|
752
754
|
|
|
753
755
|
it('AC-9: kanban priorities, dependency relations, arrows and node borders read the inks', () => {
|
|
@@ -967,7 +969,8 @@ describe('Component pairings of 3.22.4 (request 034)', () => {
|
|
|
967
969
|
['nc', '.lc-nc__item--unread .lc-nc__item-priority--low', { 'background-image': flat('--color-surface-hover') }],
|
|
968
970
|
// F-2: the ring arcs take the progress-bar inks.
|
|
969
971
|
['ring', '.lc-progress-ring__value--primary', { stroke: 'var(--color-primary-500)' }],
|
|
970
|
-
|
|
972
|
+
// 036: secondary reads the data-mark token (dark secondary-600 was 1.07:1 from info).
|
|
973
|
+
['ring', '.lc-progress-ring__value--secondary', { stroke: 'var(--color-secondary-graphic)' }],
|
|
971
974
|
...['success', 'warning', 'error', 'info'].map((v): Row => ['ring', `.lc-progress-ring__value--${v}`, { stroke: ink(v) }]),
|
|
972
975
|
// F-3: subtle line tints, secondary line numbers.
|
|
973
976
|
['diff', '.lc-diff__line--added', { background: 'var(--color-success-subtle)' }],
|
|
@@ -1021,9 +1024,11 @@ describe('Component pairings of 3.22.4 (request 034)', () => {
|
|
|
1021
1024
|
// The dash style still tells the relations apart (not colour alone).
|
|
1022
1025
|
expect(depTs).toMatch(/\n {2}uses:\s*\{ color: '[^']+', dashed: true,/);
|
|
1023
1026
|
expect(depTs).toMatch(/\n {2}extends:\s*\{ color: '[^']+', dashed: true,/);
|
|
1024
|
-
//
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
+
// Follow-up F-9, done in request 036: `depends` reads the secondary text
|
|
1028
|
+
// (neutral-400 was 2.53:1 light) and the tree edges the field border
|
|
1029
|
+
// (neutral-300 was 1.47:1 light); their contrast is in the 036 block.
|
|
1030
|
+
expect(relationColor('depends')).toBe('var(--color-text-secondary)');
|
|
1031
|
+
expect(depTs.match(/color: 'var\(--color-field-border\)', dashed: false, isCrossRef: false/g)).toHaveLength(2);
|
|
1027
1032
|
});
|
|
1028
1033
|
|
|
1029
1034
|
// The shared status values of 3.22.3, per palette [light, dark] (AC-2).
|
|
@@ -1043,12 +1048,15 @@ describe('Component pairings of 3.22.4 (request 034)', () => {
|
|
|
1043
1048
|
* `+` (4.85 L, 5.17 D). Graphic minimum: the card border on hover and
|
|
1044
1049
|
* selected and the `uses` cross-reference line (3.75 L), the `uses` line
|
|
1045
1050
|
* (4.76 D). The terminal is always dark: 5.28 (debug level and meta).
|
|
1051
|
+
* Request 036: the dark ring secondary moved from the inverted
|
|
1052
|
+
* secondary-600 (8.35, 1.07:1 from info) to --color-secondary-graphic
|
|
1053
|
+
* (4.05), which is now the dark graphic minimum.
|
|
1046
1054
|
*/
|
|
1047
1055
|
const expected = {
|
|
1048
1056
|
text: [4.85, 5.17],
|
|
1049
|
-
graphic: [3.75, 4.
|
|
1057
|
+
graphic: [3.75, 4.05],
|
|
1050
1058
|
ncUnread: { high: [5.52, 5.55], urgent: [10.97, 8.37], low: [5.3, 5.99], category: [5.3, 5.99] },
|
|
1051
|
-
ringTrack: { primary: [3.96, 6.69], secondary: [4.19,
|
|
1059
|
+
ringTrack: { primary: [3.96, 6.69], secondary: [4.19, 4.05], success: [4.81, 6.15], warning: [5.47, 5.6], error: [11.43, 6.37], info: [9.22, 7.8] },
|
|
1052
1060
|
diff: {
|
|
1053
1061
|
numAdded: [6.91, 6.86], numRemoved: [6.58, 9.26], numContext: [7.23, 9.25],
|
|
1054
1062
|
plus: [4.85, 5.17], minus: [10.97, 7.21], contentAdded: [16.24, 9.75], contentRemoved: [15.46, 13.16],
|
|
@@ -1267,3 +1275,278 @@ describe('Component pairings of 3.22.4 (request 034)', () => {
|
|
|
1267
1275
|
expect(levels).toEqual([5.81, 7.78, 11.43, 6.19]);
|
|
1268
1276
|
});
|
|
1269
1277
|
});
|
|
1278
|
+
|
|
1279
|
+
describe('Component pairings of 3.23.1 (request 036)', () => {
|
|
1280
|
+
const lib = (path: string) => resolve(__dirname, '../lib', path);
|
|
1281
|
+
const sheets = {
|
|
1282
|
+
dl: compile(lib('description-list/description-list.component.scss')).css,
|
|
1283
|
+
nc: compile(lib('notification-center/notification-center.component.scss')).css,
|
|
1284
|
+
dep: compile(lib('dependency-viewer/dependency-viewer.component.scss')).css,
|
|
1285
|
+
log: compile(lib('log-viewer/log-viewer.component.scss')).css,
|
|
1286
|
+
progress: compile(lib('progress-bar/progress-bar.component.scss')).css,
|
|
1287
|
+
ring: compile(lib('progress-ring/progress-ring.component.scss')).css,
|
|
1288
|
+
};
|
|
1289
|
+
type Sheet = keyof typeof sheets;
|
|
1290
|
+
const depTs = readFileSync(lib('dependency-viewer/dependency-viewer.component.ts'), 'utf8');
|
|
1291
|
+
const depHtml = readFileSync(lib('dependency-viewer/dependency-viewer.component.html'), 'utf8');
|
|
1292
|
+
|
|
1293
|
+
/** Every rule as its selector list and body (`a, b { … }` names both). */
|
|
1294
|
+
const rulesOf = (css: string) =>
|
|
1295
|
+
[...css.matchAll(/([^{}]+)\{([^{}]*)\}/g)].map((m) => ({
|
|
1296
|
+
selectors: m[1].split(/,(?![^(]*\))/).map((s) => s.trim()),
|
|
1297
|
+
body: m[2],
|
|
1298
|
+
}));
|
|
1299
|
+
const decls = (body: string): Record<string, string> =>
|
|
1300
|
+
Object.fromEntries([...body.matchAll(/([\w-]+):\s*([^;]+);/g)].map((m) => [m[1], m[2].trim()]));
|
|
1301
|
+
const forcedBlock = /@media \(forced-colors: active\) \{((?:[^{}]*\{[^{}]*\})*)\s*\}/g;
|
|
1302
|
+
/**
|
|
1303
|
+
* The declarations of every rule that names `selector`, merged in source
|
|
1304
|
+
* order; rules in forced-colours blocks are left out (`Mark` is no colour).
|
|
1305
|
+
*/
|
|
1306
|
+
const fills = (sheet: Sheet, selector: string): Record<string, string> => {
|
|
1307
|
+
const found = rulesOf(sheets[sheet].replace(forcedBlock, '')).filter((r) => r.selectors.includes(selector));
|
|
1308
|
+
expect(found.length).toBeGreaterThan(0);
|
|
1309
|
+
return Object.assign({}, ...found.map((r) => decls(r.body)));
|
|
1310
|
+
};
|
|
1311
|
+
/** The body of the `@media (forced-colors: active)` blocks of a sheet. */
|
|
1312
|
+
const forced = (sheet: Sheet) => [...sheets[sheet].matchAll(forcedBlock)].map((m) => m[1]).join('\n');
|
|
1313
|
+
const relationColor = (relation: string) => {
|
|
1314
|
+
const found = depTs.match(new RegExp(`\\n ${relation}:\\s*\\{ color: '([^']+)'`));
|
|
1315
|
+
expect(found).not.toBeNull();
|
|
1316
|
+
return (found as RegExpMatchArray)[1];
|
|
1317
|
+
};
|
|
1318
|
+
|
|
1319
|
+
const secondary = 'var(--color-text-secondary)';
|
|
1320
|
+
const graphic = 'var(--color-secondary-graphic)';
|
|
1321
|
+
type Row = [Sheet, string, Record<string, string>];
|
|
1322
|
+
|
|
1323
|
+
const declared: Row[] = [
|
|
1324
|
+
// A (BA-10): the link and primary inks, a 2 px outline instead of the halo.
|
|
1325
|
+
['dl', '.lc-dl__value--primary', { color: 'var(--color-on-primary-subtle)', 'font-weight': 'var(--font-weight-semibold)' }],
|
|
1326
|
+
['dl', '.lc-dl__link', { color: 'var(--color-link)', 'text-decoration': 'none' }],
|
|
1327
|
+
['dl', '.lc-dl__link:hover', { color: 'var(--color-link-hover)', 'text-decoration': 'underline' }],
|
|
1328
|
+
['dl', '.lc-dl__row--clickable:focus-visible', { outline: '2px solid var(--color-primary-500)', 'outline-offset': '2px' }],
|
|
1329
|
+
// F-8: unread message and time in the secondary ink.
|
|
1330
|
+
['nc', '.lc-nc__item--unread .lc-nc__item-message', { color: secondary }],
|
|
1331
|
+
['nc', '.lc-nc__item--unread .lc-nc__item-time', { color: secondary }],
|
|
1332
|
+
// F-10: an opaque marker with its own ink.
|
|
1333
|
+
['log', '.lc-log-viewer__match', { 'background-color': 'var(--color-warning)', color: 'var(--color-on-warning)' }],
|
|
1334
|
+
['log', '.lc-log-viewer--terminal .lc-log-viewer__match', { 'background-color': '#f9e2af', color: '#1e1e2e' }],
|
|
1335
|
+
// F-13: gray is Overlay2 (Mocha) and Subtext1 (Latte).
|
|
1336
|
+
['log', '.ansi-gray', { color: '#9399b2' }],
|
|
1337
|
+
['log', ':root.light .lc-log-viewer--log .ansi-gray', { color: '#5c5f77' }],
|
|
1338
|
+
// F-11 and the ring: the secondary data-mark token.
|
|
1339
|
+
['progress', '.progress-bar--secondary .progress-bar__fill', { 'background-color': graphic }],
|
|
1340
|
+
['progress', '.progress-bar-circular--secondary .progress-bar-circular__fill', { stroke: graphic }],
|
|
1341
|
+
['ring', '.lc-progress-ring__value--secondary', { stroke: graphic }],
|
|
1342
|
+
];
|
|
1343
|
+
|
|
1344
|
+
it.each(declared)('AC-1…13: %s %s declares the design 036 values', (sheet, selector, expectedDecls) => {
|
|
1345
|
+
const found = fills(sheet, selector);
|
|
1346
|
+
for (const [property, value] of Object.entries(expectedDecls)) expect(found[property]).toBe(value);
|
|
1347
|
+
});
|
|
1348
|
+
|
|
1349
|
+
it('AC-2: the clickable row has no halo any more; forced colours draw the outline in Highlight', () => {
|
|
1350
|
+
const clickable = rulesOf(sheets.dl).filter((r) => r.selectors.some((s) => s.includes('lc-dl__row--clickable')));
|
|
1351
|
+
for (const r of clickable) expect(decls(r.body)['box-shadow']).toBeUndefined();
|
|
1352
|
+
expect(sheets.dl).not.toMatch(/color-mix/);
|
|
1353
|
+
expect(forced('dl')).toMatch(/\.lc-dl__row--clickable:focus-visible \{\s*outline-color: Highlight;\s*\}/);
|
|
1354
|
+
});
|
|
1355
|
+
|
|
1356
|
+
it('AC-9: forced colours paint every search match, the terminal one too, with Mark / MarkText', () => {
|
|
1357
|
+
expect(forced('log')).toMatch(
|
|
1358
|
+
/\.lc-log-viewer__match,\s*\.lc-log-viewer--terminal \.lc-log-viewer__match \{\s*background-color: Mark;\s*color: MarkText;\s*\}/,
|
|
1359
|
+
);
|
|
1360
|
+
});
|
|
1361
|
+
|
|
1362
|
+
it('AC-8: depends, the structural edges and both arrows read the secondary text; tree edges the field border', () => {
|
|
1363
|
+
expect(relationColor('depends')).toBe(secondary);
|
|
1364
|
+
expect(depTs).toContain(`color: edge.structural ? '${secondary}' : style.color,`);
|
|
1365
|
+
expect(depTs.match(/color: 'var\(--color-field-border\)', dashed: false, isCrossRef: false/g)).toHaveLength(2);
|
|
1366
|
+
for (const id of ['default', 'depends']) {
|
|
1367
|
+
expect(depHtml).toMatch(new RegExp(`<marker id="arrow-${id}"[^>]*><path [^>]*fill="var\\(--color-text-secondary\\)"/>`));
|
|
1368
|
+
}
|
|
1369
|
+
expect(depTs).not.toMatch(/--color-neutral-400/);
|
|
1370
|
+
expect(depHtml).not.toMatch(/--color-neutral-400/);
|
|
1371
|
+
// `depends` stays solid; the relations stay apart by dash and label too.
|
|
1372
|
+
expect(depTs).toMatch(/\n {2}depends:\s*\{ color: '[^']+', dashed: false,/);
|
|
1373
|
+
});
|
|
1374
|
+
|
|
1375
|
+
it('AC-12: the log tool buttons stay 28 × 28 (WCAG 2.5.8 by size)', () => {
|
|
1376
|
+
const btn = fills('log', '.lc-log-viewer__tool-btn');
|
|
1377
|
+
expect([btn.width, btn.height]).toEqual(['28px', '28px']);
|
|
1378
|
+
});
|
|
1379
|
+
|
|
1380
|
+
/**
|
|
1381
|
+
* Design 036 §5, floored, per palette [light, dark]. Pages: background,
|
|
1382
|
+
* surface, surface-2; a hovered row is --color-surface-hover over them; an
|
|
1383
|
+
* unread NC row is --color-surface-selected over surface and surface-2; the
|
|
1384
|
+
* progress track is --color-surface-hover over the pages.
|
|
1385
|
+
*/
|
|
1386
|
+
const expected = {
|
|
1387
|
+
dl: {
|
|
1388
|
+
linkPage: [5.94, 8.96], linkHover: [5.64, 7.92], linkHoverInkPage: [8.74, 10.53], linkHoverInkHover: [8.29, 9.3],
|
|
1389
|
+
primaryPage: [8.74, 7.57], primaryHover: [8.29, 6.69], ring: [4.17, 7.57],
|
|
1390
|
+
},
|
|
1391
|
+
ncUnread: [6.49, 7.05],
|
|
1392
|
+
dep: { dependsLabel: [7.55, 11.15], dependsLine: [7.55, 11.15], dependsCrossRef: [4.52, 7.55], dependsLegend: [7.23, 9.25], treeSurface: [4.83, 6.7], treeSurface2: [4.62, 5.56] },
|
|
1393
|
+
dependsVsUses: [1.29, 1.66],
|
|
1394
|
+
match: [7.85, 7.85],
|
|
1395
|
+
secondary: { track: [4.19, 4.05], page: [4.41, 4.59], vsInfo: [2.19, 1.92] },
|
|
1396
|
+
// The log variant's gray: Latte in light, Mocha in dark; plain surface and the worst line.
|
|
1397
|
+
ansiGray: { plain: [6.25, 6.11], worst: [4.63, 4.55] },
|
|
1398
|
+
};
|
|
1399
|
+
const floor = (n: number) => Math.floor(n * 100) / 100;
|
|
1400
|
+
|
|
1401
|
+
describe.each(palettes.map(([name, tokens], i) => [name, tokens, i] as const))('%s palette', (_palette, tokens, i) => {
|
|
1402
|
+
const c = (name: string) => color(tokens, name);
|
|
1403
|
+
const value = (text: string): Rgba => {
|
|
1404
|
+
const ref = text.match(/^var\((--[\w-]+)\)$/);
|
|
1405
|
+
return ref ? c(ref[1]) : parse(text);
|
|
1406
|
+
};
|
|
1407
|
+
const lowest = (fg: Rgba, bases: Rgba[]) => Math.min(...bases.map((bg) => ratio(over(fg, bg), bg)));
|
|
1408
|
+
const S = c('--color-surface');
|
|
1409
|
+
const S2 = c('--color-surface-2');
|
|
1410
|
+
const BG = c('--color-background');
|
|
1411
|
+
const pages = [BG, S, S2];
|
|
1412
|
+
const hovered = pages.map((p) => over(c('--color-surface-hover'), p));
|
|
1413
|
+
let cache: ReturnType<typeof measure> | undefined;
|
|
1414
|
+
/** Every §5 cell, measured once on first use (inside a test, not at collection). */
|
|
1415
|
+
const measured = () => (cache ??= measure());
|
|
1416
|
+
|
|
1417
|
+
function measure() {
|
|
1418
|
+
const dlInk = (selector: string) => value(fills('dl', selector).color);
|
|
1419
|
+
const ringInk = value(fills('dl', '.lc-dl__row--clickable:focus-visible').outline.replace(/^2px solid /, ''));
|
|
1420
|
+
const dl = {
|
|
1421
|
+
linkPage: lowest(dlInk('.lc-dl__link'), pages),
|
|
1422
|
+
linkHover: lowest(dlInk('.lc-dl__link'), hovered),
|
|
1423
|
+
linkHoverInkPage: lowest(dlInk('.lc-dl__link:hover'), pages),
|
|
1424
|
+
linkHoverInkHover: lowest(dlInk('.lc-dl__link:hover'), hovered),
|
|
1425
|
+
primaryPage: lowest(dlInk('.lc-dl__value--primary'), pages),
|
|
1426
|
+
primaryHover: lowest(dlInk('.lc-dl__value--primary'), hovered),
|
|
1427
|
+
// The outline sits 2 px outside the row, on the card or the page.
|
|
1428
|
+
ring: lowest(ringInk, pages),
|
|
1429
|
+
};
|
|
1430
|
+
|
|
1431
|
+
const unreadRows = [S, S2].map((row) => over(c('--color-surface-selected'), row));
|
|
1432
|
+
const ncUnread = Math.min(
|
|
1433
|
+
lowest(value(fills('nc', '.lc-nc__item--unread .lc-nc__item-message').color), unreadRows),
|
|
1434
|
+
lowest(value(fills('nc', '.lc-nc__item--unread .lc-nc__item-time').color), unreadRows),
|
|
1435
|
+
);
|
|
1436
|
+
|
|
1437
|
+
// Labels on their surface halo, lines on the viewer surface (cross-refs
|
|
1438
|
+
// at their opacity), legend lines on the legend's surface-2.
|
|
1439
|
+
const halo = value(fills('dep', '.dep-viewer__edge-label').stroke);
|
|
1440
|
+
const lineOpacity = Number(fills('dep', '.dep-viewer__edge--cross-ref').opacity);
|
|
1441
|
+
const legend = value(fills('dep', '.dep-viewer__legend').background);
|
|
1442
|
+
const depends = value(relationColor('depends'));
|
|
1443
|
+
const tree = c('--color-field-border');
|
|
1444
|
+
const dep = {
|
|
1445
|
+
dependsLabel: lowest(depends, [halo]),
|
|
1446
|
+
dependsLine: lowest(depends, [S]),
|
|
1447
|
+
dependsCrossRef: lowest([depends[0], depends[1], depends[2], depends[3] * lineOpacity], [S]),
|
|
1448
|
+
dependsLegend: lowest(depends, [legend]),
|
|
1449
|
+
treeSurface: lowest(tree, [S]),
|
|
1450
|
+
treeSurface2: lowest(tree, [S2]),
|
|
1451
|
+
};
|
|
1452
|
+
const dependsVsUses = ratio(depends, value(relationColor('uses')));
|
|
1453
|
+
|
|
1454
|
+
const mark = fills('log', '.lc-log-viewer__match');
|
|
1455
|
+
const match = ratio(value(mark.color), value(mark['background-color']));
|
|
1456
|
+
|
|
1457
|
+
const track = value(fills('progress', '.progress-bar__track')['background-color']);
|
|
1458
|
+
const bar = value(fills('progress', '.progress-bar--secondary .progress-bar__fill')['background-color']);
|
|
1459
|
+
const ringTrack = value(fills('ring', '.lc-progress-ring__track').stroke);
|
|
1460
|
+
const arc = (v: string) => value(fills('ring', `.lc-progress-ring__value--${v}`).stroke);
|
|
1461
|
+
const secondaryCells = {
|
|
1462
|
+
track: Math.min(lowest(bar, pages.map((p) => over(track, p))), lowest(arc('secondary'), pages.map((p) => over(ringTrack, p)))),
|
|
1463
|
+
page: Math.min(lowest(bar, pages), lowest(arc('secondary'), pages)),
|
|
1464
|
+
vsInfo: ratio(arc('secondary'), arc('info')),
|
|
1465
|
+
};
|
|
1466
|
+
|
|
1467
|
+
// The log variant: surface, the warn and error tints, each with and without hover.
|
|
1468
|
+
const logBg = value(fills('log', '.lc-log-viewer--log')['background-color']);
|
|
1469
|
+
const hover = parse(fills('log', '.lc-log-viewer__line:hover')['background-color']);
|
|
1470
|
+
const tintOf = (lv: string) => over(parse(fills('log', `.lc-log-viewer--log .lc-log-viewer__line--${lv}`)['background-color']), logBg);
|
|
1471
|
+
const logLines = [logBg, tintOf('warn'), tintOf('error')].flatMap((b) => [b, over(hover, b)]);
|
|
1472
|
+
const gray = parse(fills('log', i === 0 ? ':root.light .lc-log-viewer--log .ansi-gray' : '.ansi-gray').color);
|
|
1473
|
+
const ansiGray = { plain: lowest(gray, [logBg]), worst: lowest(gray, logLines) };
|
|
1474
|
+
|
|
1475
|
+
return { dl, ncUnread, dep, dependsVsUses, match, secondaryCells, ansiGray };
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
it('AC-1, AC-2: dl link and primary values reach 4.5:1 on the page and a hovered row; the focus ring 3:1', () => {
|
|
1479
|
+
const { dl } = measured();
|
|
1480
|
+
for (const key of Object.keys(dl) as (keyof typeof dl)[]) {
|
|
1481
|
+
expect([key, floor(dl[key])]).toEqual([key, expected.dl[key][i]]);
|
|
1482
|
+
}
|
|
1483
|
+
expect(Math.min(dl.linkPage, dl.linkHover, dl.linkHoverInkPage, dl.linkHoverInkHover, dl.primaryPage, dl.primaryHover)).toBeGreaterThanOrEqual(4.5);
|
|
1484
|
+
expect(dl.ring).toBeGreaterThanOrEqual(3);
|
|
1485
|
+
});
|
|
1486
|
+
|
|
1487
|
+
it('AC-7: the NC unread message and time reach 4.5:1 on every unread row', () => {
|
|
1488
|
+
const { ncUnread } = measured();
|
|
1489
|
+
expect(floor(ncUnread)).toBe(expected.ncUnread[i]);
|
|
1490
|
+
expect(ncUnread).toBeGreaterThanOrEqual(4.5);
|
|
1491
|
+
});
|
|
1492
|
+
|
|
1493
|
+
it('AC-8: the depends label reaches 4.5:1; depends, cross-ref, legend and tree lines 3:1', () => {
|
|
1494
|
+
const { dep, dependsVsUses } = measured();
|
|
1495
|
+
for (const key of Object.keys(dep) as (keyof typeof dep)[]) {
|
|
1496
|
+
expect([key, floor(dep[key])]).toEqual([key, expected.dep[key][i]]);
|
|
1497
|
+
}
|
|
1498
|
+
expect(dep.dependsLabel).toBeGreaterThanOrEqual(4.5);
|
|
1499
|
+
expect(Math.min(...Object.values(dep))).toBeGreaterThanOrEqual(3);
|
|
1500
|
+
expect(floor(dependsVsUses)).toBe(expected.dependsVsUses[i]);
|
|
1501
|
+
});
|
|
1502
|
+
|
|
1503
|
+
it('AC-9: the search match ink reaches 4.5:1 on its opaque marker', () => {
|
|
1504
|
+
const { match } = measured();
|
|
1505
|
+
expect(floor(match)).toBe(expected.match[i]);
|
|
1506
|
+
expect(match).toBeGreaterThanOrEqual(4.5);
|
|
1507
|
+
});
|
|
1508
|
+
|
|
1509
|
+
it('AC-10, AC-11: the secondary bar fill and ring arc reach 3:1 on the track and the page, 1.5:1 from info', () => {
|
|
1510
|
+
const { secondaryCells } = measured();
|
|
1511
|
+
for (const key of Object.keys(secondaryCells) as (keyof typeof secondaryCells)[]) {
|
|
1512
|
+
expect([key, floor(secondaryCells[key])]).toEqual([key, expected.secondary[key][i]]);
|
|
1513
|
+
}
|
|
1514
|
+
expect(Math.min(secondaryCells.track, secondaryCells.page)).toBeGreaterThanOrEqual(3);
|
|
1515
|
+
expect(secondaryCells.vsInfo).toBeGreaterThanOrEqual(1.5);
|
|
1516
|
+
});
|
|
1517
|
+
|
|
1518
|
+
it('AC-13: the log variant gray ANSI text reaches 4.5:1 on every line', () => {
|
|
1519
|
+
const { ansiGray } = measured();
|
|
1520
|
+
expect([floor(ansiGray.plain), floor(ansiGray.worst)]).toEqual([expected.ansiGray.plain[i], expected.ansiGray.worst[i]]);
|
|
1521
|
+
expect(ansiGray.worst).toBeGreaterThanOrEqual(4.5);
|
|
1522
|
+
});
|
|
1523
|
+
|
|
1524
|
+
it('AC-15: the shared status values keep their hex; the new token has the design 036 values', () => {
|
|
1525
|
+
const shared: Record<string, [string, string]> = {
|
|
1526
|
+
'--color-success': ['#8ea475', '#8ea475'],
|
|
1527
|
+
'--color-error': ['#9d0e0e', '#9d0e0e'],
|
|
1528
|
+
'--color-warning': ['#e1a040', '#e1a040'],
|
|
1529
|
+
'--color-info': ['#3b6588', '#3b6588'],
|
|
1530
|
+
'--color-secondary-graphic': ['#5a798c', '#7097af'],
|
|
1531
|
+
};
|
|
1532
|
+
for (const [name, hexes] of Object.entries(shared)) expect([name, hex(tokens, name)]).toEqual([name, hexes[i]]);
|
|
1533
|
+
});
|
|
1534
|
+
});
|
|
1535
|
+
|
|
1536
|
+
it('AC-9, AC-13: the terminal match reads 12.90:1 on every line; gray 4.5:1 on every line', () => {
|
|
1537
|
+
const T = parse(fills('log', '.lc-log-viewer--terminal')['background-color']);
|
|
1538
|
+
const hover = parse(fills('log', '.lc-log-viewer__line:hover')['background-color']);
|
|
1539
|
+
const tint = (lv: string) => over(parse(fills('log', `.lc-log-viewer--terminal .lc-log-viewer__line--${lv}`)['background-color']), T);
|
|
1540
|
+
const lines = [T, tint('warn'), tint('error')].flatMap((b) => [b, over(hover, b)]);
|
|
1541
|
+
const mark = fills('log', '.lc-log-viewer--terminal .lc-log-viewer__match');
|
|
1542
|
+
const gray = parse(fills('log', '.ansi-gray').color);
|
|
1543
|
+
const lowest = (fg: Rgba, bases: Rgba[]) => Math.min(...bases.map((bg) => ratio(fg, bg)));
|
|
1544
|
+
const terminal = {
|
|
1545
|
+
match: ratio(parse(mark.color), parse(mark['background-color'])),
|
|
1546
|
+
grayPlain: ratio(gray, T),
|
|
1547
|
+
grayWorst: lowest(gray, lines),
|
|
1548
|
+
};
|
|
1549
|
+
expect(Object.fromEntries(Object.entries(terminal).map(([k, v]) => [k, floor(v)]))).toEqual({ match: 12.9, grayPlain: 5.81, grayWorst: 4.61 });
|
|
1550
|
+
expect(Math.min(...Object.values(terminal))).toBeGreaterThanOrEqual(4.5);
|
|
1551
|
+
});
|
|
1552
|
+
});
|
|
@@ -62,6 +62,8 @@ export declare class AccordionContentDirective {
|
|
|
62
62
|
}
|
|
63
63
|
/** Where the disclosure chevron sits relative to the header content. */
|
|
64
64
|
export type AccordionChevronPosition = 'leading' | 'trailing';
|
|
65
|
+
/** Visual variant of `lc-accordion`. */
|
|
66
|
+
export type AccordionVariant = 'outlined' | 'flat' | 'plain';
|
|
65
67
|
/**
|
|
66
68
|
* Accordion component for collapsible content sections.
|
|
67
69
|
*
|
|
@@ -117,8 +119,16 @@ export declare class AccordionComponent {
|
|
|
117
119
|
readonly ariaLabel: import("@angular/core").InputSignal<string>;
|
|
118
120
|
/** Whether the accordion is expanded (two-way binding) */
|
|
119
121
|
readonly expanded: import("@angular/core").ModelSignal<boolean>;
|
|
120
|
-
/**
|
|
121
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Visual variant. `'outlined'`: border and surface. `'flat'`: no border or
|
|
124
|
+
* background; header and body keep their inset. `'plain'`: no border,
|
|
125
|
+
* background or inline inset, so the title, chevron and body line up with
|
|
126
|
+
* the content edge of the sheet or card around it; the hover background and
|
|
127
|
+
* focus ring reach 8 px past that edge (`--lc-accordion-header-bleed`), so
|
|
128
|
+
* keep that much room before a clipping edge.
|
|
129
|
+
* @default 'outlined'
|
|
130
|
+
*/
|
|
131
|
+
readonly variant: import("@angular/core").InputSignal<AccordionVariant>;
|
|
122
132
|
/** Size of the header */
|
|
123
133
|
readonly size: import("@angular/core").InputSignal<"sm" | "md" | "lg">;
|
|
124
134
|
/** Whether the accordion is disabled */
|