@eagami/ui 5.27.0 → 5.29.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.27.0",
3
+ "version": "5.29.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",
@@ -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;
@@ -867,7 +870,9 @@ declare class AvatarEditorComponent implements OnDestroy {
867
870
  private readonly boundWheel;
868
871
  constructor();
869
872
  ngOnDestroy(): void;
873
+ onDragEnter(event: DragEvent): void;
870
874
  onDragOver(event: DragEvent): void;
875
+ private acceptDrag;
871
876
  onDragLeave(event: DragEvent): void;
872
877
  onDrop(event: DragEvent): void;
873
878
  onFileSelected(event: Event): void;
@@ -900,6 +905,7 @@ declare class AvatarEditorComponent implements OnDestroy {
900
905
  private loadFromUrl;
901
906
  private loadFile;
902
907
  private scheduleDrawAfterRender;
908
+ private drawLoadedImage;
903
909
  private centerImage;
904
910
  private getScale;
905
911
  private getDrawParams;
@@ -1102,6 +1108,12 @@ declare class CheckboxComponent implements ControlValueAccessor {
1102
1108
  /** Per-validator-key message overrides for a bound form control (e.g. `{ required: '...' }`). */
1103
1109
  readonly errorMessages: _angular_core.InputSignal<Partial<Record<string, string>> | undefined>;
1104
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>;
1105
1117
  readonly disabled: _angular_core.InputSignal<boolean>;
1106
1118
  readonly required: _angular_core.InputSignal<boolean>;
1107
1119
  readonly indeterminate: _angular_core.InputSignal<boolean>;
@@ -1117,8 +1129,11 @@ declare class CheckboxComponent implements ControlValueAccessor {
1117
1129
  readonly hasError: _angular_core.Signal<boolean>;
1118
1130
  readonly showError: _angular_core.Signal<boolean>;
1119
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>;
1120
1134
  readonly hostClasses: _angular_core.Signal<{
1121
1135
  [x: string]: boolean;
1136
+ 'ea-checkbox--truncate': boolean;
1122
1137
  'ea-checkbox--disabled': boolean;
1123
1138
  'ea-checkbox--checked': boolean;
1124
1139
  'ea-checkbox--indeterminate': boolean;
@@ -1130,9 +1145,10 @@ declare class CheckboxComponent implements ControlValueAccessor {
1130
1145
  registerOnChange(fn: (value: boolean) => void): void;
1131
1146
  registerOnTouched(fn: () => void): void;
1132
1147
  setDisabledState(isDisabled: boolean): void;
1148
+ handleKeydown(event: KeyboardEvent): void;
1133
1149
  handleChange(): void;
1134
1150
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<CheckboxComponent, never>;
1135
- 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>;
1136
1152
  }
1137
1153
 
1138
1154
  /**
@@ -1256,6 +1272,7 @@ interface GroupedItems {
1256
1272
  declare class CommandPaletteComponent {
1257
1273
  private readonly i18n;
1258
1274
  private readonly hostEl;
1275
+ private readonly press;
1259
1276
  readonly items: _angular_core.InputSignal<readonly CommandPaletteItem<unknown>[]>;
1260
1277
  readonly open: _angular_core.ModelSignal<boolean>;
1261
1278
  readonly placeholder: _angular_core.InputSignal<string>;
@@ -1372,6 +1389,12 @@ declare class ColorPickerComponent implements ControlValueAccessor {
1372
1389
  readonly showAlpha: _angular_core.InputSignal<boolean>;
1373
1390
  /** Whether to show the clear button when a value is set. */
1374
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>;
1375
1398
  /** Output format. `all` lets the user cycle hex/rgb/hsl in the popover; a specific value locks it. */
1376
1399
  readonly format: _angular_core.InputSignal<ColorPickerFormat>;
1377
1400
  /** Preset swatches shown at the bottom of the popover. Pass an empty array to hide. */
@@ -1438,6 +1461,7 @@ declare class ColorPickerComponent implements ControlValueAccessor {
1438
1461
  readonly triggerLabelledBy: _angular_core.Signal<string | null>;
1439
1462
  readonly triggerClasses: _angular_core.Signal<{
1440
1463
  [x: string]: boolean;
1464
+ 'ea-color-picker__trigger--compact': boolean;
1441
1465
  'ea-color-picker__trigger--error': boolean;
1442
1466
  'ea-color-picker__trigger--open': boolean;
1443
1467
  'ea-color-picker__trigger--disabled': boolean;
@@ -1514,7 +1538,7 @@ declare class ColorPickerComponent implements ControlValueAccessor {
1514
1538
  private commit;
1515
1539
  private refreshHexInput;
1516
1540
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ColorPickerComponent, never>;
1517
- 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>;
1518
1542
  }
1519
1543
 
1520
1544
  /** Vertical density preset for table rows and header cells. */
@@ -1826,10 +1850,24 @@ declare class DialogComponent implements AfterContentChecked {
1826
1850
  private previouslyFocused;
1827
1851
  protected readonly i18n: EagamiI18nService;
1828
1852
  private readonly isBrowser;
1853
+ private readonly press;
1829
1854
  readonly width: _angular_core.InputSignal<EaWidth>;
1830
1855
  readonly closeOnBackdrop: _angular_core.InputSignal<boolean>;
1831
1856
  readonly closeOnEscape: _angular_core.InputSignal<boolean>;
1832
1857
  readonly showClose: _angular_core.InputSignal<boolean>;
1858
+ /**
1859
+ * Disables the built-in close button while a task is in flight (a save, an
1860
+ * upload). It governs that button alone; pair it with `closeOnEscape` /
1861
+ * `closeOnBackdrop` or `manualClose` to hold the other routes shut too.
1862
+ */
1863
+ readonly closeDisabled: _angular_core.InputSignal<boolean>;
1864
+ /**
1865
+ * Hands every close route to the consumer: the dialog reports
1866
+ * `closeRequested` and stays open until `open` is set false, so an unsaved
1867
+ * edit can be confirmed first. Escape and the backdrop still report, which is
1868
+ * what `closeOnEscape` / `closeOnBackdrop` remove entirely.
1869
+ */
1870
+ readonly manualClose: _angular_core.InputSignal<boolean>;
1833
1871
  readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
1834
1872
  readonly id: _angular_core.InputSignal<string>;
1835
1873
  readonly open: _angular_core.ModelSignal<boolean>;
@@ -1837,6 +1875,8 @@ declare class DialogComponent implements AfterContentChecked {
1837
1875
  readonly opened: _angular_core.OutputEmitterRef<void>;
1838
1876
  /** Fires when the dialog closes (via close button, backdrop, or Escape). */
1839
1877
  readonly closed: _angular_core.OutputEmitterRef<void>;
1878
+ /** Fires under `manualClose` for every close the user asks for, leaving the dialog open. */
1879
+ readonly closeRequested: _angular_core.OutputEmitterRef<void>;
1840
1880
  readonly panelClasses: _angular_core.Signal<{
1841
1881
  [x: string]: boolean;
1842
1882
  }>;
@@ -1845,10 +1885,12 @@ declare class DialogComponent implements AfterContentChecked {
1845
1885
  ngAfterContentChecked(): void;
1846
1886
  constructor();
1847
1887
  handleClose(): void;
1888
+ /** Every close route the user can take, routed through `manualClose`. */
1889
+ protected requestClose(): void;
1848
1890
  handleBackdropClick(event: MouseEvent): void;
1849
1891
  handleCancel(event: Event): void;
1850
1892
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DialogComponent, never>;
1851
- 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>;
1893
+ 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>;
1852
1894
  }
1853
1895
 
1854
1896
  /** Orientation of the divider rule. */
@@ -1913,9 +1955,10 @@ declare class DrawerComponent implements AfterContentChecked {
1913
1955
  private pushRaf;
1914
1956
  private leaveTimer;
1915
1957
  private leaveOnEnd;
1916
- private documentPointerListener;
1958
+ private documentClickListener;
1917
1959
  protected readonly i18n: EagamiI18nService;
1918
1960
  private readonly isBrowser;
1961
+ private readonly press;
1919
1962
  readonly position: _angular_core.InputSignal<DrawerPosition>;
1920
1963
  /**
1921
1964
  * Extent of the panel along its main axis (width for side drawers, height for
@@ -2636,6 +2679,7 @@ type PopoverMaxWidth = number | 'anchor';
2636
2679
  */
2637
2680
  declare class PopoverComponent {
2638
2681
  private readonly destroyRef;
2682
+ private readonly press;
2639
2683
  private readonly surfaceEl;
2640
2684
  /** Anchor element the popover positions itself against. */
2641
2685
  readonly anchor: _angular_core.InputSignal<HTMLElement | ElementRef<HTMLElement> | undefined>;
@@ -2678,6 +2722,7 @@ declare class PopoverComponent {
2678
2722
  /** Requested close. The parent should mirror this into `[open]`. */
2679
2723
  readonly closeRequested: _angular_core.OutputEmitterRef<void>;
2680
2724
  private readonly position;
2725
+ private latched;
2681
2726
  /** True placement after flip, for class-based styling (e.g. arrow direction). */
2682
2727
  readonly effectivePlacement: _angular_core.Signal<PopoverPlacement>;
2683
2728
  /** Latches true once the post-rAF reposition has run, so the surface is
@@ -2713,6 +2758,7 @@ type MultiSelectSize = EaSize;
2713
2758
  */
2714
2759
  declare class MultiSelectComponent implements ControlValueAccessor {
2715
2760
  protected readonly wrapperEl: _angular_core.Signal<ElementRef<HTMLElement> | undefined>;
2761
+ private readonly popover;
2716
2762
  protected readonly triggerEl: _angular_core.Signal<ElementRef<HTMLElement> | undefined>;
2717
2763
  protected readonly searchEl: _angular_core.Signal<ElementRef<HTMLInputElement> | undefined>;
2718
2764
  private readonly listEl;
@@ -2739,6 +2785,13 @@ declare class MultiSelectComponent implements ControlValueAccessor {
2739
2785
  readonly searchable: _angular_core.InputSignal<boolean>;
2740
2786
  /** Toggle the "Select all" row at the top of the option list. */
2741
2787
  readonly selectAll: _angular_core.InputSignal<boolean>;
2788
+ /**
2789
+ * Offer a "Create" row when the search text matches no option, for a value
2790
+ * the list cannot know about yet (a new tag, a new person). The component
2791
+ * only reports the text through `created`; the consumer creates the record
2792
+ * and pushes its value into `value`.
2793
+ */
2794
+ readonly allowCreate: _angular_core.InputSignal<boolean>;
2742
2795
  /** 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. */
2743
2796
  readonly maxVisibleChips: _angular_core.InputSignal<number>;
2744
2797
  /**
@@ -2756,6 +2809,8 @@ declare class MultiSelectComponent implements ControlValueAccessor {
2756
2809
  readonly value: _angular_core.ModelSignal<readonly string[]>;
2757
2810
  /** Fires with the new value whenever the selection changes. */
2758
2811
  readonly changed: _angular_core.OutputEmitterRef<readonly string[]>;
2812
+ /** Fires with the typed text when the user takes the `allowCreate` row. */
2813
+ readonly created: _angular_core.OutputEmitterRef<string>;
2759
2814
  readonly isOpen: _angular_core.WritableSignal<boolean>;
2760
2815
  readonly searchTerm: _angular_core.WritableSignal<string>;
2761
2816
  /** Index into `filteredOptions()` for keyboard navigation. `-1` when none focused. */
@@ -2789,6 +2844,10 @@ declare class MultiSelectComponent implements ControlValueAccessor {
2789
2844
  protected readonly selectAllVisible: _angular_core.Signal<boolean>;
2790
2845
  /** Row-index offset the Select-all row adds ahead of the filtered options. */
2791
2846
  protected readonly selectAllOffset: _angular_core.Signal<1 | 0>;
2847
+ /** The text a Create row would carry, or `''` when no such row is offered. */
2848
+ protected readonly creatableText: _angular_core.Signal<string>;
2849
+ /** Row index of the Create row, which sits after the options, or `-1`. */
2850
+ protected readonly createRow: _angular_core.Signal<number>;
2792
2851
  private readonly rowCount;
2793
2852
  protected readonly selectAllAriaChecked: _angular_core.Signal<"true" | "mixed" | "false">;
2794
2853
  /** Id of the keyboard-focused option, for `aria-activedescendant`. */
@@ -2853,6 +2912,8 @@ declare class MultiSelectComponent implements ControlValueAccessor {
2853
2912
  */
2854
2913
  toggleSelectAll(): void;
2855
2914
  onSearchInput(event: Event): void;
2915
+ private soleOptionRow;
2916
+ private clearSearchForNextValue;
2856
2917
  handleTriggerKeydown(event: KeyboardEvent): void;
2857
2918
  /**
2858
2919
  * Keyboard navigation inside the popover. Bound to both the search input
@@ -2860,10 +2921,11 @@ declare class MultiSelectComponent implements ControlValueAccessor {
2860
2921
  * so users can type spaces in their query.
2861
2922
  */
2862
2923
  handlePopoverKeydown(event: KeyboardEvent): void;
2863
- private focusSearchWhenReady;
2864
2924
  private moveFocusedRow;
2865
2925
  /** Enter/Space on the focused row: row 0 is Select-all when visible. */
2866
2926
  private activateRow;
2927
+ /** Report the typed text, then clear it so the new value can be followed by another. */
2928
+ protected createOption(): void;
2867
2929
  /** Reorder a value-set against the input `options` array. */
2868
2930
  private orderedValues;
2869
2931
  private optionsFor;
@@ -2877,7 +2939,7 @@ declare class MultiSelectComponent implements ControlValueAccessor {
2877
2939
  private measureClippedOptions;
2878
2940
  private watchListWidth;
2879
2941
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<MultiSelectComponent, never>;
2880
- 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>;
2942
+ 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>;
2881
2943
  }
2882
2944
 
2883
2945
  /** Visual size of the number input. */
@@ -3672,6 +3734,19 @@ declare class TooltipDirective implements OnDestroy {
3672
3734
  private readonly viewContainer;
3673
3735
  readonly eaTooltip: _angular_core.InputSignal<string | TemplateRef<unknown>>;
3674
3736
  readonly tooltipPosition: _angular_core.InputSignal<TooltipPosition>;
3737
+ /**
3738
+ * Whether a bubble with no room on the requested side moves to the opposite
3739
+ * one. The side is resolved when the bubble opens and held while it still
3740
+ * fits, so a bubble does not hop across its trigger mid-hover.
3741
+ */
3742
+ readonly flip: _angular_core.InputSignal<boolean>;
3743
+ /**
3744
+ * Show only while the trigger is cutting its own content off, which is how a
3745
+ * label that ellipsizes reveals its full text without a bubble on every
3746
+ * label that fits. The whole subtree is measured, since the box doing the
3747
+ * cutting is usually an inner one.
3748
+ */
3749
+ readonly whenClipped: _angular_core.InputSignal<boolean>;
3675
3750
  /**
3676
3751
  * Max width in px; the text wraps at this width. Clamped to a 50px floor, and
3677
3752
  * to the viewport, which no value can push the bubble past.
@@ -3684,6 +3759,8 @@ declare class TooltipDirective implements OnDestroy {
3684
3759
  */
3685
3760
  readonly dismissDelay: _angular_core.InputSignal<number>;
3686
3761
  private tooltipEl;
3762
+ /** Side the open bubble settled on, held across repositions while it fits. */
3763
+ private placedPosition;
3687
3764
  private templateView;
3688
3765
  private scrollable;
3689
3766
  private hideTimer;
@@ -3698,6 +3775,7 @@ declare class TooltipDirective implements OnDestroy {
3698
3775
  private readonly hoverChangeHandler;
3699
3776
  private rafId;
3700
3777
  private readonly repositionHandler;
3778
+ private readonly relayoutHandler;
3701
3779
  private readonly scrollListenerOptions;
3702
3780
  private resizeObserver;
3703
3781
  constructor();
@@ -3713,10 +3791,11 @@ declare class TooltipDirective implements OnDestroy {
3713
3791
  private appendDescribedBy;
3714
3792
  private removeDescribedBy;
3715
3793
  private positionTooltip;
3794
+ private applyPlacedPosition;
3716
3795
  private viewportMargin;
3717
3796
  private syncScrollable;
3718
3797
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<TooltipDirective, never>;
3719
- 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>;
3798
+ 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>;
3720
3799
  }
3721
3800
 
3722
3801
  /** Semantic colour scheme of a tag. */
@@ -3745,10 +3824,17 @@ declare class TagComponent {
3745
3824
  readonly disabled: _angular_core.InputSignal<boolean>;
3746
3825
  readonly removeLabel: _angular_core.InputSignal<string | undefined>;
3747
3826
  /**
3748
- * Widest the chip may grow, in px; a longer label ellipsizes instead. Also
3749
- * settable in CSS as `--ea-tag-max-width`, which this input overrides.
3827
+ * Widest the chip may grow: a number of px, or any CSS length for a chip that
3828
+ * has to give way to its container (`'100%'` in a responsive grid cell).
3829
+ * Also settable in CSS as `--ea-tag-max-width`, which this input overrides.
3750
3830
  */
3751
- readonly maxWidth: _angular_core.InputSignal<number | undefined>;
3831
+ readonly maxWidth: _angular_core.InputSignal<string | number | undefined>;
3832
+ /**
3833
+ * Fill colour as a hex value, for a tag carrying a colour of its own (a
3834
+ * user-chosen label). Paints the chip and its border, and picks whichever ink
3835
+ * reads better on it. Takes precedence over `variant`.
3836
+ */
3837
+ readonly color: _angular_core.InputSignal<string | undefined>;
3752
3838
  /**
3753
3839
  * Where a label clipped by `maxWidth` reveals its full text. Set `none` for
3754
3840
  * a tag rendered inside a tooltip, which would otherwise stack a second
@@ -3774,6 +3860,11 @@ declare class TagComponent {
3774
3860
  [x: string]: boolean;
3775
3861
  'ea-tag--disabled': boolean;
3776
3862
  }>;
3863
+ /** `maxWidth` as a CSS length; a bare number is px, as the input documents. */
3864
+ protected readonly resolvedMaxWidth: _angular_core.Signal<string | null>;
3865
+ /** Ink that reads on `color`, or `null` when it is not a hex the library can measure. */
3866
+ protected readonly resolvedInk: _angular_core.Signal<string | null>;
3867
+ protected readonly resolvedColor: _angular_core.Signal<string | null>;
3777
3868
  constructor();
3778
3869
  onRemove(event: MouseEvent): void;
3779
3870
  /**
@@ -3783,7 +3874,7 @@ declare class TagComponent {
3783
3874
  */
3784
3875
  private watchLabel;
3785
3876
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<TagComponent, never>;
3786
- 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>;
3877
+ 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>;
3787
3878
  }
3788
3879
 
3789
3880
  /** Visual size of the textarea. */