@eagami/ui 5.19.0 → 5.21.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.
- package/fesm2022/eagami-ui.mjs +428 -255
- package/fesm2022/eagami-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/src/styles/_mixins.scss +66 -0
- package/src/styles/wcag-floors.spec.ts +122 -0
- package/types/eagami-ui.d.ts +52 -33
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eagami/ui",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.21.0",
|
|
4
4
|
"description": "Lightweight, accessible, themeable Angular UI component library and icon set built on CSS custom properties",
|
|
5
5
|
"author": "Michal Wiraszka <michal@eagami.com>",
|
|
6
6
|
"license": "MIT",
|
package/src/styles/_mixins.scss
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
// @use '../../styles/mixins' as ea;
|
|
3
3
|
// .ea-foo__close { @include ea.icon-button; }
|
|
4
4
|
|
|
5
|
+
// WCAG 2.2 SC 2.5.8 Target Size (Minimum), Level AA. Any pointer target the
|
|
6
|
+
// library ships has to reach this in at least one dimension pair, or qualify
|
|
7
|
+
// for one of the SC's exceptions (inline, spacing, essential).
|
|
8
|
+
$target-size-min: 24px;
|
|
9
|
+
|
|
5
10
|
// Standard focus indicator. The ring is a soft box-shadow halo, but box-shadow
|
|
6
11
|
// is dropped in forced-colors (Windows High Contrast) mode, which would leave
|
|
7
12
|
// keyboard users with no visible focus. Pair the halo with a real outline that
|
|
@@ -25,6 +30,46 @@
|
|
|
25
30
|
}
|
|
26
31
|
}
|
|
27
32
|
|
|
33
|
+
// A readonly field takes no input, so it offers a pointer nothing: no ring on
|
|
34
|
+
// click, no icon hover, no pointer cursor. Keyboard focus still has to be
|
|
35
|
+
// visible, so the border alone picks up the focus colour, without the halo.
|
|
36
|
+
@mixin readonly-focus-cue {
|
|
37
|
+
border-color: var(--color-border-focus);
|
|
38
|
+
box-shadow: none;
|
|
39
|
+
|
|
40
|
+
// Border colour is unreliable in forced-colors, so the ring's outline stands
|
|
41
|
+
// in there, matching what `focus-ring` paints for an editable field
|
|
42
|
+
@media (forced-colors: active) {
|
|
43
|
+
outline: 2px solid Highlight;
|
|
44
|
+
outline-offset: 2px;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@mixin readonly-field {
|
|
49
|
+
&:has(:focus-visible) {
|
|
50
|
+
@include readonly-focus-cue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
button {
|
|
54
|
+
cursor: default;
|
|
55
|
+
|
|
56
|
+
&:hover {
|
|
57
|
+
background-color: transparent;
|
|
58
|
+
color: var(--color-text-secondary);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// `readonly-field` for a control whose root is the focusable element itself: it
|
|
64
|
+
// keeps the quiet keyboard cue but stops offering to be pressed or typed into.
|
|
65
|
+
@mixin readonly-control {
|
|
66
|
+
cursor: default;
|
|
67
|
+
|
|
68
|
+
&:focus-visible {
|
|
69
|
+
@include readonly-focus-cue;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
28
73
|
// Hides an element visually while keeping it in the accessibility tree, so
|
|
29
74
|
// screen readers still announce it. The clip pattern is used instead of
|
|
30
75
|
// `display: none` or `visibility: hidden`, which would remove it entirely.
|
|
@@ -47,6 +92,8 @@
|
|
|
47
92
|
// it reads clearly inside the box regardless of how much padding the icon's own
|
|
48
93
|
// viewBox carries (the feather `x`, for instance, only fills its middle half).
|
|
49
94
|
@mixin icon-button {
|
|
95
|
+
// Anchors the grown pointer target below
|
|
96
|
+
position: relative;
|
|
50
97
|
display: inline-flex;
|
|
51
98
|
align-items: center;
|
|
52
99
|
justify-content: center;
|
|
@@ -67,6 +114,25 @@
|
|
|
67
114
|
font-size: 1.25em;
|
|
68
115
|
}
|
|
69
116
|
|
|
117
|
+
// The visible box is deliberately small on the dense tiers (17.5px at 2xs,
|
|
118
|
+
// 21px at xs), which is under the 24px WCAG 2.2 SC 2.5.8 target minimum.
|
|
119
|
+
// SC 2.5.8 measures the interactive target rather than the painted control,
|
|
120
|
+
// so the target is grown here and the visuals are left alone.
|
|
121
|
+
//
|
|
122
|
+
// A layout that stacks or abuts these buttons closer than the minimum must
|
|
123
|
+
// opt out via `--ea-icon-button-target: 0`, because grown targets that
|
|
124
|
+
// overlap steal each other's clicks, which is worse than the undersized
|
|
125
|
+
// targets the SC's spacing exception already covers.
|
|
126
|
+
&::after {
|
|
127
|
+
content: '';
|
|
128
|
+
position: absolute;
|
|
129
|
+
top: 50%;
|
|
130
|
+
left: 50%;
|
|
131
|
+
width: max(100%, var(--ea-icon-button-target, #{$target-size-min}));
|
|
132
|
+
height: max(100%, var(--ea-icon-button-target, #{$target-size-min}));
|
|
133
|
+
transform: translate(-50%, -50%);
|
|
134
|
+
}
|
|
135
|
+
|
|
70
136
|
&:hover {
|
|
71
137
|
background-color: var(--color-state-hover);
|
|
72
138
|
color: var(--color-text-primary);
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { readFileSync, readdirSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Source-level guards for the accessibility floors the library commits to.
|
|
7
|
+
*
|
|
8
|
+
* These cannot be covered by the per-component axe specs: jsdom has no layout,
|
|
9
|
+
* so nothing at runtime can measure a rendered target box or a computed
|
|
10
|
+
* font-size. The floors are therefore asserted against the stylesheets that
|
|
11
|
+
* define them. Both floors regressed silently once, when the `2xs` tier scaled
|
|
12
|
+
* every em-derived dimension down a step without anything failing.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const SRC = process.cwd();
|
|
16
|
+
|
|
17
|
+
function read(relativePath: string): string {
|
|
18
|
+
return readFileSync(join(SRC, relativePath), 'utf8');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function componentStylesheets(): { name: string; css: string }[] {
|
|
22
|
+
const lib = join(SRC, 'src/lib');
|
|
23
|
+
return readdirSync(lib, { withFileTypes: true })
|
|
24
|
+
.filter(entry => entry.isDirectory())
|
|
25
|
+
.flatMap(dir =>
|
|
26
|
+
readdirSync(join(lib, dir.name))
|
|
27
|
+
.filter(file => file.endsWith('.component.scss'))
|
|
28
|
+
.map(file => ({
|
|
29
|
+
name: `${dir.name}/${file}`,
|
|
30
|
+
css: readFileSync(join(lib, dir.name, file), 'utf8'),
|
|
31
|
+
})),
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Font-size in px of the smallest tier, from the typography tokens. */
|
|
36
|
+
const SMALLEST_TIER_PX = 10;
|
|
37
|
+
|
|
38
|
+
describe('WCAG floors', () => {
|
|
39
|
+
describe('SC 2.5.8 Target Size (Minimum)', () => {
|
|
40
|
+
const mixins = read('src/styles/_mixins.scss');
|
|
41
|
+
|
|
42
|
+
it('declares the 24px minimum as a single shared constant', () => {
|
|
43
|
+
expect(mixins).toMatch(/\$target-size-min:\s*24px;/);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('grows the shared icon-button target to that minimum', () => {
|
|
47
|
+
const mixin = mixins.slice(mixins.indexOf('@mixin icon-button'));
|
|
48
|
+
const body = mixin.slice(0, mixin.indexOf('\n}\n'));
|
|
49
|
+
|
|
50
|
+
// The painted box stays small on the dense tiers, so the target has to be
|
|
51
|
+
// grown independently of width/height, defaulting to the shared minimum
|
|
52
|
+
expect(body).toContain('position: relative');
|
|
53
|
+
expect(body).toMatch(
|
|
54
|
+
/width:\s*max\(100%,\s*var\(--ea-icon-button-target,\s*#\{\$target-size-min\}\)\)/,
|
|
55
|
+
);
|
|
56
|
+
expect(body).toMatch(
|
|
57
|
+
/height:\s*max\(100%,\s*var\(--ea-icon-button-target,\s*#\{\$target-size-min\}\)\)/,
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('makes a component that shrinks the box decide about the grown target', () => {
|
|
62
|
+
// A box smaller than the minimum either grows its target or opts out; it
|
|
63
|
+
// must not silently keep a 24px target that can overlap its neighbour
|
|
64
|
+
const shrunk = componentStylesheets().filter(({ css }) =>
|
|
65
|
+
/--ea-icon-button-size:\s*(0|1(\.\d+)?)em/.test(css),
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// Zero matches is a valid state: it means nothing currently shrinks the
|
|
69
|
+
// box below the minimum, which is the outcome this rule is steering toward
|
|
70
|
+
for (const { name, css } of shrunk) {
|
|
71
|
+
expect(`${name}: ${/--ea-icon-button-target:/.test(css)}`).toBe(`${name}: true`);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('routes every icon button through the mixin rather than hand-rolling the box', () => {
|
|
76
|
+
const handRolled = componentStylesheets().filter(({ css }) =>
|
|
77
|
+
/\.ea-[a-z-]+__(close|clear|dismiss)\s*\{[^}]*\bwidth:/.test(css),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
expect(handRolled.map(f => f.name)).toEqual([]);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('Legible floors for field sub-text', () => {
|
|
85
|
+
it('floors the field label at 12px however far the tier scales down', () => {
|
|
86
|
+
const css = read('src/lib/field/field-label.component.scss');
|
|
87
|
+
|
|
88
|
+
expect(css).toMatch(
|
|
89
|
+
/font-size:\s*max\(var\(--ea-field-label-size[^)]*\)[^,]*,\s*0\.75rem\)/,
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('floors error and hint text at 11px however far the tier scales down', () => {
|
|
94
|
+
const css = read('src/lib/field/field-messages.component.scss');
|
|
95
|
+
|
|
96
|
+
expect(css).toMatch(
|
|
97
|
+
/font-size:\s*max\(var\(--ea-field-messages-size[^)]*\)[^,]*,\s*0\.6875rem\)/,
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('keeps the floor at the point of use, not in each component that sets the variable', () => {
|
|
102
|
+
// 18 components declare these variables; a floor copied into each would
|
|
103
|
+
// be missed by the next one added
|
|
104
|
+
const setters = componentStylesheets().filter(({ css }) =>
|
|
105
|
+
/--ea-field-(label|messages)-size:/.test(css),
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
expect(setters.length).toBeGreaterThan(10);
|
|
109
|
+
for (const { name, css } of setters) {
|
|
110
|
+
expect(`${name}: ${/--ea-field-\w+-size:\s*max\(/.test(css)}`).toBe(
|
|
111
|
+
`${name}: false`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('would otherwise scale sub-text below the floors at the smallest tier', () => {
|
|
117
|
+
// Documents why the floors exist: the unclamped em values at 2xs
|
|
118
|
+
expect(SMALLEST_TIER_PX * 0.875).toBeLessThan(12);
|
|
119
|
+
expect(SMALLEST_TIER_PX * 0.8125).toBeLessThan(11);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
package/types/eagami-ui.d.ts
CHANGED
|
@@ -147,10 +147,6 @@ interface EagamiMessages {
|
|
|
147
147
|
hidePassword: string;
|
|
148
148
|
clear: string;
|
|
149
149
|
};
|
|
150
|
-
numberInput: {
|
|
151
|
-
increment: string;
|
|
152
|
-
decrement: string;
|
|
153
|
-
};
|
|
154
150
|
menu: {
|
|
155
151
|
label: string;
|
|
156
152
|
};
|
|
@@ -737,6 +733,7 @@ declare class AutocompleteComponent implements ControlValueAccessor {
|
|
|
737
733
|
[x: string]: boolean;
|
|
738
734
|
'ea-autocomplete__wrapper--error': boolean;
|
|
739
735
|
'ea-autocomplete__wrapper--focused': boolean;
|
|
736
|
+
'ea-autocomplete__wrapper--readonly': boolean;
|
|
740
737
|
'ea-autocomplete__wrapper--disabled': boolean;
|
|
741
738
|
}>;
|
|
742
739
|
readonly listboxClasses: _angular_core.Signal<{
|
|
@@ -1337,6 +1334,7 @@ declare class ColorPickerComponent implements ControlValueAccessor {
|
|
|
1337
1334
|
'ea-color-picker__trigger--error': boolean;
|
|
1338
1335
|
'ea-color-picker__trigger--open': boolean;
|
|
1339
1336
|
'ea-color-picker__trigger--disabled': boolean;
|
|
1337
|
+
'ea-color-picker__trigger--readonly': boolean;
|
|
1340
1338
|
}>;
|
|
1341
1339
|
readonly wrapperClasses: _angular_core.Signal<{
|
|
1342
1340
|
[x: string]: boolean;
|
|
@@ -1561,7 +1559,7 @@ declare class CodeInputComponent implements ControlValueAccessor {
|
|
|
1561
1559
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<CodeInputComponent, "ea-code-input", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "length": { "alias": "length"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "errorMsg": { "alias": "errorMsg"; "required": false; "isSignal": true; }; "errorMessages": { "alias": "errorMessages"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "allowAllChars": { "alias": "allowAllChars"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "completed": "completed"; }, never, never, true, never>;
|
|
1562
1560
|
}
|
|
1563
1561
|
|
|
1564
|
-
/** Visual size of the date picker
|
|
1562
|
+
/** Visual size of the date picker field. */
|
|
1565
1563
|
type DatePickerSize = EaSize;
|
|
1566
1564
|
/** Locale-aware date format used for the displayed value. */
|
|
1567
1565
|
type DatePickerFormat = 'short' | 'medium' | 'long';
|
|
@@ -1579,17 +1577,21 @@ interface CalendarDay {
|
|
|
1579
1577
|
isFocused: boolean;
|
|
1580
1578
|
}
|
|
1581
1579
|
/**
|
|
1582
|
-
*
|
|
1583
|
-
*
|
|
1584
|
-
* and
|
|
1585
|
-
*
|
|
1580
|
+
* Date field with a calendar popover. The date can be typed straight into the
|
|
1581
|
+
* field in any reasonable shape (ISO, all-numeric in the locale's field order,
|
|
1582
|
+
* or with a month name) and is rewritten in the configured `format` on commit.
|
|
1583
|
+
* Supports `min`/`max` bounds, configurable week start, locale-aware formatting
|
|
1584
|
+
* via `Intl.DateTimeFormat`, and full keyboard navigation (arrows,
|
|
1585
|
+
* PageUp/PageDown, Home/End, Enter, Escape). Integrates with Angular forms via
|
|
1586
|
+
* `ControlValueAccessor`.
|
|
1586
1587
|
*/
|
|
1587
1588
|
declare class DatePickerComponent implements ControlValueAccessor {
|
|
1588
|
-
protected readonly
|
|
1589
|
+
protected readonly fieldEl: _angular_core.Signal<ElementRef<HTMLElement> | undefined>;
|
|
1590
|
+
protected readonly inputEl: _angular_core.Signal<ElementRef<HTMLInputElement> | undefined>;
|
|
1589
1591
|
private readonly injector;
|
|
1590
1592
|
protected readonly i18n: EagamiI18nService;
|
|
1591
1593
|
readonly label: _angular_core.InputSignal<string | undefined>;
|
|
1592
|
-
/** Placeholder shown when no date is selected.
|
|
1594
|
+
/** Placeholder shown in the field when no date is selected. */
|
|
1593
1595
|
readonly placeholder: _angular_core.InputSignal<string | undefined>;
|
|
1594
1596
|
readonly size: _angular_core.InputSignal<EaSize>;
|
|
1595
1597
|
readonly disabled: _angular_core.InputSignal<boolean>;
|
|
@@ -1613,6 +1615,9 @@ declare class DatePickerComponent implements ControlValueAccessor {
|
|
|
1613
1615
|
readonly viewMonth: _angular_core.WritableSignal<number>;
|
|
1614
1616
|
readonly focusedDate: _angular_core.WritableSignal<Date | null>;
|
|
1615
1617
|
private readonly _formDisabled;
|
|
1618
|
+
private readonly isFocused;
|
|
1619
|
+
/** Entry in progress, held verbatim until it is committed or abandoned. */
|
|
1620
|
+
private readonly draft;
|
|
1616
1621
|
private onChange;
|
|
1617
1622
|
private onTouched;
|
|
1618
1623
|
readonly isDisabled: _angular_core.Signal<boolean>;
|
|
@@ -1632,23 +1637,23 @@ declare class DatePickerComponent implements ControlValueAccessor {
|
|
|
1632
1637
|
* Some browsers ship a reduced ICU that silently falls back to English for
|
|
1633
1638
|
* less common locales, so a matching request is not a given. */
|
|
1634
1639
|
private readonly intlLocalizesEffectiveLocale;
|
|
1635
|
-
/** Placeholder text
|
|
1640
|
+
/** Placeholder text, empty unless a `placeholder` is given. */
|
|
1636
1641
|
readonly resolvedPlaceholder: _angular_core.Signal<string>;
|
|
1642
|
+
/** Accessible name when no `label` is given. */
|
|
1643
|
+
protected readonly fallbackLabel: _angular_core.Signal<string>;
|
|
1637
1644
|
readonly dialogId: _angular_core.Signal<string>;
|
|
1638
|
-
readonly
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
'ea-date-
|
|
1642
|
-
'ea-date-
|
|
1643
|
-
'ea-date-picker__trigger--disabled': boolean;
|
|
1644
|
-
}>;
|
|
1645
|
-
readonly wrapperClasses: _angular_core.Signal<{
|
|
1646
|
-
[x: string]: boolean;
|
|
1645
|
+
readonly fieldClasses: _angular_core.Signal<{
|
|
1646
|
+
'ea-date-picker__field--focused': boolean;
|
|
1647
|
+
'ea-date-picker__field--error': boolean;
|
|
1648
|
+
'ea-date-picker__field--disabled': boolean;
|
|
1649
|
+
'ea-date-picker__field--readonly': boolean;
|
|
1647
1650
|
}>;
|
|
1648
1651
|
readonly popoverClasses: _angular_core.Signal<{
|
|
1649
1652
|
[x: string]: boolean;
|
|
1650
1653
|
}>;
|
|
1651
1654
|
readonly displayValue: _angular_core.Signal<string>;
|
|
1655
|
+
/** Field text: the entry in progress while typing, else the formatted value. */
|
|
1656
|
+
readonly inputText: _angular_core.Signal<string>;
|
|
1652
1657
|
readonly monthYearLabel: _angular_core.Signal<string>;
|
|
1653
1658
|
readonly weekdayLabels: _angular_core.Signal<string[]>;
|
|
1654
1659
|
readonly weeks: _angular_core.Signal<CalendarDay[][]>;
|
|
@@ -1663,7 +1668,7 @@ declare class DatePickerComponent implements ControlValueAccessor {
|
|
|
1663
1668
|
/** Closes the calendar popover. */
|
|
1664
1669
|
close(): void;
|
|
1665
1670
|
private focusFocusedDayCell;
|
|
1666
|
-
/** Moves keyboard focus to the
|
|
1671
|
+
/** Moves keyboard focus to the date field. */
|
|
1667
1672
|
focus(): void;
|
|
1668
1673
|
selectDay(day: CalendarDay): void;
|
|
1669
1674
|
/** Clears the selected date and emits `changed` with `null`. */
|
|
@@ -1680,7 +1685,13 @@ declare class DatePickerComponent implements ControlValueAccessor {
|
|
|
1680
1685
|
*/
|
|
1681
1686
|
private pullFocusIntoView;
|
|
1682
1687
|
goToToday(): void;
|
|
1683
|
-
|
|
1688
|
+
protected onInput(event: Event): void;
|
|
1689
|
+
protected onInputFocus(): void;
|
|
1690
|
+
protected onInputBlur(): void;
|
|
1691
|
+
protected handleInputKeydown(event: KeyboardEvent): void;
|
|
1692
|
+
private commitDraft;
|
|
1693
|
+
private applyValue;
|
|
1694
|
+
private isOutOfRange;
|
|
1684
1695
|
handleGridKeydown(event: KeyboardEvent): void;
|
|
1685
1696
|
/** Called by `<ea-popover>` when the user clicks outside the picker. */
|
|
1686
1697
|
onPopoverCloseRequested(): void;
|
|
@@ -1905,6 +1916,7 @@ declare class DropdownComponent implements ControlValueAccessor {
|
|
|
1905
1916
|
'ea-dropdown__trigger--error': boolean;
|
|
1906
1917
|
'ea-dropdown__trigger--open': boolean;
|
|
1907
1918
|
'ea-dropdown__trigger--disabled': boolean;
|
|
1919
|
+
'ea-dropdown__trigger--readonly': boolean;
|
|
1908
1920
|
}>;
|
|
1909
1921
|
readonly menuClasses: _angular_core.Signal<{
|
|
1910
1922
|
[x: string]: boolean;
|
|
@@ -2465,6 +2477,7 @@ declare class MultiSelectComponent implements ControlValueAccessor {
|
|
|
2465
2477
|
'ea-multi-select__trigger--error': boolean;
|
|
2466
2478
|
'ea-multi-select__trigger--open': boolean;
|
|
2467
2479
|
'ea-multi-select__trigger--disabled': boolean;
|
|
2480
|
+
'ea-multi-select__trigger--readonly': boolean;
|
|
2468
2481
|
'ea-multi-select__trigger--placeholder': boolean;
|
|
2469
2482
|
}>;
|
|
2470
2483
|
readonly menuClasses: _angular_core.Signal<{
|
|
@@ -2530,7 +2543,7 @@ declare class MultiSelectComponent implements ControlValueAccessor {
|
|
|
2530
2543
|
/** Visual size of the number input. */
|
|
2531
2544
|
type NumberInputSize = EaSize;
|
|
2532
2545
|
/**
|
|
2533
|
-
* Numeric field with
|
|
2546
|
+
* Numeric field with min/max/step bounds, native arrow-key stepping, and
|
|
2534
2547
|
* the standard label, hint, and error chrome. The native input carries the
|
|
2535
2548
|
* `spinbutton` role, so arrow keys step it; the steppers are pointer
|
|
2536
2549
|
* affordances. Integrates with Angular forms via `ControlValueAccessor`.
|
|
@@ -2558,10 +2571,16 @@ declare class NumberInputComponent implements ControlValueAccessor {
|
|
|
2558
2571
|
readonly required: _angular_core.InputSignal<boolean>;
|
|
2559
2572
|
/** Minimum value; typed values are clamped to it on blur and the steppers respect it. */
|
|
2560
2573
|
readonly min: _angular_core.InputSignal<number | undefined>;
|
|
2561
|
-
/** Maximum value; typed values are clamped to it on blur
|
|
2574
|
+
/** Maximum value; typed values are clamped to it on blur. */
|
|
2562
2575
|
readonly max: _angular_core.InputSignal<number | undefined>;
|
|
2563
|
-
/** Amount each
|
|
2576
|
+
/** Amount each arrow-key step adds or subtracts. */
|
|
2564
2577
|
readonly step: _angular_core.InputSignal<number>;
|
|
2578
|
+
/**
|
|
2579
|
+
* Caps how many characters the field accepts, counting the digits, the minus
|
|
2580
|
+
* sign, and the decimal point. Also sets how wide the field renders; without
|
|
2581
|
+
* it the field is six characters wide.
|
|
2582
|
+
*/
|
|
2583
|
+
readonly maxDigits: _angular_core.InputSignal<number | undefined>;
|
|
2565
2584
|
/** Whether negative values are allowed; when `false` the value floors at 0. */
|
|
2566
2585
|
readonly allowNegative: _angular_core.InputSignal<boolean>;
|
|
2567
2586
|
/** Accessible name for the field when no visible `label` is set. */
|
|
@@ -2588,8 +2607,6 @@ declare class NumberInputComponent implements ControlValueAccessor {
|
|
|
2588
2607
|
readonly hasError: _angular_core.Signal<boolean>;
|
|
2589
2608
|
readonly showError: _angular_core.Signal<boolean>;
|
|
2590
2609
|
readonly showHint: _angular_core.Signal<boolean>;
|
|
2591
|
-
readonly canIncrement: _angular_core.Signal<boolean>;
|
|
2592
|
-
readonly canDecrement: _angular_core.Signal<boolean>;
|
|
2593
2610
|
readonly wrapperClasses: _angular_core.Signal<{
|
|
2594
2611
|
[x: string]: boolean;
|
|
2595
2612
|
'ea-number-input-wrapper--error': boolean;
|
|
@@ -2603,20 +2620,17 @@ declare class NumberInputComponent implements ControlValueAccessor {
|
|
|
2603
2620
|
registerOnTouched(fn: () => void): void;
|
|
2604
2621
|
setDisabledState(isDisabled: boolean): void;
|
|
2605
2622
|
protected handleInput(): void;
|
|
2623
|
+
private enforceMaxDigits;
|
|
2606
2624
|
protected handleFocus(event: FocusEvent): void;
|
|
2607
2625
|
protected handleBlur(event: FocusEvent): void;
|
|
2608
2626
|
protected handleWheel(event: WheelEvent): void;
|
|
2609
2627
|
protected handleKeydown(event: KeyboardEvent): void;
|
|
2610
|
-
protected onStepMousedown(event: MouseEvent): void;
|
|
2611
|
-
protected increment(): void;
|
|
2612
|
-
protected decrement(): void;
|
|
2613
2628
|
/** Moves keyboard focus to the underlying native input element. */
|
|
2614
2629
|
focus(): void;
|
|
2615
|
-
private stepBy;
|
|
2616
2630
|
private commitFromElement;
|
|
2617
2631
|
private clampToBounds;
|
|
2618
2632
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NumberInputComponent, never>;
|
|
2619
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NumberInputComponent, "ea-number-input", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "errorMsg": { "alias": "errorMsg"; "required": false; "isSignal": true; }; "errorMessages": { "alias": "errorMessages"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "allowNegative": { "alias": "allowNegative"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "changed": "changed"; "focused": "focused"; "blurred": "blurred"; }, never, never, true, never>;
|
|
2633
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NumberInputComponent, "ea-number-input", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "errorMsg": { "alias": "errorMsg"; "required": false; "isSignal": true; }; "errorMessages": { "alias": "errorMessages"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "maxDigits": { "alias": "maxDigits"; "required": false; "isSignal": true; }; "allowNegative": { "alias": "allowNegative"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "changed": "changed"; "focused": "focused"; "blurred": "blurred"; }, never, never, true, never>;
|
|
2620
2634
|
}
|
|
2621
2635
|
|
|
2622
2636
|
/** Horizontal alignment of paginator controls within their container. */
|
|
@@ -3646,6 +3660,7 @@ declare class TimePickerComponent implements ControlValueAccessor {
|
|
|
3646
3660
|
'ea-time-picker__trigger--error': boolean;
|
|
3647
3661
|
'ea-time-picker__trigger--open': boolean;
|
|
3648
3662
|
'ea-time-picker__trigger--disabled': boolean;
|
|
3663
|
+
'ea-time-picker__trigger--readonly': boolean;
|
|
3649
3664
|
'ea-time-picker__trigger--placeholder': boolean;
|
|
3650
3665
|
}>;
|
|
3651
3666
|
readonly wrapperClasses: _angular_core.Signal<{
|
|
@@ -3780,6 +3795,8 @@ type ToastVariant = 'default' | 'success' | 'warning' | 'error' | 'info';
|
|
|
3780
3795
|
interface Toast {
|
|
3781
3796
|
id: number;
|
|
3782
3797
|
message: string;
|
|
3798
|
+
/** Heading shown above the message; the message steps back when set. */
|
|
3799
|
+
title?: string;
|
|
3783
3800
|
variant: ToastVariant;
|
|
3784
3801
|
duration: number;
|
|
3785
3802
|
/** Icon component rendered in place of the variant's own; `null` renders none. */
|
|
@@ -3787,6 +3804,8 @@ interface Toast {
|
|
|
3787
3804
|
}
|
|
3788
3805
|
/** Optional configuration for a toast; defaults to `default` variant and 4s duration. */
|
|
3789
3806
|
interface ToastOptions {
|
|
3807
|
+
/** Heading shown above the message; the message steps back when set. */
|
|
3808
|
+
title?: string;
|
|
3790
3809
|
variant?: ToastVariant;
|
|
3791
3810
|
duration?: number;
|
|
3792
3811
|
/** Any icon component to render in place of the variant's own; `null` for no icon. */
|