@forgeroute/ui 0.4.8 → 0.4.10

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.
@@ -578,7 +578,7 @@ export declare class ColumnFilterComponent {
578
578
  cancel(): void;
579
579
  clear(): void;
580
580
  onDocumentClick(_event: Event): void;
581
- onEscape(): void;
581
+ onEscape(event?: Event): void;
582
582
  onArrow(event: Event, dir: 1 | -1): void;
583
583
  /**
584
584
  * Places the fixed dropdown from the trigger's viewport rect: centred under the trigger, clamped
@@ -725,7 +725,7 @@ export declare class MoreMenuComponent {
725
725
  onDocumentClick(): void;
726
726
  /** A touch or mouse press anywhere outside the menu closes it (more reliable than a click on phones: iOS does not send clicks for plain page areas). */
727
727
  onDocumentPointerDown(event: Event): void;
728
- onEscape(): void;
728
+ onEscape(event?: Event): void;
729
729
  onArrow(event: Event, dir: 1 | -1): void;
730
730
  /** Visible top/bottom of the nearest scrolling ancestor, clipped to the viewport. */
731
731
  private _visibleBounds;
@@ -2495,6 +2495,8 @@ export interface CheckboxOption {
2495
2495
  disabled?: boolean;
2496
2496
  /** `data-testid` of this option's native checkbox (e.g. for end-to-end tests); none when omitted. */
2497
2497
  testId?: string;
2498
+ /** `data-testid` of this option's label text; none when omitted. */
2499
+ labelTestId?: string;
2498
2500
  }
2499
2501
  export declare class CheckboxComponent implements ControlValueAccessor, Validator, UiFieldValidity {
2500
2502
  readonly label: import("@angular/core").InputSignal<string>;
@@ -2502,6 +2504,8 @@ export declare class CheckboxComponent implements ControlValueAccessor, Validato
2502
2504
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
2503
2505
  /** `data-testid` of the native checkbox (single mode), for end-to-end tests; none when empty. (Group options have their own `testId`.) */
2504
2506
  readonly testId: import("@angular/core").InputSignal<string>;
2507
+ /** `data-testid` of the label text (single mode), e.g. to find a product name that is also its checkbox label; none when empty. */
2508
+ readonly labelTestId: import("@angular/core").InputSignal<string>;
2505
2509
  /**
2506
2510
  * 1-6 makes the label text a real heading for screen readers (`role="heading"` + `aria-level`) while it stays the checkbox's label and
2507
2511
  * clicking it still toggles the box - e.g. a product name that is both the heading of its card and the label of its checkbox.
@@ -2610,6 +2614,11 @@ export declare class CheckboxComponent implements ControlValueAccessor, Validato
2610
2614
  "required": false;
2611
2615
  "isSignal": true;
2612
2616
  };
2617
+ "labelTestId": {
2618
+ "alias": "labelTestId";
2619
+ "required": false;
2620
+ "isSignal": true;
2621
+ };
2613
2622
  "headingLevel": {
2614
2623
  "alias": "headingLevel";
2615
2624
  "required": false;
@@ -2792,8 +2801,16 @@ export interface StepperStep {
2792
2801
  * mark every step the user has already completed `complete: true`.
2793
2802
  */
2794
2803
  complete?: boolean;
2804
+ /**
2805
+ * `false` = never a button, even when the step is complete and the stepper is `clickable`: it is plain text and keeps its normal look
2806
+ * (no dimming, not announced "disabled"). Use it for a step the user has finished but may not jump back or forward to. Omitted / `true`
2807
+ * = the normal rule (a complete step is a button when `clickable`). It cannot make an upcoming step selectable; use `linear`.
2808
+ */
2809
+ selectable?: boolean;
2795
2810
  }
2796
2811
  export type StepperOrientation = 'horizontal' | 'vertical';
2812
+ /** Viewport width below which a `compact` stepper shows its summary: 'sm' (480px) | 'md' (768px) | 'lg' (1024px) or a pixel number. */
2813
+ export type StepperCompactBreakpoint = 'sm' | 'md' | 'lg' | number;
2797
2814
  /**
2798
2815
  * Step indicator for wizards, onboarding flows and progress timelines. The state of every step comes from the order of
2799
2816
  * `steps` and the key in `current`: steps before it are complete, it is current, steps after it are upcoming.
@@ -2818,6 +2835,9 @@ export type StepperOrientation = 'horizontal' | 'vertical';
2818
2835
  *
2819
2836
  * steps = all.map((s, i) => ({ ...s, complete: i <= furthestReached }))
2820
2837
  *
2838
+ * A step with `selectable: false` is never a button (finished, but not a place to go back to) and looks normal; `disabled` is for a step
2839
+ * that is switched off (dimmed, announced "disabled").
2840
+ *
2821
2841
  * Interaction (`clickable`): a selectable step is a native `<button>` (Tab / Enter / Space, visible focus ring). With
2822
2842
  * `linear` (default) only complete steps are selectable, so the user can go back but not skip ahead; with
2823
2843
  * `[linear]="false"` every non-disabled step is. The current step is never a button (you are already there): it is
@@ -2837,6 +2857,22 @@ export type StepperOrientation = 'horizontal' | 'vertical';
2837
2857
  * on the left). Long labels wrap. At <= 480px a horizontal stepper with `labelsOnSmallScreens="current"` (default) shows
2838
2858
  * only the current step's label (the others stay in the accessible name); `"all"` keeps them. Touch devices and phones
2839
2859
  * get >= 44px tall step buttons. The connector transition honours `prefers-reduced-motion`.
2860
+ *
2861
+ * Wide / responsive headers (all optional, default off, nothing changes without them):
2862
+ * - `scrollable`: the step list sits in an `overflow-x: auto` region with 4px top / bottom padding so focus rings are not clipped.
2863
+ * - `minStepWidth` (CSS length, e.g. `10.5rem`): horizontal only; the list gets `min-width: calc(<step count> * <minStepWidth>)`, so with
2864
+ * `scrollable` it scrolls sideways instead of breaking labels mid-word. The page-level `max-width` / centring stays the host's job.
2865
+ * - `<img stepper-leading>` (any element with the `stepper-leading` attribute) + `leadingWidth` (CSS length): a logo shown at the start of a
2866
+ * horizontal stepper, vertically centred and absolutely positioned, so the steps stay centred; the steps start at `leadingWidth + 1rem`.
2867
+ * Hidden in the compact summary and in vertical orientation.
2868
+ * - `compact` (`'sm' | 'md' | 'lg'` or a pixel number; default null = never): below that viewport width (a width exactly at it is NOT below)
2869
+ * the list is hidden (`display: none`, so it leaves the accessibility tree) and a summary is shown instead: the current step's label
2870
+ * (semibold, large, in `accentColor` when set) with "n / m" at the right, and a `ui-progress-bar` (`aria-label` "Step n of m: <label>").
2871
+ * At / above the breakpoint the summary is hidden. Without a current step the summary reads "0 / m".
2872
+ *
2873
+ * <ui-stepper [steps]="steps" [current]="key" [scrollable]="true" minStepWidth="10.5rem" leadingWidth="7.5rem" compact="md" accentColor="#f97316">
2874
+ * <img stepper-leading src="logo.svg" alt="Acme" />
2875
+ * </ui-stepper>
2840
2876
  */
2841
2877
  export declare class StepperComponent {
2842
2878
  /** The steps in order. Keys must be unique. */
@@ -2853,13 +2889,35 @@ export declare class StepperComponent {
2853
2889
  readonly accentColor: import("@angular/core").InputSignal<string>;
2854
2890
  /** Colour (any CSS colour) of complete steps and the filled connectors, when it should differ from the current step's accent (e.g. green checks, orange current step). */
2855
2891
  readonly completeColor: import("@angular/core").InputSignal<string>;
2892
+ /** true = the current step's label is drawn in the accent colour as well as its indicator. Default false: the label keeps the dark text colour. */
2893
+ readonly accentLabels: import("@angular/core").InputSignal<boolean>;
2856
2894
  /** Accessible name of the list. */
2857
2895
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
2858
2896
  /** Horizontal, <= 480px: show only the current step's label (`'current'`, default) or every label (`'all'`). */
2859
2897
  readonly labelsOnSmallScreens: import("@angular/core").InputSignal<"all" | "current">;
2898
+ /** CSS length (e.g. `10.5rem`): horizontal only - the list gets `min-width: calc(<step count> * <value>)`. Empty (default) = no minimum. */
2899
+ readonly minStepWidth: import("@angular/core").InputSignal<string>;
2900
+ /** true = the list scrolls sideways (`overflow-x: auto`, 4px top / bottom padding so focus rings are not clipped) instead of squeezing. Default false. */
2901
+ readonly scrollable: import("@angular/core").InputSignal<boolean>;
2902
+ /** CSS length: width reserved for the `[stepper-leading]` element (a logo); the steps start at this width + 1rem. Empty = no leading area. */
2903
+ readonly leadingWidth: import("@angular/core").InputSignal<string>;
2904
+ /** Below this viewport width ('sm' 480 | 'md' 768 | 'lg' 1024 | pixels) the list is replaced by a summary (label, "n / m", progress bar). null (default) = never. */
2905
+ readonly compact: import("@angular/core").InputSignal<StepperCompactBreakpoint | null>;
2860
2906
  /** Emits the key of an activated selectable step that was not already current (after `current` was updated). */
2861
2907
  readonly stepClick: import("@angular/core").OutputEmitterRef<string>;
2908
+ private readonly _win;
2909
+ private readonly _narrow;
2910
+ /** True when `compact` is a pixel number and the viewport is below it (tokens use CSS media queries instead). */
2911
+ protected readonly compactPx: import("@angular/core").Signal<boolean>;
2862
2912
  private readonly _id;
2913
+ constructor();
2914
+ protected readonly olMinWidth: import("@angular/core").Signal<string | null>;
2915
+ protected readonly summary: import("@angular/core").Signal<{
2916
+ n: number;
2917
+ m: number;
2918
+ label: string;
2919
+ aria: string;
2920
+ }>;
2863
2921
  protected readonly rows: import("@angular/core").Signal<{
2864
2922
  step: StepperStep;
2865
2923
  index: number;
@@ -2918,6 +2976,11 @@ export declare class StepperComponent {
2918
2976
  "required": false;
2919
2977
  "isSignal": true;
2920
2978
  };
2979
+ "accentLabels": {
2980
+ "alias": "accentLabels";
2981
+ "required": false;
2982
+ "isSignal": true;
2983
+ };
2921
2984
  "ariaLabel": {
2922
2985
  "alias": "ariaLabel";
2923
2986
  "required": false;
@@ -2928,10 +2991,30 @@ export declare class StepperComponent {
2928
2991
  "required": false;
2929
2992
  "isSignal": true;
2930
2993
  };
2994
+ "minStepWidth": {
2995
+ "alias": "minStepWidth";
2996
+ "required": false;
2997
+ "isSignal": true;
2998
+ };
2999
+ "scrollable": {
3000
+ "alias": "scrollable";
3001
+ "required": false;
3002
+ "isSignal": true;
3003
+ };
3004
+ "leadingWidth": {
3005
+ "alias": "leadingWidth";
3006
+ "required": false;
3007
+ "isSignal": true;
3008
+ };
3009
+ "compact": {
3010
+ "alias": "compact";
3011
+ "required": false;
3012
+ "isSignal": true;
3013
+ };
2931
3014
  }, {
2932
3015
  "current": "currentChange";
2933
3016
  "stepClick": "stepClick";
2934
- }, never, never, true, never>;
3017
+ }, never, ["[stepper-leading]"], true, never>;
2935
3018
  }
2936
3019
  /** One weekday of the schedule. `open` / `close` are `HH:mm`; `open2` / `close2` are the optional second shift (split shift). */
2937
3020
  export interface BusinessHoursDay {
@@ -3430,6 +3513,12 @@ export declare class ButtonComponent {
3430
3513
  readonly queryParams: import("@angular/core").InputSignal<Record<string, unknown> | null>;
3431
3514
  /** Fragment (hash) of the `routerLink`, without the `#` (e.g. `'billing'` -> `/settings#billing`). */
3432
3515
  readonly fragment: import("@angular/core").InputSignal<string | null>;
3516
+ /**
3517
+ * Router navigation state of the `routerLink` (the `history.state` of the page it opens), e.g. `{ returnTo: '/compliance' }` so the
3518
+ * target page can offer a "Back" link. Ignored without `routerLink`. Middle-click / open-in-new-tab open the plain href, which carries
3519
+ * no state (the target page then falls back to its default back target).
3520
+ */
3521
+ readonly state: import("@angular/core").InputSignal<Record<string, unknown> | null>;
3433
3522
  /**
3434
3523
  * Renders a plain `<a href>` instead of a button: for `mailto:`, `tel:`, `sms:`, `https://…` and relative URLs (use with
3435
3524
  * `variant="link"` for an inline text link). The browser handles the click, so middle-click, copy-link and open-in-new-tab work and
@@ -3444,9 +3533,25 @@ export declare class ButtonComponent {
3444
3533
  /** The href when it is allowed (http, https, mailto, tel, sms or a relative URL), else null. */
3445
3534
  protected readonly _safeHref: import("@angular/core").Signal<string | null>;
3446
3535
  protected readonly _rel: import("@angular/core").Signal<string | null>;
3536
+ /**
3537
+ * A shorter text for narrow screens (e.g. content "Previous", `shortLabel="Back"`). Below `shortBelow` the button shows this text instead of
3538
+ * its content. Accessibility: the projected (long) content stays in the page, only visually hidden, so the accessible name is always the
3539
+ * long text - the short text is `aria-hidden` and never read twice; an explicit `ariaLabel` still wins. Empty (default) = the content is
3540
+ * rendered exactly as before. Meant for text content (icons inside the content are hidden together with it).
3541
+ */
3542
+ readonly shortLabel: import("@angular/core").InputSignal<string>;
3543
+ /**
3544
+ * Where `shortLabel` applies: a library token `'sm'` (480px) / `'md'` (768px) / `'lg'` (1024px), or a pixel number (e.g. `640`). The short text
3545
+ * shows when the viewport is narrower than this; from the width itself the long text shows (`640`: >= 640px long, < 640px short, like a
3546
+ * `min-width: 640px` switch). Tokens are pure CSS; a number is tracked with `matchMedia`. Default `'md'`.
3547
+ */
3548
+ readonly shortBelow: import("@angular/core").InputSignal<number | "sm" | "md" | "lg">;
3549
+ /** Classes of the two label spans: the token class, or `btn-sl-narrow` while a pixel breakpoint is active. */
3550
+ protected readonly _slClass: import("@angular/core").Signal<string>;
3551
+ private readonly _narrow;
3447
3552
  readonly color: import("@angular/core").InputSignal<string | undefined>;
3448
3553
  readonly active: import("@angular/core").InputSignal<boolean>;
3449
- readonly size: import("@angular/core").InputSignal<"sm" | "md" | "xs" | "lg">;
3554
+ readonly size: import("@angular/core").InputSignal<"sm" | "md" | "lg" | "xs">;
3450
3555
  readonly type: import("@angular/core").InputSignal<"reset" | "submit" | "button">;
3451
3556
  readonly disabled: import("@angular/core").InputSignal<boolean>;
3452
3557
  readonly loading: import("@angular/core").InputSignal<boolean>;
@@ -3456,6 +3561,7 @@ export declare class ButtonComponent {
3456
3561
  readonly ariaPressed: import("@angular/core").InputSignal<boolean | undefined>;
3457
3562
  /** Id of the element that describes this button (an error or hint rendered next to it), e.g. `<ui-error errorId="x">`. Absent when empty. */
3458
3563
  readonly ariaDescribedBy: import("@angular/core").InputSignal<string | undefined>;
3564
+ constructor();
3459
3565
  _footerLeft?: string;
3460
3566
  _footerRight?: string;
3461
3567
  static ɵfac: i0.ɵɵFactoryDeclaration<ButtonComponent, never>;
@@ -3480,6 +3586,11 @@ export declare class ButtonComponent {
3480
3586
  "required": false;
3481
3587
  "isSignal": true;
3482
3588
  };
3589
+ "state": {
3590
+ "alias": "state";
3591
+ "required": false;
3592
+ "isSignal": true;
3593
+ };
3483
3594
  "href": {
3484
3595
  "alias": "href";
3485
3596
  "required": false;
@@ -3495,6 +3606,16 @@ export declare class ButtonComponent {
3495
3606
  "required": false;
3496
3607
  "isSignal": true;
3497
3608
  };
3609
+ "shortLabel": {
3610
+ "alias": "shortLabel";
3611
+ "required": false;
3612
+ "isSignal": true;
3613
+ };
3614
+ "shortBelow": {
3615
+ "alias": "shortBelow";
3616
+ "required": false;
3617
+ "isSignal": true;
3618
+ };
3498
3619
  "color": {
3499
3620
  "alias": "color";
3500
3621
  "required": false;
@@ -4014,6 +4135,14 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
4014
4135
  * phone formatting runs first and the formatter then sees its result.
4015
4136
  */
4016
4137
  readonly formatter: import("@angular/core").InputSignal<((raw: string) => string) | undefined>;
4138
+ /**
4139
+ * Whole numbers only (default off). Every typed or pasted value is cut at its first `.`, `e` or `E` (`2.7` -> `2`, `1e1` -> `1`, `12` stays),
4140
+ * the same filter as cremo's `wholeNumber`. It runs after the phone formatting and before a host `formatter`. It also picks the numeric
4141
+ * on-screen keyboard (`inputmode="numeric"`), the native `step` 1 and `maxDecimals` 0 for `type="number"` - each only while the host has not
4142
+ * set `inputmode` / `step` / `maxDecimals` itself. Values the host writes (`writeValue`) are shown as they are (a decimal there still fails
4143
+ * the 0-decimals rule).
4144
+ */
4145
+ readonly integer: import("@angular/core").InputSignal<boolean>;
4017
4146
  /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
4018
4147
  readonly showErrors: import("@angular/core").InputSignal<boolean>;
4019
4148
  /** Emits the new value when the USER changes it (typing, paste, autofill) - the same value the form control receives. Not emitted for values the host writes. */
@@ -4167,6 +4296,11 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
4167
4296
  "required": false;
4168
4297
  "isSignal": true;
4169
4298
  };
4299
+ "integer": {
4300
+ "alias": "integer";
4301
+ "required": false;
4302
+ "isSignal": true;
4303
+ };
4170
4304
  "showErrors": {
4171
4305
  "alias": "showErrors";
4172
4306
  "required": false;
@@ -4313,7 +4447,7 @@ export declare class TextareaInputComponent implements ControlValueAccessor, Val
4313
4447
  }, never, never, true, never>;
4314
4448
  }
4315
4449
  export type TextSize = 'sm' | 'md' | 'lg';
4316
- export type TextTone = 'default' | 'muted';
4450
+ export type TextTone = 'default' | 'muted' | 'accent';
4317
4451
  export type TextWeight = 'normal' | 'medium' | 'semibold' | 'bold';
4318
4452
  /**
4319
4453
  * Plain text that keeps its line breaks: a note, a message, an address, a pasted block. It is page content, not a form control —
@@ -4340,6 +4474,8 @@ export declare class TextComponent {
4340
4474
  readonly text: import("@angular/core").InputSignal<string | null | undefined>;
4341
4475
  readonly size: import("@angular/core").InputSignal<TextSize>;
4342
4476
  readonly tone: import("@angular/core").InputSignal<TextTone>;
4477
+ /** Any CSS colour for the text (e.g. the brand colour). Wins over `tone`; empty = the tone's colour. `tone="accent"` uses `--ui-accent` (default blue). */
4478
+ readonly color: import("@angular/core").InputSignal<string>;
4343
4479
  /** Snippet(s) of `text` to show in bold. Empty / not found = no change. */
4344
4480
  readonly strong: import("@angular/core").InputSignal<string | string[] | null | undefined>;
4345
4481
  /** The text cut into plain and bold pieces; empty when nothing is to be bold (then the text renders as a single text node). */
@@ -4368,6 +4504,11 @@ export declare class TextComponent {
4368
4504
  "required": false;
4369
4505
  "isSignal": true;
4370
4506
  };
4507
+ "color": {
4508
+ "alias": "color";
4509
+ "required": false;
4510
+ "isSignal": true;
4511
+ };
4371
4512
  "strong": {
4372
4513
  "alias": "strong";
4373
4514
  "required": false;
@@ -5457,6 +5598,10 @@ export declare class DropdownComponent {
5457
5598
  * - `ariaLabel` (or `ariaLabelledby`): the form's name. A named form is a landmark, so give it one only for a main form of the page.
5458
5599
  * - The browser's own validation bubbles are off (`novalidate`): library inputs show their own messages.
5459
5600
  * - `submitted` emits the submit event after the default action (a page reload) was prevented.
5601
+ * - `focusFirstInvalid({ scroll })`: after a failed Save, call it (e.g. `form.focusFirstInvalid()` from a `viewChild(FormComponent)`) to scroll to and focus the first
5602
+ * field that shows an error. It looks for `aria-invalid="true"` in DOM order (what every library input sets once it shows an error); on a
5603
+ * group (radio group, checkbox group, business hours) it focuses the group's first enabled control. Disabled and hidden controls are
5604
+ * skipped. Returns whether something was focused. `invalidFields()` returns those controls without moving focus.
5460
5605
  * - Layout: the host is a block and the form inside is a plain block - it adds no spacing; put a `ui-stack` / `ui-form-section` inside.
5461
5606
  */
5462
5607
  export declare class FormComponent {
@@ -5468,6 +5613,20 @@ export declare class FormComponent {
5468
5613
  readonly autocomplete: import("@angular/core").InputSignal<"" | "off" | "on">;
5469
5614
  /** Emits the submit event (Enter in a field, or a submit button). The page is never reloaded. */
5470
5615
  readonly submitted: import("@angular/core").OutputEmitterRef<Event>;
5616
+ private readonly _host;
5617
+ private static _usable;
5618
+ /**
5619
+ * The native controls that currently show an error (`aria-invalid="true"`), in DOM order. A group marked invalid (radio group, checkbox
5620
+ * group, business hours...) contributes its first enabled, visible control. Disabled and hidden controls are left out.
5621
+ */
5622
+ invalidFields(): HTMLElement[];
5623
+ /**
5624
+ * Scrolls the first invalid field (see `invalidFields`) to the middle of the screen and focuses it without a second scroll.
5625
+ * `scroll: false` only focuses. Returns false (and does nothing) when no field is invalid.
5626
+ */
5627
+ focusFirstInvalid(options?: {
5628
+ scroll?: boolean;
5629
+ }): boolean;
5471
5630
  protected onSubmit(event: Event): void;
5472
5631
  static ɵfac: i0.ɵɵFactoryDeclaration<FormComponent, never>;
5473
5632
  static ɵcmp: i0.ɵɵComponentDeclaration<FormComponent, "ui-form", never, {
@@ -6855,6 +7014,8 @@ export declare class ImageComponent {
6855
7014
  readonly height: import("@angular/core").InputSignal<string>;
6856
7015
  readonly maxWidth: import("@angular/core").InputSignal<string>;
6857
7016
  readonly maxHeight: import("@angular/core").InputSignal<string>;
7017
+ /** Minimum height of the image box (any CSS length). Empty = none. */
7018
+ readonly minHeight: import("@angular/core").InputSignal<string>;
6858
7019
  /** CSS aspect-ratio, e.g. "4 / 3". Reserves the space while the image loads. */
6859
7020
  readonly aspectRatio: import("@angular/core").InputSignal<string>;
6860
7021
  readonly radius: import("@angular/core").InputSignal<ImageRadius>;
@@ -6916,6 +7077,11 @@ export declare class ImageComponent {
6916
7077
  "required": false;
6917
7078
  "isSignal": true;
6918
7079
  };
7080
+ "minHeight": {
7081
+ "alias": "minHeight";
7082
+ "required": false;
7083
+ "isSignal": true;
7084
+ };
6919
7085
  "aspectRatio": {
6920
7086
  "alias": "aspectRatio";
6921
7087
  "required": false;
@@ -6989,11 +7155,19 @@ export declare class ImageGalleryComponent {
6989
7155
  readonly maxHeight: import("@angular/core").InputSignal<string>;
6990
7156
  readonly fit: import("@angular/core").InputSignal<"contain" | "cover">;
6991
7157
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
7158
+ /**
7159
+ * true = when the gallery sits in a `ui-modal`, the dialog opens with focus on the gallery's "Next image" button (or "Previous image" when
7160
+ * Next is disabled at the last picture of a non-looping gallery), so the arrow keys work at once without a Tab. With a single picture there are
7161
+ * no buttons, so the dialog keeps its normal initial focus. Default false: unchanged.
7162
+ */
7163
+ readonly autofocus: import("@angular/core").InputSignal<boolean>;
6992
7164
  protected readonly count: import("@angular/core").Signal<number>;
6993
7165
  /** `index` clamped into the list. */
6994
7166
  protected readonly position: import("@angular/core").Signal<number>;
6995
7167
  protected readonly current: import("@angular/core").Signal<GalleryImage>;
6996
7168
  protected readonly currentAlt: import("@angular/core").Signal<string>;
7169
+ protected readonly autofocusNext: import("@angular/core").Signal<boolean>;
7170
+ protected readonly autofocusPrev: import("@angular/core").Signal<boolean>;
6997
7171
  protected readonly canPrev: import("@angular/core").Signal<boolean>;
6998
7172
  protected readonly canNext: import("@angular/core").Signal<boolean>;
6999
7173
  protected readonly announcement: import("@angular/core").Signal<string>;
@@ -7048,6 +7222,11 @@ export declare class ImageGalleryComponent {
7048
7222
  "required": false;
7049
7223
  "isSignal": true;
7050
7224
  };
7225
+ "autofocus": {
7226
+ "alias": "autofocus";
7227
+ "required": false;
7228
+ "isSignal": true;
7229
+ };
7051
7230
  }, {
7052
7231
  "index": "indexChange";
7053
7232
  }, never, never, true, never>;
@@ -8049,7 +8228,9 @@ export declare class PdfHotspotComponent {
8049
8228
  * ("Edit informant information") when the visible label alone is ambiguous; it should contain the visible label.
8050
8229
  * - `fill`: the card stretches to the height of its container (a grid cell or flex item) and its body grows, so cards in
8051
8230
  * one row end at the same height; the default card is only as tall as its content.
8231
+ * Use it in grid / flex cells: the spacing between cells comes from the gap, so a filled card's margin-bottom is 0 (the default card keeps 16px).
8052
8232
  * - `background`: the card's background colour (any CSS colour; default white).
8233
+ * - `headerBackground`: the background colour of the header bar only (any CSS colour; default none, the card's own background shows). The body keeps the card's `background`, and a header-less card (`showHeader` false) has no bar to colour. A collapsible header keeps this colour on hover. Pair it with `textColor` when the colour is dark.
8053
8234
  * - `textColor`: the colour of the title, subtitle, chevron and body text (any CSS colour; default: the normal slate colours). Use it for light text on a dark `background`. Text you colour yourself inside the body keeps its own colour.
8054
8235
  * - The body has built-in padding (16px 18px, matching the header's 18px side padding); there is no padding input.
8055
8236
  * - `collapsible` (default true): a chevron toggle and a clickable header; `[(expanded)]` is two-way.
@@ -8057,6 +8238,15 @@ export declare class PdfHotspotComponent {
8057
8238
  *
8058
8239
  * The title is shown in capitals unless `[uppercaseTitle]="false"` (then it shows as written, e.g. "Case IDs"); the casing is CSS only, so the accessible name and heading text are always the text you gave; the subtitle keeps the case you give it. The body is the default content slot. A collapsed body is removed from the tab order and from assistive tech.
8059
8240
  *
8241
+ * - `selectable` (default false) + `[(selected)]` + `selectedColor` / `selectedBackground`: a pickable card (a product card, a plan). A click anywhere on the card
8242
+ * toggles `selected`, except a click on or inside an interactive element (`button, a[href], input, select, textarea, label, [role=button],
8243
+ * [role=link], [data-no-select]`; mark any other control with `data-no-select`) and except when text inside the card is being selected
8244
+ * (a drag). A selected card gets `data-selected="true"` on the host, a 2px outline (`selectedColor`, default `#3b82f6`, drawn 1px inside the edge) and,
8245
+ * when `selectedBackground` is set, that background (instead of `background`). A selectable card shows the pointer cursor.
8246
+ * The card is NOT focusable and has no extra role: **a selectable card must contain its own checkbox (or radio)**, which is the keyboard and
8247
+ * assistive-tech path (`[checked]="selected()"` / `(change)`). With `selectable` false there is no handler, cursor or outline.
8248
+ * (A click on a collapsible header outside its controls still collapses the card as before.)
8249
+ *
8060
8250
  * <ui-detail-card title="COMMUNICATIONS" subtitle="All calls, texts, and emails"> ...body... </ui-detail-card>
8061
8251
  * <ui-detail-card title="CONTACT INFO" [showEdit]="true" (editClick)="openEdit()"> ... </ui-detail-card>
8062
8252
  * <ui-detail-card [showHeader]="false"> ...body only... </ui-detail-card>
@@ -8082,6 +8272,8 @@ export declare class DetailCardComponent {
8082
8272
  readonly subtitle: import("@angular/core").InputSignal<string>;
8083
8273
  /** Card background as any CSS colour (`#f8fafc`, `var(--surface)` …). Empty = white. */
8084
8274
  readonly background: import("@angular/core").InputSignal<string>;
8275
+ /** Background colour of the header bar only, as any CSS colour (`#eaf3ff`, `var(--surface-2)` …). Empty = the header has no colour of its own (the card background shows). The body is not affected. */
8276
+ readonly headerBackground: import("@angular/core").InputSignal<string>;
8085
8277
  /** Text colour as any CSS colour (`#fff`, `var(--on-dark)` …). Empty = the default colours. Colours the title, subtitle, chevron and body text. */
8086
8278
  readonly textColor: import("@angular/core").InputSignal<string>;
8087
8279
  /** false = no header at all (no title, edit button, toggle or divider): the card is only the body, always open. */
@@ -8094,14 +8286,28 @@ export declare class DetailCardComponent {
8094
8286
  readonly showEdit: import("@angular/core").InputSignal<boolean>;
8095
8287
  readonly editLabel: import("@angular/core").InputSignal<string>;
8096
8288
  readonly editClick: import("@angular/core").OutputEmitterRef<void>;
8289
+ /** `data-testid` of the built-in Edit button (on the `ui-button` host); none when empty. */
8290
+ readonly editTestId: import("@angular/core").InputSignal<string>;
8291
+ /** false = no pencil icon in the Edit button (text only). Default true: unchanged. */
8292
+ readonly editIcon: import("@angular/core").InputSignal<boolean>;
8097
8293
  /** Accessible name of the Edit button, e.g. "Edit informant information". Empty = the visible `editLabel`. */
8098
8294
  readonly editAriaLabel: import("@angular/core").InputSignal<string>;
8099
- /** true = the card fills the height of its container so sibling cards line up; the body grows. Default false: unchanged. */
8295
+ /** true = the card fills the height of its container (a grid cell / flex item) so sibling cards line up; the body grows. Spacing between cells comes from the gap: the filled card's margin-bottom is 0. Default false: unchanged. */
8100
8296
  readonly fill: import("@angular/core").InputSignal<boolean>;
8297
+ /** true = a click on the card (outside interactive controls and text selections) toggles `selected`. The card must contain its own checkbox for keyboard / screen-reader users. Default false: no handler, cursor or outline. */
8298
+ readonly selectable: import("@angular/core").InputSignal<boolean>;
8299
+ /** Two-way: whether the card is selected (only shown / toggled when `selectable`). */
8300
+ readonly selected: import("@angular/core").ModelSignal<boolean>;
8301
+ /** CSS colour of the 2px outline of a selected card. Default `#3b82f6`. */
8302
+ readonly selectedColor: import("@angular/core").InputSignal<string>;
8303
+ /** CSS colour used as the card background while selected (wins over `background`). Empty = the background does not change. */
8304
+ readonly selectedBackground: import("@angular/core").InputSignal<string>;
8101
8305
  /** The group's aria-label: the visible title (unless `titleId` names the card instead), else `ariaLabel`, else none. */
8102
8306
  groupLabel(): string | null;
8103
8307
  /** The body is open unless the card has a header that is collapsible and was collapsed. */
8104
8308
  isOpen(): boolean;
8309
+ /** selectable: a click on the card toggles `selected` unless it came from an interactive element or ends a text selection. */
8310
+ onCardClick(event: Event): void;
8105
8311
  toggle(): void;
8106
8312
  /** A click on the header toggles, except on a control inside it (Edit, your own header actions, links, inputs). */
8107
8313
  onHeaderClick(event: Event): void;
@@ -8142,6 +8348,11 @@ export declare class DetailCardComponent {
8142
8348
  "required": false;
8143
8349
  "isSignal": true;
8144
8350
  };
8351
+ "headerBackground": {
8352
+ "alias": "headerBackground";
8353
+ "required": false;
8354
+ "isSignal": true;
8355
+ };
8145
8356
  "textColor": {
8146
8357
  "alias": "textColor";
8147
8358
  "required": false;
@@ -8172,6 +8383,16 @@ export declare class DetailCardComponent {
8172
8383
  "required": false;
8173
8384
  "isSignal": true;
8174
8385
  };
8386
+ "editTestId": {
8387
+ "alias": "editTestId";
8388
+ "required": false;
8389
+ "isSignal": true;
8390
+ };
8391
+ "editIcon": {
8392
+ "alias": "editIcon";
8393
+ "required": false;
8394
+ "isSignal": true;
8395
+ };
8175
8396
  "editAriaLabel": {
8176
8397
  "alias": "editAriaLabel";
8177
8398
  "required": false;
@@ -8182,9 +8403,30 @@ export declare class DetailCardComponent {
8182
8403
  "required": false;
8183
8404
  "isSignal": true;
8184
8405
  };
8406
+ "selectable": {
8407
+ "alias": "selectable";
8408
+ "required": false;
8409
+ "isSignal": true;
8410
+ };
8411
+ "selected": {
8412
+ "alias": "selected";
8413
+ "required": false;
8414
+ "isSignal": true;
8415
+ };
8416
+ "selectedColor": {
8417
+ "alias": "selectedColor";
8418
+ "required": false;
8419
+ "isSignal": true;
8420
+ };
8421
+ "selectedBackground": {
8422
+ "alias": "selectedBackground";
8423
+ "required": false;
8424
+ "isSignal": true;
8425
+ };
8185
8426
  }, {
8186
8427
  "expanded": "expandedChange";
8187
8428
  "editClick": "editClick";
8429
+ "selected": "selectedChange";
8188
8430
  }, never, ["[card-header-leading]", "[card-header]", "[card-header-action]", "*"], true, never>;
8189
8431
  }
8190
8432
  export type DividerSpace = 'none' | 'sm' | 'md' | 'lg';
@@ -8625,11 +8867,26 @@ export declare class ColumnsComponent {
8625
8867
  readonly countBelowMd: import("@angular/core").InputSignal<ColumnsCount | null>;
8626
8868
  /** Column count at <= 480px (falls back to `countBelowMd`, then `countBelowLg`, then `count`). */
8627
8869
  readonly countBelowSm: import("@angular/core").InputSignal<ColumnsCount | null>;
8870
+ /**
8871
+ * Mobile-first alternative to `count` + `countBelow*`: `countBase` columns on the narrowest screens (default 1), then `countFromSm` from 480px,
8872
+ * `countFromMd` from 768px, `countFromLg` from 1024px (min-width, inclusive; each tier falls back to the next narrower one). Setting any `countFrom*`
8873
+ * switches the grid to this mode: `count`, `countBelow*` and `collapseAt` are then ignored. Unset = unchanged.
8874
+ * <ui-columns [countFromMd]="2" [countFromLg]="3"> ... </ui-columns> <!-- 1 column, 2 from 768px, 3 from 1024px -->
8875
+ */
8876
+ readonly countBase: import("@angular/core").InputSignal<ColumnsCount>;
8877
+ readonly countFromSm: import("@angular/core").InputSignal<ColumnsCount | null>;
8878
+ readonly countFromMd: import("@angular/core").InputSignal<ColumnsCount | null>;
8879
+ readonly countFromLg: import("@angular/core").InputSignal<ColumnsCount | null>;
8628
8880
  protected readonly cols: import("@angular/core").Signal<ColumnsCount>;
8629
8881
  private static clampTier;
8630
8882
  protected readonly colsLg: import("@angular/core").Signal<ColumnsCount | null>;
8631
8883
  protected readonly colsMd: import("@angular/core").Signal<ColumnsCount | null>;
8632
8884
  protected readonly colsSm: import("@angular/core").Signal<ColumnsCount | null>;
8885
+ protected readonly fromMode: import("@angular/core").Signal<boolean>;
8886
+ protected readonly base: import("@angular/core").Signal<ColumnsCount | null>;
8887
+ protected readonly fromSm: import("@angular/core").Signal<ColumnsCount | null>;
8888
+ protected readonly fromMd: import("@angular/core").Signal<ColumnsCount | null>;
8889
+ protected readonly fromLg: import("@angular/core").Signal<ColumnsCount | null>;
8633
8890
  protected readonly gapCss: import("@angular/core").Signal<string>;
8634
8891
  protected readonly collapseClass: import("@angular/core").Signal<string>;
8635
8892
  static ɵfac: i0.ɵɵFactoryDeclaration<ColumnsComponent, never>;
@@ -8669,6 +8926,26 @@ export declare class ColumnsComponent {
8669
8926
  "required": false;
8670
8927
  "isSignal": true;
8671
8928
  };
8929
+ "countBase": {
8930
+ "alias": "countBase";
8931
+ "required": false;
8932
+ "isSignal": true;
8933
+ };
8934
+ "countFromSm": {
8935
+ "alias": "countFromSm";
8936
+ "required": false;
8937
+ "isSignal": true;
8938
+ };
8939
+ "countFromMd": {
8940
+ "alias": "countFromMd";
8941
+ "required": false;
8942
+ "isSignal": true;
8943
+ };
8944
+ "countFromLg": {
8945
+ "alias": "countFromLg";
8946
+ "required": false;
8947
+ "isSignal": true;
8948
+ };
8672
8949
  }, {}, never, ["*"], true, never>;
8673
8950
  }
8674
8951
  export type StackDirection = 'vertical' | 'horizontal';
@@ -8688,6 +8965,7 @@ export type StackJustify = 'start' | 'center' | 'end' | 'between';
8688
8965
  * - `align`: start | center | end | stretch (cross axis, default stretch).
8689
8966
  * - `justify`: start | center | end | between (main axis, default start).
8690
8967
  * - `wrap`: let a horizontal stack wrap onto more lines (default false).
8968
+ * - `maxWidth` (CSS length) / `padding` (CSS padding) / `centered` (margin-inline auto): limit, pad and centre the stack. Defaults '' / '' / false = unchanged.
8691
8969
  *
8692
8970
  * <ui-stack gap="20px">
8693
8971
  * <ui-detail-card title="EMAIL"> ... </ui-detail-card>
@@ -8701,6 +8979,16 @@ export declare class StackComponent {
8701
8979
  readonly align: import("@angular/core").InputSignal<StackAlign>;
8702
8980
  readonly justify: import("@angular/core").InputSignal<StackJustify>;
8703
8981
  readonly wrap: import("@angular/core").InputSignal<boolean>;
8982
+ /** Minimum height of the stack (any CSS length, e.g. "12rem"); with `justify="center"` it centres the content vertically. Empty = none. */
8983
+ readonly minHeight: import("@angular/core").InputSignal<string>;
8984
+ /** Width of the stack (any CSS length or "100%"). Empty = the normal block width. */
8985
+ readonly width: import("@angular/core").InputSignal<string>;
8986
+ /** Maximum width of the stack (any CSS length). Empty = none. */
8987
+ readonly maxWidth: import("@angular/core").InputSignal<string>;
8988
+ /** Padding of the stack (any CSS padding value). Empty = none. */
8989
+ readonly padding: import("@angular/core").InputSignal<string>;
8990
+ /** Centre the stack horizontally (margin-inline: auto; use with `maxWidth`). */
8991
+ readonly centered: import("@angular/core").InputSignal<boolean>;
8704
8992
  protected readonly gapCss: import("@angular/core").Signal<string>;
8705
8993
  protected readonly alignCss: import("@angular/core").Signal<string>;
8706
8994
  protected readonly justifyCss: import("@angular/core").Signal<string>;
@@ -8731,6 +9019,31 @@ export declare class StackComponent {
8731
9019
  "required": false;
8732
9020
  "isSignal": true;
8733
9021
  };
9022
+ "minHeight": {
9023
+ "alias": "minHeight";
9024
+ "required": false;
9025
+ "isSignal": true;
9026
+ };
9027
+ "width": {
9028
+ "alias": "width";
9029
+ "required": false;
9030
+ "isSignal": true;
9031
+ };
9032
+ "maxWidth": {
9033
+ "alias": "maxWidth";
9034
+ "required": false;
9035
+ "isSignal": true;
9036
+ };
9037
+ "padding": {
9038
+ "alias": "padding";
9039
+ "required": false;
9040
+ "isSignal": true;
9041
+ };
9042
+ "centered": {
9043
+ "alias": "centered";
9044
+ "required": false;
9045
+ "isSignal": true;
9046
+ };
8734
9047
  }, {}, never, ["*"], true, never>;
8735
9048
  }
8736
9049
  export type ActionBarAlign = 'start' | 'center' | 'end' | 'between';
@@ -8805,4 +9118,694 @@ export declare class ActionBarComponent {
8805
9118
  "isSignal": true;
8806
9119
  };
8807
9120
  }, {}, never, ["*"], true, never>;
8808
- }
9121
+ }
9122
+ /** Pure date helpers for `ui-calendar`. Dates are plain `YYYY-MM-DD` strings and times `HH:mm`; nothing here parses a non-ISO string. */
9123
+ type CalendarViewMode = 'month' | 'week' | 'agenda';
9124
+ interface CalendarDay {
9125
+ dateStr: string;
9126
+ dayNum: number;
9127
+ isToday: boolean;
9128
+ isCurrentMonth: boolean;
9129
+ isWeekend: boolean;
9130
+ }
9131
+ interface CalendarRange {
9132
+ view: CalendarViewMode;
9133
+ /** First visible date, `YYYY-MM-DD`. */
9134
+ start: string;
9135
+ /** Last visible date (inclusive), `YYYY-MM-DD`. */
9136
+ end: string;
9137
+ /** The date the view is anchored on. */
9138
+ anchor: Date;
9139
+ }
9140
+ declare const WEEK_DAY_LABELS: string[];
9141
+ declare function toDateStr(d: Date): string;
9142
+ /** `YYYY-MM-DD` → local Date at midnight (ISO local form, parsed the same way in every browser). */
9143
+ declare function fromDateStr(dateStr: string): Date;
9144
+ /** The 42 cells (6 weeks, Sunday first) of the month grid containing `anchor`. */
9145
+ declare function buildMonthCells(anchor: Date, todayStr: string): CalendarDay[];
9146
+ /** The 7 days (Sunday first) of the week containing `anchor`. */
9147
+ declare function buildWeekDays(anchor: Date, todayStr: string): CalendarDay[];
9148
+ /** Month view: the whole 6-week grid. Week view: the 7 days. Agenda view: the anchor month and the next one. */
9149
+ declare function rangeFor(view: CalendarViewMode, anchor: Date, todayStr: string): CalendarRange;
9150
+ /**
9151
+ * Anchor after pressing Previous (`-1`) / Next (`1`): a week, two months (agenda, on the 1st) or one month. A month step keeps the
9152
+ * day of the month (clamped to the target month's length), so switching to the week view afterwards shows a sensible week.
9153
+ */
9154
+ declare function shiftAnchor(view: CalendarViewMode, anchor: Date, direction: -1 | 1): Date;
9155
+ /** `Wednesday, October 21, 2026` — one cached formatter, used for every cell's screen-reader name. */
9156
+ declare function formatDayLabel(dateStr: string): string;
9157
+ declare function periodLabelFor(view: CalendarViewMode, anchor: Date, todayStr: string): string;
9158
+ /** `14:30` → `2:30 PM`. */
9159
+ declare function formatTime$1(time: string): string;
9160
+ declare function formatHour(h: number): string;
9161
+ /** Pixel height of one hour row in the week view. */
9162
+ declare const HOUR_HEIGHT = 60;
9163
+ /**
9164
+ * Top offset and height (px) of a timed event in a week grid whose first row is `startHour` and last row `endHour`.
9165
+ * The box is clamped to the visible rows (an event that starts before `startHour` or ends after the last row is cut, never drawn outside).
9166
+ */
9167
+ declare function timedBox(startTime: string | undefined, endTime: string | undefined, startHour: number, endHour?: number): {
9168
+ top: number;
9169
+ height: number;
9170
+ };
9171
+ interface CalendarLane {
9172
+ lane: number;
9173
+ lanes: number;
9174
+ }
9175
+ /**
9176
+ * Side-by-side lanes for events that overlap in time. Events are grouped into clusters of transitively overlapping events; inside a
9177
+ * cluster each event takes the first free lane and every event of the cluster shares the cluster's lane count.
9178
+ */
9179
+ declare function layoutLanes(boxes: {
9180
+ id: string;
9181
+ top: number;
9182
+ height: number;
9183
+ }[]): Record<string, CalendarLane>;
9184
+ /** One thing on the calendar. The host maps its own records to this shape. */
9185
+ export interface CalendarItem {
9186
+ /** Unique across ALL items passed in (prefix ids by source when merging lists, e.g. `task-…`, `event-…`). */
9187
+ id: string;
9188
+ title: string;
9189
+ /** Local calendar day, `YYYY-MM-DD`. */
9190
+ date: string;
9191
+ /** `HH:mm` (24 hour). Without it (or with `allDay`) the item is an all-day item in the week view. */
9192
+ startTime?: string;
9193
+ endTime?: string;
9194
+ allDay?: boolean;
9195
+ /** Filter key; matched against `CalendarFilter.value`. */
9196
+ type?: string;
9197
+ /** Accent colour (left border / bar) and soft background of the chip, any CSS colour. */
9198
+ color: string;
9199
+ bgColor: string;
9200
+ /** Replaces the formatted `startTime` on chips and agenda rows (e.g. a time already converted to another time zone, or "All day"). */
9201
+ timeLabel?: string;
9202
+ /** Small marker at the end of a month chip (e.g. `T`). */
9203
+ tag?: string;
9204
+ /** Extra badges on the agenda row. */
9205
+ badges?: {
9206
+ label: string;
9207
+ variant: BadgeVariant;
9208
+ }[];
9209
+ /** Extra grey lines under the title on the agenda row (location, contact…). */
9210
+ meta?: string[];
9211
+ /** SVG path `d` (24x24 stroke icon) drawn before the time on month chips. */
9212
+ iconPath?: string;
9213
+ /** Strike the title through (e.g. a completed reminder). */
9214
+ strike?: boolean;
9215
+ /** Screen-reader name of the item's button; defaults to "<time> <title>". */
9216
+ ariaLabel?: string;
9217
+ }
9218
+ export interface CalendarFilter {
9219
+ value: string;
9220
+ label: string;
9221
+ color: string;
9222
+ bgColor?: string;
9223
+ }
9224
+ export interface CalendarMoreClick {
9225
+ /** `YYYY-MM-DD` */
9226
+ date: string;
9227
+ /** Every item of that day that passes the active filters, in display order. */
9228
+ items: CalendarItem[];
9229
+ }
9230
+ export interface CalendarSlotClick {
9231
+ /** `YYYY-MM-DD` */
9232
+ date: string;
9233
+ /** `HH:00` of the clicked hour row. */
9234
+ time: string;
9235
+ }
9236
+ /**
9237
+ * Month / week / agenda calendar. The host owns the data: it listens to `(rangeChange)`, loads that range and passes
9238
+ * the result as `items`. The calendar owns navigation, the view switcher, type filters, layout and keyboard access.
9239
+ *
9240
+ * <ui-calendar [items]="items()" [filters]="filters" [loading]="loading()" [canCreate]="canCreate()"
9241
+ * [(view)]="view" (rangeChange)="load($event)" (itemClick)="open($event)" (dateClick)="create($event)">
9242
+ * <ui-kpi-card calendar-summary ... />
9243
+ * <ui-button calendar-actions (click)="create()">New Event</ui-button>
9244
+ * </ui-calendar>
9245
+ *
9246
+ * Keep the state you bind (`loading`, `items`, `view` …) in signals: `rangeChange` fires during change detection on the first render,
9247
+ * so a handler that writes a plain property would raise ExpressionChangedAfterItHasBeenChecked in dev mode.
9248
+ *
9249
+ * The library toast outlet (`ui-toast`) is rendered here, like in `ui-data-table`, so a page with a calendar and no table still shows
9250
+ * `ToastService` messages.
9251
+ *
9252
+ * Keyboard: the month grid is a real ARIA grid whose DAY CELLS have one tab stop (roving tabindex): arrows move by day/week, Home/End jump
9253
+ * to the start/end of the week, Enter/Space on a day creates (when `canCreate`); the item buttons inside the cells stay in the Tab order.
9254
+ * In the week view each all-day cell and each day column has a visually hidden "+ Add" button that appears when focused; Enter/Space on it
9255
+ * creates (all-day, or the first visible hour). The initial `view` must be one of `views`.
9256
+ *
9257
+ * Content slots: `[calendar-actions]` (right of the view switcher), `[calendar-summary]` (centre of the toolbar on
9258
+ * desktop) and `[calendar-summary-mobile]` (shown instead of it on phones).
9259
+ */
9260
+ export declare class CalendarComponent {
9261
+ /** Everything to show in the visible range. Ids must be unique across the whole list. */
9262
+ readonly items: import("@angular/core").InputSignal<CalendarItem[]>;
9263
+ readonly loading: import("@angular/core").InputSignal<boolean>;
9264
+ /** Active view; two-way bindable. A value that is not in `views` is replaced by the first allowed view. */
9265
+ readonly view: import("@angular/core").ModelSignal<CalendarViewMode>;
9266
+ /** Views the switcher offers. One entry hides the switcher. */
9267
+ readonly views: import("@angular/core").InputSignal<CalendarViewMode[]>;
9268
+ /** Date the visible period is anchored on; two-way bindable. */
9269
+ readonly anchorDate: import("@angular/core").ModelSignal<Date>;
9270
+ /** Filter chips (with an "All" chip first). Empty = no filter bar. */
9271
+ readonly filters: import("@angular/core").InputSignal<CalendarFilter[]>;
9272
+ readonly filterLabel: import("@angular/core").InputSignal<string>;
9273
+ /** `multi` toggles any number of types; `single` keeps at most one active (clicking the active chip clears it). */
9274
+ readonly filterMode: import("@angular/core").InputSignal<"multi" | "single">;
9275
+ /** Active filter values; empty = everything. Two-way bindable. */
9276
+ readonly activeFilters: import("@angular/core").ModelSignal<string[]>;
9277
+ readonly showFilterCounts: import("@angular/core").InputSignal<boolean>;
9278
+ /** Whether empty days / time slots can start a new item (`dateClick` / `slotClick`). Read-only users: false. */
9279
+ readonly canCreate: import("@angular/core").InputSignal<boolean>;
9280
+ /** Days before today cannot start a new item. */
9281
+ readonly disablePast: import("@angular/core").InputSignal<boolean>;
9282
+ /** Items shown per month cell before "+N more". */
9283
+ readonly maxVisible: import("@angular/core").InputSignal<number>;
9284
+ /** `inline`: time and title on one line. `stacked`: time on the first line, title below it (title hidden on phones). */
9285
+ readonly chipLayout: import("@angular/core").InputSignal<"inline" | "stacked">;
9286
+ /** Order each day's items by start time (default). Off = keep the order the host passed them in. */
9287
+ readonly sortByTime: import("@angular/core").InputSignal<boolean>;
9288
+ /** First and last hour row of the week view. */
9289
+ readonly startHour: import("@angular/core").InputSignal<number>;
9290
+ readonly endHour: import("@angular/core").InputSignal<number>;
9291
+ readonly emptyMessage: import("@angular/core").InputSignal<string>;
9292
+ /** Builds the screen-reader name of a month cell; default "<weekday, date>, N events". */
9293
+ readonly dayLabelFn: import("@angular/core").InputSignal<((dateStr: string, items: CalendarItem[]) => string) | null>;
9294
+ /** Fires on first render and whenever the view or the visible range changes: load this range, then pass `items`. */
9295
+ readonly rangeChange: import("@angular/core").OutputEmitterRef<CalendarRange>;
9296
+ readonly itemClick: import("@angular/core").OutputEmitterRef<CalendarItem>;
9297
+ /** Empty day clicked (month view / all-day row) — only when `canCreate` and the day is allowed. */
9298
+ readonly dateClick: import("@angular/core").OutputEmitterRef<string>;
9299
+ /** Empty hour row clicked in the week view (or Enter on a day column: the first visible hour). */
9300
+ readonly slotClick: import("@angular/core").OutputEmitterRef<CalendarSlotClick>;
9301
+ /** "+N more" clicked in a month cell. */
9302
+ readonly moreClick: import("@angular/core").OutputEmitterRef<CalendarMoreClick>;
9303
+ private readonly host;
9304
+ protected readonly weekDayLabels: string[];
9305
+ protected readonly weekDayNames: string[];
9306
+ protected readonly skeletonCells: number[];
9307
+ protected readonly formatHour: typeof formatHour;
9308
+ /** Today as `YYYY-MM-DD`; refreshed at local midnight, when the tab becomes visible again and when the user presses Today. */
9309
+ protected readonly todayStr: import("@angular/core").WritableSignal<string>;
9310
+ /** The month-grid day that holds the roving tab stop. */
9311
+ protected readonly focusedDate: import("@angular/core").WritableSignal<string | null>;
9312
+ private lastRangeKey;
9313
+ protected readonly hours: import("@angular/core").Signal<number[]>;
9314
+ protected readonly monthCells: import("@angular/core").Signal<CalendarDay[]>;
9315
+ protected readonly weekDays: import("@angular/core").Signal<CalendarDay[]>;
9316
+ protected readonly periodLabel: import("@angular/core").Signal<string>;
9317
+ protected readonly viewTabs: import("@angular/core").Signal<PillTab[]>;
9318
+ protected readonly typeCounts: import("@angular/core").Signal<Record<string, number>>;
9319
+ private readonly byDate;
9320
+ protected readonly agendaGroups: import("@angular/core").Signal<{
9321
+ dateStr: string;
9322
+ items: CalendarItem[];
9323
+ }[]>;
9324
+ /** Whether the day at `dateStr` may start a new item. */
9325
+ private clickable;
9326
+ /** The 6 rows of the month grid with everything a cell draws, computed once per input change. */
9327
+ protected readonly monthRows: import("@angular/core").Signal<{
9328
+ key: string;
9329
+ cells: {
9330
+ day: CalendarDay;
9331
+ items: CalendarItem[];
9332
+ visible: CalendarItem[];
9333
+ overflow: number;
9334
+ clickable: boolean;
9335
+ label: string;
9336
+ }[];
9337
+ }[]>;
9338
+ /** The 7 week columns with all-day items and the timed items laid out side by side when they overlap. */
9339
+ protected readonly weekColumns: import("@angular/core").Signal<{
9340
+ day: CalendarDay;
9341
+ label: string;
9342
+ clickable: boolean;
9343
+ allDay: CalendarItem[];
9344
+ timed: {
9345
+ lane: CalendarLane;
9346
+ top: number;
9347
+ height: number;
9348
+ item: CalendarItem;
9349
+ }[];
9350
+ }[]>;
9351
+ /** The month-grid day holding the tab stop: the last focused one if it is on screen, else today, else the 1st of the anchor month. */
9352
+ protected readonly focusDate: import("@angular/core").Signal<string>;
9353
+ constructor();
9354
+ protected isFilterActive(value: string): boolean;
9355
+ protected toggleFilter(value: string): void;
9356
+ protected clearFilters(): void;
9357
+ protected setView(v: CalendarViewMode): void;
9358
+ protected navigate(direction: -1 | 1): void;
9359
+ protected goToday(): void;
9360
+ protected dowLabel(dateStr: string): string;
9361
+ protected agendaDow(dateStr: string): string;
9362
+ protected agendaDate(dateStr: string): string;
9363
+ protected chipTime(e: CalendarItem): string;
9364
+ protected timeRange(e: CalendarItem): string;
9365
+ /** The button's name includes the visible time (WCAG 2.5.3 label in name) unless the host set `ariaLabel`. */
9366
+ protected itemLabel(e: CalendarItem): string;
9367
+ protected agendaMeta(e: CalendarItem): string[];
9368
+ private dayAriaLabel;
9369
+ protected onDateClick(dateStr: string): void;
9370
+ /** Grid keys on a day cell: arrows / Home / End move the tab stop, Enter / Space create. Keys on the chips inside never reach here. */
9371
+ protected onCellKey(event: KeyboardEvent, dateStr: string): void;
9372
+ /** The hidden "+ Add" button of an all-day cell (keyboard / screen-reader path to the same action as clicking the cell). */
9373
+ protected onAddAllDay(dateStr: string, event: Event): void;
9374
+ /** The hidden "+ Add" button of a day column: creates at the first visible hour. */
9375
+ protected onAddTimed(dateStr: string, event: Event): void;
9376
+ protected onSlotClick(dateStr: string, event: MouseEvent): void;
9377
+ protected onItemClick(item: CalendarItem, event: Event): void;
9378
+ protected onMoreClick(dateStr: string, items: CalendarItem[], event: Event): void;
9379
+ static ɵfac: i0.ɵɵFactoryDeclaration<CalendarComponent, never>;
9380
+ static ɵcmp: i0.ɵɵComponentDeclaration<CalendarComponent, "ui-calendar", never, {
9381
+ "items": {
9382
+ "alias": "items";
9383
+ "required": false;
9384
+ "isSignal": true;
9385
+ };
9386
+ "loading": {
9387
+ "alias": "loading";
9388
+ "required": false;
9389
+ "isSignal": true;
9390
+ };
9391
+ "view": {
9392
+ "alias": "view";
9393
+ "required": false;
9394
+ "isSignal": true;
9395
+ };
9396
+ "views": {
9397
+ "alias": "views";
9398
+ "required": false;
9399
+ "isSignal": true;
9400
+ };
9401
+ "anchorDate": {
9402
+ "alias": "anchorDate";
9403
+ "required": false;
9404
+ "isSignal": true;
9405
+ };
9406
+ "filters": {
9407
+ "alias": "filters";
9408
+ "required": false;
9409
+ "isSignal": true;
9410
+ };
9411
+ "filterLabel": {
9412
+ "alias": "filterLabel";
9413
+ "required": false;
9414
+ "isSignal": true;
9415
+ };
9416
+ "filterMode": {
9417
+ "alias": "filterMode";
9418
+ "required": false;
9419
+ "isSignal": true;
9420
+ };
9421
+ "activeFilters": {
9422
+ "alias": "activeFilters";
9423
+ "required": false;
9424
+ "isSignal": true;
9425
+ };
9426
+ "showFilterCounts": {
9427
+ "alias": "showFilterCounts";
9428
+ "required": false;
9429
+ "isSignal": true;
9430
+ };
9431
+ "canCreate": {
9432
+ "alias": "canCreate";
9433
+ "required": false;
9434
+ "isSignal": true;
9435
+ };
9436
+ "disablePast": {
9437
+ "alias": "disablePast";
9438
+ "required": false;
9439
+ "isSignal": true;
9440
+ };
9441
+ "maxVisible": {
9442
+ "alias": "maxVisible";
9443
+ "required": false;
9444
+ "isSignal": true;
9445
+ };
9446
+ "chipLayout": {
9447
+ "alias": "chipLayout";
9448
+ "required": false;
9449
+ "isSignal": true;
9450
+ };
9451
+ "sortByTime": {
9452
+ "alias": "sortByTime";
9453
+ "required": false;
9454
+ "isSignal": true;
9455
+ };
9456
+ "startHour": {
9457
+ "alias": "startHour";
9458
+ "required": false;
9459
+ "isSignal": true;
9460
+ };
9461
+ "endHour": {
9462
+ "alias": "endHour";
9463
+ "required": false;
9464
+ "isSignal": true;
9465
+ };
9466
+ "emptyMessage": {
9467
+ "alias": "emptyMessage";
9468
+ "required": false;
9469
+ "isSignal": true;
9470
+ };
9471
+ "dayLabelFn": {
9472
+ "alias": "dayLabelFn";
9473
+ "required": false;
9474
+ "isSignal": true;
9475
+ };
9476
+ }, {
9477
+ "view": "viewChange";
9478
+ "anchorDate": "anchorDateChange";
9479
+ "activeFilters": "activeFiltersChange";
9480
+ "rangeChange": "rangeChange";
9481
+ "itemClick": "itemClick";
9482
+ "dateClick": "dateClick";
9483
+ "slotClick": "slotClick";
9484
+ "moreClick": "moreClick";
9485
+ }, never, ["[calendar-summary]", "[calendar-actions]", "[calendar-summary-mobile]"], true, never>;
9486
+ }
9487
+ /**
9488
+ * The shell of a public (not signed-in) page or wizard: an optional header, the content in a single `<main>`, an optional footer.
9489
+ *
9490
+ * <ui-page maxWidth="80rem" padding="responsive" background="#f9fafb" [fillViewport]="true" [stickyHeader]="true" [stickyFooter]="true"
9491
+ * [ownScroll]="true" [transparent]="embed()" [focusKey]="step()">
9492
+ * <div page-header> ...stepper... </div>
9493
+ * ...the current screen...
9494
+ * <div page-footer> ...navigation bar... </div>
9495
+ * </ui-page>
9496
+ *
9497
+ * Inputs (all defaults leave the page plain: no limits, no padding, no sticky parts):
9498
+ * - `maxWidth`: CSS length of the main content area ("80rem"). Default '' = none.
9499
+ * - `padding`: '' (none) | 'responsive' (32px 16px 16px; 32px 24px 16px from 640px; 32px 0 16px from 1024px) | any CSS padding value.
9500
+ * - `centered`: centre the main area when `maxWidth` is set (default true).
9501
+ * - `background`: CSS colour of the page. Default '' = none.
9502
+ * - `fillViewport`: the page is at least one viewport high (100dvh, 100vh fallback) and the footer sticks to the bottom (default false).
9503
+ * - `stickyHeader` / `stickyFooter`: the header slot is `position: sticky; top: 0`, the footer slot `bottom: 0`, z-index 20 (default false).
9504
+ * Sticky is relative to the nearest scrolling ancestor: NO ancestor may be an overflow container (overflow other than visible), or
9505
+ * the bars stop sticking. When the page owns the scrolling, use `ownScroll`.
9506
+ * - `transparent`: embed (iframe) mode: transparent background, no minimum height, no maximum width, the padding reduced to 8px 0 16px
9507
+ * (only when a padding is set) and neither bar is sticky (default false).
9508
+ * - `ownScroll`: make the document the scroll container (html overflow auto; body and app-root overflow visible; with `transparent` also
9509
+ * a transparent html/body background). The previous inline values are restored when the page is destroyed (default false).
9510
+ * - `focusKey`: when this value CHANGES (not on the first render), the page scrolls its top into view and moves focus to a zero-height
9511
+ * anchor so screen readers start at the new content. Smooth scrolling follows the page CSS, instant with prefers-reduced-motion.
9512
+ * `focusTop()` does the same on demand.
9513
+ *
9514
+ * Accessibility: the content wrapper is the only `<main>`; the header and footer slots are plain divs (they are landmarks only if the
9515
+ * host projects a `<header>` / `<footer>` / role itself).
9516
+ */
9517
+ export declare class PageComponent {
9518
+ readonly maxWidth: import("@angular/core").InputSignal<string>;
9519
+ readonly padding: import("@angular/core").InputSignal<string>;
9520
+ readonly centered: import("@angular/core").InputSignal<boolean>;
9521
+ readonly background: import("@angular/core").InputSignal<string>;
9522
+ readonly fillViewport: import("@angular/core").InputSignal<boolean>;
9523
+ readonly stickyHeader: import("@angular/core").InputSignal<boolean>;
9524
+ readonly stickyFooter: import("@angular/core").InputSignal<boolean>;
9525
+ readonly transparent: import("@angular/core").InputSignal<boolean>;
9526
+ readonly ownScroll: import("@angular/core").InputSignal<boolean>;
9527
+ readonly focusKey: import("@angular/core").InputSignal<unknown>;
9528
+ private readonly anchor;
9529
+ private readonly doc;
9530
+ private readonly injector;
9531
+ private readonly browser;
9532
+ protected readonly backgroundCss: import("@angular/core").Signal<string | null>;
9533
+ protected readonly maxWidthCss: import("@angular/core").Signal<string | null>;
9534
+ protected readonly paddingCss: import("@angular/core").Signal<string | null>;
9535
+ private scrollSaved;
9536
+ private bgSaved;
9537
+ private focusInitialised;
9538
+ private lastFocusKey;
9539
+ constructor();
9540
+ /** Scrolls the top of the page into view and moves focus to the (invisible) top anchor. */
9541
+ focusTop(): void;
9542
+ private save;
9543
+ private applyScroll;
9544
+ private releaseScroll;
9545
+ private applyBackground;
9546
+ private releaseBackground;
9547
+ static ɵfac: i0.ɵɵFactoryDeclaration<PageComponent, never>;
9548
+ static ɵcmp: i0.ɵɵComponentDeclaration<PageComponent, "ui-page", never, {
9549
+ "maxWidth": {
9550
+ "alias": "maxWidth";
9551
+ "required": false;
9552
+ "isSignal": true;
9553
+ };
9554
+ "padding": {
9555
+ "alias": "padding";
9556
+ "required": false;
9557
+ "isSignal": true;
9558
+ };
9559
+ "centered": {
9560
+ "alias": "centered";
9561
+ "required": false;
9562
+ "isSignal": true;
9563
+ };
9564
+ "background": {
9565
+ "alias": "background";
9566
+ "required": false;
9567
+ "isSignal": true;
9568
+ };
9569
+ "fillViewport": {
9570
+ "alias": "fillViewport";
9571
+ "required": false;
9572
+ "isSignal": true;
9573
+ };
9574
+ "stickyHeader": {
9575
+ "alias": "stickyHeader";
9576
+ "required": false;
9577
+ "isSignal": true;
9578
+ };
9579
+ "stickyFooter": {
9580
+ "alias": "stickyFooter";
9581
+ "required": false;
9582
+ "isSignal": true;
9583
+ };
9584
+ "transparent": {
9585
+ "alias": "transparent";
9586
+ "required": false;
9587
+ "isSignal": true;
9588
+ };
9589
+ "ownScroll": {
9590
+ "alias": "ownScroll";
9591
+ "required": false;
9592
+ "isSignal": true;
9593
+ };
9594
+ "focusKey": {
9595
+ "alias": "focusKey";
9596
+ "required": false;
9597
+ "isSignal": true;
9598
+ };
9599
+ }, {}, never, ["[page-header]", "*", "[page-footer]"], true, never>;
9600
+ }
9601
+ /**
9602
+ * A block wrapper whose content fades in (opacity 0 to 1) when it is created and again whenever `key` changes.
9603
+ * The projected content is NOT re-created: the animation restarts by alternating between two identical keyframes.
9604
+ *
9605
+ * <ui-fade [key]="step()"> ...the current screen... </ui-fade>
9606
+ *
9607
+ * - `key`: any value; a change restarts the fade (default undefined).
9608
+ * - `duration`: milliseconds (default 300).
9609
+ * - `disabled`: no animation at all (default false).
9610
+ * With prefers-reduced-motion: reduce nothing animates.
9611
+ */
9612
+ export declare class FadeComponent {
9613
+ readonly key: import("@angular/core").InputSignal<unknown>;
9614
+ readonly duration: import("@angular/core").InputSignal<number>;
9615
+ readonly disabled: import("@angular/core").InputSignal<boolean>;
9616
+ protected readonly odd: import("@angular/core").WritableSignal<boolean>;
9617
+ private first;
9618
+ private last;
9619
+ constructor();
9620
+ static ɵfac: i0.ɵɵFactoryDeclaration<FadeComponent, never>;
9621
+ static ɵcmp: i0.ɵɵComponentDeclaration<FadeComponent, "ui-fade", never, {
9622
+ "key": {
9623
+ "alias": "key";
9624
+ "required": false;
9625
+ "isSignal": true;
9626
+ };
9627
+ "duration": {
9628
+ "alias": "duration";
9629
+ "required": false;
9630
+ "isSignal": true;
9631
+ };
9632
+ "disabled": {
9633
+ "alias": "disabled";
9634
+ "required": false;
9635
+ "isSignal": true;
9636
+ };
9637
+ }, {}, never, ["*"], true, never>;
9638
+ }
9639
+ export type ShowBreakpoint = 'sm' | 'md' | 'lg' | number;
9640
+ /**
9641
+ * Responsive visibility wrapper (display: block when visible, display: none when hidden; never `display: contents`).
9642
+ *
9643
+ * <ui-show from="md"> desktop only </ui-show> visible at width >= 768px
9644
+ * <ui-show below="md"> phone/tablet only </ui-show> visible at width < 768px
9645
+ * <ui-show [from]="640" [below]="1024"> a range </ui-show>
9646
+ *
9647
+ * - `from`: visible only at viewport width >= from. `below`: visible only at width < below. Both = a range; none = always visible.
9648
+ * - Breakpoints are the tokens 'sm' (480px) | 'md' (768px) | 'lg' (1024px) or a pixel number.
9649
+ *
9650
+ * Difference: TOKEN breakpoints are pure CSS media queries (no JavaScript, correct on first paint and when server rendered).
9651
+ * NUMERIC breakpoints use `matchMedia` with a signal that updates on change (the listener is removed on destroy); without
9652
+ * `matchMedia` (server rendering) the content counts as visible. The two kinds can be mixed. Hidden content stays in the DOM.
9653
+ */
9654
+ export declare class ShowComponent {
9655
+ readonly from: import("@angular/core").InputSignal<ShowBreakpoint | null>;
9656
+ readonly below: import("@angular/core").InputSignal<ShowBreakpoint | null>;
9657
+ private readonly win;
9658
+ protected readonly fromToken: import("@angular/core").Signal<"sm" | "md" | "lg" | null>;
9659
+ protected readonly belowToken: import("@angular/core").Signal<"sm" | "md" | "lg" | null>;
9660
+ protected readonly fromMatch: import("@angular/core").WritableSignal<boolean>;
9661
+ protected readonly belowMatch: import("@angular/core").WritableSignal<boolean>;
9662
+ constructor();
9663
+ private watch;
9664
+ static ɵfac: i0.ɵɵFactoryDeclaration<ShowComponent, never>;
9665
+ static ɵcmp: i0.ɵɵComponentDeclaration<ShowComponent, "ui-show", never, {
9666
+ "from": {
9667
+ "alias": "from";
9668
+ "required": false;
9669
+ "isSignal": true;
9670
+ };
9671
+ "below": {
9672
+ "alias": "below";
9673
+ "required": false;
9674
+ "isSignal": true;
9675
+ };
9676
+ }, {}, never, ["*"], true, never>;
9677
+ }
9678
+ /**
9679
+ * Small formatting helpers shared by apps (money and postal addresses).
9680
+ */
9681
+ export interface FormatCurrencyOptions {
9682
+ /** ISO 4217 code. Default `'USD'`. */
9683
+ currency?: string;
9684
+ /** BCP 47 locale. Default `'en-US'`. */
9685
+ locale?: string;
9686
+ /** Thousands separators. Default `true`; `false` gives `$1605.00` (like a plain `'$' + n.toFixed(2)`). */
9687
+ grouping?: boolean;
9688
+ /** Digits after the decimal point. Default 2. */
9689
+ decimals?: number;
9690
+ }
9691
+ /**
9692
+ * Formats an amount as money: `formatCurrency(1605)` -> `$1,605.00`, `formatCurrency(-5)` -> `-$5.00`.
9693
+ * `null`, `undefined`, `NaN`, infinities and text that is not a number count as 0 (a numeric string such as `'12.5'` is parsed with
9694
+ * `parseFloat`, like cremo's `formatPrice`). `{ grouping: false }` reproduces `'$' + price.toFixed(2)` exactly (`$1605.00`).
9695
+ * An amount that rounds to zero is shown without a minus sign (`-0.001` -> `$0.00`).
9696
+ */
9697
+ export declare function formatCurrency(value: number | string | null | undefined, options?: FormatCurrencyOptions): string;
9698
+ export interface AddressParts {
9699
+ street?: string | null;
9700
+ apt?: string | null;
9701
+ city?: string | null;
9702
+ state?: string | null;
9703
+ zip?: string | null;
9704
+ }
9705
+ export interface FormatAddressOptions {
9706
+ /** Joiner between the parts. Default `', '`. */
9707
+ separator?: string;
9708
+ /**
9709
+ * `'comma'` (default): every non-empty part joined with the separator - `Street, Apt 4, City, ST, 12345` (cremo's next-of-kin and
9710
+ * informant address). `'usa'`: the postal layout - `Street, Apt 4, City, ST 12345`: the apartment is prefixed with `Apt ` and the
9711
+ * zip follows the state with a space (cremo's summary `joinAddress`); a state or city alone is still shown.
9712
+ */
9713
+ style?: 'comma' | 'usa';
9714
+ }
9715
+ /**
9716
+ * Joins the non-empty, trimmed address parts in the order street, apt, city, state, zip. See `FormatAddressOptions.style`.
9717
+ * `formatAddress({ street: '1 Main', city: 'Austin', state: 'TX', zip: '78701' })` -> `1 Main, Austin, TX, 78701`;
9718
+ * with `{ style: 'usa' }` -> `1 Main, Austin, TX 78701`.
9719
+ */
9720
+ export declare function formatAddress(parts: AddressParts, options?: FormatAddressOptions): string;
9721
+ /**
9722
+ * Starts the browser download of a blob under `fileName`. The anchor is attached to the page while it is clicked (Firefox ignores a click on
9723
+ * a detached anchor) and the object URL is revoked 1000 ms later (Safari reads it asynchronously, so an immediate revoke can cancel the
9724
+ * download). A no-op without a DOM (server-side rendering).
9725
+ */
9726
+ export declare function downloadBlob(blob: Blob, fileName: string): void;
9727
+ /**
9728
+ * A lightbox: a `ui-modal` that shows a `ui-image-gallery` with a Close button in the footer.
9729
+ *
9730
+ * <ui-image-gallery-dialog [(open)]="galleryOpen" [images]="images" title="Photos of the urn" galleryLabel="Urn photos"
9731
+ * dialogTestId="gallery-dialog" closeTestId="gallery-close" />
9732
+ *
9733
+ * - `open` (two-way): shown while true. Escape, a click on the backdrop and the footer Close button set it to false (the header X is
9734
+ * hidden, the footer button replaces it). Focus returns to the element that opened the dialog (modal behaviour).
9735
+ * - `images` (`GalleryImage[]`), `index` (two-way): the shown picture; it resets to 0 every time the dialog opens.
9736
+ * - `title`, `dialogTestId` (on the dialog element), `closeLabel` (default "Close"), `closeTestId` (on the Close button), `maxWidth`
9737
+ * (default `56rem`), `galleryLabel` (accessible name of the gallery group, default "Image gallery").
9738
+ * - The gallery has `autofocus` on: the dialog opens with focus on "Next image" so the arrow keys work at once (touch screens focus the dialog itself).
9739
+ * - The gallery is only created while the dialog is open, so closed dialogs load no pictures.
9740
+ */
9741
+ export declare class ImageGalleryDialogComponent {
9742
+ /** Two-way: whether the dialog is shown. */
9743
+ readonly open: import("@angular/core").ModelSignal<boolean>;
9744
+ readonly images: import("@angular/core").InputSignal<GalleryImage[]>;
9745
+ /** Two-way: the shown picture. Reset to 0 whenever the dialog opens. */
9746
+ readonly index: import("@angular/core").ModelSignal<number>;
9747
+ readonly title: import("@angular/core").InputSignal<string>;
9748
+ /** `data-testid` of the dialog element. */
9749
+ readonly dialogTestId: import("@angular/core").InputSignal<string>;
9750
+ /** Text of the footer Close button. */
9751
+ readonly closeLabel: import("@angular/core").InputSignal<string>;
9752
+ /** `data-testid` of the footer Close button (on the `ui-button` host); none when empty. */
9753
+ readonly closeTestId: import("@angular/core").InputSignal<string>;
9754
+ /** Max width of the dialog (any CSS length). */
9755
+ readonly maxWidth: import("@angular/core").InputSignal<string>;
9756
+ /** Accessible name of the gallery group. */
9757
+ readonly galleryLabel: import("@angular/core").InputSignal<string>;
9758
+ constructor();
9759
+ static ɵfac: i0.ɵɵFactoryDeclaration<ImageGalleryDialogComponent, never>;
9760
+ static ɵcmp: i0.ɵɵComponentDeclaration<ImageGalleryDialogComponent, "ui-image-gallery-dialog", never, {
9761
+ "open": {
9762
+ "alias": "open";
9763
+ "required": false;
9764
+ "isSignal": true;
9765
+ };
9766
+ "images": {
9767
+ "alias": "images";
9768
+ "required": false;
9769
+ "isSignal": true;
9770
+ };
9771
+ "index": {
9772
+ "alias": "index";
9773
+ "required": false;
9774
+ "isSignal": true;
9775
+ };
9776
+ "title": {
9777
+ "alias": "title";
9778
+ "required": false;
9779
+ "isSignal": true;
9780
+ };
9781
+ "dialogTestId": {
9782
+ "alias": "dialogTestId";
9783
+ "required": false;
9784
+ "isSignal": true;
9785
+ };
9786
+ "closeLabel": {
9787
+ "alias": "closeLabel";
9788
+ "required": false;
9789
+ "isSignal": true;
9790
+ };
9791
+ "closeTestId": {
9792
+ "alias": "closeTestId";
9793
+ "required": false;
9794
+ "isSignal": true;
9795
+ };
9796
+ "maxWidth": {
9797
+ "alias": "maxWidth";
9798
+ "required": false;
9799
+ "isSignal": true;
9800
+ };
9801
+ "galleryLabel": {
9802
+ "alias": "galleryLabel";
9803
+ "required": false;
9804
+ "isSignal": true;
9805
+ };
9806
+ }, {
9807
+ "open": "openChange";
9808
+ "index": "indexChange";
9809
+ }, never, never, true, never>;
9810
+ }
9811
+ export type { CalendarDay, CalendarRange, CalendarViewMode };