@forgeroute/ui 0.4.5 → 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgeroute/ui",
3
- "version": "0.4.5",
3
+ "version": "0.4.7",
4
4
  "peerDependencies": {
5
5
  "@angular/common": ">=22.0.0",
6
6
  "@angular/core": ">=22.0.0",
@@ -1812,7 +1812,7 @@ export declare class SidePanelComponent implements OnDestroy {
1812
1812
  readonly cancelLabel: import("@angular/core").InputSignal<string>;
1813
1813
  /** Right-aligned primary action button label. Empty string = hidden. */
1814
1814
  readonly primaryLabel: import("@angular/core").InputSignal<string>;
1815
- readonly primaryVariant: import("@angular/core").InputSignal<"primary" | "danger" | "warning">;
1815
+ readonly primaryVariant: import("@angular/core").InputSignal<"warning" | "danger" | "primary">;
1816
1816
  readonly primaryLoading: import("@angular/core").InputSignal<boolean>;
1817
1817
  readonly primaryDisabled: import("@angular/core").InputSignal<boolean>;
1818
1818
  /** `data-testid` of the Cancel button; none when empty (default). */
@@ -3040,6 +3040,11 @@ export interface RadioOption {
3040
3040
  * Built-in validation: `required` -> "<label> is required."; a non-empty value that is not one of the `options` ->
3041
3041
  * "Select a valid option." (not checked while `options` is empty). Disabled groups are never invalid.
3042
3042
  *
3043
+ * Option content (`<ng-template uiRadioOptionContent="value">`) is rendered right under its option, inside the fieldset, so the layout and
3044
+ * keyboard flow stay as they are. Because it is not a radio, it is exposed as its own `role="group"` named by that option's label
3045
+ * (`aria-labelledby` = the radio's label id, e.g. "Deliver, group") instead of being read as part of the radio group. Groups without
3046
+ * templates render no extra attributes or ids.
3047
+ *
3043
3048
  * Validity API (same on every ui input): Angular `Validator`, signals `invalid` + `errorMessage`, `invalidChange` output,
3044
3049
  * provides `UiFieldValidity`. Messages show after the group lost focus or while `[showErrors]="true"`; a host `[error]` wins.
3045
3050
  */
@@ -3065,6 +3070,8 @@ export declare class RadioGroupComponent implements ControlValueAccessor, Valida
3065
3070
  protected readonly _descId: string;
3066
3071
  /** Id of the content block under the selected option; that radio points at it with aria-controls. */
3067
3072
  protected readonly _nestedId: string;
3073
+ /** Id of an option's label text (set on the radio only for options that have nested content); the nested group is named by it. */
3074
+ protected _optionLabelId(index: number): string;
3068
3075
  protected readonly _value: import("@angular/core").WritableSignal<string>;
3069
3076
  private readonly _reveal;
3070
3077
  private readonly _issue;
@@ -3336,7 +3343,7 @@ export declare class ButtonComponent {
3336
3343
  * `ghost-start`: a ghost button for list / section toggles - a full-width row with its content aligned to the start, transparent
3337
3344
  * background, hover tint and the normal focus ring. Pair it with `ariaExpanded` / `ariaPressed`; the label may contain a heading element.
3338
3345
  */
3339
- readonly variant: import("@angular/core").InputSignal<"primary" | "secondary" | "danger" | "warning" | "link" | "ghost" | "ghost-start" | "tab" | "icon" | "icon-danger">;
3346
+ readonly variant: import("@angular/core").InputSignal<"warning" | "danger" | "primary" | "secondary" | "link" | "ghost" | "ghost-start" | "tab" | "icon" | "icon-danger">;
3340
3347
  /** 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`). */
3341
3348
  readonly routerLink: import("@angular/core").InputSignal<string | readonly unknown[] | null>;
3342
3349
  /** Query params of the `routerLink` (e.g. `{ section: 'deal-defaults' }`). */
@@ -3739,7 +3746,7 @@ export declare class BulkMessagePanelComponent {
3739
3746
  readonly sending: import("@angular/core").InputSignal<boolean>;
3740
3747
  readonly closed: import("@angular/core").OutputEmitterRef<void>;
3741
3748
  readonly send: import("@angular/core").OutputEmitterRef<BulkMessageSendEvent>;
3742
- readonly channel: import("@angular/core").WritableSignal<"text" | "email">;
3749
+ readonly channel: import("@angular/core").WritableSignal<"email" | "text">;
3743
3750
  private readonly _subject;
3744
3751
  private readonly _body;
3745
3752
  get subject(): string;
@@ -3888,7 +3895,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
3888
3895
  * Meant for a short mark of 1-3 characters.
3889
3896
  */
3890
3897
  readonly prefix: import("@angular/core").InputSignal<string>;
3891
- readonly type: import("@angular/core").InputSignal<"number" | "text" | "email" | "tel" | "password" | "url">;
3898
+ readonly type: import("@angular/core").InputSignal<"number" | "tel" | "email" | "text" | "password" | "url">;
3892
3899
  readonly maxlength: import("@angular/core").InputSignal<number | undefined>;
3893
3900
  readonly required: import("@angular/core").InputSignal<boolean>;
3894
3901
  readonly autocomplete: import("@angular/core").InputSignal<string>;
@@ -3897,7 +3904,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
3897
3904
  * `search`, `text`, `none`). Empty (default) = the browser's default for the field, except `type="tel"`, which keeps `tel`.
3898
3905
  * It only picks the keyboard; it does not restrict what can be typed or pasted.
3899
3906
  */
3900
- readonly inputmode: import("@angular/core").InputSignal<"" | "none" | "text" | "search" | "email" | "tel" | "url" | "decimal" | "numeric">;
3907
+ readonly inputmode: import("@angular/core").InputSignal<"" | "tel" | "email" | "none" | "text" | "search" | "url" | "decimal" | "numeric">;
3901
3908
  readonly readonly: import("@angular/core").InputSignal<boolean>;
3902
3909
  readonly hint: import("@angular/core").InputSignal<string>;
3903
3910
  readonly error: import("@angular/core").InputSignal<string>;
@@ -5338,7 +5345,7 @@ export declare class FormSectionComponent {
5338
5345
  }, {}, never, ["*"], true, never>;
5339
5346
  }
5340
5347
  export declare class FormRowComponent {
5341
- readonly cols: import("@angular/core").InputSignal<1 | 2 | 3>;
5348
+ readonly cols: import("@angular/core").InputSignal<1 | 2 | 3 | 4>;
5342
5349
  static ɵfac: i0.ɵɵFactoryDeclaration<FormRowComponent, never>;
5343
5350
  static ɵcmp: i0.ɵɵComponentDeclaration<FormRowComponent, "ui-form-row", never, {
5344
5351
  "cols": {
@@ -5355,7 +5362,7 @@ export declare class FormRowComponent {
5355
5362
  * child simply takes the full width. Keep a numeric span within the row's `cols` (use `all` for the whole row).
5356
5363
  */
5357
5364
  export declare class FormColSpanDirective {
5358
- readonly uiColSpan: import("@angular/core").InputSignal<"" | "2" | "3" | 2 | 3 | "all">;
5365
+ readonly uiColSpan: import("@angular/core").InputSignal<"" | 2 | 3 | "2" | "3" | "all">;
5359
5366
  protected readonly _class: import("@angular/core").Signal<string>;
5360
5367
  static ɵfac: i0.ɵɵFactoryDeclaration<FormColSpanDirective, never>;
5361
5368
  static ɵdir: i0.ɵɵDirectiveDeclaration<FormColSpanDirective, "[uiColSpan]", never, {
@@ -5958,6 +5965,12 @@ export interface PanelInfoSection {
5958
5965
  export declare class PanelInfoListComponent {
5959
5966
  readonly sections: import("@angular/core").InputSignal<PanelInfoSection[]>;
5960
5967
  readonly showEmptyState: import("@angular/core").InputSignal<boolean>;
5968
+ /**
5969
+ * true = each row reads "Label: value" (a colon after the label and a real space, so `textContent` is "Label: value") with the value
5970
+ * next to the label instead of pushed to the right edge. Works with plain values, links (href / email / phone / link) and badges.
5971
+ * Default false = the label and value as before.
5972
+ */
5973
+ readonly labelColon: import("@angular/core").InputSignal<boolean>;
5961
5974
  readonly displaySections: import("@angular/core").Signal<PanelInfoSection[]>;
5962
5975
  /**
5963
5976
  * The safe href of an item, or null: `href` first, else `mailto:`/`tel:` built from `email`/`phone`. Only mailto, tel, http and https
@@ -5980,6 +5993,11 @@ export declare class PanelInfoListComponent {
5980
5993
  "required": false;
5981
5994
  "isSignal": true;
5982
5995
  };
5996
+ "labelColon": {
5997
+ "alias": "labelColon";
5998
+ "required": false;
5999
+ "isSignal": true;
6000
+ };
5983
6001
  }, {}, never, never, true, never>;
5984
6002
  }
5985
6003
  /**
@@ -6386,7 +6404,7 @@ export declare class IconComponent {
6386
6404
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
6387
6405
  /** Icon size in px. */
6388
6406
  readonly size: import("@angular/core").InputSignal<number>;
6389
- readonly variant: import("@angular/core").InputSignal<"danger" | "default">;
6407
+ readonly variant: import("@angular/core").InputSignal<"default" | "danger">;
6390
6408
  readonly disabled: import("@angular/core").InputSignal<boolean>;
6391
6409
  /** The host is running the request this icon started: a spinner replaces the picture and the button is disabled (no click) until it is false again. */
6392
6410
  readonly loading: import("@angular/core").InputSignal<boolean>;
@@ -6444,23 +6462,36 @@ export declare class IconComponent {
6444
6462
  }, never, never, true, never>;
6445
6463
  }
6446
6464
  export type TimelineTone = 'default' | 'success' | 'warning' | 'danger';
6465
+ /** A badge of a timeline item. `tooltip` shows on hover and keyboard focus (the badge becomes focusable); `testId` is its `data-testid`. */
6466
+ export interface TimelineBadge {
6467
+ label: string;
6468
+ variant: BadgeVariant;
6469
+ tooltip?: string;
6470
+ testId?: string;
6471
+ }
6447
6472
  export interface TimelineItem {
6448
6473
  /** Stable id used for `track`; the index is used when absent. */
6449
6474
  id?: string;
6475
+ /** `data-testid` of the `<li>`. */
6476
+ testId?: string;
6450
6477
  title: string;
6451
6478
  description?: string;
6452
6479
  /** Pre-formatted time text shown to the reader, e.g. "Oct 20, 2026, 3:15 PM". */
6453
6480
  time?: string;
6454
6481
  /** ISO date / date-time for the `datetime` attribute of the `<time>` element (machine-readable). */
6455
6482
  dateTime?: string;
6456
- badge?: {
6457
- label: string;
6458
- variant: BadgeVariant;
6459
- };
6483
+ badge?: TimelineBadge;
6484
+ /** Any number of badges, shown after `badge` (if also set), in order. They wrap onto the next line when the row is narrow. */
6485
+ badges?: TimelineBadge[];
6460
6486
  /** Icon drawn inside the dot (static, decorative). Unknown names draw nothing. */
6461
6487
  icon?: IconName | (string & {});
6462
6488
  /** Colour of the dot / icon. Default `default`. */
6463
6489
  tone?: TimelineTone;
6490
+ /**
6491
+ * Colours the dot / icon with a badge colour (any `BadgeVariant`): the solid dot is the badge's own dark shade (`BADGE_VARIANT_STYLES[v].color`,
6492
+ * at least 3:1 on white, so the dot and a white icon on it are readable). Overrides `tone`; without it `tone` works as before.
6493
+ */
6494
+ dotVariant?: BadgeVariant;
6464
6495
  }
6465
6496
  /**
6466
6497
  * Vertical activity feed: an ordered list of events joined by a line, each with a dot (or icon), title, optional badge,
@@ -6480,6 +6511,12 @@ export declare class TimelineComponent {
6480
6511
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
6481
6512
  /** Shown (as a hint) when there are no items. Empty = render nothing. */
6482
6513
  readonly emptyMessage: import("@angular/core").InputSignal<string>;
6514
+ /** Any CSS length (e.g. `600px`). When set, the list scrolls inside a keyboard-focusable region of at most this height. Empty = no wrapper. */
6515
+ readonly maxHeight: import("@angular/core").InputSignal<string>;
6516
+ /** `below` (default): the time is under the title / description. `end`: the time sits right-aligned on the title row. */
6517
+ readonly timePosition: import("@angular/core").InputSignal<"below" | "end">;
6518
+ /** Solid dot colour of an item's `dotVariant`, or null (then `tone` colours it). */
6519
+ dotColor(item: TimelineItem): string | null;
6483
6520
  static ɵfac: i0.ɵɵFactoryDeclaration<TimelineComponent, never>;
6484
6521
  static ɵcmp: i0.ɵɵComponentDeclaration<TimelineComponent, "ui-timeline", never, {
6485
6522
  "items": {
@@ -6497,6 +6534,16 @@ export declare class TimelineComponent {
6497
6534
  "required": false;
6498
6535
  "isSignal": true;
6499
6536
  };
6537
+ "maxHeight": {
6538
+ "alias": "maxHeight";
6539
+ "required": false;
6540
+ "isSignal": true;
6541
+ };
6542
+ "timePosition": {
6543
+ "alias": "timePosition";
6544
+ "required": false;
6545
+ "isSignal": true;
6546
+ };
6500
6547
  }, {}, never, never, true, never>;
6501
6548
  }
6502
6549
  /**
@@ -7003,7 +7050,10 @@ export declare class RadioComponent {
7003
7050
  /** Public so a host template can bind `[disabled]` (a protected input fails strict template type-checking). */
7004
7051
  readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
7005
7052
  protected readonly disabled: import("@angular/core").InputSignal<boolean>;
7006
- protected readonly _labelId: string;
7053
+ /** Id of the visible label text. Optional: a host (e.g. `ui-radio-group`) can set it to point another element at the label with `aria-labelledby`; a unique id is generated when empty. */
7054
+ readonly labelId: import("@angular/core").InputSignal<string>;
7055
+ private readonly _generatedLabelId;
7056
+ protected readonly _labelId: import("@angular/core").Signal<string>;
7007
7057
  /** With a description inside the <label>, the accessible name would read "Email We send a message": name the input by the label text only. */
7008
7058
  protected readonly _labelledBy: import("@angular/core").Signal<string | null>;
7009
7059
  protected readonly _descriptionId: string;
@@ -7064,6 +7114,11 @@ export declare class RadioComponent {
7064
7114
  "required": false;
7065
7115
  "isSignal": true;
7066
7116
  };
7117
+ "labelId": {
7118
+ "alias": "labelId";
7119
+ "required": false;
7120
+ "isSignal": true;
7121
+ };
7067
7122
  }, {
7068
7123
  "selected": "selected";
7069
7124
  }, never, ["*"], true, never>;
@@ -7414,6 +7469,14 @@ export declare class SignaturePadComponent implements ControlValueAccessor {
7414
7469
  * `state="ready"` is a clickable button (`label`), `"blocked"` the same button disabled (`blockedLabel`, e.g. "create your signature first"),
7415
7470
  * and `"signed"` shows the applied `image` (a signature data URL) contained inside the box instead (signed without an image is a disabled button showing `label`). The box size comes from the document
7416
7471
  * so the text is scaled to it (height x 0.25, clamped to 7-11px); on touch devices the tap area is extended to at least 44px tall.
7472
+ *
7473
+ * Inside an ancestor scaled with CSS `transform: scale(s)` (e.g. a PDF page shrunk to fit a phone), pass that factor as `scale` so the tap area
7474
+ * stays at least 44 CSS px on screen (the area is made 44 / s px tall before the ancestor shrinks it). Default 1; values <= 0, NaN or
7475
+ * non-finite count as 1. Only the touch tap area changes, not the look, font size or accessibility.
7476
+ *
7477
+ * <div [style.transform]="'scale(' + s + ')'" style="transform-origin: top left">
7478
+ * <ui-pdf-hotspot ... [scale]="s" /> <!-- s = 0.5 -> tap area at least 88px tall before scaling = 44px on screen -->
7479
+ * </div>
7417
7480
  */
7418
7481
  export declare class PdfHotspotComponent {
7419
7482
  /** Position and size in pixels, from the page's top-left corner. */
@@ -7424,7 +7487,7 @@ export declare class PdfHotspotComponent {
7424
7487
  /** `ready`: clickable; `blocked`: disabled (a prerequisite is missing); `signed`: shows `image`. */
7425
7488
  readonly state: import("@angular/core").InputSignal<"ready" | "blocked" | "signed">;
7426
7489
  /** `warning` gives the ready state an amber look (e.g. for initials), default is blue. */
7427
- readonly tone: import("@angular/core").InputSignal<"primary" | "warning">;
7490
+ readonly tone: import("@angular/core").InputSignal<"warning" | "primary">;
7428
7491
  /** Text of the ready button (e.g. "Sign Here"). */
7429
7492
  readonly label: import("@angular/core").InputSignal<string>;
7430
7493
  /** Text of the blocked button (e.g. "Add signature above"). */
@@ -7434,8 +7497,12 @@ export declare class PdfHotspotComponent {
7434
7497
  /** The applied signature (data URL), shown when `state` is `signed`. */
7435
7498
  readonly image: import("@angular/core").InputSignal<string | null>;
7436
7499
  readonly imageAlt: import("@angular/core").InputSignal<string>;
7500
+ /** The CSS scale factor an ancestor applies (`transform: scale(s)`); keeps the touch tap area at least 44px on screen. Invalid values count as 1. */
7501
+ readonly scale: import("@angular/core").InputSignal<number>;
7437
7502
  /** The ready button was clicked. */
7438
7503
  readonly activate: import("@angular/core").OutputEmitterRef<void>;
7504
+ /** `--ph-scale` value, or null (no property at all) for scale 1 and invalid values. */
7505
+ protected readonly _scaleVar: import("@angular/core").Signal<string | null>;
7439
7506
  protected readonly fontSize: import("@angular/core").Signal<number>;
7440
7507
  static ɵfac: i0.ɵɵFactoryDeclaration<PdfHotspotComponent, never>;
7441
7508
  static ɵcmp: i0.ɵɵComponentDeclaration<PdfHotspotComponent, "ui-pdf-hotspot", never, {
@@ -7494,6 +7561,11 @@ export declare class PdfHotspotComponent {
7494
7561
  "required": false;
7495
7562
  "isSignal": true;
7496
7563
  };
7564
+ "scale": {
7565
+ "alias": "scale";
7566
+ "required": false;
7567
+ "isSignal": true;
7568
+ };
7497
7569
  }, {
7498
7570
  "activate": "activate";
7499
7571
  }, never, never, true, never>;
@@ -7533,7 +7605,7 @@ export declare class DetailCardComponent {
7533
7605
  /** true (default) = the title is displayed in capitals (CSS only); false = shown as written. The text, aria-label and heading name are never changed. */
7534
7606
  readonly uppercaseTitle: import("@angular/core").InputSignal<boolean>;
7535
7607
  /** 1-6 makes the title a real heading for screen readers (role=heading, aria-level); null keeps it plain text. */
7536
- readonly headingLevel: import("@angular/core").InputSignal<1 | 2 | 3 | 4 | 5 | 6 | null>;
7608
+ readonly headingLevel: import("@angular/core").InputSignal<1 | 2 | 3 | 4 | 6 | 5 | null>;
7537
7609
  /** Optional id for the title text; the card is then labelled by it. Without it the title is the card's aria-label. */
7538
7610
  readonly titleId: import("@angular/core").InputSignal<string>;
7539
7611
  /** Accessible name of the card when the header gives none (no header, or no title). A visible title wins; blank = no name. */