@forgeroute/ui 0.4.66 → 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/fesm2022/forgeroute-ui.mjs +441 -185
- package/fesm2022/forgeroute-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/src/_detail-columns.scss +32 -0
- package/types/forgeroute-ui.d.ts +72 -5
package/package.json
CHANGED
|
@@ -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
|
+
}
|
package/types/forgeroute-ui.d.ts
CHANGED
|
@@ -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
|
|
@@ -3963,7 +3965,7 @@ export declare class ButtonComponent {
|
|
|
3963
3965
|
* `ghost-start`: a ghost button for list / section toggles - a full-width row with its content aligned to the start, transparent
|
|
3964
3966
|
* background, hover tint and the normal focus ring. Pair it with `ariaExpanded` / `ariaPressed`; the label may contain a heading element.
|
|
3965
3967
|
*/
|
|
3966
|
-
readonly variant: import("@angular/core").InputSignal<"
|
|
3968
|
+
readonly variant: import("@angular/core").InputSignal<"link" | "primary" | "secondary" | "danger" | "warning" | "ghost" | "ghost-start" | "tab" | "icon" | "icon-danger">;
|
|
3967
3969
|
/** 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`). */
|
|
3968
3970
|
readonly routerLink: import("@angular/core").InputSignal<string | readonly unknown[] | null>;
|
|
3969
3971
|
/** Query params of the `routerLink` (e.g. `{ section: 'deal-defaults' }`). */
|
|
@@ -4009,7 +4011,7 @@ export declare class ButtonComponent {
|
|
|
4009
4011
|
readonly color: import("@angular/core").InputSignal<string | undefined>;
|
|
4010
4012
|
readonly active: import("@angular/core").InputSignal<boolean>;
|
|
4011
4013
|
readonly size: import("@angular/core").InputSignal<"sm" | "md" | "lg" | "xs">;
|
|
4012
|
-
readonly type: import("@angular/core").InputSignal<"
|
|
4014
|
+
readonly type: import("@angular/core").InputSignal<"button" | "reset" | "submit">;
|
|
4013
4015
|
readonly disabled: import("@angular/core").InputSignal<boolean>;
|
|
4014
4016
|
readonly loading: import("@angular/core").InputSignal<boolean>;
|
|
4015
4017
|
readonly fullWidth: import("@angular/core").InputSignal<boolean>;
|
|
@@ -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<"" | "
|
|
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. */
|
|
@@ -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<"
|
|
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>;
|
|
@@ -6526,6 +6528,8 @@ export declare class DropdownComponent {
|
|
|
6526
6528
|
private _typeahead;
|
|
6527
6529
|
private _typeaheadTimer;
|
|
6528
6530
|
private _destroyed;
|
|
6531
|
+
/** Identifies the current loader request, so a late or stale answer (menu closed / reopened meanwhile) is ignored. */
|
|
6532
|
+
private _loadToken;
|
|
6529
6533
|
protected readonly triggerId: string;
|
|
6530
6534
|
protected readonly menuId: string;
|
|
6531
6535
|
protected readonly _ariaLabel: import("@angular/core").Signal<string | null>;
|
|
@@ -7823,6 +7827,10 @@ export declare class PanelInfoListComponent {
|
|
|
7823
7827
|
isWeb(href: string): boolean;
|
|
7824
7828
|
/** Link text: the value, else the email / phone as written. */
|
|
7825
7829
|
textOf(item: PanelInfoItem): string;
|
|
7830
|
+
/** Plain value, or the dash for an empty / blank one. */
|
|
7831
|
+
valueOf(item: PanelInfoItem): string;
|
|
7832
|
+
/** A disabled header action never runs, even when the click reaches the host element. */
|
|
7833
|
+
runHeaderAction(ha: NonNullable<PanelInfoSection['headerAction']>): void;
|
|
7826
7834
|
visibleItems(section: PanelInfoSection): PanelInfoItem[];
|
|
7827
7835
|
static ɵfac: i0.ɵɵFactoryDeclaration<PanelInfoListComponent, never>;
|
|
7828
7836
|
static ɵcmp: i0.ɵɵComponentDeclaration<PanelInfoListComponent, "ui-panel-info-list", never, {
|
|
@@ -8080,6 +8088,11 @@ export declare class AppShellComponent implements OnInit, OnDestroy {
|
|
|
8080
8088
|
* when the title is not set.
|
|
8081
8089
|
*/
|
|
8082
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>;
|
|
8083
8096
|
readonly appName: import("@angular/core").InputSignal<string>;
|
|
8084
8097
|
readonly user: import("@angular/core").InputSignal<ShellUser | null>;
|
|
8085
8098
|
readonly readOnly: import("@angular/core").InputSignal<boolean>;
|
|
@@ -8097,7 +8110,13 @@ export declare class AppShellComponent implements OnInit, OnDestroy {
|
|
|
8097
8110
|
readonly persistKey: import("@angular/core").InputSignal<string>;
|
|
8098
8111
|
readonly logoutClick: import("@angular/core").OutputEmitterRef<void>;
|
|
8099
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>;
|
|
8100
8117
|
protected readonly _collapsed: import("@angular/core").WritableSignal<boolean>;
|
|
8118
|
+
/** The rail (icons-only sidebar) only exists on the desktop layout; on the drawer layout (≤1024px) a saved rail choice is ignored. */
|
|
8119
|
+
protected readonly _drawerLayout: import("@angular/core").WritableSignal<boolean>;
|
|
8101
8120
|
protected readonly _isRail: import("@angular/core").Signal<boolean>;
|
|
8102
8121
|
private readonly _collapsedGroups;
|
|
8103
8122
|
protected readonly _visibleGroups: import("@angular/core").Signal<NavGroup[]>;
|
|
@@ -8106,6 +8125,8 @@ export declare class AppShellComponent implements OnInit, OnDestroy {
|
|
|
8106
8125
|
private readonly _iconCache;
|
|
8107
8126
|
_safeIcon(svg: string): SafeHtml;
|
|
8108
8127
|
_visibleLinks(group: NavGroup): NavLink[];
|
|
8128
|
+
/** Groups can only be collapsed when there is more than one: a lone group stays open so the navigation can never be hidden. */
|
|
8129
|
+
protected _canCollapseGroups(): boolean;
|
|
8109
8130
|
_isCollapsed(key: string): boolean;
|
|
8110
8131
|
toggleGroup(key: string): void;
|
|
8111
8132
|
private _readSavedGroups;
|
|
@@ -8114,9 +8135,28 @@ export declare class AppShellComponent implements OnInit, OnDestroy {
|
|
|
8114
8135
|
toggleCollapsed(): void;
|
|
8115
8136
|
private static readonly _COLLAPSE_KEY;
|
|
8116
8137
|
private static _loadCollapsed;
|
|
8138
|
+
private readonly _host;
|
|
8139
|
+
private readonly _injector;
|
|
8140
|
+
private readonly _document;
|
|
8141
|
+
/** The drawer layout is exactly the complement of the desktop layout the CSS rail rules use (min-width: 1025px): no viewport width falls in between. */
|
|
8142
|
+
private static readonly _DRAWER_MQ;
|
|
8143
|
+
private static readonly _FOCUSABLE;
|
|
8144
|
+
private _sidebarFocusables;
|
|
8145
|
+
private _hamburger;
|
|
8117
8146
|
toggleSidebar(): void;
|
|
8118
|
-
|
|
8147
|
+
/** Opens the drawer (drawer layout only; a no-op on desktop) and moves keyboard focus into it, so the links behind the backdrop are not reachable until it closes. */
|
|
8148
|
+
openSidebar(): void;
|
|
8149
|
+
/** Closes the drawer; `returnFocus` puts focus back on the hamburger that opened it (keyboard users keep their place). */
|
|
8150
|
+
closeSidebar(returnFocus?: boolean): void;
|
|
8151
|
+
/** Escape closes an open drawer; Tab stays inside it while it is open. */
|
|
8152
|
+
onShellKeydown(e: KeyboardEvent): void;
|
|
8153
|
+
/** Skip link: focuses the main content (`tabindex="-1"`) without changing the URL (the app uses the router). */
|
|
8154
|
+
skipToContent(e: Event): void;
|
|
8119
8155
|
ngOnInit(): void;
|
|
8156
|
+
private _drawerMq?;
|
|
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;
|
|
8120
8160
|
ngOnDestroy(): void;
|
|
8121
8161
|
private _expandActiveGroup;
|
|
8122
8162
|
static ɵfac: i0.ɵɵFactoryDeclaration<AppShellComponent, never>;
|
|
@@ -8131,6 +8171,11 @@ export declare class AppShellComponent implements OnInit, OnDestroy {
|
|
|
8131
8171
|
"required": false;
|
|
8132
8172
|
"isSignal": true;
|
|
8133
8173
|
};
|
|
8174
|
+
"showToast": {
|
|
8175
|
+
"alias": "showToast";
|
|
8176
|
+
"required": false;
|
|
8177
|
+
"isSignal": true;
|
|
8178
|
+
};
|
|
8134
8179
|
"appName": {
|
|
8135
8180
|
"alias": "appName";
|
|
8136
8181
|
"required": false;
|
|
@@ -11170,6 +11215,28 @@ export declare class SidebarLayoutComponent {
|
|
|
11170
11215
|
};
|
|
11171
11216
|
}, {}, never, ["[layout-main]", "[layout-side]"], true, never>;
|
|
11172
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
|
+
}
|
|
11173
11240
|
export type ActionBarAlign = 'start' | 'center' | 'end' | 'between';
|
|
11174
11241
|
/**
|
|
11175
11242
|
* Bar for page-level actions (Save / Cancel) that stays at the bottom of the scrolling area.
|