@lifecorner/angular-ui-kit 3.18.0 → 3.19.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-combobox.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-combobox.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-document-viewer.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-document-viewer.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-drawer.mjs +4 -4
- package/fesm2022/lifecorner-angular-ui-kit-drawer.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-field-group.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-field-group.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-file-upload.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-file-upload.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-gallery.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-gallery.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-menu.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-menu.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-notification-center.mjs +4 -4
- package/fesm2022/lifecorner-angular-ui-kit-notification-center.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-table.mjs +31 -8
- package/fesm2022/lifecorner-angular-ui-kit-table.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-toast.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-toast.mjs.map +1 -1
- package/package.json +1 -1
- package/src/styles/theme-contrast.spec.ts +147 -0
- package/types/lifecorner-angular-ui-kit-table.d.ts +18 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { compile } from 'sass';
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
2
3
|
import { resolve } from 'path';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -359,3 +360,149 @@ describe('Component pairings of 3.17 (request 021)', () => {
|
|
|
359
360
|
});
|
|
360
361
|
});
|
|
361
362
|
});
|
|
363
|
+
|
|
364
|
+
// Request 024 (3.19): the lc-menu danger item (020 review S2: --color-error was
|
|
365
|
+
// 2.06:1 on the dark menu) and the restyled lc-table pager. The token names
|
|
366
|
+
// come from the compiled stylesheets, the values from the themes.
|
|
367
|
+
describe('Component pairings of 3.19 (request 024)', () => {
|
|
368
|
+
const menuScss = readFileSync(resolve(__dirname, '../lib/menu/menu.component.scss'), 'utf8');
|
|
369
|
+
const menuCss = compile(resolve(__dirname, '../lib/menu/menu.component.scss')).css;
|
|
370
|
+
const tableCss = compile(resolve(__dirname, '../lib/table/table.component.scss')).css;
|
|
371
|
+
const body = (css: string, selector: string) => {
|
|
372
|
+
const at = css.indexOf(`\n${selector} {`);
|
|
373
|
+
expect(at).toBeGreaterThan(-1);
|
|
374
|
+
return css.slice(at, css.indexOf('}', at));
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
it('AC-8: the danger item reads --color-text-error, its hover --color-error-subtle; no raw colour', () => {
|
|
378
|
+
expect(body(menuCss, '.lc-menu__item--danger')).toMatch(/\scolor: var\(--color-text-error\);/);
|
|
379
|
+
expect(body(menuCss, '.lc-menu__item--danger:hover:not(.lc-menu__item--disabled)')).toMatch(
|
|
380
|
+
/background-color: var\(--color-error-subtle\);/,
|
|
381
|
+
);
|
|
382
|
+
expect(menuCss).not.toMatch(/--danger--disabled/);
|
|
383
|
+
expect(menuScss).not.toMatch(/rgba\(|#[0-9a-f]{3,8}\b/i);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it('AC-4: the pager reads the field border, the second surface and the kit ring', () => {
|
|
387
|
+
const btn = body(tableCss, '.lc-table-pagination__btn');
|
|
388
|
+
expect(btn).toMatch(/border: 1px solid var\(--color-field-border\);/);
|
|
389
|
+
expect(btn).toMatch(/background-color: var\(--color-surface-2\);/);
|
|
390
|
+
expect(btn).toMatch(/\scolor: var\(--color-text-primary\);/);
|
|
391
|
+
expect(body(tableCss, '.lc-table-pagination__btn:focus-visible')).toMatch(/outline: 2px solid var\(--color-primary-500\);/);
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
/** Design 024 §5, per palette [light, dark]: the minimum over both panel ends. */
|
|
395
|
+
const expected = { dangerRest: [12.05, 7.21], dangerHover: [10.98, 7.21], dangerFocus: [11.44, 6.37] };
|
|
396
|
+
|
|
397
|
+
describe.each(palettes.map(([name, tokens], i) => [name, tokens, i] as const))('%s palette', (_palette, tokens, i) => {
|
|
398
|
+
const page = color(tokens, '--color-background');
|
|
399
|
+
/** A token over `base` (translucent ones composited), on the opaque page. */
|
|
400
|
+
const on = (name: string, base: Rgba = page) => over(color(tokens, name), base);
|
|
401
|
+
/** The menu panel's ends: --color-surface and --color-surface-2 (its gradient runs between them). */
|
|
402
|
+
const panels = [on('--color-surface'), on('--color-surface-2', on('--color-surface'))];
|
|
403
|
+
const ink = (fill: Rgba) => ratio(on('--color-text-error', fill), fill);
|
|
404
|
+
|
|
405
|
+
it('AC-8: danger text at rest, on hover and on focus reaches 4.5:1 on the menu', () => {
|
|
406
|
+
const rest = Math.min(...panels.map(ink));
|
|
407
|
+
const hover = Math.min(...panels.map((p) => ink(on('--color-error-subtle', p))));
|
|
408
|
+
const focus = Math.min(...panels.map((p) => ink(on('--color-surface-hover', p))));
|
|
409
|
+
expect(rest).toBeCloseTo(expected.dangerRest[i], 2);
|
|
410
|
+
expect(hover).toBeCloseTo(expected.dangerHover[i], 2);
|
|
411
|
+
expect(focus).toBeCloseTo(expected.dangerFocus[i], 2);
|
|
412
|
+
expect(Math.min(rest, hover, focus)).toBeGreaterThanOrEqual(4.5);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
it('AC-8: the focus ring (--color-primary-500) reaches 3:1 on the focused danger item', () => {
|
|
416
|
+
for (const p of panels) {
|
|
417
|
+
const fill = on('--color-surface-hover', p);
|
|
418
|
+
expect(ratio(on('--color-primary-500', fill), fill)).toBeGreaterThanOrEqual(3);
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
it.each(['--color-background', '--color-surface'])('AC-4: pager border 3:1, ring 3:1 and glyph 4.5:1 on %s', (ground) => {
|
|
423
|
+
const g = on(ground);
|
|
424
|
+
expect(ratio(on('--color-field-border', g), g)).toBeGreaterThanOrEqual(3);
|
|
425
|
+
expect(ratio(on('--color-primary-500', g), g)).toBeGreaterThanOrEqual(3);
|
|
426
|
+
const fill = on('--color-surface-2', g);
|
|
427
|
+
expect(ratio(on('--color-text-primary', fill), fill)).toBeGreaterThanOrEqual(4.5);
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
// Request 025 (3.19.1): the lc-notification-center filter chips and unread
|
|
433
|
+
// badge (024 review finding 4, axe color-contrast: white on the level colours
|
|
434
|
+
// was 1.89 to 4.37:1, the badge 1.99:1 in dark).
|
|
435
|
+
describe('Component pairings of 3.19.1 (request 025)', () => {
|
|
436
|
+
const ncCss = compile(resolve(__dirname, '../lib/notification-center/notification-center.component.scss')).css;
|
|
437
|
+
const body = (selector: string) => {
|
|
438
|
+
const at = ncCss.indexOf(`\n${selector} {`);
|
|
439
|
+
expect(at).toBeGreaterThan(-1);
|
|
440
|
+
return ncCss.slice(at, ncCss.indexOf('}', at));
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
it('AC-7: the chips and the badge read tokens only; one pressed style for every level', () => {
|
|
444
|
+
expect(body('.lc-nc__filter')).toMatch(/\scolor: var\(--color-text-secondary\);/);
|
|
445
|
+
expect(body('.lc-nc__filter:hover:not(.lc-nc__filter--active)')).toMatch(/background: var\(--color-surface-2\);/);
|
|
446
|
+
const active = body('.lc-nc__filter--active');
|
|
447
|
+
expect(active).toMatch(/background: var\(--color-primary-fill\);/);
|
|
448
|
+
expect(active).toMatch(/\scolor: var\(--color-on-primary\);/);
|
|
449
|
+
expect(active).toMatch(/border-color: var\(--color-primary-500\);/);
|
|
450
|
+
const badge = body('.lc-nc__badge');
|
|
451
|
+
expect(badge).toMatch(/background: var\(--color-error-fill\);/);
|
|
452
|
+
expect(badge).toMatch(/\scolor: var\(--color-on-error\);/);
|
|
453
|
+
// No per-level pressed colours, and no raw colour in the chip or badge rules.
|
|
454
|
+
expect(ncCss).not.toMatch(/\.lc-nc__filter--(error|warning|success|info)\.lc-nc__filter--active/);
|
|
455
|
+
const chipRules = [...ncCss.matchAll(/(^|\n)([^{}\n]*\.lc-nc__(filter|badge)[^{}]*)\{([^{}]*)\}/g)];
|
|
456
|
+
expect(chipRules.length).toBeGreaterThanOrEqual(4);
|
|
457
|
+
for (const rule of chipRules) expect(rule[4]).not.toMatch(/#[0-9a-f]{3,8}\b|rgba?\(|:\s*white\b/i);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
it('AC-13: in forced colours the pressed chip keeps a Highlight outline unless it is focused', () => {
|
|
461
|
+
const at = ncCss.indexOf('@media (forced-colors: active)');
|
|
462
|
+
expect(at).toBeGreaterThan(-1);
|
|
463
|
+
const media = ncCss.slice(at, ncCss.indexOf('}\n}', at));
|
|
464
|
+
expect(media).toMatch(/\.lc-nc__filter--active:not\(:focus-visible\) \{/);
|
|
465
|
+
expect(media).toMatch(/outline: 2px solid Highlight;/);
|
|
466
|
+
expect(media).toMatch(/outline-offset: 1px;/);
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
/** Design 025 §5, per palette [light, dark]: the minimum over both panel ends. */
|
|
470
|
+
const expected = { rest: [7.23, 9.26], active: [6.21, 6.21], rim: [4.18, 7.58], badge: [8.39, 8.39] };
|
|
471
|
+
|
|
472
|
+
describe.each(palettes.map(([name, tokens], i) => [name, tokens, i] as const))('%s palette', (_palette, tokens, i) => {
|
|
473
|
+
const page = color(tokens, '--color-background');
|
|
474
|
+
const on = (name: string, base: Rgba = page) => over(color(tokens, name), base);
|
|
475
|
+
/** The panel's ends: --color-surface and --color-surface-2 (its gradient runs between them). */
|
|
476
|
+
const panels = [on('--color-surface'), on('--color-surface-2', on('--color-surface'))];
|
|
477
|
+
|
|
478
|
+
it('AC-7: chip text at rest and on hover reaches 4.5:1 on the panel', () => {
|
|
479
|
+
const rest = Math.min(...panels.map((p) => ratio(on('--color-text-secondary', p), p)));
|
|
480
|
+
const hover = Math.min(
|
|
481
|
+
...panels.map((p) => {
|
|
482
|
+
const fill = on('--color-surface-2', p);
|
|
483
|
+
return ratio(on('--color-text-secondary', fill), fill);
|
|
484
|
+
}),
|
|
485
|
+
);
|
|
486
|
+
expect(rest).toBeCloseTo(expected.rest[i], 2);
|
|
487
|
+
expect(hover).toBeCloseTo(expected.rest[i], 2);
|
|
488
|
+
expect(Math.min(rest, hover)).toBeGreaterThanOrEqual(4.5);
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
it('AC-7: the pressed chip: text 4.5:1 on its fill, rim 3:1 on the panel', () => {
|
|
492
|
+
const fill = on('--color-primary-fill');
|
|
493
|
+
const text = ratio(on('--color-on-primary', fill), fill);
|
|
494
|
+
const rim = Math.min(...panels.map((p) => ratio(on('--color-primary-500', p), p)));
|
|
495
|
+
expect(text).toBeCloseTo(expected.active[i], 2);
|
|
496
|
+
expect(rim).toBeCloseTo(expected.rim[i], 2);
|
|
497
|
+
expect(text).toBeGreaterThanOrEqual(4.5);
|
|
498
|
+
expect(rim).toBeGreaterThanOrEqual(3);
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
it('AC-7: the unread badge reaches 4.5:1', () => {
|
|
502
|
+
const fill = on('--color-error-fill');
|
|
503
|
+
const badge = ratio(on('--color-on-error', fill), fill);
|
|
504
|
+
expect(badge).toBeCloseTo(expected.badge[i], 2);
|
|
505
|
+
expect(badge).toBeGreaterThanOrEqual(4.5);
|
|
506
|
+
});
|
|
507
|
+
});
|
|
508
|
+
});
|
|
@@ -39,8 +39,8 @@ export interface TableColumn {
|
|
|
39
39
|
cssClass?: string;
|
|
40
40
|
/**
|
|
41
41
|
* Optional CSS class(es) for td cells only (string or resolver callback).
|
|
42
|
-
*
|
|
43
|
-
* `cellStyle
|
|
42
|
+
* Since 3.19 a class colour or font size wins over the kit's cell defaults;
|
|
43
|
+
* `cellStyle` still wins over the class.
|
|
44
44
|
*/
|
|
45
45
|
cellClass?: TableCellClass;
|
|
46
46
|
/** Optional inline styles for td cells only (object or resolver callback) */
|
|
@@ -274,6 +274,12 @@ export declare class TableComponent {
|
|
|
274
274
|
pageSize: import("@angular/core").InputSignal<number>;
|
|
275
275
|
/** Available page size options */
|
|
276
276
|
pageSizeOptions: import("@angular/core").InputSignal<number[]>;
|
|
277
|
+
/**
|
|
278
|
+
* Pagination: the text after the number in each page-size option
|
|
279
|
+
* (`10 / page`). German: `'/ Seite'`. (3.19)
|
|
280
|
+
* @default '/ page'
|
|
281
|
+
*/
|
|
282
|
+
pageSizeLabel: import("@angular/core").InputSignal<string>;
|
|
277
283
|
/** Enable row selection checkboxes */
|
|
278
284
|
selectable: import("@angular/core").InputSignal<boolean>;
|
|
279
285
|
/** Enable per-column text filters */
|
|
@@ -418,6 +424,11 @@ export declare class TableComponent {
|
|
|
418
424
|
value: number;
|
|
419
425
|
label: string;
|
|
420
426
|
}[]>;
|
|
427
|
+
/**
|
|
428
|
+
* Size of the pagination controls: the page-size select's `size` and the
|
|
429
|
+
* `lc-table-pagination--<size>` class that sizes prev/next to match it.
|
|
430
|
+
*/
|
|
431
|
+
protected readonly paginationSize: import("@angular/core").Signal<TableSize>;
|
|
421
432
|
/**
|
|
422
433
|
* Computed CSS classes for the table element
|
|
423
434
|
*/
|
|
@@ -608,6 +619,11 @@ export declare class TableComponent {
|
|
|
608
619
|
"required": false;
|
|
609
620
|
"isSignal": true;
|
|
610
621
|
};
|
|
622
|
+
"pageSizeLabel": {
|
|
623
|
+
"alias": "pageSizeLabel";
|
|
624
|
+
"required": false;
|
|
625
|
+
"isSignal": true;
|
|
626
|
+
};
|
|
611
627
|
"selectable": {
|
|
612
628
|
"alias": "selectable";
|
|
613
629
|
"required": false;
|