@forgeroute/ui 0.4.18 → 0.4.20

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.18",
3
+ "version": "0.4.20",
4
4
  "peerDependencies": {
5
5
  "@angular/common": ">=22.0.0",
6
6
  "@angular/core": ">=22.0.0",
@@ -3029,6 +3029,14 @@ export declare class StepperComponent {
3029
3029
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
3030
3030
  /** Horizontal, <= 480px: show only the current step's label (`'current'`, default) or every label (`'all'`). */
3031
3031
  readonly labelsOnSmallScreens: import("@angular/core").InputSignal<"all" | "current">;
3032
+ /**
3033
+ * Horizontal only. `'beside'` (default): the label sits to the right of its circle. `'below'`: equal-width columns, the label centred under
3034
+ * its circle, one continuous line behind the circles that fills as steps complete; a complete step shows a check, the current step an
3035
+ * accent ring with a dot, an upcoming step an empty circle (no numbers). Circles are 40px (32px with `size="sm"`).
3036
+ */
3037
+ readonly labelPosition: import("@angular/core").InputSignal<"beside" | "below">;
3038
+ /** Viewport width in px below which a horizontal stepper is drawn vertical (labels beside the circles), e.g. `640`. null (default) = never. */
3039
+ readonly stackBelow: import("@angular/core").InputSignal<number | null>;
3032
3040
  /** CSS length (e.g. `10.5rem`): horizontal only - the list gets `min-width: calc(<step count> * <value>)`. Empty (default) = no minimum. */
3033
3041
  readonly minStepWidth: import("@angular/core").InputSignal<string>;
3034
3042
  /** true = the list scrolls sideways (`overflow-x: auto`, 4px top / bottom padding so focus rings are not clipped) instead of squeezing. Default false. */
@@ -3041,6 +3049,9 @@ export declare class StepperComponent {
3041
3049
  readonly stepClick: import("@angular/core").OutputEmitterRef<string>;
3042
3050
  private readonly _win;
3043
3051
  private readonly _narrow;
3052
+ private readonly _stacked;
3053
+ /** The orientation actually drawn: `orientation`, or vertical while the viewport is below `stackBelow`. */
3054
+ protected readonly orient: import("@angular/core").Signal<StepperOrientation>;
3044
3055
  /** True when `compact` is a pixel number and the viewport is below it (tokens use CSS media queries instead). */
3045
3056
  protected readonly compactPx: import("@angular/core").Signal<boolean>;
3046
3057
  private readonly _id;
@@ -3125,6 +3136,16 @@ export declare class StepperComponent {
3125
3136
  "required": false;
3126
3137
  "isSignal": true;
3127
3138
  };
3139
+ "labelPosition": {
3140
+ "alias": "labelPosition";
3141
+ "required": false;
3142
+ "isSignal": true;
3143
+ };
3144
+ "stackBelow": {
3145
+ "alias": "stackBelow";
3146
+ "required": false;
3147
+ "isSignal": true;
3148
+ };
3128
3149
  "minStepWidth": {
3129
3150
  "alias": "minStepWidth";
3130
3151
  "required": false;
@@ -4271,6 +4292,12 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
4271
4292
  readonly label: import("@angular/core").InputSignal<string>;
4272
4293
  /** Accessible name for a field with no visible label (e.g. an inline cell or title input). */
4273
4294
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
4295
+ /**
4296
+ * `data-testid` placed on the inner `<input>` (the host `<ui-text-input>` keeps its own attributes). Lets e2e tests `fill()` / `blur()` the
4297
+ * field directly instead of `getByTestId('x').locator('input')`. Pass a different id than the host's, e.g. host `data-testid="email"`
4298
+ * and `inputTestId="email-input"`. Omitted = no attribute.
4299
+ */
4300
+ readonly inputTestId: import("@angular/core").InputSignal<string>;
4274
4301
  readonly placeholder: import("@angular/core").InputSignal<string>;
4275
4302
  /**
4276
4303
  * An optional leading mark shown inside the field, left of the text (e.g. `prefix="$"` for a dollar amount). Hidden unless set; it is
@@ -4416,6 +4443,11 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
4416
4443
  "required": false;
4417
4444
  "isSignal": true;
4418
4445
  };
4446
+ "inputTestId": {
4447
+ "alias": "inputTestId";
4448
+ "required": false;
4449
+ "isSignal": true;
4450
+ };
4419
4451
  "placeholder": {
4420
4452
  "alias": "placeholder";
4421
4453
  "required": false;
@@ -4536,7 +4568,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
4536
4568
  "focused": "focused";
4537
4569
  "blurred": "blurred";
4538
4570
  "invalidChange": "invalidChange";
4539
- }, never, never, true, never>;
4571
+ }, never, ["[uiLabelEnd]"], true, never>;
4540
4572
  }
4541
4573
  export declare class TextareaInputComponent implements ControlValueAccessor, Validator, UiFieldValidity {
4542
4574
  readonly label: import("@angular/core").InputSignal<string>;
@@ -8557,7 +8589,7 @@ export declare class DetailCardComponent {
8557
8589
  readonly showEdit: import("@angular/core").InputSignal<boolean>;
8558
8590
  readonly editLabel: import("@angular/core").InputSignal<string>;
8559
8591
  readonly editClick: import("@angular/core").OutputEmitterRef<void>;
8560
- /** `data-testid` of the built-in Edit button (on the `ui-button` host); none when empty. */
8592
+ /** `data-testid` of the built-in Edit button (on the Edit `<button>`); none when empty. */
8561
8593
  readonly editTestId: import("@angular/core").InputSignal<string>;
8562
8594
  /** false = no pencil icon in the Edit button (text only). Default true: unchanged. */
8563
8595
  readonly editIcon: import("@angular/core").InputSignal<boolean>;
@@ -8739,6 +8771,204 @@ export declare class DividerComponent {
8739
8771
  };
8740
8772
  }, {}, never, never, true, never>;
8741
8773
  }
8774
+ /** One column (stage) of a [ui-board]. `items` are the host's own records; the board never reads their fields. */
8775
+ export interface BoardColumn<T = unknown> {
8776
+ /** Unique id of the column (the stage key); reported in `from` / `to` of a move. */
8777
+ key: string;
8778
+ /** Column title (shown uppercase). */
8779
+ label: string;
8780
+ items: T[];
8781
+ /** Dot colour: a CSS colour, or one of blue / cyan / green / teal / amber / orange / red / pink / slate / gray. */
8782
+ color?: string;
8783
+ /** Small line under the title, e.g. a pre-formatted total ("$120,000"). */
8784
+ summary?: string;
8785
+ /** Spoken version of `summary` (aria-label). Defaults to the summary text. */
8786
+ summaryLabel?: string;
8787
+ /** 'success' = green column and green card edge (a won / done stage). */
8788
+ tone?: 'default' | 'success';
8789
+ /** true = display-only column: items can't be dropped into it. */
8790
+ dropDisabled?: boolean;
8791
+ /** Text of the empty column; defaults to the board's `emptyColumnText`. */
8792
+ emptyText?: string;
8793
+ }
8794
+ /** Fired when the user moves a card to another column (drag and drop, or Shift + Arrow keys on a focused card). */
8795
+ export interface BoardMoveEvent<T = unknown> {
8796
+ item: T;
8797
+ from: string;
8798
+ to: string;
8799
+ /** The board has ALREADY moved the card on screen. Call this if the host's save fails to put it back. */
8800
+ revert: () => void;
8801
+ }
8802
+ export interface BoardCardActionEvent<T = unknown> {
8803
+ type: string;
8804
+ item: T;
8805
+ }
8806
+ /** Context of the card template: `<ng-template uiBoardCard let-item let-column="column" let-menu="menu">`. */
8807
+ export interface BoardCardContext<T = unknown> {
8808
+ $implicit: T;
8809
+ column: BoardColumn<T>;
8810
+ /** Template of the card's "⋮" menu (renders nothing without `cardActions`). Output it with `{ $implicit: item }` in the card's top row. */
8811
+ menu: TemplateRef<{
8812
+ $implicit: T;
8813
+ }>;
8814
+ }
8815
+ /** Marks the template that renders the INSIDE of a card (the board draws the card frame, menu and drag handling). */
8816
+ export declare class BoardCardDirective<T = unknown> {
8817
+ readonly template: TemplateRef<BoardCardContext<T>>;
8818
+ static ngTemplateContextGuard<T>(_dir: BoardCardDirective<T>, _ctx: unknown): _ctx is BoardCardContext<T>;
8819
+ static ɵfac: i0.ɵɵFactoryDeclaration<BoardCardDirective<any>, never>;
8820
+ static ɵdir: i0.ɵɵDirectiveDeclaration<BoardCardDirective<any>, "ng-template[uiBoardCard]", never, {}, {}, never, never, true, never>;
8821
+ }
8822
+ /**
8823
+ * Kanban board: columns of cards that can be dragged between columns. Data and saving stay with the host.
8824
+ *
8825
+ * <ui-board [columns]="columns()" [itemKey]="key" [itemLabel]="label" [cardActions]="actions" [readOnly]="perm() !== 'full'"
8826
+ * [loading]="loading()" [error]="error()" (retry)="load()"
8827
+ * (cardClick)="open($event)" (cardAction)="onAction($event)" (itemMove)="onMove($event)">
8828
+ * <ng-template uiBoardCard let-deal let-menu="menu">
8829
+ * <div class="ub-card__top"><span class="ub-card__title">{{ deal.title }}</span>
8830
+ * <ng-container [ngTemplateOutlet]="menu" [ngTemplateOutletContext]="{ $implicit: deal }" /></div>
8831
+ * <div class="ub-card__contact">{{ deal.contactName }}</div>
8832
+ * </ng-template>
8833
+ * </ui-board>
8834
+ *
8835
+ * - A drop moves the card on screen at once and emits `itemMove`; the host saves it and calls `event.revert()` if that fails.
8836
+ * - Keyboard: Enter / Space opens a card; Shift + ← / → moves it to the neighbouring column (announced to screen readers).
8837
+ * - `readOnly` removes dragging and keyboard moves. On phones (≤640px) the columns stack.
8838
+ */
8839
+ export declare class BoardComponent<T = unknown> {
8840
+ /** The columns in display order, each with its items. A new value replaces the board's content (and any on-screen move). */
8841
+ readonly columns: import("@angular/core").InputSignal<BoardColumn<T>[]>;
8842
+ /** Stable unique id of a card (used to track cards between renders). */
8843
+ readonly itemKey: import("@angular/core").InputSignal<(item: T) => string>;
8844
+ /** Spoken name of a card: title, who, status, value... The card's visible content is the `uiBoardCard` template. */
8845
+ readonly itemLabel: import("@angular/core").InputSignal<(item: T) => string>;
8846
+ /** Menu on every card (the "⋮" button). Empty = no menu. Handle the pick in `(cardAction)`. */
8847
+ readonly cardActions: import("@angular/core").InputSignal<RowAction[]>;
8848
+ readonly loading: import("@angular/core").InputSignal<boolean>;
8849
+ /** Error text: replaces the board with the message and a Retry button. */
8850
+ readonly error: import("@angular/core").InputSignal<string | null>;
8851
+ /** true = no dragging, no keyboard moves. */
8852
+ readonly readOnly: import("@angular/core").InputSignal<boolean>;
8853
+ /** true = moves are paused (e.g. a save is running) so a second card can't be moved before the first is saved. */
8854
+ readonly moveDisabled: import("@angular/core").InputSignal<boolean>;
8855
+ /** Optional rule: may this card go from this column to that one? A refused drop does nothing. */
8856
+ readonly canMove: import("@angular/core").InputSignal<((item: T, from: string, to: string) => boolean) | null>;
8857
+ readonly ariaLabel: import("@angular/core").InputSignal<string>;
8858
+ readonly emptyMessage: import("@angular/core").InputSignal<string>;
8859
+ readonly emptyColumnText: import("@angular/core").InputSignal<string>;
8860
+ /** Singular / plural noun for the column's spoken count ("3 deals"). */
8861
+ readonly itemNoun: import("@angular/core").InputSignal<string>;
8862
+ readonly itemNounPlural: import("@angular/core").InputSignal<string>;
8863
+ readonly retryLabel: import("@angular/core").InputSignal<string>;
8864
+ readonly cardClick: import("@angular/core").OutputEmitterRef<T>;
8865
+ readonly cardAction: import("@angular/core").OutputEmitterRef<BoardCardActionEvent<T>>;
8866
+ readonly itemMove: import("@angular/core").OutputEmitterRef<BoardMoveEvent<T>>;
8867
+ readonly retry: import("@angular/core").OutputEmitterRef<void>;
8868
+ protected readonly card: import("@angular/core").Signal<BoardCardDirective<any> | undefined>;
8869
+ /** The columns as shown: the host's value, plus any move not yet replaced by new data. */
8870
+ protected readonly cols: import("@angular/core").WritableSignal<BoardColumn<T>[]>;
8871
+ protected readonly overKey: import("@angular/core").WritableSignal<string | null>;
8872
+ protected readonly draggingKey: import("@angular/core").WritableSignal<string | null>;
8873
+ protected readonly announcement: import("@angular/core").WritableSignal<string>;
8874
+ private readonly host;
8875
+ private drag;
8876
+ protected readonly skeletonColumns: import("@angular/core").Signal<number[]>;
8877
+ protected readonly canDrag: import("@angular/core").Signal<boolean>;
8878
+ protected readonly canMoveAny: import("@angular/core").Signal<boolean>;
8879
+ protected dot(color?: string): string;
8880
+ protected onDragStart(event: DragEvent, item: T, col: BoardColumn<T>): void;
8881
+ protected onDragEnd(): void;
8882
+ protected onDragOver(event: DragEvent, col: BoardColumn<T>): void;
8883
+ protected onDragLeave(event: DragEvent, col: BoardColumn<T>): void;
8884
+ protected onDrop(event: DragEvent, col: BoardColumn<T>): void;
8885
+ protected onCardKey(event: KeyboardEvent, item: T, col: BoardColumn<T>): void;
8886
+ private accepts;
8887
+ private move;
8888
+ static ɵfac: i0.ɵɵFactoryDeclaration<BoardComponent<any>, never>;
8889
+ static ɵcmp: i0.ɵɵComponentDeclaration<BoardComponent<any>, "ui-board", never, {
8890
+ "columns": {
8891
+ "alias": "columns";
8892
+ "required": true;
8893
+ "isSignal": true;
8894
+ };
8895
+ "itemKey": {
8896
+ "alias": "itemKey";
8897
+ "required": true;
8898
+ "isSignal": true;
8899
+ };
8900
+ "itemLabel": {
8901
+ "alias": "itemLabel";
8902
+ "required": true;
8903
+ "isSignal": true;
8904
+ };
8905
+ "cardActions": {
8906
+ "alias": "cardActions";
8907
+ "required": false;
8908
+ "isSignal": true;
8909
+ };
8910
+ "loading": {
8911
+ "alias": "loading";
8912
+ "required": false;
8913
+ "isSignal": true;
8914
+ };
8915
+ "error": {
8916
+ "alias": "error";
8917
+ "required": false;
8918
+ "isSignal": true;
8919
+ };
8920
+ "readOnly": {
8921
+ "alias": "readOnly";
8922
+ "required": false;
8923
+ "isSignal": true;
8924
+ };
8925
+ "moveDisabled": {
8926
+ "alias": "moveDisabled";
8927
+ "required": false;
8928
+ "isSignal": true;
8929
+ };
8930
+ "canMove": {
8931
+ "alias": "canMove";
8932
+ "required": false;
8933
+ "isSignal": true;
8934
+ };
8935
+ "ariaLabel": {
8936
+ "alias": "ariaLabel";
8937
+ "required": false;
8938
+ "isSignal": true;
8939
+ };
8940
+ "emptyMessage": {
8941
+ "alias": "emptyMessage";
8942
+ "required": false;
8943
+ "isSignal": true;
8944
+ };
8945
+ "emptyColumnText": {
8946
+ "alias": "emptyColumnText";
8947
+ "required": false;
8948
+ "isSignal": true;
8949
+ };
8950
+ "itemNoun": {
8951
+ "alias": "itemNoun";
8952
+ "required": false;
8953
+ "isSignal": true;
8954
+ };
8955
+ "itemNounPlural": {
8956
+ "alias": "itemNounPlural";
8957
+ "required": false;
8958
+ "isSignal": true;
8959
+ };
8960
+ "retryLabel": {
8961
+ "alias": "retryLabel";
8962
+ "required": false;
8963
+ "isSignal": true;
8964
+ };
8965
+ }, {
8966
+ "cardClick": "cardClick";
8967
+ "cardAction": "cardAction";
8968
+ "itemMove": "itemMove";
8969
+ "retry": "retry";
8970
+ }, ["card"], never, true, never>;
8971
+ }
8742
8972
  /**
8743
8973
  * Wraps a block of form controls (a settings page, a configuration card) so a view-only user can look at the current
8744
8974
  * values but change nothing. While `readOnly` is true the wrapper's native `<fieldset>` is `disabled`, and the browser