@lifecorner/angular-ui-kit 3.16.0 → 3.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -302,3 +302,60 @@ describe('Component pairings of 3.16 (request 022)', () => {
302
302
  });
303
303
  });
304
304
  });
305
+
306
+ // Request 021 (3.17): the lc-list status badges (12 px / 500, so 4.5:1) and the
307
+ // focus ring of a loading lc-button, which its 0.5 opacity fades. The token
308
+ // names come from the compiled component stylesheets, the values from the themes.
309
+ describe('Component pairings of 3.17 (request 021)', () => {
310
+ const listCss = compile(resolve(__dirname, '../lib/list/list.component.scss')).css;
311
+ const buttonCss = compile(resolve(__dirname, '../lib/button/button.component.scss')).css;
312
+
313
+ /** The background and ink token of a list badge variant (a fallback after the name is ignored). */
314
+ function badgeTokens(variant: string): [string, string] {
315
+ const body = listCss.match(new RegExp(`\\n\\.lc-list__badge--${variant} \\{([^}]*)\\}`))?.[1] ?? '';
316
+ const bg = body.match(/background-color: var\((--[\w-]+)/)?.[1] ?? '';
317
+ const ink = body.match(/\scolor: var\((--[\w-]+)/)?.[1] ?? '';
318
+ expect([bg, ink]).toEqual([expect.stringMatching(/^--color-/), expect.stringMatching(/^--color-/)]);
319
+ return [bg, ink];
320
+ }
321
+
322
+ /** Design 021 §5: the minimum over the bases, per palette [light, dark]. */
323
+ const badges: [string, [string, string], [number, number]][] = [
324
+ ['success', ['--color-success-subtle', '--color-on-success-subtle'], [4.85, 5.17]],
325
+ ['warning', ['--color-warning-subtle', '--color-on-warning-subtle'], [5.52, 4.61]],
326
+ ['error', ['--color-error-100', '--color-on-error-subtle'], [6.33, 7.17]],
327
+ ['primary', ['--color-primary-100', '--color-primary-700'], [7.85, 9.68]],
328
+ ['default', ['--color-surface-hover', '--color-text-secondary'], [6.87, 8.18]],
329
+ ];
330
+
331
+ describe.each(palettes.map(([name, tokens], i) => [name, tokens, i] as const))('%s palette', (_palette, tokens, i) => {
332
+ /** The grounds a list sits on: the page, the card surfaces and a hovered row (over the surface). */
333
+ const bases: Rgba[] = [
334
+ color(tokens, '--color-background'),
335
+ color(tokens, '--color-surface'),
336
+ over(color(tokens, '--color-surface-2'), color(tokens, '--color-surface')),
337
+ over(color(tokens, '--color-surface-hover'), color(tokens, '--color-surface')),
338
+ ].map((c) => over(c, color(tokens, '--color-background')));
339
+
340
+ it.each(badges)('AC-12: the %s list badge reaches 4.5:1 on every ground', (variant, pair, values) => {
341
+ expect(badgeTokens(variant)).toEqual(pair);
342
+ const [bg, ink] = pair;
343
+ const min = Math.min(
344
+ ...bases.map((base) => {
345
+ const fill = over(color(tokens, bg), base);
346
+ return ratio(over(color(tokens, ink), fill), fill);
347
+ }),
348
+ );
349
+ expect(min).toBeCloseTo(values[i], 2);
350
+ expect(min).toBeGreaterThanOrEqual(4.5);
351
+ });
352
+
353
+ it('AC-7: the ring of a focused loading button (--color-text-primary at 50 %) reaches 3:1 on the page and the surfaces', () => {
354
+ expect(buttonCss).toMatch(/\n\.btn\.btn-loading:focus-visible \{\s*outline-color: var\(--color-text-primary\);/);
355
+ const ink = color(tokens, '--color-text-primary');
356
+ for (const base of bases.slice(0, 3)) {
357
+ expect(ratio(over([ink[0], ink[1], ink[2], 0.5], base), base)).toBeGreaterThanOrEqual(3);
358
+ }
359
+ });
360
+ });
361
+ });
@@ -28,7 +28,28 @@ export declare class ButtonComponent {
28
28
  */
29
29
  readonly tone: import("@angular/core").InputSignal<ButtonTone>;
30
30
  readonly size: import("@angular/core").InputSignal<ButtonSize>;
31
+ /**
32
+ * Natively disabled: the button leaves the focus order and ignores clicks.
33
+ * For a temporary busy state that keeps focus, use `loading`.
34
+ * @default false
35
+ */
31
36
  readonly disabled: import("@angular/core").InputSignal<boolean>;
37
+ /**
38
+ * Shows a spinner in place of the icon slots and makes the button
39
+ * unavailable without removing it from the focus order (3.17). The inner
40
+ * `<button>` gets `aria-disabled="true"` and `aria-busy="true"` instead of
41
+ * the native `disabled`, so a focused button keeps focus. While it is
42
+ * loading, click, Enter and Space are ignored: `clicked` is not emitted, the
43
+ * click event stops at the button (a `(click)` on the host doesn't fire),
44
+ * and a `type="submit"`/`"reset"` button doesn't submit or reset its form.
45
+ * The look is unchanged: spinner, 50 % opacity, no hover. Screen readers may
46
+ * announce the state change ("unavailable"/"dimmed"), but the button doesn't
47
+ * announce the outcome: the page does that, for example with a polite live
48
+ * region ("USM wird geladen.", then the result). `disabledReason` also
49
+ * applies while loading. If `disabled` is set too, the native `disabled`
50
+ * wins.
51
+ * @default false
52
+ */
32
53
  readonly loading: import("@angular/core").InputSignal<boolean>;
33
54
  readonly iconOnly: import("@angular/core").InputSignal<boolean>;
34
55
  readonly fullWidth: import("@angular/core").InputSignal<boolean>;
@@ -72,7 +93,13 @@ export declare class ButtonComponent {
72
93
  * `title` otherwise.
73
94
  */
74
95
  readonly effectiveTitle: import("@angular/core").Signal<string | null>;
75
- handleClick(): void;
96
+ /**
97
+ * Emits `clicked` unless the button is disabled or loading. While loading
98
+ * (and not natively disabled) the event is cancelled and stopped, so a form
99
+ * isn't submitted and a host `(click)` doesn't fire. The parameter is
100
+ * optional, so callers without an argument still work.
101
+ */
102
+ handleClick(event?: Event): void;
76
103
  handleFocus(): void;
77
104
  handleBlur(): void;
78
105
  focus(): void;
@@ -12,6 +12,13 @@ export type ProgressBarVariant = 'linear' | 'circular';
12
12
  * - Animated value transitions
13
13
  * - Accessible with ARIA progressbar role
14
14
  *
15
+ * The bar is a visual aid; the text next to it carries the meaning. Write the
16
+ * status as text ('USM wird geladen …') and announce changes from a live
17
+ * region (`role="status"`). Screen readers don't announce a progress bar's
18
+ * changes by themselves. Give `ariaLabel` the same words as the status. Under
19
+ * `forced-colors: active` the fill is `Highlight`, the linear track gets a
20
+ * 1 px `CanvasText` outline and the circle's track is `GrayText` (3.17).
21
+ *
15
22
  * @example
16
23
  * ```html
17
24
  * <lc-progress-bar [value]="75" color="primary" size="md"></lc-progress-bar>
@@ -57,7 +64,11 @@ export declare class ProgressBarComponent {
57
64
  */
58
65
  inline: import("@angular/core").InputSignal<boolean>;
59
66
  /**
60
- * Whether the progress is indeterminate (animated, no fixed value).
67
+ * Progress of unknown length: no value (`aria-valuenow` is absent) and no
68
+ * label. The linear bar moves a 40 % segment across the track, and the
69
+ * circle spins. Under `prefers-reduced-motion: reduce` nothing moves: the
70
+ * linear bar shows a full-width striped fill and the circle a dashed ring,
71
+ * so it still reads as busy, not as a value (3.17).
61
72
  * @default false
62
73
  */
63
74
  indeterminate: import("@angular/core").InputSignal<boolean>;
@@ -37,7 +37,11 @@ export interface TableColumn {
37
37
  width?: string;
38
38
  /** Optional CSS class(es) applied to both th and td cells */
39
39
  cssClass?: string;
40
- /** Optional CSS class(es) for td cells only (string or resolver callback) */
40
+ /**
41
+ * Optional CSS class(es) for td cells only (string or resolver callback).
42
+ * A class colour or font size loses to the kit's cell rule; set them with
43
+ * `cellStyle`.
44
+ */
41
45
  cellClass?: TableCellClass;
42
46
  /** Optional inline styles for td cells only (object or resolver callback) */
43
47
  cellStyle?: TableCellStyle;
@@ -49,7 +53,21 @@ export interface TableColumn {
49
53
  editType?: 'text' | 'number' | 'select';
50
54
  /** Options for select edit type */
51
55
  editOptions?: string[];
56
+ /**
57
+ * Horizontal alignment of the column's header and cells. `end` aligns both
58
+ * at the end edge (right in LTR) and sets `font-variant-numeric:
59
+ * tabular-nums`, for amounts, counts and percentages. A sort arrow then sits
60
+ * before the label, so the label stays flush with the figures. Adds
61
+ * `lc-table__cell--end` to the `th` and every `td`. It wins over a
62
+ * `cellClass` that sets `text-align`; use `cellStyle` to override it. A
63
+ * custom `lcTableCell` template inherits the alignment, but a flex or block
64
+ * child needs its own `justify-content: flex-end`. (3.17)
65
+ * @default 'start'
66
+ */
67
+ align?: TableColumnAlign;
52
68
  }
69
+ /** Horizontal alignment of a table column (3.17). */
70
+ export type TableColumnAlign = 'start' | 'end';
53
71
  /**
54
72
  * A row-level action rendered in the table's actions column (e.g. Freigeben, Ablehnen).
55
73
  * Action button clicks never trigger the row's `rowClick` output.
@@ -22,7 +22,9 @@ export interface Toast extends Required<Omit<ToastConfig, 'action'>> {
22
22
  * Toast service for showing ephemeral notifications.
23
23
  *
24
24
  * The toasts are rendered by `<lc-toast-outlet />`, which the application
25
- * places once (e.g. in its shell); without it nothing is shown.
25
+ * places once (e.g. in its shell); without it nothing is shown. The options,
26
+ * their defaults, the timing and how a toast is announced to screen readers
27
+ * are documented under *Feedback/Toast Outlet* (3.17).
26
28
  *
27
29
  * @example
28
30
  * ```typescript