@forgeroute/ui 0.4.67 → 0.4.68

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.67",
3
+ "version": "0.4.68",
4
4
  "peerDependencies": {
5
5
  "@angular/common": ">=22.0.0",
6
6
  "@angular/core": ">=22.0.0",
@@ -0,0 +1,32 @@
1
+ // Independent column scrolling for detail pages (`<ui-sidebar-layout uiFillViewport>`): the viewport does not scroll; the two columns are capped
2
+ // to the room under the page's top block (`--cols-h`, set by the `uiFillViewport` directive) and each scrolls inside its own box.
3
+ //
4
+ // @use 'detail-columns' as dc; // @forgeroute/ui/src is on the stylePreprocessorOptions includePaths
5
+ // @include dc.independent-columns; // or (1200px) for collapseAt="lg"
6
+ //
7
+ // Markup: `.detail-page` wraps the page, `.col-main` is the `layout-main` element, `.col-side` is the `layout-side` element.
8
+ // Only applies while the layout has two columns: `$collapse` = the sidebar-layout `collapseAt` width in px (900 = md, 1200 = lg); collapsed it is
9
+ // one column and the page scrolls as usual. `$bleed` is the room inside the main column's scroll box so a focus ring or shadow at its edge is not clipped.
10
+ @mixin independent-columns($collapse: 900px, $bleed: 4px) {
11
+ @media (min-width: #{$collapse + 1}) {
12
+ .detail-page { padding-bottom: 0; } // the columns end at the bottom of the content area
13
+ .col-main {
14
+ position: relative; // visually hidden / absolutely positioned content (sr-only text, menus) stays inside this scroll box; otherwise it is positioned against the page and stretches the document, which then scrolls
15
+ box-sizing: border-box;
16
+ padding: $bleed;
17
+ margin: -$bleed;
18
+ max-height: calc(var(--cols-h) + #{2 * $bleed});
19
+ overflow-y: auto;
20
+ overscroll-behavior: contain;
21
+ -webkit-overflow-scrolling: touch;
22
+ }
23
+ .col-side {
24
+ display: block;
25
+ position: relative; // absolutely positioned content (visually hidden text, menus) stays inside this scroll box; otherwise it would stretch the library's outer side wrapper and give the column a second scrollbar
26
+ max-height: var(--cols-h);
27
+ overflow-y: auto;
28
+ overscroll-behavior: contain;
29
+ -webkit-overflow-scrolling: touch;
30
+ }
31
+ }
32
+ }
@@ -1095,7 +1095,7 @@ export declare class SelectComponent implements ControlValueAccessor, Validator,
1095
1095
  readonly error: import("@angular/core").InputSignal<string>;
1096
1096
  /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
1097
1097
  readonly showErrors: import("@angular/core").InputSignal<boolean>;
1098
- readonly size: import("@angular/core").InputSignal<"sm" | "default">;
1098
+ readonly size: import("@angular/core").InputSignal<"default" | "sm">;
1099
1099
  readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
1100
1100
  private readonly _cvaDisabled;
1101
1101
  protected readonly disabled: import("@angular/core").Signal<boolean>;
@@ -1591,6 +1591,8 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1591
1591
  */
1592
1592
  private _columnBadgeLabel;
1593
1593
  protected readonly _error: import("@angular/core").WritableSignal<string | null>;
1594
+ /** Phone card list is only a role=list while it contains listitems: skeleton cards or real rows (not error / empty / no-match). */
1595
+ protected readonly _cardListHasItems: Signal<boolean>;
1594
1596
  private readonly _loadFailed;
1595
1597
  /**
1596
1598
  * True from a failed load (the table shows its error state) until a later load SUCCEEDS. Unlike the error state itself it stays true while
@@ -2682,7 +2684,7 @@ export declare class AudioPlayerComponent {
2682
2684
  /** Accessible name of the player. */
2683
2685
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
2684
2686
  /** How much to load before play: 'metadata' (default), 'auto' or 'none'. */
2685
- readonly preload: import("@angular/core").InputSignal<"none" | "metadata" | "auto">;
2687
+ readonly preload: import("@angular/core").InputSignal<"none" | "auto" | "metadata">;
2686
2688
  /** Fires when the browser can't load or decode the source. */
2687
2689
  readonly playbackError: import("@angular/core").OutputEmitterRef<void>;
2688
2690
  protected readonly failed: import("@angular/core").WritableSignal<boolean>;
@@ -2936,7 +2938,7 @@ export declare class CheckboxComponent implements ControlValueAccessor, Validato
2936
2938
  * 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.
2937
2939
  * Default null: plain label text, exactly as before. Single mode only.
2938
2940
  */
2939
- readonly headingLevel: import("@angular/core").InputSignal<1 | 2 | 5 | 3 | 6 | 4 | null>;
2941
+ readonly headingLevel: import("@angular/core").InputSignal<1 | 2 | 3 | 4 | 5 | 6 | null>;
2940
2942
  readonly indeterminate: import("@angular/core").InputSignal<boolean>;
2941
2943
  readonly checked: import("@angular/core").ModelSignal<boolean>;
2942
2944
  /**
@@ -4948,7 +4950,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
4948
4950
  readonly passwordRequirements: import("@angular/core").InputSignal<boolean>;
4949
4951
  /** Rules for `passwordRequirements`; default = the library's five rules (8+ characters, upper, lower, digit, special). */
4950
4952
  readonly passwordRules: import("@angular/core").InputSignal<readonly PasswordRule[] | undefined>;
4951
- readonly type: import("@angular/core").InputSignal<"number" | "text" | "tel" | "email" | "password" | "url">;
4953
+ readonly type: import("@angular/core").InputSignal<"number" | "text" | "email" | "tel" | "password" | "url">;
4952
4954
  readonly maxlength: import("@angular/core").InputSignal<number | undefined>;
4953
4955
  readonly required: import("@angular/core").InputSignal<boolean>;
4954
4956
  readonly autocomplete: import("@angular/core").InputSignal<string>;
@@ -4957,7 +4959,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
4957
4959
  * `search`, `text`, `none`). Empty (default) = the browser's default for the field, except `type="tel"`, which keeps `tel`.
4958
4960
  * It only picks the keyboard; it does not restrict what can be typed or pasted.
4959
4961
  */
4960
- readonly inputmode: import("@angular/core").InputSignal<"" | "none" | "text" | "search" | "tel" | "email" | "url" | "decimal" | "numeric">;
4962
+ readonly inputmode: import("@angular/core").InputSignal<"" | "search" | "none" | "text" | "email" | "tel" | "url" | "decimal" | "numeric">;
4961
4963
  readonly readonly: import("@angular/core").InputSignal<boolean>;
4962
4964
  readonly hint: import("@angular/core").InputSignal<string>;
4963
4965
  /** Id(s) of an external element that also describes this control (e.g. one shared error text for a group of fields). Space separated; MERGED after the control's own hint / error id in `aria-describedby`, never replacing it. Empty = unchanged. */
@@ -5023,7 +5025,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
5023
5025
  protected readonly _stepAttr: import("@angular/core").Signal<string | null>;
5024
5026
  protected readonly _revealable: import("@angular/core").Signal<boolean>;
5025
5027
  protected readonly _shown: import("@angular/core").WritableSignal<boolean>;
5026
- protected readonly _inputType: import("@angular/core").Signal<"number" | "text" | "tel" | "email" | "password" | "url">;
5028
+ protected readonly _inputType: import("@angular/core").Signal<"number" | "text" | "email" | "tel" | "password" | "url">;
5027
5029
  protected readonly _eyePath: string;
5028
5030
  protected readonly _eyeOffPath: string;
5029
5031
  protected readonly _showRequirements: import("@angular/core").Signal<boolean>;
@@ -6493,7 +6495,7 @@ export declare class DropdownComponent {
6493
6495
  readonly loader: import("@angular/core").InputSignal<(() => Promise<DropdownItem[]>) | null>;
6494
6496
  readonly active: import("@angular/core").InputSignal<boolean>;
6495
6497
  readonly activeValue: import("@angular/core").InputSignal<string>;
6496
- readonly variant: import("@angular/core").InputSignal<"badge" | "button">;
6498
+ readonly variant: import("@angular/core").InputSignal<"button" | "badge">;
6497
6499
  /** Trigger size for `variant="button"`: `sm` (default, the compact toolbar look) or `md` (same padding and type as a medium `ui-button`). */
6498
6500
  readonly size: import("@angular/core").InputSignal<"sm" | "md">;
6499
6501
  readonly menuWidth: import("@angular/core").InputSignal<string>;
@@ -6823,7 +6825,7 @@ export declare class FormRowComponent {
6823
6825
  * child simply takes the full width. Keep a numeric span within the row's `cols` (use `all` for the whole row).
6824
6826
  */
6825
6827
  export declare class FormColSpanDirective {
6826
- readonly uiColSpan: import("@angular/core").InputSignal<"" | 2 | 3 | "2" | "3" | "all">;
6828
+ readonly uiColSpan: import("@angular/core").InputSignal<"" | "2" | "3" | 2 | 3 | "all">;
6827
6829
  protected readonly _class: import("@angular/core").Signal<string>;
6828
6830
  static ɵfac: i0.ɵɵFactoryDeclaration<FormColSpanDirective, never>;
6829
6831
  static ɵdir: i0.ɵɵDirectiveDeclaration<FormColSpanDirective, "[uiColSpan]", never, {
@@ -8086,6 +8088,11 @@ export declare class AppShellComponent implements OnInit, OnDestroy {
8086
8088
  * when the title is not set.
8087
8089
  */
8088
8090
  readonly pageTitle: import("@angular/core").InputSignal<string>;
8091
+ /**
8092
+ * Show the app's toasts (renders one `<ui-toast />` for the whole shell). Default false so an app that already renders its own `<ui-toast />`
8093
+ * is unchanged; an app that sets this removes its own.
8094
+ */
8095
+ readonly showToast: import("@angular/core").InputSignal<boolean>;
8089
8096
  readonly appName: import("@angular/core").InputSignal<string>;
8090
8097
  readonly user: import("@angular/core").InputSignal<ShellUser | null>;
8091
8098
  readonly readOnly: import("@angular/core").InputSignal<boolean>;
@@ -8103,6 +8110,10 @@ export declare class AppShellComponent implements OnInit, OnDestroy {
8103
8110
  readonly persistKey: import("@angular/core").InputSignal<string>;
8104
8111
  readonly logoutClick: import("@angular/core").OutputEmitterRef<void>;
8105
8112
  protected readonly _sidebarOpen: import("@angular/core").WritableSignal<boolean>;
8113
+ /** `data.pageTitle` of the deepest activated route that sets one ('' when none does). Updated on every NavigationEnd. */
8114
+ protected readonly _routeTitle: import("@angular/core").WritableSignal<string>;
8115
+ /** The title shown in the top bar: the `pageTitle` input when the app sets one (it wins), else the route's `data.pageTitle`. */
8116
+ protected readonly _title: import("@angular/core").Signal<string>;
8106
8117
  protected readonly _collapsed: import("@angular/core").WritableSignal<boolean>;
8107
8118
  /** The rail (icons-only sidebar) only exists on the desktop layout; on the drawer layout (≤1024px) a saved rail choice is ignored. */
8108
8119
  protected readonly _drawerLayout: import("@angular/core").WritableSignal<boolean>;
@@ -8144,6 +8155,8 @@ export declare class AppShellComponent implements OnInit, OnDestroy {
8144
8155
  ngOnInit(): void;
8145
8156
  private _drawerMq?;
8146
8157
  private readonly _onDrawerMqChange;
8158
+ /** The `data.pageTitle` of the deepest activated route that has a non-empty string one (a child route's title wins over its parent's). */
8159
+ private _titleOfRoute;
8147
8160
  ngOnDestroy(): void;
8148
8161
  private _expandActiveGroup;
8149
8162
  static ɵfac: i0.ɵɵFactoryDeclaration<AppShellComponent, never>;
@@ -8158,6 +8171,11 @@ export declare class AppShellComponent implements OnInit, OnDestroy {
8158
8171
  "required": false;
8159
8172
  "isSignal": true;
8160
8173
  };
8174
+ "showToast": {
8175
+ "alias": "showToast";
8176
+ "required": false;
8177
+ "isSignal": true;
8178
+ };
8161
8179
  "appName": {
8162
8180
  "alias": "appName";
8163
8181
  "required": false;
@@ -9913,7 +9931,7 @@ export declare class DetailCardComponent {
9913
9931
  /** true (default) = the title is displayed in capitals (CSS only); false = shown as written. The text, aria-label and heading name are never changed. */
9914
9932
  readonly uppercaseTitle: import("@angular/core").InputSignal<boolean>;
9915
9933
  /** 1-6 makes the title a real heading for screen readers (role=heading, aria-level); null keeps it plain text. */
9916
- readonly headingLevel: import("@angular/core").InputSignal<1 | 2 | 5 | 3 | 6 | 4 | null>;
9934
+ readonly headingLevel: import("@angular/core").InputSignal<1 | 2 | 3 | 4 | 5 | 6 | null>;
9917
9935
  /** Optional id for the title text; the card is then labelled by it. Without it the title is the card's aria-label. */
9918
9936
  readonly titleId: import("@angular/core").InputSignal<string>;
9919
9937
  /** Accessible name of the card when the header gives none (no header, or no title). A visible title wins; blank = no name. */
@@ -11197,6 +11215,28 @@ export declare class SidebarLayoutComponent {
11197
11215
  };
11198
11216
  }, {}, never, ["[layout-main]", "[layout-side]"], true, never>;
11199
11217
  }
11218
+ /**
11219
+ * Independent column scrolling for a detail page's `<ui-sidebar-layout uiFillViewport>`.
11220
+ *
11221
+ * Sets `--cols-h` on the host: the room left between the top of the layout and the bottom of the shell's content area (the nearest
11222
+ * `<main>`). Pair it with the `independent-columns` mixin (`@use 'detail-columns' as dc;` from `@forgeroute/ui/src/_detail-columns.scss`),
11223
+ * which caps both columns to `--cols-h` so each scrolls on its own while the viewport does not scroll.
11224
+ *
11225
+ * <ui-sidebar-layout uiFillViewport sideWidth="320px" collapseAt="md">
11226
+ * <div layout-main class="col-main"> ... </div>
11227
+ * <aside layout-side class="col-side"> ... </aside>
11228
+ * </ui-sidebar-layout>
11229
+ *
11230
+ * Re-measured when the content area or the element's parent changes size (window resize, tabs wrapping, a card loading). Pure layout maths
11231
+ * on the element's position inside the scroller's content, so it does not depend on how far the page happens to be scrolled. The height is
11232
+ * never below 240px. With no `<main>` ancestor nothing is set. Not related to `ui-page`'s `fillViewport` input (a page at least one viewport high).
11233
+ */
11234
+ export declare class FillViewportDirective {
11235
+ private readonly el;
11236
+ constructor();
11237
+ static ɵfac: i0.ɵɵFactoryDeclaration<FillViewportDirective, never>;
11238
+ static ɵdir: i0.ɵɵDirectiveDeclaration<FillViewportDirective, "[uiFillViewport]", never, {}, {}, never, never, true, never>;
11239
+ }
11200
11240
  export type ActionBarAlign = 'start' | 'center' | 'end' | 'between';
11201
11241
  /**
11202
11242
  * Bar for page-level actions (Save / Cancel) that stays at the bottom of the scrolling area.