@forgeroute/ui 0.4.8 → 0.4.9

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.
@@ -961,7 +961,7 @@ export declare class SelectComponent implements ControlValueAccessor, Validator,
961
961
  readonly error: import("@angular/core").InputSignal<string>;
962
962
  /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
963
963
  readonly showErrors: import("@angular/core").InputSignal<boolean>;
964
- readonly size: import("@angular/core").InputSignal<"default" | "sm">;
964
+ readonly size: import("@angular/core").InputSignal<"sm" | "default">;
965
965
  readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
966
966
  private readonly _cvaDisabled;
967
967
  protected readonly disabled: import("@angular/core").Signal<boolean>;
@@ -1909,7 +1909,7 @@ export declare class ModalComponent implements OnInit, OnDestroy {
1909
1909
  readonly title: import("@angular/core").InputSignal<string>;
1910
1910
  readonly description: import("@angular/core").InputSignal<string>;
1911
1911
  readonly maxWidth: import("@angular/core").InputSignal<string>;
1912
- readonly bodyOverflow: import("@angular/core").InputSignal<"hidden" | "auto" | "visible">;
1912
+ readonly bodyOverflow: import("@angular/core").InputSignal<"auto" | "hidden" | "visible">;
1913
1913
  /** `data-testid` of the dialog element itself (the host `<ui-modal>` is always in the page, the dialog only while open). None when empty. */
1914
1914
  readonly dialogTestId: import("@angular/core").InputSignal<string>;
1915
1915
  /** Hides the header X button (e.g. while a request is running). Escape and a backdrop click still close unless `closable` is false. */
@@ -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,6 +2801,12 @@ 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';
2797
2812
  /**
@@ -2818,6 +2833,9 @@ export type StepperOrientation = 'horizontal' | 'vertical';
2818
2833
  *
2819
2834
  * steps = all.map((s, i) => ({ ...s, complete: i <= furthestReached }))
2820
2835
  *
2836
+ * 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
2837
+ * that is switched off (dimmed, announced "disabled").
2838
+ *
2821
2839
  * Interaction (`clickable`): a selectable step is a native `<button>` (Tab / Enter / Space, visible focus ring). With
2822
2840
  * `linear` (default) only complete steps are selectable, so the user can go back but not skip ahead; with
2823
2841
  * `[linear]="false"` every non-disabled step is. The current step is never a button (you are already there): it is
@@ -2853,6 +2871,8 @@ export declare class StepperComponent {
2853
2871
  readonly accentColor: import("@angular/core").InputSignal<string>;
2854
2872
  /** 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
2873
  readonly completeColor: import("@angular/core").InputSignal<string>;
2874
+ /** 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. */
2875
+ readonly accentLabels: import("@angular/core").InputSignal<boolean>;
2856
2876
  /** Accessible name of the list. */
2857
2877
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
2858
2878
  /** Horizontal, <= 480px: show only the current step's label (`'current'`, default) or every label (`'all'`). */
@@ -2918,6 +2938,11 @@ export declare class StepperComponent {
2918
2938
  "required": false;
2919
2939
  "isSignal": true;
2920
2940
  };
2941
+ "accentLabels": {
2942
+ "alias": "accentLabels";
2943
+ "required": false;
2944
+ "isSignal": true;
2945
+ };
2921
2946
  "ariaLabel": {
2922
2947
  "alias": "ariaLabel";
2923
2948
  "required": false;
@@ -3423,7 +3448,7 @@ export declare class ButtonComponent {
3423
3448
  * `ghost-start`: a ghost button for list / section toggles - a full-width row with its content aligned to the start, transparent
3424
3449
  * background, hover tint and the normal focus ring. Pair it with `ariaExpanded` / `ariaPressed`; the label may contain a heading element.
3425
3450
  */
3426
- readonly variant: import("@angular/core").InputSignal<"primary" | "secondary" | "danger" | "warning" | "link" | "ghost" | "ghost-start" | "tab" | "icon" | "icon-danger">;
3451
+ readonly variant: import("@angular/core").InputSignal<"primary" | "secondary" | "ghost" | "ghost-start" | "danger" | "link" | "warning" | "tab" | "icon" | "icon-danger">;
3427
3452
  /** Renders an anchor to this route instead of a button (use with `variant="link"` for an inline text link). `['/settings']` or `'/settings'`. While `disabled` or `loading` it renders a non-clickable `<span role="link" aria-disabled>` with no href (like `href`). */
3428
3453
  readonly routerLink: import("@angular/core").InputSignal<string | readonly unknown[] | null>;
3429
3454
  /** Query params of the `routerLink` (e.g. `{ section: 'deal-defaults' }`). */
@@ -3438,7 +3463,7 @@ export declare class ButtonComponent {
3438
3463
  */
3439
3464
  readonly href: import("@angular/core").InputSignal<string | null>;
3440
3465
  /** Where to open the `href` (`_blank` = a new tab). */
3441
- readonly target: import("@angular/core").InputSignal<"_self" | "_blank" | "_parent" | "_top" | null>;
3466
+ readonly target: import("@angular/core").InputSignal<"_blank" | "_self" | "_parent" | "_top" | null>;
3442
3467
  /** `rel` of the `href` link. A `_blank` target always gets `noopener noreferrer` added. */
3443
3468
  readonly rel: import("@angular/core").InputSignal<string | null>;
3444
3469
  /** The href when it is allowed (http, https, mailto, tel, sms or a relative URL), else null. */
@@ -3446,8 +3471,8 @@ export declare class ButtonComponent {
3446
3471
  protected readonly _rel: import("@angular/core").Signal<string | null>;
3447
3472
  readonly color: import("@angular/core").InputSignal<string | undefined>;
3448
3473
  readonly active: import("@angular/core").InputSignal<boolean>;
3449
- readonly size: import("@angular/core").InputSignal<"sm" | "md" | "xs" | "lg">;
3450
- readonly type: import("@angular/core").InputSignal<"reset" | "submit" | "button">;
3474
+ readonly size: import("@angular/core").InputSignal<"xs" | "sm" | "md" | "lg">;
3475
+ readonly type: import("@angular/core").InputSignal<"button" | "submit" | "reset">;
3451
3476
  readonly disabled: import("@angular/core").InputSignal<boolean>;
3452
3477
  readonly loading: import("@angular/core").InputSignal<boolean>;
3453
3478
  readonly fullWidth: import("@angular/core").InputSignal<boolean>;
@@ -3975,7 +4000,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
3975
4000
  * Meant for a short mark of 1-3 characters.
3976
4001
  */
3977
4002
  readonly prefix: import("@angular/core").InputSignal<string>;
3978
- readonly type: import("@angular/core").InputSignal<"number" | "text" | "email" | "tel" | "password" | "url">;
4003
+ readonly type: import("@angular/core").InputSignal<"number" | "text" | "tel" | "email" | "password" | "url">;
3979
4004
  readonly maxlength: import("@angular/core").InputSignal<number | undefined>;
3980
4005
  readonly required: import("@angular/core").InputSignal<boolean>;
3981
4006
  readonly autocomplete: import("@angular/core").InputSignal<string>;
@@ -3984,7 +4009,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
3984
4009
  * `search`, `text`, `none`). Empty (default) = the browser's default for the field, except `type="tel"`, which keeps `tel`.
3985
4010
  * It only picks the keyboard; it does not restrict what can be typed or pasted.
3986
4011
  */
3987
- readonly inputmode: import("@angular/core").InputSignal<"" | "none" | "text" | "search" | "email" | "tel" | "url" | "decimal" | "numeric">;
4012
+ readonly inputmode: import("@angular/core").InputSignal<"" | "none" | "text" | "tel" | "search" | "email" | "url" | "decimal" | "numeric">;
3988
4013
  readonly readonly: import("@angular/core").InputSignal<boolean>;
3989
4014
  readonly hint: import("@angular/core").InputSignal<string>;
3990
4015
  readonly error: import("@angular/core").InputSignal<string>;
@@ -4313,7 +4338,7 @@ export declare class TextareaInputComponent implements ControlValueAccessor, Val
4313
4338
  }, never, never, true, never>;
4314
4339
  }
4315
4340
  export type TextSize = 'sm' | 'md' | 'lg';
4316
- export type TextTone = 'default' | 'muted';
4341
+ export type TextTone = 'default' | 'muted' | 'accent';
4317
4342
  export type TextWeight = 'normal' | 'medium' | 'semibold' | 'bold';
4318
4343
  /**
4319
4344
  * 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 +4365,8 @@ export declare class TextComponent {
4340
4365
  readonly text: import("@angular/core").InputSignal<string | null | undefined>;
4341
4366
  readonly size: import("@angular/core").InputSignal<TextSize>;
4342
4367
  readonly tone: import("@angular/core").InputSignal<TextTone>;
4368
+ /** 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). */
4369
+ readonly color: import("@angular/core").InputSignal<string>;
4343
4370
  /** Snippet(s) of `text` to show in bold. Empty / not found = no change. */
4344
4371
  readonly strong: import("@angular/core").InputSignal<string | string[] | null | undefined>;
4345
4372
  /** 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 +4395,11 @@ export declare class TextComponent {
4368
4395
  "required": false;
4369
4396
  "isSignal": true;
4370
4397
  };
4398
+ "color": {
4399
+ "alias": "color";
4400
+ "required": false;
4401
+ "isSignal": true;
4402
+ };
4371
4403
  "strong": {
4372
4404
  "alias": "strong";
4373
4405
  "required": false;
@@ -5345,7 +5377,7 @@ export declare class DropdownComponent {
5345
5377
  readonly loader: import("@angular/core").InputSignal<(() => Promise<DropdownItem[]>) | null>;
5346
5378
  readonly active: import("@angular/core").InputSignal<boolean>;
5347
5379
  readonly activeValue: import("@angular/core").InputSignal<string>;
5348
- readonly variant: import("@angular/core").InputSignal<"badge" | "button">;
5380
+ readonly variant: import("@angular/core").InputSignal<"button" | "badge">;
5349
5381
  readonly menuWidth: import("@angular/core").InputSignal<string>;
5350
5382
  /**
5351
5383
  * Accessible name. Set it when the trigger has no meaningful visible text. Applied as `aria-label` on the
@@ -5525,7 +5557,7 @@ export declare class FormRowComponent {
5525
5557
  * child simply takes the full width. Keep a numeric span within the row's `cols` (use `all` for the whole row).
5526
5558
  */
5527
5559
  export declare class FormColSpanDirective {
5528
- readonly uiColSpan: import("@angular/core").InputSignal<"" | "2" | "3" | 2 | 3 | "all">;
5560
+ readonly uiColSpan: import("@angular/core").InputSignal<"" | 2 | 3 | "all" | "2" | "3">;
5529
5561
  protected readonly _class: import("@angular/core").Signal<string>;
5530
5562
  static ɵfac: i0.ɵɵFactoryDeclaration<FormColSpanDirective, never>;
5531
5563
  static ɵdir: i0.ɵɵDirectiveDeclaration<FormColSpanDirective, "[uiColSpan]", never, {
@@ -6260,12 +6292,12 @@ export declare class ChipGroupComponent {
6260
6292
  /** Space between each chip. */
6261
6293
  readonly gap: import("@angular/core").InputSignal<"sm" | "md" | "lg">;
6262
6294
  /** Space above the chip group. */
6263
- readonly spaceAbove: import("@angular/core").InputSignal<"none" | "sm" | "md">;
6295
+ readonly spaceAbove: import("@angular/core").InputSignal<"sm" | "md" | "none">;
6264
6296
  /** Space below the chip group. */
6265
- readonly spaceBelow: import("@angular/core").InputSignal<"none" | "sm" | "md">;
6266
- protected readonly _gap: import("@angular/core").Signal<"6px" | "12px" | "8px">;
6267
- protected readonly _spaceAbove: import("@angular/core").Signal<"0" | "6px" | "12px">;
6268
- protected readonly _spaceBelow: import("@angular/core").Signal<"0" | "6px" | "12px">;
6297
+ readonly spaceBelow: import("@angular/core").InputSignal<"sm" | "md" | "none">;
6298
+ protected readonly _gap: import("@angular/core").Signal<"12px" | "6px" | "8px">;
6299
+ protected readonly _spaceAbove: import("@angular/core").Signal<"0" | "12px" | "6px">;
6300
+ protected readonly _spaceBelow: import("@angular/core").Signal<"0" | "12px" | "6px">;
6269
6301
  static ɵfac: i0.ɵɵFactoryDeclaration<ChipGroupComponent, never>;
6270
6302
  static ɵcmp: i0.ɵɵComponentDeclaration<ChipGroupComponent, "ui-chip-group", never, {
6271
6303
  "gap": {
@@ -6855,6 +6887,8 @@ export declare class ImageComponent {
6855
6887
  readonly height: import("@angular/core").InputSignal<string>;
6856
6888
  readonly maxWidth: import("@angular/core").InputSignal<string>;
6857
6889
  readonly maxHeight: import("@angular/core").InputSignal<string>;
6890
+ /** Minimum height of the image box (any CSS length). Empty = none. */
6891
+ readonly minHeight: import("@angular/core").InputSignal<string>;
6858
6892
  /** CSS aspect-ratio, e.g. "4 / 3". Reserves the space while the image loads. */
6859
6893
  readonly aspectRatio: import("@angular/core").InputSignal<string>;
6860
6894
  readonly radius: import("@angular/core").InputSignal<ImageRadius>;
@@ -6916,6 +6950,11 @@ export declare class ImageComponent {
6916
6950
  "required": false;
6917
6951
  "isSignal": true;
6918
6952
  };
6953
+ "minHeight": {
6954
+ "alias": "minHeight";
6955
+ "required": false;
6956
+ "isSignal": true;
6957
+ };
6919
6958
  "aspectRatio": {
6920
6959
  "alias": "aspectRatio";
6921
6960
  "required": false;
@@ -6989,11 +7028,19 @@ export declare class ImageGalleryComponent {
6989
7028
  readonly maxHeight: import("@angular/core").InputSignal<string>;
6990
7029
  readonly fit: import("@angular/core").InputSignal<"contain" | "cover">;
6991
7030
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
7031
+ /**
7032
+ * 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
7033
+ * 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
7034
+ * no buttons, so the dialog keeps its normal initial focus. Default false: unchanged.
7035
+ */
7036
+ readonly autofocus: import("@angular/core").InputSignal<boolean>;
6992
7037
  protected readonly count: import("@angular/core").Signal<number>;
6993
7038
  /** `index` clamped into the list. */
6994
7039
  protected readonly position: import("@angular/core").Signal<number>;
6995
7040
  protected readonly current: import("@angular/core").Signal<GalleryImage>;
6996
7041
  protected readonly currentAlt: import("@angular/core").Signal<string>;
7042
+ protected readonly autofocusNext: import("@angular/core").Signal<boolean>;
7043
+ protected readonly autofocusPrev: import("@angular/core").Signal<boolean>;
6997
7044
  protected readonly canPrev: import("@angular/core").Signal<boolean>;
6998
7045
  protected readonly canNext: import("@angular/core").Signal<boolean>;
6999
7046
  protected readonly announcement: import("@angular/core").Signal<string>;
@@ -7048,6 +7095,11 @@ export declare class ImageGalleryComponent {
7048
7095
  "required": false;
7049
7096
  "isSignal": true;
7050
7097
  };
7098
+ "autofocus": {
7099
+ "alias": "autofocus";
7100
+ "required": false;
7101
+ "isSignal": true;
7102
+ };
7051
7103
  }, {
7052
7104
  "index": "indexChange";
7053
7105
  }, never, never, true, never>;
@@ -8049,6 +8101,7 @@ export declare class PdfHotspotComponent {
8049
8101
  * ("Edit informant information") when the visible label alone is ambiguous; it should contain the visible label.
8050
8102
  * - `fill`: the card stretches to the height of its container (a grid cell or flex item) and its body grows, so cards in
8051
8103
  * one row end at the same height; the default card is only as tall as its content.
8104
+ * 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
8105
  * - `background`: the card's background colour (any CSS colour; default white).
8053
8106
  * - `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
8107
  * - The body has built-in padding (16px 18px, matching the header's 18px side padding); there is no padding input.
@@ -8094,9 +8147,13 @@ export declare class DetailCardComponent {
8094
8147
  readonly showEdit: import("@angular/core").InputSignal<boolean>;
8095
8148
  readonly editLabel: import("@angular/core").InputSignal<string>;
8096
8149
  readonly editClick: import("@angular/core").OutputEmitterRef<void>;
8150
+ /** `data-testid` of the built-in Edit button (on the `ui-button` host); none when empty. */
8151
+ readonly editTestId: import("@angular/core").InputSignal<string>;
8152
+ /** false = no pencil icon in the Edit button (text only). Default true: unchanged. */
8153
+ readonly editIcon: import("@angular/core").InputSignal<boolean>;
8097
8154
  /** Accessible name of the Edit button, e.g. "Edit informant information". Empty = the visible `editLabel`. */
8098
8155
  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. */
8156
+ /** 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
8157
  readonly fill: import("@angular/core").InputSignal<boolean>;
8101
8158
  /** The group's aria-label: the visible title (unless `titleId` names the card instead), else `ariaLabel`, else none. */
8102
8159
  groupLabel(): string | null;
@@ -8172,6 +8229,16 @@ export declare class DetailCardComponent {
8172
8229
  "required": false;
8173
8230
  "isSignal": true;
8174
8231
  };
8232
+ "editTestId": {
8233
+ "alias": "editTestId";
8234
+ "required": false;
8235
+ "isSignal": true;
8236
+ };
8237
+ "editIcon": {
8238
+ "alias": "editIcon";
8239
+ "required": false;
8240
+ "isSignal": true;
8241
+ };
8175
8242
  "editAriaLabel": {
8176
8243
  "alias": "editAriaLabel";
8177
8244
  "required": false;
@@ -8625,11 +8692,26 @@ export declare class ColumnsComponent {
8625
8692
  readonly countBelowMd: import("@angular/core").InputSignal<ColumnsCount | null>;
8626
8693
  /** Column count at <= 480px (falls back to `countBelowMd`, then `countBelowLg`, then `count`). */
8627
8694
  readonly countBelowSm: import("@angular/core").InputSignal<ColumnsCount | null>;
8695
+ /**
8696
+ * Mobile-first alternative to `count` + `countBelow*`: `countBase` columns on the narrowest screens (default 1), then `countFromSm` from 480px,
8697
+ * `countFromMd` from 768px, `countFromLg` from 1024px (min-width, inclusive; each tier falls back to the next narrower one). Setting any `countFrom*`
8698
+ * switches the grid to this mode: `count`, `countBelow*` and `collapseAt` are then ignored. Unset = unchanged.
8699
+ * <ui-columns [countFromMd]="2" [countFromLg]="3"> ... </ui-columns> <!-- 1 column, 2 from 768px, 3 from 1024px -->
8700
+ */
8701
+ readonly countBase: import("@angular/core").InputSignal<ColumnsCount>;
8702
+ readonly countFromSm: import("@angular/core").InputSignal<ColumnsCount | null>;
8703
+ readonly countFromMd: import("@angular/core").InputSignal<ColumnsCount | null>;
8704
+ readonly countFromLg: import("@angular/core").InputSignal<ColumnsCount | null>;
8628
8705
  protected readonly cols: import("@angular/core").Signal<ColumnsCount>;
8629
8706
  private static clampTier;
8630
8707
  protected readonly colsLg: import("@angular/core").Signal<ColumnsCount | null>;
8631
8708
  protected readonly colsMd: import("@angular/core").Signal<ColumnsCount | null>;
8632
8709
  protected readonly colsSm: import("@angular/core").Signal<ColumnsCount | null>;
8710
+ protected readonly fromMode: import("@angular/core").Signal<boolean>;
8711
+ protected readonly base: import("@angular/core").Signal<ColumnsCount | null>;
8712
+ protected readonly fromSm: import("@angular/core").Signal<ColumnsCount | null>;
8713
+ protected readonly fromMd: import("@angular/core").Signal<ColumnsCount | null>;
8714
+ protected readonly fromLg: import("@angular/core").Signal<ColumnsCount | null>;
8633
8715
  protected readonly gapCss: import("@angular/core").Signal<string>;
8634
8716
  protected readonly collapseClass: import("@angular/core").Signal<string>;
8635
8717
  static ɵfac: i0.ɵɵFactoryDeclaration<ColumnsComponent, never>;
@@ -8669,6 +8751,26 @@ export declare class ColumnsComponent {
8669
8751
  "required": false;
8670
8752
  "isSignal": true;
8671
8753
  };
8754
+ "countBase": {
8755
+ "alias": "countBase";
8756
+ "required": false;
8757
+ "isSignal": true;
8758
+ };
8759
+ "countFromSm": {
8760
+ "alias": "countFromSm";
8761
+ "required": false;
8762
+ "isSignal": true;
8763
+ };
8764
+ "countFromMd": {
8765
+ "alias": "countFromMd";
8766
+ "required": false;
8767
+ "isSignal": true;
8768
+ };
8769
+ "countFromLg": {
8770
+ "alias": "countFromLg";
8771
+ "required": false;
8772
+ "isSignal": true;
8773
+ };
8672
8774
  }, {}, never, ["*"], true, never>;
8673
8775
  }
8674
8776
  export type StackDirection = 'vertical' | 'horizontal';
@@ -8701,6 +8803,10 @@ export declare class StackComponent {
8701
8803
  readonly align: import("@angular/core").InputSignal<StackAlign>;
8702
8804
  readonly justify: import("@angular/core").InputSignal<StackJustify>;
8703
8805
  readonly wrap: import("@angular/core").InputSignal<boolean>;
8806
+ /** Minimum height of the stack (any CSS length, e.g. "12rem"); with `justify="center"` it centres the content vertically. Empty = none. */
8807
+ readonly minHeight: import("@angular/core").InputSignal<string>;
8808
+ /** Width of the stack (any CSS length or "100%"). Empty = the normal block width. */
8809
+ readonly width: import("@angular/core").InputSignal<string>;
8704
8810
  protected readonly gapCss: import("@angular/core").Signal<string>;
8705
8811
  protected readonly alignCss: import("@angular/core").Signal<string>;
8706
8812
  protected readonly justifyCss: import("@angular/core").Signal<string>;
@@ -8731,6 +8837,16 @@ export declare class StackComponent {
8731
8837
  "required": false;
8732
8838
  "isSignal": true;
8733
8839
  };
8840
+ "minHeight": {
8841
+ "alias": "minHeight";
8842
+ "required": false;
8843
+ "isSignal": true;
8844
+ };
8845
+ "width": {
8846
+ "alias": "width";
8847
+ "required": false;
8848
+ "isSignal": true;
8849
+ };
8734
8850
  }, {}, never, ["*"], true, never>;
8735
8851
  }
8736
8852
  export type ActionBarAlign = 'start' | 'center' | 'end' | 'between';
@@ -8805,4 +8921,370 @@ export declare class ActionBarComponent {
8805
8921
  "isSignal": true;
8806
8922
  };
8807
8923
  }, {}, never, ["*"], true, never>;
8808
- }
8924
+ }
8925
+ /** Pure date helpers for `ui-calendar`. Dates are plain `YYYY-MM-DD` strings and times `HH:mm`; nothing here parses a non-ISO string. */
8926
+ type CalendarViewMode = 'month' | 'week' | 'agenda';
8927
+ interface CalendarDay {
8928
+ dateStr: string;
8929
+ dayNum: number;
8930
+ isToday: boolean;
8931
+ isCurrentMonth: boolean;
8932
+ isWeekend: boolean;
8933
+ }
8934
+ interface CalendarRange {
8935
+ view: CalendarViewMode;
8936
+ /** First visible date, `YYYY-MM-DD`. */
8937
+ start: string;
8938
+ /** Last visible date (inclusive), `YYYY-MM-DD`. */
8939
+ end: string;
8940
+ /** The date the view is anchored on. */
8941
+ anchor: Date;
8942
+ }
8943
+ declare const WEEK_DAY_LABELS: string[];
8944
+ declare function toDateStr(d: Date): string;
8945
+ /** `YYYY-MM-DD` → local Date at midnight (ISO local form, parsed the same way in every browser). */
8946
+ declare function fromDateStr(dateStr: string): Date;
8947
+ /** The 42 cells (6 weeks, Sunday first) of the month grid containing `anchor`. */
8948
+ declare function buildMonthCells(anchor: Date, todayStr: string): CalendarDay[];
8949
+ /** The 7 days (Sunday first) of the week containing `anchor`. */
8950
+ declare function buildWeekDays(anchor: Date, todayStr: string): CalendarDay[];
8951
+ /** Month view: the whole 6-week grid. Week view: the 7 days. Agenda view: the anchor month and the next one. */
8952
+ declare function rangeFor(view: CalendarViewMode, anchor: Date, todayStr: string): CalendarRange;
8953
+ /**
8954
+ * Anchor after pressing Previous (`-1`) / Next (`1`): a week, two months (agenda, on the 1st) or one month. A month step keeps the
8955
+ * day of the month (clamped to the target month's length), so switching to the week view afterwards shows a sensible week.
8956
+ */
8957
+ declare function shiftAnchor(view: CalendarViewMode, anchor: Date, direction: -1 | 1): Date;
8958
+ /** `Wednesday, October 21, 2026` — one cached formatter, used for every cell's screen-reader name. */
8959
+ declare function formatDayLabel(dateStr: string): string;
8960
+ declare function periodLabelFor(view: CalendarViewMode, anchor: Date, todayStr: string): string;
8961
+ /** `14:30` → `2:30 PM`. */
8962
+ declare function formatTime$1(time: string): string;
8963
+ declare function formatHour(h: number): string;
8964
+ /** Pixel height of one hour row in the week view. */
8965
+ declare const HOUR_HEIGHT = 60;
8966
+ /**
8967
+ * Top offset and height (px) of a timed event in a week grid whose first row is `startHour` and last row `endHour`.
8968
+ * 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).
8969
+ */
8970
+ declare function timedBox(startTime: string | undefined, endTime: string | undefined, startHour: number, endHour?: number): {
8971
+ top: number;
8972
+ height: number;
8973
+ };
8974
+ interface CalendarLane {
8975
+ lane: number;
8976
+ lanes: number;
8977
+ }
8978
+ /**
8979
+ * Side-by-side lanes for events that overlap in time. Events are grouped into clusters of transitively overlapping events; inside a
8980
+ * cluster each event takes the first free lane and every event of the cluster shares the cluster's lane count.
8981
+ */
8982
+ declare function layoutLanes(boxes: {
8983
+ id: string;
8984
+ top: number;
8985
+ height: number;
8986
+ }[]): Record<string, CalendarLane>;
8987
+ /** One thing on the calendar. The host maps its own records to this shape. */
8988
+ export interface CalendarItem {
8989
+ /** Unique across ALL items passed in (prefix ids by source when merging lists, e.g. `task-…`, `event-…`). */
8990
+ id: string;
8991
+ title: string;
8992
+ /** Local calendar day, `YYYY-MM-DD`. */
8993
+ date: string;
8994
+ /** `HH:mm` (24 hour). Without it (or with `allDay`) the item is an all-day item in the week view. */
8995
+ startTime?: string;
8996
+ endTime?: string;
8997
+ allDay?: boolean;
8998
+ /** Filter key; matched against `CalendarFilter.value`. */
8999
+ type?: string;
9000
+ /** Accent colour (left border / bar) and soft background of the chip, any CSS colour. */
9001
+ color: string;
9002
+ bgColor: string;
9003
+ /** Replaces the formatted `startTime` on chips and agenda rows (e.g. a time already converted to another time zone, or "All day"). */
9004
+ timeLabel?: string;
9005
+ /** Small marker at the end of a month chip (e.g. `T`). */
9006
+ tag?: string;
9007
+ /** Extra badges on the agenda row. */
9008
+ badges?: {
9009
+ label: string;
9010
+ variant: BadgeVariant;
9011
+ }[];
9012
+ /** Extra grey lines under the title on the agenda row (location, contact…). */
9013
+ meta?: string[];
9014
+ /** SVG path `d` (24x24 stroke icon) drawn before the time on month chips. */
9015
+ iconPath?: string;
9016
+ /** Strike the title through (e.g. a completed reminder). */
9017
+ strike?: boolean;
9018
+ /** Screen-reader name of the item's button; defaults to "<time> <title>". */
9019
+ ariaLabel?: string;
9020
+ }
9021
+ export interface CalendarFilter {
9022
+ value: string;
9023
+ label: string;
9024
+ color: string;
9025
+ bgColor?: string;
9026
+ }
9027
+ export interface CalendarMoreClick {
9028
+ /** `YYYY-MM-DD` */
9029
+ date: string;
9030
+ /** Every item of that day that passes the active filters, in display order. */
9031
+ items: CalendarItem[];
9032
+ }
9033
+ export interface CalendarSlotClick {
9034
+ /** `YYYY-MM-DD` */
9035
+ date: string;
9036
+ /** `HH:00` of the clicked hour row. */
9037
+ time: string;
9038
+ }
9039
+ /**
9040
+ * Month / week / agenda calendar. The host owns the data: it listens to `(rangeChange)`, loads that range and passes
9041
+ * the result as `items`. The calendar owns navigation, the view switcher, type filters, layout and keyboard access.
9042
+ *
9043
+ * <ui-calendar [items]="items()" [filters]="filters" [loading]="loading()" [canCreate]="canCreate()"
9044
+ * [(view)]="view" (rangeChange)="load($event)" (itemClick)="open($event)" (dateClick)="create($event)">
9045
+ * <ui-kpi-card calendar-summary ... />
9046
+ * <ui-button calendar-actions (click)="create()">New Event</ui-button>
9047
+ * </ui-calendar>
9048
+ *
9049
+ * Keep the state you bind (`loading`, `items`, `view` …) in signals: `rangeChange` fires during change detection on the first render,
9050
+ * so a handler that writes a plain property would raise ExpressionChangedAfterItHasBeenChecked in dev mode.
9051
+ *
9052
+ * 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
9053
+ * `ToastService` messages.
9054
+ *
9055
+ * 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
9056
+ * 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.
9057
+ * 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
9058
+ * creates (all-day, or the first visible hour). The initial `view` must be one of `views`.
9059
+ *
9060
+ * Content slots: `[calendar-actions]` (right of the view switcher), `[calendar-summary]` (centre of the toolbar on
9061
+ * desktop) and `[calendar-summary-mobile]` (shown instead of it on phones).
9062
+ */
9063
+ export declare class CalendarComponent {
9064
+ /** Everything to show in the visible range. Ids must be unique across the whole list. */
9065
+ readonly items: import("@angular/core").InputSignal<CalendarItem[]>;
9066
+ readonly loading: import("@angular/core").InputSignal<boolean>;
9067
+ /** Active view; two-way bindable. A value that is not in `views` is replaced by the first allowed view. */
9068
+ readonly view: import("@angular/core").ModelSignal<CalendarViewMode>;
9069
+ /** Views the switcher offers. One entry hides the switcher. */
9070
+ readonly views: import("@angular/core").InputSignal<CalendarViewMode[]>;
9071
+ /** Date the visible period is anchored on; two-way bindable. */
9072
+ readonly anchorDate: import("@angular/core").ModelSignal<Date>;
9073
+ /** Filter chips (with an "All" chip first). Empty = no filter bar. */
9074
+ readonly filters: import("@angular/core").InputSignal<CalendarFilter[]>;
9075
+ readonly filterLabel: import("@angular/core").InputSignal<string>;
9076
+ /** `multi` toggles any number of types; `single` keeps at most one active (clicking the active chip clears it). */
9077
+ readonly filterMode: import("@angular/core").InputSignal<"multi" | "single">;
9078
+ /** Active filter values; empty = everything. Two-way bindable. */
9079
+ readonly activeFilters: import("@angular/core").ModelSignal<string[]>;
9080
+ readonly showFilterCounts: import("@angular/core").InputSignal<boolean>;
9081
+ /** Whether empty days / time slots can start a new item (`dateClick` / `slotClick`). Read-only users: false. */
9082
+ readonly canCreate: import("@angular/core").InputSignal<boolean>;
9083
+ /** Days before today cannot start a new item. */
9084
+ readonly disablePast: import("@angular/core").InputSignal<boolean>;
9085
+ /** Items shown per month cell before "+N more". */
9086
+ readonly maxVisible: import("@angular/core").InputSignal<number>;
9087
+ /** `inline`: time and title on one line. `stacked`: time on the first line, title below it (title hidden on phones). */
9088
+ readonly chipLayout: import("@angular/core").InputSignal<"inline" | "stacked">;
9089
+ /** Order each day's items by start time (default). Off = keep the order the host passed them in. */
9090
+ readonly sortByTime: import("@angular/core").InputSignal<boolean>;
9091
+ /** First and last hour row of the week view. */
9092
+ readonly startHour: import("@angular/core").InputSignal<number>;
9093
+ readonly endHour: import("@angular/core").InputSignal<number>;
9094
+ readonly emptyMessage: import("@angular/core").InputSignal<string>;
9095
+ /** Builds the screen-reader name of a month cell; default "<weekday, date>, N events". */
9096
+ readonly dayLabelFn: import("@angular/core").InputSignal<((dateStr: string, items: CalendarItem[]) => string) | null>;
9097
+ /** Fires on first render and whenever the view or the visible range changes: load this range, then pass `items`. */
9098
+ readonly rangeChange: import("@angular/core").OutputEmitterRef<CalendarRange>;
9099
+ readonly itemClick: import("@angular/core").OutputEmitterRef<CalendarItem>;
9100
+ /** Empty day clicked (month view / all-day row) — only when `canCreate` and the day is allowed. */
9101
+ readonly dateClick: import("@angular/core").OutputEmitterRef<string>;
9102
+ /** Empty hour row clicked in the week view (or Enter on a day column: the first visible hour). */
9103
+ readonly slotClick: import("@angular/core").OutputEmitterRef<CalendarSlotClick>;
9104
+ /** "+N more" clicked in a month cell. */
9105
+ readonly moreClick: import("@angular/core").OutputEmitterRef<CalendarMoreClick>;
9106
+ private readonly host;
9107
+ protected readonly weekDayLabels: string[];
9108
+ protected readonly weekDayNames: string[];
9109
+ protected readonly skeletonCells: number[];
9110
+ protected readonly formatHour: typeof formatHour;
9111
+ /** Today as `YYYY-MM-DD`; refreshed at local midnight, when the tab becomes visible again and when the user presses Today. */
9112
+ protected readonly todayStr: import("@angular/core").WritableSignal<string>;
9113
+ /** The month-grid day that holds the roving tab stop. */
9114
+ protected readonly focusedDate: import("@angular/core").WritableSignal<string | null>;
9115
+ private lastRangeKey;
9116
+ protected readonly hours: import("@angular/core").Signal<number[]>;
9117
+ protected readonly monthCells: import("@angular/core").Signal<CalendarDay[]>;
9118
+ protected readonly weekDays: import("@angular/core").Signal<CalendarDay[]>;
9119
+ protected readonly periodLabel: import("@angular/core").Signal<string>;
9120
+ protected readonly viewTabs: import("@angular/core").Signal<PillTab[]>;
9121
+ protected readonly typeCounts: import("@angular/core").Signal<Record<string, number>>;
9122
+ private readonly byDate;
9123
+ protected readonly agendaGroups: import("@angular/core").Signal<{
9124
+ dateStr: string;
9125
+ items: CalendarItem[];
9126
+ }[]>;
9127
+ /** Whether the day at `dateStr` may start a new item. */
9128
+ private clickable;
9129
+ /** The 6 rows of the month grid with everything a cell draws, computed once per input change. */
9130
+ protected readonly monthRows: import("@angular/core").Signal<{
9131
+ key: string;
9132
+ cells: {
9133
+ day: CalendarDay;
9134
+ items: CalendarItem[];
9135
+ visible: CalendarItem[];
9136
+ overflow: number;
9137
+ clickable: boolean;
9138
+ label: string;
9139
+ }[];
9140
+ }[]>;
9141
+ /** The 7 week columns with all-day items and the timed items laid out side by side when they overlap. */
9142
+ protected readonly weekColumns: import("@angular/core").Signal<{
9143
+ day: CalendarDay;
9144
+ label: string;
9145
+ clickable: boolean;
9146
+ allDay: CalendarItem[];
9147
+ timed: {
9148
+ lane: CalendarLane;
9149
+ top: number;
9150
+ height: number;
9151
+ item: CalendarItem;
9152
+ }[];
9153
+ }[]>;
9154
+ /** 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. */
9155
+ protected readonly focusDate: import("@angular/core").Signal<string>;
9156
+ constructor();
9157
+ protected isFilterActive(value: string): boolean;
9158
+ protected toggleFilter(value: string): void;
9159
+ protected clearFilters(): void;
9160
+ protected setView(v: CalendarViewMode): void;
9161
+ protected navigate(direction: -1 | 1): void;
9162
+ protected goToday(): void;
9163
+ protected dowLabel(dateStr: string): string;
9164
+ protected agendaDow(dateStr: string): string;
9165
+ protected agendaDate(dateStr: string): string;
9166
+ protected chipTime(e: CalendarItem): string;
9167
+ protected timeRange(e: CalendarItem): string;
9168
+ /** The button's name includes the visible time (WCAG 2.5.3 label in name) unless the host set `ariaLabel`. */
9169
+ protected itemLabel(e: CalendarItem): string;
9170
+ protected agendaMeta(e: CalendarItem): string[];
9171
+ private dayAriaLabel;
9172
+ protected onDateClick(dateStr: string): void;
9173
+ /** Grid keys on a day cell: arrows / Home / End move the tab stop, Enter / Space create. Keys on the chips inside never reach here. */
9174
+ protected onCellKey(event: KeyboardEvent, dateStr: string): void;
9175
+ /** The hidden "+ Add" button of an all-day cell (keyboard / screen-reader path to the same action as clicking the cell). */
9176
+ protected onAddAllDay(dateStr: string, event: Event): void;
9177
+ /** The hidden "+ Add" button of a day column: creates at the first visible hour. */
9178
+ protected onAddTimed(dateStr: string, event: Event): void;
9179
+ protected onSlotClick(dateStr: string, event: MouseEvent): void;
9180
+ protected onItemClick(item: CalendarItem, event: Event): void;
9181
+ protected onMoreClick(dateStr: string, items: CalendarItem[], event: Event): void;
9182
+ static ɵfac: i0.ɵɵFactoryDeclaration<CalendarComponent, never>;
9183
+ static ɵcmp: i0.ɵɵComponentDeclaration<CalendarComponent, "ui-calendar", never, {
9184
+ "items": {
9185
+ "alias": "items";
9186
+ "required": false;
9187
+ "isSignal": true;
9188
+ };
9189
+ "loading": {
9190
+ "alias": "loading";
9191
+ "required": false;
9192
+ "isSignal": true;
9193
+ };
9194
+ "view": {
9195
+ "alias": "view";
9196
+ "required": false;
9197
+ "isSignal": true;
9198
+ };
9199
+ "views": {
9200
+ "alias": "views";
9201
+ "required": false;
9202
+ "isSignal": true;
9203
+ };
9204
+ "anchorDate": {
9205
+ "alias": "anchorDate";
9206
+ "required": false;
9207
+ "isSignal": true;
9208
+ };
9209
+ "filters": {
9210
+ "alias": "filters";
9211
+ "required": false;
9212
+ "isSignal": true;
9213
+ };
9214
+ "filterLabel": {
9215
+ "alias": "filterLabel";
9216
+ "required": false;
9217
+ "isSignal": true;
9218
+ };
9219
+ "filterMode": {
9220
+ "alias": "filterMode";
9221
+ "required": false;
9222
+ "isSignal": true;
9223
+ };
9224
+ "activeFilters": {
9225
+ "alias": "activeFilters";
9226
+ "required": false;
9227
+ "isSignal": true;
9228
+ };
9229
+ "showFilterCounts": {
9230
+ "alias": "showFilterCounts";
9231
+ "required": false;
9232
+ "isSignal": true;
9233
+ };
9234
+ "canCreate": {
9235
+ "alias": "canCreate";
9236
+ "required": false;
9237
+ "isSignal": true;
9238
+ };
9239
+ "disablePast": {
9240
+ "alias": "disablePast";
9241
+ "required": false;
9242
+ "isSignal": true;
9243
+ };
9244
+ "maxVisible": {
9245
+ "alias": "maxVisible";
9246
+ "required": false;
9247
+ "isSignal": true;
9248
+ };
9249
+ "chipLayout": {
9250
+ "alias": "chipLayout";
9251
+ "required": false;
9252
+ "isSignal": true;
9253
+ };
9254
+ "sortByTime": {
9255
+ "alias": "sortByTime";
9256
+ "required": false;
9257
+ "isSignal": true;
9258
+ };
9259
+ "startHour": {
9260
+ "alias": "startHour";
9261
+ "required": false;
9262
+ "isSignal": true;
9263
+ };
9264
+ "endHour": {
9265
+ "alias": "endHour";
9266
+ "required": false;
9267
+ "isSignal": true;
9268
+ };
9269
+ "emptyMessage": {
9270
+ "alias": "emptyMessage";
9271
+ "required": false;
9272
+ "isSignal": true;
9273
+ };
9274
+ "dayLabelFn": {
9275
+ "alias": "dayLabelFn";
9276
+ "required": false;
9277
+ "isSignal": true;
9278
+ };
9279
+ }, {
9280
+ "view": "viewChange";
9281
+ "anchorDate": "anchorDateChange";
9282
+ "activeFilters": "activeFiltersChange";
9283
+ "rangeChange": "rangeChange";
9284
+ "itemClick": "itemClick";
9285
+ "dateClick": "dateClick";
9286
+ "slotClick": "slotClick";
9287
+ "moreClick": "moreClick";
9288
+ }, never, ["[calendar-summary]", "[calendar-actions]", "[calendar-summary-mobile]"], true, never>;
9289
+ }
9290
+ export type { CalendarDay, CalendarRange, CalendarViewMode };