@nexterajs/ui 0.0.1 → 0.1.0
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/README.md +279 -34
- package/fesm2022/nexterajs-ui-charts.mjs +1096 -0
- package/fesm2022/nexterajs-ui-charts.mjs.map +1 -0
- package/fesm2022/nexterajs-ui-core.mjs +835 -11
- package/fesm2022/nexterajs-ui-core.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-display.mjs +1142 -0
- package/fesm2022/nexterajs-ui-display.mjs.map +1 -0
- package/fesm2022/nexterajs-ui-dropdowns.mjs +621 -69
- package/fesm2022/nexterajs-ui-dropdowns.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-file-uploader.mjs +576 -11
- package/fesm2022/nexterajs-ui-file-uploader.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-forms.mjs +2702 -452
- package/fesm2022/nexterajs-ui-forms.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-grid.mjs +2350 -336
- package/fesm2022/nexterajs-ui-grid.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-intl.mjs +117 -15
- package/fesm2022/nexterajs-ui-intl.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-navigation.mjs +1054 -0
- package/fesm2022/nexterajs-ui-navigation.mjs.map +1 -0
- package/fesm2022/nexterajs-ui-notify.mjs +353 -0
- package/fesm2022/nexterajs-ui-notify.mjs.map +1 -0
- package/fesm2022/nexterajs-ui-overlay.mjs +1671 -0
- package/fesm2022/nexterajs-ui-overlay.mjs.map +1 -0
- package/fesm2022/nexterajs-ui-pivot.mjs +191 -136
- package/fesm2022/nexterajs-ui-pivot.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-shell.mjs +542 -0
- package/fesm2022/nexterajs-ui-shell.mjs.map +1 -0
- package/fesm2022/nexterajs-ui-styling.mjs +568 -3
- package/fesm2022/nexterajs-ui-styling.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-tree-view.mjs +150 -18
- package/fesm2022/nexterajs-ui-tree-view.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-validation.mjs +283 -97
- package/fesm2022/nexterajs-ui-validation.mjs.map +1 -1
- package/fesm2022/nexterajs-ui.mjs +6 -0
- package/fesm2022/nexterajs-ui.mjs.map +1 -1
- package/package.json +37 -2
- package/styles/_dropdown.scss +150 -1
- package/styles/_editor.scss +75 -21
- package/styles/_icons.scss +92 -0
- package/styles/_mixins.scss +104 -1
- package/styles/_scrollbar.scss +134 -0
- package/styles/_status.scss +21 -0
- package/styles/_toast.scss +243 -0
- package/styles/_tokens.scss +467 -2
- package/styles/_widget.scss +14 -3
- package/styles/index.scss +10 -4
- package/types/nexterajs-ui-charts.d.ts +446 -0
- package/types/nexterajs-ui-core.d.ts +515 -30
- package/types/nexterajs-ui-display.d.ts +720 -0
- package/types/nexterajs-ui-dropdowns.d.ts +318 -57
- package/types/nexterajs-ui-file-uploader.d.ts +240 -8
- package/types/nexterajs-ui-forms.d.ts +772 -43
- package/types/nexterajs-ui-grid.d.ts +878 -135
- package/types/nexterajs-ui-intl.d.ts +39 -4
- package/types/nexterajs-ui-navigation.d.ts +531 -0
- package/types/nexterajs-ui-notify.d.ts +149 -0
- package/types/nexterajs-ui-overlay.d.ts +703 -0
- package/types/nexterajs-ui-pivot.d.ts +91 -70
- package/types/nexterajs-ui-shell.d.ts +294 -0
- package/types/nexterajs-ui-styling.d.ts +163 -3
- package/types/nexterajs-ui-tree-view.d.ts +56 -4
- package/types/nexterajs-ui-validation.d.ts +110 -22
- package/types/nexterajs-ui.d.ts +6 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
import { InjectionToken, Signal, TemplateRef } from '@angular/core';
|
|
3
|
+
import { Params } from '@angular/router';
|
|
4
|
+
import { NxeStatusFamily } from '@nexterajs/ui/display';
|
|
5
|
+
import { NxeMessageKey } from '@nexterajs/ui/core';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* One entry of the side navigation.
|
|
9
|
+
*
|
|
10
|
+
* - A **link** has `route` (router) or `href` (plain anchor).
|
|
11
|
+
* - A **parent** has `children`: it is a disclosure button, not a link. Its children appear under it
|
|
12
|
+
* when it is open, and it opens by itself when one of them is the current page.
|
|
13
|
+
* - A **group** has `heading: true` and `children`: a non-interactive heading, with its items in a
|
|
14
|
+
* labelled list under it. Groups sit at the top level; items inside them nest as deep as needed.
|
|
15
|
+
* - An entry with none of those is a plain button; `itemClick` reports it.
|
|
16
|
+
*/
|
|
17
|
+
interface NxeNavItem {
|
|
18
|
+
/** Unique within the tree. Keys the open state and the DOM ids. */
|
|
19
|
+
readonly id: string;
|
|
20
|
+
/** What the entry says. Translate it. */
|
|
21
|
+
readonly label: string;
|
|
22
|
+
/**
|
|
23
|
+
* The icon, named for `<i class="nxe-icon nxe-icon-NAME">`, or, when the app supplies an
|
|
24
|
+
* `ng-template[nxeSidenavIcon]`, any key that template maps to an icon. An entry without one
|
|
25
|
+
* shows the first letter of its label so a collapsed rail is still usable.
|
|
26
|
+
*/
|
|
27
|
+
readonly icon?: string;
|
|
28
|
+
/** Router link: a URL (`'/buyer/inbox'`) or commands (`['/buyer/price-lists', id]`). */
|
|
29
|
+
readonly route?: string | unknown[];
|
|
30
|
+
/** Query parameters for `route`. When set they take part in the active match. */
|
|
31
|
+
readonly queryParams?: Params;
|
|
32
|
+
/** A plain `href`, for a link that leaves the app. Never shown as the current page. */
|
|
33
|
+
readonly href?: string;
|
|
34
|
+
/** A count, or a signal of one (read in the template, so it updates without a new tree). */
|
|
35
|
+
readonly badge?: number | Signal<number | null | undefined>;
|
|
36
|
+
/** Colour of the badge; `danger` by default. */
|
|
37
|
+
readonly badgeFamily?: NxeStatusFamily;
|
|
38
|
+
/** Spoken name of the badge ("5 items need action"); defaults to the number. */
|
|
39
|
+
readonly badgeLabel?: string;
|
|
40
|
+
/** Children of a parent entry, or the items of a group. */
|
|
41
|
+
readonly children?: readonly NxeNavItem[];
|
|
42
|
+
/** Make this a group heading; its `children` are the group's items. */
|
|
43
|
+
readonly heading?: boolean;
|
|
44
|
+
/** Not interactive, not focusable, announced as disabled. */
|
|
45
|
+
readonly disabled?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Match the URL exactly. Without it an entry is the current page for its URL and everything
|
|
48
|
+
* below it (`/buyer/purchase-orders` for `/buyer/purchase-orders/42`). Give the home entry
|
|
49
|
+
* (`/buyer`) `exact: true`, or it is current everywhere.
|
|
50
|
+
*/
|
|
51
|
+
readonly exact?: boolean;
|
|
52
|
+
}
|
|
53
|
+
/** `docked`: beside the content, expanded or a rail. `drawer`: off-canvas, over the content. */
|
|
54
|
+
type NxeShellMode = 'docked' | 'drawer';
|
|
55
|
+
/**
|
|
56
|
+
* What `nxe-topbar` and `nxe-sidenav` need from the `nxe-shell` around them, through
|
|
57
|
+
* {@link NXE_SHELL}. Both also work without a shell; they then do not toggle anything.
|
|
58
|
+
*/
|
|
59
|
+
interface NxeShellState {
|
|
60
|
+
readonly mode: Signal<NxeShellMode>;
|
|
61
|
+
/** The sidenav is a narrow icon rail (docked and collapsed). */
|
|
62
|
+
readonly rail: Signal<boolean>;
|
|
63
|
+
/** Docked: the user's collapsed choice. */
|
|
64
|
+
readonly collapsed: Signal<boolean>;
|
|
65
|
+
/** The drawer is on screen (drawer mode and open). */
|
|
66
|
+
readonly drawerShown: Signal<boolean>;
|
|
67
|
+
/** DOM id of the projected `nxe-sidenav`, for `aria-controls`. */
|
|
68
|
+
readonly sidenavId: Signal<string | null>;
|
|
69
|
+
setCollapsed(collapsed: boolean): void;
|
|
70
|
+
/** Hamburger: open or close the drawer, or collapse or expand the dock. */
|
|
71
|
+
toggleNavigation(): void;
|
|
72
|
+
closeDrawer(): void;
|
|
73
|
+
}
|
|
74
|
+
/** Provided by `nxe-shell` to the topbar and sidenav projected into it. */
|
|
75
|
+
declare const NXE_SHELL: InjectionToken<NxeShellState>;
|
|
76
|
+
/**
|
|
77
|
+
* `<ng-template nxeSidenavIcon let-item>` inside `nxe-sidenav` draws the icon of every entry that
|
|
78
|
+
* has an `icon`, given the entry. Use it to map `icon` keys to your own SVGs:
|
|
79
|
+
*
|
|
80
|
+
* ```html
|
|
81
|
+
* <nxe-sidenav [items]="items">
|
|
82
|
+
* <ng-template nxeSidenavIcon let-item>
|
|
83
|
+
* <svg viewBox="0 0 24 24"><path [attr.d]="paths[item.icon]" /></svg>
|
|
84
|
+
* </ng-template>
|
|
85
|
+
* </nxe-sidenav>
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
declare class NxeSidenavIconDirective {
|
|
89
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NxeSidenavIconDirective, never>;
|
|
90
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<NxeSidenavIconDirective, "ng-template[nxeSidenavIcon]", never, {}, {}, never, never, true, never>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* `nxe-shell` is the page frame of an application: an optional banner, the topbar, the sidenav and
|
|
95
|
+
* the main content.
|
|
96
|
+
*
|
|
97
|
+
* ```html
|
|
98
|
+
* <nxe-shell [(collapsed)]="collapsed">
|
|
99
|
+
* <sb-impersonation-banner nxeShellBanner />
|
|
100
|
+
* <nxe-topbar>...</nxe-topbar>
|
|
101
|
+
* <nxe-sidenav [items]="items" />
|
|
102
|
+
* <router-outlet />
|
|
103
|
+
* </nxe-shell>
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* **Slots.** `[nxeShellBanner]` (full width above the topbar, for a banner that must stay on screen),
|
|
107
|
+
* an `nxe-topbar`, an `nxe-sidenav`, and everything else, which goes in the `<main>` landmark. A
|
|
108
|
+
* "Skip to content" link, the first tab stop, jumps to that `<main>`.
|
|
109
|
+
*
|
|
110
|
+
* **Responsive.** The shell measures its own width. At or above `breakpoint` (960px by default, the
|
|
111
|
+
* design system's `md`) the sidenav is docked beside the content, expanded or, when `collapsed`, an
|
|
112
|
+
* icon rail. Below it the sidenav is an off-canvas drawer over the content with a scrim: the
|
|
113
|
+
* topbar's toggle button opens it, focus is trapped inside while it is open, Esc and a click on the
|
|
114
|
+
* scrim close it, a navigation closes it, and focus returns to the control that opened it.
|
|
115
|
+
* Widening the shell past the breakpoint closes the drawer.
|
|
116
|
+
*
|
|
117
|
+
* The shell is as tall as `--nxe-shell-height` (default `100dvh`): give it the height of the space
|
|
118
|
+
* it fills, and the content scrolls inside `<main>`.
|
|
119
|
+
*/
|
|
120
|
+
declare class NxeShellComponent implements NxeShellState {
|
|
121
|
+
private readonly host;
|
|
122
|
+
private readonly messages;
|
|
123
|
+
private readonly router;
|
|
124
|
+
private readonly injector;
|
|
125
|
+
private readonly focusTrapFactory;
|
|
126
|
+
/** Docked sidenav shows only icons. Two-way: `[(collapsed)]`. */
|
|
127
|
+
readonly collapsed: _angular_core.ModelSignal<boolean>;
|
|
128
|
+
/** The off-canvas drawer is open (only meaningful below the breakpoint). Two-way: `[(drawerOpen)]`. */
|
|
129
|
+
readonly drawerOpen: _angular_core.ModelSignal<boolean>;
|
|
130
|
+
/** Shell width, in CSS px, from which the sidenav is docked rather than a drawer. */
|
|
131
|
+
readonly breakpoint: _angular_core.InputSignalWithTransform<number, unknown>;
|
|
132
|
+
/** Skip-link target id; unique per shell. */
|
|
133
|
+
protected readonly mainId: string;
|
|
134
|
+
private readonly sidenav;
|
|
135
|
+
/** Own width, kept by a ResizeObserver; the window's until the first measurement. */
|
|
136
|
+
private readonly width;
|
|
137
|
+
readonly mode: _angular_core.Signal<NxeShellMode>;
|
|
138
|
+
readonly rail: _angular_core.Signal<boolean>;
|
|
139
|
+
readonly drawerShown: _angular_core.Signal<boolean>;
|
|
140
|
+
readonly sidenavId: _angular_core.Signal<string | null>;
|
|
141
|
+
private trap;
|
|
142
|
+
private returnFocusTo;
|
|
143
|
+
constructor();
|
|
144
|
+
setCollapsed(collapsed: boolean): void;
|
|
145
|
+
/** The hamburger: the drawer below the breakpoint, the dock's collapsed state above it. */
|
|
146
|
+
toggleNavigation(): void;
|
|
147
|
+
closeDrawer(): void;
|
|
148
|
+
protected t(key: 'shell.skipToContent'): string;
|
|
149
|
+
protected skipToContent(event: Event): void;
|
|
150
|
+
protected onEscape(event: Event): void;
|
|
151
|
+
private onDrawerShown;
|
|
152
|
+
private onDrawerHidden;
|
|
153
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NxeShellComponent, never>;
|
|
154
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NxeShellComponent, "nxe-shell", never, { "collapsed": { "alias": "collapsed"; "required": false; "isSignal": true; }; "drawerOpen": { "alias": "drawerOpen"; "required": false; "isSignal": true; }; "breakpoint": { "alias": "breakpoint"; "required": false; "isSignal": true; }; }, { "collapsed": "collapsedChange"; "drawerOpen": "drawerOpenChange"; }, ["sidenav"], ["[nxeShellBanner]", "nxe-topbar", "nxe-sidenav", "*"], true, never>;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* `nxe-sidenav` is the application's primary navigation, drawn from a tree of {@link NxeNavItem}.
|
|
159
|
+
*
|
|
160
|
+
* ```html
|
|
161
|
+
* <nxe-sidenav [items]="items" (itemClick)="track($event)">
|
|
162
|
+
* <img nxeSidenavHeader src="logo.svg" alt="Nextera" />
|
|
163
|
+
* </nxe-sidenav>
|
|
164
|
+
* ```
|
|
165
|
+
*
|
|
166
|
+
* **Structure and ARIA.** A `<nav>` landmark holding nested lists, in the pattern the ARIA Authoring
|
|
167
|
+
* Practices call a *disclosure navigation menu*: a link is `<a aria-current="page">` when it is the
|
|
168
|
+
* current page; a parent is a `<button aria-expanded aria-controls>` that shows or hides the list
|
|
169
|
+
* under it; a group heading labels its list (`aria-labelledby`). It is deliberately not
|
|
170
|
+
* `role="tree"`: a tree makes one node focusable and needs the full tree keyboard contract, where
|
|
171
|
+
* every link here is an ordinary tab stop and the arrow keys are a shortcut on top of Tab.
|
|
172
|
+
*
|
|
173
|
+
* **Keyboard.** Tab and Shift+Tab visit every link and parent. On a link or parent, Arrow Down/Up
|
|
174
|
+
* move to the next/previous visible entry, Home/End to the first/last. Arrow Right opens a closed
|
|
175
|
+
* parent, or moves into an open one's first child; Arrow Left closes an open parent, or moves from
|
|
176
|
+
* a child to its parent (Right and Left swap in a right-to-left document). Enter and Space activate.
|
|
177
|
+
*
|
|
178
|
+
* **Current page.** From the router: an entry is current when its URL matches (a prefix, or the
|
|
179
|
+
* whole URL with `exact`), and when several do, the most specific one alone is `aria-current`
|
|
180
|
+
* (`/payments/aging` over `/payments`). The parents of the current page open themselves on
|
|
181
|
+
* navigation; what the user opened or closed by hand holds until the next navigation into it.
|
|
182
|
+
*
|
|
183
|
+
* **Collapsed rail.** With the sidenav collapsed (through `nxe-shell` or the `collapsed` model) only
|
|
184
|
+
* the icons show, each with its label as a native `title` and as visually-hidden text, and a badge
|
|
185
|
+
* pins to the icon. There is no flyout for children (that waits for the menu): activating a parent
|
|
186
|
+
* in the rail expands the rail with that parent open.
|
|
187
|
+
*
|
|
188
|
+
* Inside an `nxe-shell` the shell owns the collapsed state and the off-canvas drawer; on its own the
|
|
189
|
+
* sidenav is a plain docked column.
|
|
190
|
+
*/
|
|
191
|
+
declare class NxeSidenavComponent {
|
|
192
|
+
private readonly router;
|
|
193
|
+
private readonly messages;
|
|
194
|
+
private readonly shell;
|
|
195
|
+
/** The sidenav's own element; `nxe-shell` traps focus in it while the drawer is open. */
|
|
196
|
+
readonly element: HTMLElement;
|
|
197
|
+
private readonly navElement;
|
|
198
|
+
/** DOM id, which the topbar's toggle button names in `aria-controls`. */
|
|
199
|
+
readonly id: string;
|
|
200
|
+
/** The navigation tree. */
|
|
201
|
+
readonly items: _angular_core.InputSignal<readonly NxeNavItem[]>;
|
|
202
|
+
/** Accessible name of the `<nav>` landmark; "Main navigation" in the active language by default. */
|
|
203
|
+
readonly label: _angular_core.InputSignal<string>;
|
|
204
|
+
/**
|
|
205
|
+
* Collapsed to the icon rail. Inside an `nxe-shell` the shell's `collapsed` wins and this is
|
|
206
|
+
* left alone; the sidenav writes the user's choice through the shell instead.
|
|
207
|
+
*/
|
|
208
|
+
readonly collapsed: _angular_core.ModelSignal<boolean>;
|
|
209
|
+
/** Show the collapse/expand button at the foot of a docked sidenav. Default true. */
|
|
210
|
+
readonly collapsible: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
211
|
+
/** An entry was activated: a link followed, a plain button pressed. Parents do not emit. */
|
|
212
|
+
readonly itemClick: _angular_core.OutputEmitterRef<NxeNavItem>;
|
|
213
|
+
/** Draws the icon of every entry that has an `icon`. */
|
|
214
|
+
protected readonly iconTemplate: _angular_core.Signal<TemplateRef<any> | undefined>;
|
|
215
|
+
protected readonly navLabel: _angular_core.Signal<string>;
|
|
216
|
+
protected readonly rail: _angular_core.Signal<boolean>;
|
|
217
|
+
protected readonly drawer: _angular_core.Signal<boolean>;
|
|
218
|
+
protected readonly drawerOpen: _angular_core.Signal<boolean>;
|
|
219
|
+
/** Every entry by id, with its place in the tree and the URL it points at. */
|
|
220
|
+
private readonly nodes;
|
|
221
|
+
/** The router's URL, re-read at every navigation so what is current is a signal. */
|
|
222
|
+
private readonly url;
|
|
223
|
+
/** Id of the one entry that is the current page. */
|
|
224
|
+
private readonly currentId;
|
|
225
|
+
/** Ids of the parents above the current page. They open by themselves. */
|
|
226
|
+
private readonly currentAncestors;
|
|
227
|
+
/**
|
|
228
|
+
* What the user opened or closed by hand. Navigating to a new page forgets the choices about
|
|
229
|
+
* its ancestors, so they open for it, and keeps the rest.
|
|
230
|
+
*/
|
|
231
|
+
private readonly manual;
|
|
232
|
+
protected t(key: NxeMessageKey): string;
|
|
233
|
+
protected isCurrent(id: string): boolean;
|
|
234
|
+
/** The current page is somewhere under this parent. */
|
|
235
|
+
protected holdsCurrent(id: string): boolean;
|
|
236
|
+
protected isOpen(id: string): boolean;
|
|
237
|
+
protected hasChildren(item: NxeNavItem): boolean;
|
|
238
|
+
protected badgeValue(item: NxeNavItem): number | null | undefined;
|
|
239
|
+
protected badgeName(item: NxeNavItem): string;
|
|
240
|
+
protected initial(item: NxeNavItem): string;
|
|
241
|
+
/** Toggle a parent; in the rail, expand the rail with the parent open instead. */
|
|
242
|
+
protected onParent(item: NxeNavItem): void;
|
|
243
|
+
protected onActivate(item: NxeNavItem): void;
|
|
244
|
+
protected toggleCollapsed(): void;
|
|
245
|
+
protected closeDrawer(): void;
|
|
246
|
+
protected onKeydown(event: KeyboardEvent, item: NxeNavItem): void;
|
|
247
|
+
/** Links and parent buttons in document order; the ones inside a closed parent are not rendered. */
|
|
248
|
+
private focusables;
|
|
249
|
+
private setOpen;
|
|
250
|
+
private setCollapsed;
|
|
251
|
+
private treeOf;
|
|
252
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NxeSidenavComponent, never>;
|
|
253
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NxeSidenavComponent, "nxe-sidenav", never, { "items": { "alias": "items"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "collapsed": { "alias": "collapsed"; "required": false; "isSignal": true; }; "collapsible": { "alias": "collapsible"; "required": false; "isSignal": true; }; }, { "collapsed": "collapsedChange"; "itemClick": "itemClick"; }, ["iconTemplate"], ["[nxeSidenavHeader]", "[nxeSidenavFooter]"], true, never>;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* `nxe-topbar` is the bar across the top of an `nxe-shell`: a start, a centre and an end slot.
|
|
258
|
+
*
|
|
259
|
+
* ```html
|
|
260
|
+
* <nxe-topbar>
|
|
261
|
+
* <img nxeTopbarStart src="logo.svg" alt="Nextera" />
|
|
262
|
+
* <sb-search nxeTopbarCenter />
|
|
263
|
+
* <ng-container nxeTopbarEnd>
|
|
264
|
+
* <sb-company-switcher />
|
|
265
|
+
* <sb-notifications />
|
|
266
|
+
* </ng-container>
|
|
267
|
+
* </nxe-topbar>
|
|
268
|
+
* ```
|
|
269
|
+
*
|
|
270
|
+
* The start slot is preceded by a hamburger button: an icon-only `nxe-button` named "Toggle
|
|
271
|
+
* navigation" with `aria-controls` the sidenav and `aria-expanded` the sidenav's state. Inside an
|
|
272
|
+
* `nxe-shell` it opens and closes the drawer below the breakpoint and collapses and expands the dock
|
|
273
|
+
* above it. `menuToggle` also fires, so a topbar used without a shell can drive its own sidenav.
|
|
274
|
+
* `[nxeTopbarEnd]` elements sit at the inline end of the bar, where a company switcher, language
|
|
275
|
+
* toggle, notification bell and user menu go.
|
|
276
|
+
*/
|
|
277
|
+
declare class NxeTopbarComponent {
|
|
278
|
+
private readonly messages;
|
|
279
|
+
private readonly shell;
|
|
280
|
+
/** Show the hamburger button. Default true. */
|
|
281
|
+
readonly menuButton: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
282
|
+
/** The hamburger was pressed. */
|
|
283
|
+
readonly menuToggle: _angular_core.OutputEmitterRef<void>;
|
|
284
|
+
protected readonly label: _angular_core.Signal<string>;
|
|
285
|
+
protected readonly controls: _angular_core.Signal<string | null>;
|
|
286
|
+
/** Drawer: open. Dock: not collapsed. Without a shell the button says nothing about it. */
|
|
287
|
+
protected readonly expanded: _angular_core.Signal<boolean | null>;
|
|
288
|
+
protected toggle(): void;
|
|
289
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NxeTopbarComponent, never>;
|
|
290
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NxeTopbarComponent, "nxe-topbar", never, { "menuButton": { "alias": "menuButton"; "required": false; "isSignal": true; }; }, { "menuToggle": "menuToggle"; }, never, ["[nxeTopbarStart]", "[nxeTopbarCenter]", "[nxeTopbarEnd]"], true, never>;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export { NXE_SHELL, NxeShellComponent, NxeSidenavComponent, NxeSidenavIconDirective, NxeTopbarComponent };
|
|
294
|
+
export type { NxeNavItem, NxeShellMode, NxeShellState };
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { OverlayRef } from '@angular/cdk/overlay';
|
|
2
2
|
import { Subscription } from 'rxjs';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { EnvironmentProviders, OnInit, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* Marker class carried by every nxe surface — component hosts and CDK overlay panes alike.
|
|
6
8
|
*
|
|
7
|
-
* It is the nxe counterpart of DevExtreme's `.
|
|
9
|
+
* It is the nxe counterpart of DevExtreme's `.nxe-widget` base and is what gives a surface its
|
|
8
10
|
* font family/size/weight/line-height (see styling/_widget.scss).
|
|
9
11
|
*
|
|
10
12
|
* It matters most on overlays: a CDK pane is appended to `<body>`, so a portaled dropdown
|
|
@@ -30,11 +32,169 @@ declare function nxePane(...extra: (string | null | undefined)[]): string[];
|
|
|
30
32
|
*
|
|
31
33
|
* DevExtreme drew dropdowns flush against the editor — no border on the shared edge — and moved
|
|
32
34
|
* that seam to the other side when the popup flipped up
|
|
33
|
-
* (`.
|
|
35
|
+
* (`.nxe-overlay-content.nxe-dropdowneditor-overlay-flipped { border-top-width:1px; border-bottom-width:0 }`).
|
|
34
36
|
* CDK does not emit any equivalent hook, so panels need this to reproduce it.
|
|
35
37
|
*
|
|
36
38
|
* Returns the subscription; callers dispose it with the overlay.
|
|
37
39
|
*/
|
|
38
40
|
declare function trackPaneFlip(overlayRef: OverlayRef): Subscription | undefined;
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Migration aid: re-emit the old `dx-*` class names alongside the library's `nxe-*` ones.
|
|
44
|
+
*
|
|
45
|
+
* The library dropped the `dx-` prefix from its DOM. Applications that still style themselves
|
|
46
|
+
* with rules like `.dx-datagrid .dx-row > td { padding: 4px }` would silently lose that styling,
|
|
47
|
+
* and no stylesheet can fix it: CSS cannot alias a class, so a rule keyed on `.dx-datagrid` will
|
|
48
|
+
* never match an element that only says `nxe-datagrid`. The class has to be back on the element.
|
|
49
|
+
*
|
|
50
|
+
* So this mirrors them at runtime. Provide it once and unmigrated stylesheets keep working
|
|
51
|
+
* unchanged; provide nothing and the library costs nothing, which is the point of it being
|
|
52
|
+
* opt-in. `tools/dx-compat/rewrite-styles.mjs` rewrites an application's own stylesheets when it
|
|
53
|
+
* is ready to drop the flag — this is a bridge, not a destination.
|
|
54
|
+
*
|
|
55
|
+
* ```ts
|
|
56
|
+
* bootstrapApplication(AppComponent, { providers: [provideNxeDxCompat()] });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
declare class NxeDxCompatService {
|
|
60
|
+
private readonly document;
|
|
61
|
+
private readonly ngZone;
|
|
62
|
+
private observer?;
|
|
63
|
+
/** Our own writes retrigger the observer; this stops it chasing its own tail. */
|
|
64
|
+
private mirroring;
|
|
65
|
+
start(): void;
|
|
66
|
+
stop(): void;
|
|
67
|
+
private onMutations;
|
|
68
|
+
private mirrorSubtree;
|
|
69
|
+
/** Keep `dx-x` present exactly while `nxe-x` is, so a removed state class is removed here too. */
|
|
70
|
+
private mirrorElement;
|
|
71
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<NxeDxCompatService, never>;
|
|
72
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<NxeDxCompatService>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Opt into the `dx-*` compatibility classes. See {@link NxeDxCompatService} for why this is a
|
|
76
|
+
* runtime mirror rather than a stylesheet.
|
|
77
|
+
*/
|
|
78
|
+
declare function provideNxeDxCompat(): EnvironmentProviders;
|
|
79
|
+
|
|
80
|
+
/** Where the scroll position sits on each axis: -1 at the start, 1 at the end, 0 in between. */
|
|
81
|
+
interface NxeScrollbarPosition {
|
|
82
|
+
x: number;
|
|
83
|
+
y: number;
|
|
84
|
+
}
|
|
85
|
+
/** Scroll geometry of the host element. */
|
|
86
|
+
interface NxeScrollbarGeometry {
|
|
87
|
+
x: number;
|
|
88
|
+
y: number;
|
|
89
|
+
w: number;
|
|
90
|
+
h: number;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The options that map onto this implementation.
|
|
94
|
+
*
|
|
95
|
+
* `wheelPropagation` is accepted and ignored: it existed because the original took the wheel over
|
|
96
|
+
* from the browser and had to decide when to hand it back. Scrolling here is native, so the
|
|
97
|
+
* browser makes that decision itself — which is what the option was trying to restore.
|
|
98
|
+
*/
|
|
99
|
+
interface NxeScrollbarOptions {
|
|
100
|
+
suppressScrollX?: boolean;
|
|
101
|
+
suppressScrollY?: boolean;
|
|
102
|
+
wheelPropagation?: boolean;
|
|
103
|
+
/** Rail is hidden below this content overflow, in px. Matches the original's default. */
|
|
104
|
+
minScrollbarLength?: number;
|
|
105
|
+
maxScrollbarLength?: number;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* `[nxeScrollbar]` — a container with custom overlay scrollbars.
|
|
109
|
+
*
|
|
110
|
+
* This replaces a Perfect Scrollbar wrapper, and reproduces its DOM and its rendering exactly:
|
|
111
|
+
* two absolutely-positioned rails, each holding a thumb, sized and offset from the host's own
|
|
112
|
+
* scroll geometry. The stylesheet (`@nexterajs/ui/styles/_scrollbar.scss`) is a value-for-value
|
|
113
|
+
* port, so applications that restyle the rails keep their appearance unchanged.
|
|
114
|
+
*
|
|
115
|
+
* **What is different, deliberately:** the original set `overflow: hidden` and reimplemented
|
|
116
|
+
* wheel, touch, keyboard and momentum scrolling in JavaScript. Here the element scrolls natively
|
|
117
|
+
* and only the native scrollbar is hidden — the rails are painted from the `scroll` event. That is
|
|
118
|
+
* less code and better behaviour on touch and trackpads, and it is invisible: a hidden native
|
|
119
|
+
* scrollbar takes no layout width, exactly like the overlay rails it replaces.
|
|
120
|
+
*
|
|
121
|
+
* The host carries `nxe-scrollbar` while enabled, which is the marker callers branch on.
|
|
122
|
+
*/
|
|
123
|
+
declare class NxeScrollbarDirective implements OnInit, OnChanges, OnDestroy {
|
|
124
|
+
private readonly elementRef;
|
|
125
|
+
private readonly zone;
|
|
126
|
+
private readonly destroyRef;
|
|
127
|
+
nxeScrollbar: boolean;
|
|
128
|
+
nxeScrollbarOptions: NxeScrollbarOptions | null;
|
|
129
|
+
private options;
|
|
130
|
+
private animation;
|
|
131
|
+
private railX?;
|
|
132
|
+
private railY?;
|
|
133
|
+
private thumbX?;
|
|
134
|
+
private thumbY?;
|
|
135
|
+
private resizeObserver?;
|
|
136
|
+
private mutationObserver?;
|
|
137
|
+
private scrollingXTimer;
|
|
138
|
+
private scrollingYTimer;
|
|
139
|
+
private teardown;
|
|
140
|
+
private initialised;
|
|
141
|
+
get element(): HTMLElement;
|
|
142
|
+
ngOnInit(): void;
|
|
143
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
144
|
+
ngOnDestroy(): void;
|
|
145
|
+
isEnabled(): boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Recompute rail and thumb geometry. Call after changing content the directive cannot observe.
|
|
148
|
+
*
|
|
149
|
+
* This reproduces the original's arithmetic exactly, down to how it rounds — the requirement was
|
|
150
|
+
* no visual difference, and each of these is worth a pixel:
|
|
151
|
+
* - the container is measured from `getBoundingClientRect()` rounded, not from `clientHeight`;
|
|
152
|
+
* - sizes and offsets are **truncated** (the original ran them through `parseInt`), not rounded;
|
|
153
|
+
* - `scrollTop` is floored before it is used;
|
|
154
|
+
* - the thumb offset is clamped so it cannot overhang the end of the rail.
|
|
155
|
+
*/
|
|
156
|
+
update(): void;
|
|
157
|
+
/** Kept for parity with the wrapper this replaces; teardown also happens in ngOnDestroy. */
|
|
158
|
+
destroy(): void;
|
|
159
|
+
isScrollableX(): boolean;
|
|
160
|
+
isScrollableY(): boolean;
|
|
161
|
+
geometry(prefix?: 'scroll' | 'client' | 'offset'): NxeScrollbarGeometry;
|
|
162
|
+
/** -1 at the start of an axis, 1 at its end, 0 anywhere between. */
|
|
163
|
+
position(absolute?: boolean): NxeScrollbarPosition;
|
|
164
|
+
scrollTo(x: number, y?: number, speed?: number): void;
|
|
165
|
+
scrollToX(x: number, speed?: number): void;
|
|
166
|
+
scrollToY(y: number, speed?: number): void;
|
|
167
|
+
scrollToTop(offset?: number, speed?: number): void;
|
|
168
|
+
scrollToBottom(offset?: number, speed?: number): void;
|
|
169
|
+
scrollToLeft(offset?: number, speed?: number): void;
|
|
170
|
+
scrollToRight(offset?: number, speed?: number): void;
|
|
171
|
+
/**
|
|
172
|
+
* Bring the first descendant matching `selector` into view.
|
|
173
|
+
*
|
|
174
|
+
* `ignoreVisible` skips the scroll when the target already sits inside the viewport less the
|
|
175
|
+
* offset, so an item that is merely low on screen is not yanked to the top on every change.
|
|
176
|
+
*/
|
|
177
|
+
scrollToElement(selector: string, offset?: number, ignoreVisible?: boolean, speed?: number): void;
|
|
178
|
+
/**
|
|
179
|
+
* Move one axis to `value`, easing over `speed` ms when one is given.
|
|
180
|
+
*
|
|
181
|
+
* The easing bails as soon as the position stops matching what it last wrote, so a user who
|
|
182
|
+
* grabs the wheel mid-flight takes over instead of fighting the animation.
|
|
183
|
+
*/
|
|
184
|
+
animateScrolling(axis: 'scrollTop' | 'scrollLeft', value: number, speed?: number): void;
|
|
185
|
+
private init;
|
|
186
|
+
private buildRail;
|
|
187
|
+
private onScroll;
|
|
188
|
+
private bindThumbDrag;
|
|
189
|
+
/** Only the configured bounds, and only when set — the same shape the original's clamp had. */
|
|
190
|
+
private clampThumb;
|
|
191
|
+
private on;
|
|
192
|
+
private dispose;
|
|
193
|
+
private cancelAnimation;
|
|
194
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<NxeScrollbarDirective, never>;
|
|
195
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<NxeScrollbarDirective, "[nxeScrollbar]", ["nxeScrollbar"], { "nxeScrollbar": { "alias": "nxeScrollbar"; "required": false; }; "nxeScrollbarOptions": { "alias": "nxeScrollbarOptions"; "required": false; }; }, {}, never, never, true, never>;
|
|
196
|
+
static ngAcceptInputType_nxeScrollbar: boolean | string | null | undefined;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export { NXE_PANE_FLIPPED_CLASS, NXE_WIDGET_CLASS, NxeDxCompatService, NxeScrollbarDirective, nxePane, provideNxeDxCompat, trackPaneFlip };
|
|
200
|
+
export type { NxeScrollbarGeometry, NxeScrollbarOptions, NxeScrollbarPosition };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
|
+
import { NxeMessageService } from '@nexterajs/ui/core';
|
|
2
3
|
|
|
3
4
|
/** A node in the assembled tree (children built from the flat `parentIdExpr` list). */
|
|
4
5
|
interface NxeTreeNode {
|
|
@@ -10,6 +11,12 @@ interface NxeTreeNode {
|
|
|
10
11
|
hasChildren: boolean;
|
|
11
12
|
level: number;
|
|
12
13
|
}
|
|
14
|
+
/** A visible node with the sibling position a flattened tree has to state explicitly. */
|
|
15
|
+
interface NxeTreeRow {
|
|
16
|
+
node: NxeTreeNode;
|
|
17
|
+
posInSet: number;
|
|
18
|
+
setSize: number;
|
|
19
|
+
}
|
|
13
20
|
/** DevExtreme-shaped `onItemClick` payload (consumers read `event.itemData.<field>`). */
|
|
14
21
|
interface NxeTreeItemClickEvent {
|
|
15
22
|
itemData: Record<string, unknown>;
|
|
@@ -29,7 +36,10 @@ interface NxeTreeItemClickEvent {
|
|
|
29
36
|
* keeps reading `event.itemData.url/urlParams/objectName`.
|
|
30
37
|
*/
|
|
31
38
|
declare class NxeTreeViewComponent {
|
|
32
|
-
|
|
39
|
+
private readonly elementRef;
|
|
40
|
+
/** The library's runtime-switchable messages. */
|
|
41
|
+
protected readonly messages: NxeMessageService;
|
|
42
|
+
readonly dataSource: _angular_core.InputSignal<readonly unknown[] | null | undefined>;
|
|
33
43
|
/** Accepted for parity; this component always assembles a tree from the flat list. */
|
|
34
44
|
readonly dataStructure: _angular_core.InputSignal<"plain" | "tree">;
|
|
35
45
|
readonly keyExpr: _angular_core.InputSignal<string>;
|
|
@@ -44,15 +54,27 @@ declare class NxeTreeViewComponent {
|
|
|
44
54
|
readonly searchMode: _angular_core.InputSignal<"contains" | "startswith" | "equals">;
|
|
45
55
|
/** Accepted for parity (native scrolling is the default here anyway). */
|
|
46
56
|
readonly useNativeScrolling: _angular_core.InputSignal<boolean>;
|
|
47
|
-
readonly width: _angular_core.InputSignal<string | number>;
|
|
57
|
+
readonly width: _angular_core.InputSignal<string | number | undefined>;
|
|
48
58
|
readonly onItemClick: _angular_core.OutputEmitterRef<NxeTreeItemClickEvent>;
|
|
49
59
|
readonly expanded: _angular_core.WritableSignal<ReadonlySet<unknown>>;
|
|
50
60
|
readonly selectedKey: _angular_core.WritableSignal<unknown>;
|
|
51
61
|
readonly searchText: _angular_core.WritableSignal<string>;
|
|
62
|
+
private readonly searchInput;
|
|
52
63
|
/** DevExtreme `.instance` facade — `expandAll()` is the only method used. */
|
|
53
64
|
get instance(): this;
|
|
54
|
-
protected readonly widthStyle: _angular_core.Signal<string>;
|
|
65
|
+
protected readonly widthStyle: _angular_core.Signal<string | undefined>;
|
|
55
66
|
private readonly tree;
|
|
67
|
+
/**
|
|
68
|
+
* The visible nodes, each with its position among its siblings.
|
|
69
|
+
*
|
|
70
|
+
* The tree renders as one flat `<ul>` with indentation rather than nested lists, so a screen
|
|
71
|
+
* reader cannot infer depth or sibling counts from the DOM. `aria-level`, `aria-setsize` and
|
|
72
|
+
* `aria-posinset` are what carry that, which makes them required for a flattened tree rather
|
|
73
|
+
* than optional extras. They are computed during the walk, where the sibling array is already
|
|
74
|
+
* in hand — reconstructing them from the flat list afterwards is possible but much harder to
|
|
75
|
+
* read for no gain.
|
|
76
|
+
*/
|
|
77
|
+
protected readonly visibleRows: _angular_core.Signal<NxeTreeRow[]>;
|
|
56
78
|
/** Flattened list of currently-visible nodes (respects expand state + search). */
|
|
57
79
|
protected readonly visibleNodes: _angular_core.Signal<NxeTreeNode[]>;
|
|
58
80
|
expandAll(): void;
|
|
@@ -61,9 +83,39 @@ declare class NxeTreeViewComponent {
|
|
|
61
83
|
protected toggle(node: NxeTreeNode, event: Event): void;
|
|
62
84
|
protected onNodeClick(node: NxeTreeNode, event: Event): void;
|
|
63
85
|
protected onSearch(event: Event): void;
|
|
86
|
+
/**
|
|
87
|
+
* The search box's clear button. dx empties the value and leaves the caret in the box (its
|
|
88
|
+
* clear button swallows the mouse-down so the input never loses focus); refocusing here covers
|
|
89
|
+
* the case where focus had already left the input.
|
|
90
|
+
*/
|
|
91
|
+
protected clearSearch(): void;
|
|
92
|
+
/**
|
|
93
|
+
* The node holding the tree's single tab stop.
|
|
94
|
+
*
|
|
95
|
+
* A tree is one stop in the tab order, not one per node, so a roving tabindex is part of the
|
|
96
|
+
* role rather than an extra: `role="tree"` on a list nothing can focus would announce a
|
|
97
|
+
* structure a keyboard user cannot reach.
|
|
98
|
+
*/
|
|
99
|
+
protected readonly focusedKey: _angular_core.WritableSignal<unknown>;
|
|
100
|
+
protected isTabStop(node: NxeTreeNode, index: number): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* The node that holds DOM focus right now, or `null` while focus is anywhere else.
|
|
103
|
+
*
|
|
104
|
+
* Deliberately not `focusedKey`: that is the roving tab stop and has to outlive a blur, so Tab
|
|
105
|
+
* comes back to the same node. dx drops `dx-state-focused` the moment focus leaves the node,
|
|
106
|
+
* and the focused look goes with it — the row colour, and the toggle, which follows the row's
|
|
107
|
+
* colour only while focused (`color: unset`, dx.light.css). Keyed off focusin/focusout so the
|
|
108
|
+
* class means exactly what it says.
|
|
109
|
+
*/
|
|
110
|
+
private readonly focusedNode;
|
|
111
|
+
protected isFocused(node: NxeTreeNode): boolean;
|
|
112
|
+
protected onNodeFocus(node: NxeTreeNode): void;
|
|
113
|
+
protected onNodeBlur(node: NxeTreeNode): void;
|
|
114
|
+
/** Arrow-key navigation, per the WAI-ARIA tree pattern. */
|
|
115
|
+
protected onKeydown(event: KeyboardEvent): void;
|
|
64
116
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NxeTreeViewComponent, never>;
|
|
65
117
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NxeTreeViewComponent, "nxe-tree-view", never, { "dataSource": { "alias": "dataSource"; "required": false; "isSignal": true; }; "dataStructure": { "alias": "dataStructure"; "required": false; "isSignal": true; }; "keyExpr": { "alias": "keyExpr"; "required": false; "isSignal": true; }; "displayExpr": { "alias": "displayExpr"; "required": false; "isSignal": true; }; "parentIdExpr": { "alias": "parentIdExpr"; "required": false; "isSignal": true; }; "rootValue": { "alias": "rootValue"; "required": false; "isSignal": true; }; "expandedExpr": { "alias": "expandedExpr"; "required": false; "isSignal": true; }; "selectionMode": { "alias": "selectionMode"; "required": false; "isSignal": true; }; "selectByClick": { "alias": "selectByClick"; "required": false; "isSignal": true; }; "searchEnabled": { "alias": "searchEnabled"; "required": false; "isSignal": true; }; "searchMode": { "alias": "searchMode"; "required": false; "isSignal": true; }; "useNativeScrolling": { "alias": "useNativeScrolling"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; }, { "onItemClick": "onItemClick"; }, never, never, true, never>;
|
|
66
118
|
}
|
|
67
119
|
|
|
68
120
|
export { NxeTreeViewComponent };
|
|
69
|
-
export type { NxeTreeItemClickEvent, NxeTreeNode };
|
|
121
|
+
export type { NxeTreeItemClickEvent, NxeTreeNode, NxeTreeRow };
|