@eagami/ui 5.28.0 → 5.30.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eagami/ui",
3
- "version": "5.28.0",
3
+ "version": "5.30.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",
@@ -48,6 +48,10 @@
48
48
  ".": {
49
49
  "types": "./types/eagami-ui.d.ts",
50
50
  "default": "./fesm2022/eagami-ui.mjs"
51
+ },
52
+ "./testing": {
53
+ "types": "./types/eagami-ui-testing.d.ts",
54
+ "default": "./fesm2022/eagami-ui-testing.mjs"
51
55
  }
52
56
  },
53
57
  "type": "module",
@@ -56,6 +60,7 @@
56
60
  "types",
57
61
  "src/styles",
58
62
  "schematics",
63
+ "testing",
59
64
  "README.md"
60
65
  ],
61
66
  "schematics": "./schematics/collection.json"
@@ -0,0 +1,4 @@
1
+ {
2
+ "module": "../fesm2022/eagami-ui-testing.mjs",
3
+ "typings": "../types/eagami-ui-testing.d.ts"
4
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Fills in the native `<dialog>` methods jsdom leaves unimplemented, so a spec
3
+ * can create a component that opens an `ea-dialog` or `ea-drawer` without the
4
+ * test runner throwing on `showModal()` or `close()`. Call once from the test
5
+ * setup file. Only missing methods are patched, so a runtime that implements
6
+ * the element keeps its own behavior.
7
+ */
8
+ declare function installNativeDialogShim(): void;
9
+
10
+ export { installNativeDialogShim };
@@ -158,6 +158,7 @@ interface EagamiMessages {
158
158
  clearAll: string;
159
159
  removeOption: (label: string) => string;
160
160
  selectedCount: (count: number) => string;
161
+ create: (text: string) => string;
161
162
  };
162
163
  paginator: {
163
164
  label: string;
@@ -588,9 +589,11 @@ declare function oklchToHex(oklch: Oklch): string;
588
589
  type EaSize = '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
589
590
  /**
590
591
  * Size scale for width-based components (panels such as drawer and dialog),
591
- * adding a full-bleed option on top of the standard scale.
592
+ * adding a step above `xl` and a full-bleed option on top of the standard
593
+ * scale. A panel holds layouts (grids, tables) that a control never does, so it
594
+ * runs one step wider before the jump to full.
592
595
  */
593
- type EaWidth = EaSize | 'full';
596
+ type EaWidth = EaSize | '2xl' | 'full';
594
597
 
595
598
  /** Heading level exposed by each item's header for assistive technology. */
596
599
  type AccordionHeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
@@ -1105,6 +1108,12 @@ declare class CheckboxComponent implements ControlValueAccessor {
1105
1108
  /** Per-validator-key message overrides for a bound form control (e.g. `{ required: '...' }`). */
1106
1109
  readonly errorMessages: _angular_core.InputSignal<Partial<Record<string, string>> | undefined>;
1107
1110
  readonly size: _angular_core.InputSignal<EaSize>;
1111
+ /**
1112
+ * Ellipsize a label too long for the space the checkbox is given, revealing
1113
+ * the full text in a tooltip while it is clipped. Off by default, since a
1114
+ * checkbox otherwise widens its column rather than hiding any of its label.
1115
+ */
1116
+ readonly truncate: _angular_core.InputSignal<boolean>;
1108
1117
  readonly disabled: _angular_core.InputSignal<boolean>;
1109
1118
  readonly required: _angular_core.InputSignal<boolean>;
1110
1119
  readonly indeterminate: _angular_core.InputSignal<boolean>;
@@ -1120,8 +1129,11 @@ declare class CheckboxComponent implements ControlValueAccessor {
1120
1129
  readonly hasError: _angular_core.Signal<boolean>;
1121
1130
  readonly showError: _angular_core.Signal<boolean>;
1122
1131
  readonly showHint: _angular_core.Signal<boolean>;
1132
+ /** What a clamped label reveals: the count rides along, since the ellipsis takes it first. */
1133
+ protected readonly clampedText: _angular_core.Signal<string>;
1123
1134
  readonly hostClasses: _angular_core.Signal<{
1124
1135
  [x: string]: boolean;
1136
+ 'ea-checkbox--truncate': boolean;
1125
1137
  'ea-checkbox--disabled': boolean;
1126
1138
  'ea-checkbox--checked': boolean;
1127
1139
  'ea-checkbox--indeterminate': boolean;
@@ -1133,9 +1145,10 @@ declare class CheckboxComponent implements ControlValueAccessor {
1133
1145
  registerOnChange(fn: (value: boolean) => void): void;
1134
1146
  registerOnTouched(fn: () => void): void;
1135
1147
  setDisabledState(isDisabled: boolean): void;
1148
+ handleKeydown(event: KeyboardEvent): void;
1136
1149
  handleChange(): void;
1137
1150
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<CheckboxComponent, never>;
1138
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<CheckboxComponent, "ea-checkbox", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "count": { "alias": "count"; "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; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "indeterminate": { "alias": "indeterminate"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "checked": { "alias": "checked"; "required": false; "isSignal": true; }; }, { "checked": "checkedChange"; "changed": "changed"; }, never, never, true, never>;
1151
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<CheckboxComponent, "ea-checkbox", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "count": { "alias": "count"; "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; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "truncate": { "alias": "truncate"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "indeterminate": { "alias": "indeterminate"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "checked": { "alias": "checked"; "required": false; "isSignal": true; }; }, { "checked": "checkedChange"; "changed": "changed"; }, never, never, true, never>;
1139
1152
  }
1140
1153
 
1141
1154
  /**
@@ -1376,6 +1389,12 @@ declare class ColorPickerComponent implements ControlValueAccessor {
1376
1389
  readonly showAlpha: _angular_core.InputSignal<boolean>;
1377
1390
  /** Whether to show the clear button when a value is set. */
1378
1391
  readonly clearable: _angular_core.InputSignal<boolean>;
1392
+ /**
1393
+ * Trigger as a bare square swatch instead of a field with the value beside
1394
+ * it, for a colour sitting in a dense row or a toolbar. The value text and
1395
+ * the clear button, which have nowhere to go at that size, are dropped.
1396
+ */
1397
+ readonly compact: _angular_core.InputSignal<boolean>;
1379
1398
  /** Output format. `all` lets the user cycle hex/rgb/hsl in the popover; a specific value locks it. */
1380
1399
  readonly format: _angular_core.InputSignal<ColorPickerFormat>;
1381
1400
  /** Preset swatches shown at the bottom of the popover. Pass an empty array to hide. */
@@ -1442,6 +1461,7 @@ declare class ColorPickerComponent implements ControlValueAccessor {
1442
1461
  readonly triggerLabelledBy: _angular_core.Signal<string | null>;
1443
1462
  readonly triggerClasses: _angular_core.Signal<{
1444
1463
  [x: string]: boolean;
1464
+ 'ea-color-picker__trigger--compact': boolean;
1445
1465
  'ea-color-picker__trigger--error': boolean;
1446
1466
  'ea-color-picker__trigger--open': boolean;
1447
1467
  'ea-color-picker__trigger--disabled': boolean;
@@ -1518,7 +1538,7 @@ declare class ColorPickerComponent implements ControlValueAccessor {
1518
1538
  private commit;
1519
1539
  private refreshHexInput;
1520
1540
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ColorPickerComponent, never>;
1521
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ColorPickerComponent, "ea-color-picker", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "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; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "errorMsg": { "alias": "errorMsg"; "required": false; "isSignal": true; }; "errorMessages": { "alias": "errorMessages"; "required": false; "isSignal": true; }; "showAlpha": { "alias": "showAlpha"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "format": { "alias": "format"; "required": false; "isSignal": true; }; "presets": { "alias": "presets"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "changed": "changed"; }, never, never, true, never>;
1541
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ColorPickerComponent, "ea-color-picker", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "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; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "errorMsg": { "alias": "errorMsg"; "required": false; "isSignal": true; }; "errorMessages": { "alias": "errorMessages"; "required": false; "isSignal": true; }; "showAlpha": { "alias": "showAlpha"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "compact": { "alias": "compact"; "required": false; "isSignal": true; }; "format": { "alias": "format"; "required": false; "isSignal": true; }; "presets": { "alias": "presets"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "changed": "changed"; }, never, never, true, never>;
1522
1542
  }
1523
1543
 
1524
1544
  /** Vertical density preset for table rows and header cells. */
@@ -1823,6 +1843,17 @@ type DialogWidth = EaWidth;
1823
1843
  * for browser-managed focus trapping, supports backdrop and Escape dismissal,
1824
1844
  * and exposes `header`, default, and `footer` content slots. The `open` state
1825
1845
  * is a two-way `model()` binding.
1846
+ *
1847
+ * The header is a row that lays its slot content out against the built-in
1848
+ * close button, and it applies the h4 type scale to that content, so a heading
1849
+ * element projected into it should carry `font: inherit`. Panel chrome is
1850
+ * tunable per dialog via `--ea-dialog-inset`, `--ea-dialog-radius`,
1851
+ * `--ea-dialog-max-height`, `--ea-dialog-header-padding`,
1852
+ * `--ea-dialog-body-padding`, and `--ea-dialog-status-padding`; an
1853
+ * edge-to-edge media surface zeroes the inset, radius, and paddings.
1854
+ *
1855
+ * Specs running under jsdom need `installNativeDialogShim()` from
1856
+ * `@eagami/ui/testing` before opening one.
1826
1857
  */
1827
1858
  declare class DialogComponent implements AfterContentChecked {
1828
1859
  private readonly dialogEl;
@@ -1835,6 +1866,19 @@ declare class DialogComponent implements AfterContentChecked {
1835
1866
  readonly closeOnBackdrop: _angular_core.InputSignal<boolean>;
1836
1867
  readonly closeOnEscape: _angular_core.InputSignal<boolean>;
1837
1868
  readonly showClose: _angular_core.InputSignal<boolean>;
1869
+ /**
1870
+ * Disables the built-in close button while a task is in flight (a save, an
1871
+ * upload). It governs that button alone; pair it with `closeOnEscape` /
1872
+ * `closeOnBackdrop` or `manualClose` to hold the other routes shut too.
1873
+ */
1874
+ readonly closeDisabled: _angular_core.InputSignal<boolean>;
1875
+ /**
1876
+ * Hands every close route to the consumer: the dialog reports
1877
+ * `closeRequested` and stays open until `open` is set false, so an unsaved
1878
+ * edit can be confirmed first. Escape and the backdrop still report, which is
1879
+ * what `closeOnEscape` / `closeOnBackdrop` remove entirely.
1880
+ */
1881
+ readonly manualClose: _angular_core.InputSignal<boolean>;
1838
1882
  readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
1839
1883
  readonly id: _angular_core.InputSignal<string>;
1840
1884
  readonly open: _angular_core.ModelSignal<boolean>;
@@ -1842,6 +1886,8 @@ declare class DialogComponent implements AfterContentChecked {
1842
1886
  readonly opened: _angular_core.OutputEmitterRef<void>;
1843
1887
  /** Fires when the dialog closes (via close button, backdrop, or Escape). */
1844
1888
  readonly closed: _angular_core.OutputEmitterRef<void>;
1889
+ /** Fires under `manualClose` for every close the user asks for, leaving the dialog open. */
1890
+ readonly closeRequested: _angular_core.OutputEmitterRef<void>;
1845
1891
  readonly panelClasses: _angular_core.Signal<{
1846
1892
  [x: string]: boolean;
1847
1893
  }>;
@@ -1850,10 +1896,12 @@ declare class DialogComponent implements AfterContentChecked {
1850
1896
  ngAfterContentChecked(): void;
1851
1897
  constructor();
1852
1898
  handleClose(): void;
1899
+ /** Every close route the user can take, routed through `manualClose`. */
1900
+ protected requestClose(): void;
1853
1901
  handleBackdropClick(event: MouseEvent): void;
1854
1902
  handleCancel(event: Event): void;
1855
1903
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DialogComponent, never>;
1856
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DialogComponent, "ea-dialog", never, { "width": { "alias": "width"; "required": false; "isSignal": true; }; "closeOnBackdrop": { "alias": "closeOnBackdrop"; "required": false; "isSignal": true; }; "closeOnEscape": { "alias": "closeOnEscape"; "required": false; "isSignal": true; }; "showClose": { "alias": "showClose"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "open": { "alias": "open"; "required": false; "isSignal": true; }; }, { "open": "openChange"; "opened": "opened"; "closed": "closed"; }, never, ["[slot=header]", "*", "[slot=footer]"], true, never>;
1904
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DialogComponent, "ea-dialog", never, { "width": { "alias": "width"; "required": false; "isSignal": true; }; "closeOnBackdrop": { "alias": "closeOnBackdrop"; "required": false; "isSignal": true; }; "closeOnEscape": { "alias": "closeOnEscape"; "required": false; "isSignal": true; }; "showClose": { "alias": "showClose"; "required": false; "isSignal": true; }; "closeDisabled": { "alias": "closeDisabled"; "required": false; "isSignal": true; }; "manualClose": { "alias": "manualClose"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "open": { "alias": "open"; "required": false; "isSignal": true; }; }, { "open": "openChange"; "opened": "opened"; "closed": "closed"; "closeRequested": "closeRequested"; }, never, ["[slot=header]", "*", "[slot=status]", "[slot=footer]"], true, never>;
1857
1905
  }
1858
1906
 
1859
1907
  /** Orientation of the divider rule. */
@@ -1904,6 +1952,9 @@ type DrawerAnimation = 'none' | 'linear' | 'eased';
1904
1952
  * Escape dismissal, and exposes `header`, default, and `footer` content
1905
1953
  * slots. The `open` state is a two-way `model()` binding. In `push` mode it
1906
1954
  * opens non-modally and reflows the page content aside instead of overlaying it.
1955
+ *
1956
+ * Specs running under jsdom need `installNativeDialogShim()` from
1957
+ * `@eagami/ui/testing` before opening one.
1907
1958
  */
1908
1959
  declare class DrawerComponent implements AfterContentChecked {
1909
1960
  private readonly drawerEl;
@@ -2748,6 +2799,13 @@ declare class MultiSelectComponent implements ControlValueAccessor {
2748
2799
  readonly searchable: _angular_core.InputSignal<boolean>;
2749
2800
  /** Toggle the "Select all" row at the top of the option list. */
2750
2801
  readonly selectAll: _angular_core.InputSignal<boolean>;
2802
+ /**
2803
+ * Offer a "Create" row when the search text matches no option, for a value
2804
+ * the list cannot know about yet (a new tag, a new person). The component
2805
+ * only reports the text through `created`; the consumer creates the record
2806
+ * and pushes its value into `value`.
2807
+ */
2808
+ readonly allowCreate: _angular_core.InputSignal<boolean>;
2751
2809
  /** Max number of chips shown inside the trigger; the rest collapse into a "+N more" pill. `0` removes the cap so every chip shows and the row scrolls horizontally. */
2752
2810
  readonly maxVisibleChips: _angular_core.InputSignal<number>;
2753
2811
  /**
@@ -2765,6 +2823,8 @@ declare class MultiSelectComponent implements ControlValueAccessor {
2765
2823
  readonly value: _angular_core.ModelSignal<readonly string[]>;
2766
2824
  /** Fires with the new value whenever the selection changes. */
2767
2825
  readonly changed: _angular_core.OutputEmitterRef<readonly string[]>;
2826
+ /** Fires with the typed text when the user takes the `allowCreate` row. */
2827
+ readonly created: _angular_core.OutputEmitterRef<string>;
2768
2828
  readonly isOpen: _angular_core.WritableSignal<boolean>;
2769
2829
  readonly searchTerm: _angular_core.WritableSignal<string>;
2770
2830
  /** Index into `filteredOptions()` for keyboard navigation. `-1` when none focused. */
@@ -2798,6 +2858,10 @@ declare class MultiSelectComponent implements ControlValueAccessor {
2798
2858
  protected readonly selectAllVisible: _angular_core.Signal<boolean>;
2799
2859
  /** Row-index offset the Select-all row adds ahead of the filtered options. */
2800
2860
  protected readonly selectAllOffset: _angular_core.Signal<1 | 0>;
2861
+ /** The text a Create row would carry, or `''` when no such row is offered. */
2862
+ protected readonly creatableText: _angular_core.Signal<string>;
2863
+ /** Row index of the Create row, which sits after the options, or `-1`. */
2864
+ protected readonly createRow: _angular_core.Signal<number>;
2801
2865
  private readonly rowCount;
2802
2866
  protected readonly selectAllAriaChecked: _angular_core.Signal<"true" | "mixed" | "false">;
2803
2867
  /** Id of the keyboard-focused option, for `aria-activedescendant`. */
@@ -2874,6 +2938,8 @@ declare class MultiSelectComponent implements ControlValueAccessor {
2874
2938
  private moveFocusedRow;
2875
2939
  /** Enter/Space on the focused row: row 0 is Select-all when visible. */
2876
2940
  private activateRow;
2941
+ /** Report the typed text, then clear it so the new value can be followed by another. */
2942
+ protected createOption(): void;
2877
2943
  /** Reorder a value-set against the input `options` array. */
2878
2944
  private orderedValues;
2879
2945
  private optionsFor;
@@ -2887,7 +2953,7 @@ declare class MultiSelectComponent implements ControlValueAccessor {
2887
2953
  private measureClippedOptions;
2888
2954
  private watchListWidth;
2889
2955
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<MultiSelectComponent, never>;
2890
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<MultiSelectComponent, "ea-multi-select", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "searchPlaceholder": { "alias": "searchPlaceholder"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "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; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "errorMsg": { "alias": "errorMsg"; "required": false; "isSignal": true; }; "errorMessages": { "alias": "errorMessages"; "required": false; "isSignal": true; }; "searchable": { "alias": "searchable"; "required": false; "isSignal": true; }; "selectAll": { "alias": "selectAll"; "required": false; "isSignal": true; }; "maxVisibleChips": { "alias": "maxVisibleChips"; "required": false; "isSignal": true; }; "maxChipWidth": { "alias": "maxChipWidth"; "required": false; "isSignal": true; }; "popoverMaxWidth": { "alias": "popoverMaxWidth"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "changed": "changed"; }, never, never, true, never>;
2956
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MultiSelectComponent, "ea-multi-select", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "searchPlaceholder": { "alias": "searchPlaceholder"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "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; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "errorMsg": { "alias": "errorMsg"; "required": false; "isSignal": true; }; "errorMessages": { "alias": "errorMessages"; "required": false; "isSignal": true; }; "searchable": { "alias": "searchable"; "required": false; "isSignal": true; }; "selectAll": { "alias": "selectAll"; "required": false; "isSignal": true; }; "allowCreate": { "alias": "allowCreate"; "required": false; "isSignal": true; }; "maxVisibleChips": { "alias": "maxVisibleChips"; "required": false; "isSignal": true; }; "maxChipWidth": { "alias": "maxChipWidth"; "required": false; "isSignal": true; }; "popoverMaxWidth": { "alias": "popoverMaxWidth"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "changed": "changed"; "created": "created"; }, never, never, true, never>;
2891
2957
  }
2892
2958
 
2893
2959
  /** Visual size of the number input. */
@@ -3682,6 +3748,19 @@ declare class TooltipDirective implements OnDestroy {
3682
3748
  private readonly viewContainer;
3683
3749
  readonly eaTooltip: _angular_core.InputSignal<string | TemplateRef<unknown>>;
3684
3750
  readonly tooltipPosition: _angular_core.InputSignal<TooltipPosition>;
3751
+ /**
3752
+ * Whether a bubble with no room on the requested side moves to the opposite
3753
+ * one. The side is resolved when the bubble opens and held while it still
3754
+ * fits, so a bubble does not hop across its trigger mid-hover.
3755
+ */
3756
+ readonly flip: _angular_core.InputSignal<boolean>;
3757
+ /**
3758
+ * Show only while the trigger is cutting its own content off, which is how a
3759
+ * label that ellipsizes reveals its full text without a bubble on every
3760
+ * label that fits. The whole subtree is measured, since the box doing the
3761
+ * cutting is usually an inner one.
3762
+ */
3763
+ readonly whenClipped: _angular_core.InputSignal<boolean>;
3685
3764
  /**
3686
3765
  * Max width in px; the text wraps at this width. Clamped to a 50px floor, and
3687
3766
  * to the viewport, which no value can push the bubble past.
@@ -3694,6 +3773,8 @@ declare class TooltipDirective implements OnDestroy {
3694
3773
  */
3695
3774
  readonly dismissDelay: _angular_core.InputSignal<number>;
3696
3775
  private tooltipEl;
3776
+ /** Side the open bubble settled on, held across repositions while it fits. */
3777
+ private placedPosition;
3697
3778
  private templateView;
3698
3779
  private scrollable;
3699
3780
  private hideTimer;
@@ -3724,10 +3805,11 @@ declare class TooltipDirective implements OnDestroy {
3724
3805
  private appendDescribedBy;
3725
3806
  private removeDescribedBy;
3726
3807
  private positionTooltip;
3808
+ private applyPlacedPosition;
3727
3809
  private viewportMargin;
3728
3810
  private syncScrollable;
3729
3811
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<TooltipDirective, never>;
3730
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TooltipDirective, "[eaTooltip]", never, { "eaTooltip": { "alias": "eaTooltip"; "required": true; "isSignal": true; }; "tooltipPosition": { "alias": "tooltipPosition"; "required": false; "isSignal": true; }; "maxWidth": { "alias": "maxWidth"; "required": false; "isSignal": true; }; "dismissDelay": { "alias": "dismissDelay"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
3812
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<TooltipDirective, "[eaTooltip]", never, { "eaTooltip": { "alias": "eaTooltip"; "required": true; "isSignal": true; }; "tooltipPosition": { "alias": "tooltipPosition"; "required": false; "isSignal": true; }; "flip": { "alias": "flip"; "required": false; "isSignal": true; }; "whenClipped": { "alias": "whenClipped"; "required": false; "isSignal": true; }; "maxWidth": { "alias": "maxWidth"; "required": false; "isSignal": true; }; "dismissDelay": { "alias": "dismissDelay"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
3731
3813
  }
3732
3814
 
3733
3815
  /** Semantic colour scheme of a tag. */
@@ -3742,8 +3824,8 @@ type TagTooltip = 'above' | 'below' | 'none';
3742
3824
  * accessible name of that button is configurable via `removeLabel` and
3743
3825
  * otherwise falls back to the active locale's translation.
3744
3826
  *
3745
- * The projected label is capped by `maxWidth` (or the `--ea-tag-max-width`
3746
- * custom property) and ellipsizes rather than widening the chip, revealing its
3827
+ * When capped by `maxWidth` (or the `--ea-tag-max-width` custom property),
3828
+ * the projected label ellipsizes rather than widening the chip, revealing its
3747
3829
  * full text in a tooltip while it is clipped.
3748
3830
  */
3749
3831
  declare class TagComponent {
@@ -3756,10 +3838,17 @@ declare class TagComponent {
3756
3838
  readonly disabled: _angular_core.InputSignal<boolean>;
3757
3839
  readonly removeLabel: _angular_core.InputSignal<string | undefined>;
3758
3840
  /**
3759
- * Widest the chip may grow, in px; a longer label ellipsizes instead. Also
3760
- * settable in CSS as `--ea-tag-max-width`, which this input overrides.
3841
+ * Widest the chip may grow: a number of px, or any CSS length for a chip that
3842
+ * has to give way to its container (`'100%'` in a responsive grid cell).
3843
+ * Also settable in CSS as `--ea-tag-max-width`, which this input overrides.
3761
3844
  */
3762
- readonly maxWidth: _angular_core.InputSignal<number | undefined>;
3845
+ readonly maxWidth: _angular_core.InputSignal<string | number | undefined>;
3846
+ /**
3847
+ * Fill colour as a hex value, for a tag carrying a colour of its own (a
3848
+ * user-chosen label). Paints the chip and its border, and picks whichever ink
3849
+ * reads better on it. Takes precedence over `variant`.
3850
+ */
3851
+ readonly color: _angular_core.InputSignal<string | undefined>;
3763
3852
  /**
3764
3853
  * Where a label clipped by `maxWidth` reveals its full text. Set `none` for
3765
3854
  * a tag rendered inside a tooltip, which would otherwise stack a second
@@ -3785,6 +3874,11 @@ declare class TagComponent {
3785
3874
  [x: string]: boolean;
3786
3875
  'ea-tag--disabled': boolean;
3787
3876
  }>;
3877
+ /** `maxWidth` as a CSS length; a bare number is px, as the input documents. */
3878
+ protected readonly resolvedMaxWidth: _angular_core.Signal<string | null>;
3879
+ /** Ink that reads on `color`, or `null` when it is not a hex the library can measure. */
3880
+ protected readonly resolvedInk: _angular_core.Signal<string | null>;
3881
+ protected readonly resolvedColor: _angular_core.Signal<string | null>;
3788
3882
  constructor();
3789
3883
  onRemove(event: MouseEvent): void;
3790
3884
  /**
@@ -3794,7 +3888,7 @@ declare class TagComponent {
3794
3888
  */
3795
3889
  private watchLabel;
3796
3890
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<TagComponent, never>;
3797
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<TagComponent, "ea-tag", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "removable": { "alias": "removable"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "removeLabel": { "alias": "removeLabel"; "required": false; "isSignal": true; }; "maxWidth": { "alias": "maxWidth"; "required": false; "isSignal": true; }; "tooltip": { "alias": "tooltip"; "required": false; "isSignal": true; }; "removeTabbable": { "alias": "removeTabbable"; "required": false; "isSignal": true; }; }, { "removed": "removed"; }, never, ["*"], true, never>;
3891
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TagComponent, "ea-tag", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "removable": { "alias": "removable"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "removeLabel": { "alias": "removeLabel"; "required": false; "isSignal": true; }; "maxWidth": { "alias": "maxWidth"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "tooltip": { "alias": "tooltip"; "required": false; "isSignal": true; }; "removeTabbable": { "alias": "removeTabbable"; "required": false; "isSignal": true; }; }, { "removed": "removed"; }, never, ["*"], true, never>;
3798
3892
  }
3799
3893
 
3800
3894
  /** Visual size of the textarea. */