@masmarino/gabarit 1.3.0 → 1.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masmarino/gabarit",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Angular design system — UI components and dataviz for self-hosted applications.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/Masmarino/Gabarit",
@@ -23,7 +23,11 @@
23
23
  "peerDependencies": {
24
24
  "@angular/common": "^22.0.0",
25
25
  "@angular/core": "^22.0.0",
26
- "@angular/forms": "^22.0.0"
26
+ "@angular/forms": "^22.0.0",
27
+ "@angular/platform-browser": "^22.0.0",
28
+ "@angular/router": "^22.0.0",
29
+ "dompurify": "^3.2.0",
30
+ "marked": "^18.0.0"
27
31
  },
28
32
  "dependencies": {
29
33
  "tslib": "^2.3.0"
@@ -41,6 +45,21 @@
41
45
  ".": {
42
46
  "types": "./types/masmarino-gabarit.d.ts",
43
47
  "default": "./fesm2022/masmarino-gabarit.mjs"
48
+ },
49
+ "./docs": {
50
+ "types": "./types/masmarino-gabarit-docs.d.ts",
51
+ "default": "./fesm2022/masmarino-gabarit-docs.mjs"
52
+ }
53
+ },
54
+ "peerDependenciesMeta": {
55
+ "@angular/router": {
56
+ "optional": true
57
+ },
58
+ "dompurify": {
59
+ "optional": true
60
+ },
61
+ "marked": {
62
+ "optional": true
44
63
  }
45
64
  },
46
65
  "module": "fesm2022/masmarino-gabarit.mjs",
@@ -85,6 +85,12 @@
85
85
  }
86
86
  }
87
87
 
88
+ // Global, so it reaches the links the app projects: each piece of the rail keeps its height, and a rail taller than the
89
+ // window scrolls rather than squeezing its links together.
90
+ .gbt-app-shell__nav > * {
91
+ flex-shrink: 0;
92
+ }
93
+
88
94
  .gbt-app-shell__link {
89
95
  position: relative;
90
96
  display: flex;
@@ -0,0 +1,385 @@
1
+ import * as i0 from "@angular/core";
2
+ import { InjectionToken, Provider, Signal } from "@angular/core";
3
+ import { Observable } from "rxjs";
4
+ import { CanActivateFn, Routes } from "@angular/router";
5
+ import { SafeHtml } from "@angular/platform-browser";
6
+ import { AutocompleteSearchFn, PanelHeadingLevel } from "@masmarino/gabarit";
7
+ interface DocsConfig {
8
+ /**
9
+ * Where the pages are, both as files and as the reader's routes: `<root>/index.json`, `<root>/<section>/<page>.md`,
10
+ * and the page `<root>/<section>/<page>`. `/docs` by default.
11
+ */
12
+ root: string;
13
+ /**
14
+ * The quotes that become callouts: a quote whose first word, in bold, is one of these keys (`> **Note** …`), drawn
15
+ * in the tone it maps to. Case does not matter.
16
+ */
17
+ callouts: Readonly<Record<string, 'note' | 'warning'>>;
18
+ }
19
+ export declare const DEFAULT_DOCS_CONFIG: Readonly<DocsConfig>;
20
+ export declare const DOCS_CONFIG: InjectionToken<DocsConfig>;
21
+ /**
22
+ * Where the shown page's title goes, for an app that names its pages somewhere of its own (a header, a breadcrumb):
23
+ * called with the page's title, "not found" or the reader's name while loading. Without it the reader leaves the
24
+ * title alone.
25
+ */
26
+ export declare const DOCS_TITLE: InjectionToken<(title: string) => void>;
27
+ export declare function provideDocs(config?: Partial<DocsConfig>): Provider;
28
+ /** Every string the documentation reader shows or announces. English by default. */
29
+ interface DocsLabels {
30
+ /** The reader's name: the navigation's heading, its landmark and the breadcrumb's first step. */
31
+ documentation: string;
32
+ showContents: string;
33
+ hideContents: string;
34
+ searchLabel: string;
35
+ searchPlaceholder: string;
36
+ searching: string;
37
+ noResults: string;
38
+ searchFailed: string;
39
+ results: (count: number) => string;
40
+ onThisPage: string;
41
+ breadcrumb: string;
42
+ neighbours: string;
43
+ previous: string;
44
+ next: string;
45
+ notFoundHeading: string;
46
+ notFoundMessage: string;
47
+ toStart: string;
48
+ loadFailed: string;
49
+ retry: string;
50
+ loading: string;
51
+ /** The accessible names given to a code block and a table, which scroll sideways and so take the focus. */
52
+ codeBlock: string;
53
+ table: string;
54
+ }
55
+ export declare const DEFAULT_DOCS_LABELS: Readonly<DocsLabels>;
56
+ export declare const DOCS_LABELS: InjectionToken<Partial<DocsLabels>>;
57
+ /** The reader's strings, over the English defaults; the ones left out keep theirs. */
58
+ export declare function provideDocsLabels(labels: Partial<DocsLabels>): Provider;
59
+ export declare function docsLabels(): Signal<DocsLabels>;
60
+ interface DocsPageEntry {
61
+ slug: string;
62
+ title: string;
63
+ description: string;
64
+ }
65
+ interface DocsSection {
66
+ slug: string;
67
+ title: string;
68
+ pages: DocsPageEntry[];
69
+ }
70
+ /** `<root>/index.json`: the sections and their pages, in reading order. */
71
+ interface DocsIndex {
72
+ sections: DocsSection[];
73
+ }
74
+ interface DocsLink {
75
+ sectionTitle: string;
76
+ title: string;
77
+ commands: string[];
78
+ }
79
+ /** A page with its neighbours in reading order, across sections. */
80
+ interface DocsLocation {
81
+ section: DocsSection;
82
+ page: DocsPageEntry;
83
+ previous: DocsLink | null;
84
+ next: DocsLink | null;
85
+ }
86
+ export declare function docsPageCommands(root: string, section: string, page: string): string[];
87
+ /** Every page in reading order, each with its section. */
88
+ export declare function docsReadingOrder(index: DocsIndex): {
89
+ section: DocsSection;
90
+ page: DocsPageEntry;
91
+ }[];
92
+ /** Where `<root>` leads: the first page of the first section, or `null` for an empty index. */
93
+ export declare function firstDocsPage(root: string, index: DocsIndex): string[] | null;
94
+ export declare function locateDocsPage(root: string, index: DocsIndex, section: string | null, page: string | null): DocsLocation | null;
95
+ /**
96
+ * The documentation, shipped as static files under the configured root. The index and each page are fetched once
97
+ * and kept, since they only change with a new version of the app. A failure isn't kept, so it gets retried.
98
+ */
99
+ export declare class DocsService {
100
+ private readonly http;
101
+ readonly root: string;
102
+ private index$;
103
+ private readonly pages;
104
+ index(): Observable<DocsIndex>;
105
+ /** The page's Markdown. A missing file fails with a 404, including when the server answers with the app shell. */
106
+ page(section: string, page: string): Observable<string>;
107
+ static ɵfac: i0.ɵɵFactoryDeclaration<DocsService, never>;
108
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
109
+ }
110
+ export declare const isNotFound: (error: unknown) => boolean;
111
+ export declare const DOCS_SEARCH_LIMIT = 8;
112
+ interface DocsSearchHit {
113
+ sectionTitle: string;
114
+ pageTitle: string;
115
+ commands: string[];
116
+ /** Id of the best matching heading (`user-content-…`), so the result lands on it. */
117
+ fragment: string | null;
118
+ heading: string | null;
119
+ /** Body text around the first match, or the page's description when only the title or headings match. */
120
+ excerpt: {
121
+ before: string;
122
+ match: string;
123
+ after: string;
124
+ };
125
+ }
126
+ export declare function searchTokens(query: string): string[];
127
+ /**
128
+ * Title, headings and body text of one page. Heading ids follow `gbt-markdown-view`: `user-content-<slug>` on every
129
+ * h1–h4, and `-2`, `-3`… on a repeated slug in document order.
130
+ */
131
+ export declare function parseDocsPage(markdown: string): {
132
+ headings: {
133
+ id: string;
134
+ text: string;
135
+ }[];
136
+ body: string;
137
+ };
138
+ /**
139
+ * Search over the whole documentation, in the browser. Nothing is fetched until the first search (or `prepare()`),
140
+ * then every page once, kept by `DocsService`. Every word of the query must appear in the page; a word in the title
141
+ * ranks higher than one in a heading, and a heading higher than the text.
142
+ */
143
+ export declare class DocsSearchService {
144
+ private docs;
145
+ private documents;
146
+ /** Starts loading the pages before the first search; the field calls it on focus. */
147
+ prepare(): void;
148
+ private load;
149
+ search(query: string): Promise<DocsSearchHit[]>;
150
+ static ɵfac: i0.ɵɵFactoryDeclaration<DocsSearchService, never>;
151
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
152
+ }
153
+ /**
154
+ * The root opens the first page of the index. If the index can't be read or is empty, the reader shows that itself,
155
+ * inside its own layout.
156
+ */
157
+ export declare const docsHomeGuard: CanActivateFn;
158
+ /**
159
+ * The reader's routes, to mount at the configured root: the root (to the first page), `<section>/<page>`, and any
160
+ * other depth, which gets the reader's own "not found". `page` is the routed component that shows the reader (often
161
+ * the app's own, wrapping `gbt-docs-page` in its layout).
162
+ */
163
+ export declare function docsRoutes(page: () => Promise<unknown>): Routes;
164
+ /**
165
+ * The documentation's left column: the search field, then every section with its pages. Only the current section
166
+ * starts open. On a narrow layout the sections fold behind a toggle and the search stays.
167
+ */
168
+ export declare class DocsNav {
169
+ index: import("@angular/core").InputSignal<DocsIndex>;
170
+ section: import("@angular/core").InputSignal<string | null>;
171
+ page: import("@angular/core").InputSignal<string | null>;
172
+ private readonly root;
173
+ protected readonly labels: import("@angular/core").Signal<import("@masmarino/gabarit/docs").DocsLabels>;
174
+ protected readonly bodyId: string;
175
+ protected readonly navOpen: import("@angular/core").WritableSignal<boolean>;
176
+ private readonly toggled;
177
+ protected readonly sections: import("@angular/core").Signal<{
178
+ slug: string;
179
+ title: string;
180
+ open: boolean;
181
+ pages: {
182
+ slug: string;
183
+ title: string;
184
+ commands: string[];
185
+ current: boolean;
186
+ }[];
187
+ }[]>;
188
+ protected setOpen(slug: string, open: boolean): void;
189
+ protected close(): void;
190
+ static ɵfac: i0.ɵɵFactoryDeclaration<DocsNav, never>;
191
+ static ɵcmp: i0.ɵɵComponentDeclaration<DocsNav, "gbt-docs-nav", never, {
192
+ "index": {
193
+ "alias": "index";
194
+ "required": true;
195
+ "isSignal": true;
196
+ };
197
+ "section": {
198
+ "alias": "section";
199
+ "required": false;
200
+ "isSignal": true;
201
+ };
202
+ "page": {
203
+ "alias": "page";
204
+ "required": false;
205
+ "isSignal": true;
206
+ };
207
+ }, {}, never, never, true, never>;
208
+ }
209
+ /** One heading of the rendered content, for an "On this page" outline. */
210
+ interface MarkdownOutlineEntry {
211
+ /** The level as rendered, after `headingOffset`: 2, 3 or 4. */
212
+ level: number;
213
+ text: string;
214
+ id: string;
215
+ }
216
+ /** GitHub-like slug, accents kept. `section` when nothing is left, e.g. a title made only of emoji. */
217
+ export declare function headingSlug(text: string): string;
218
+ export declare function decodeFragment(rawFragment: string): string;
219
+ /** The element a `#fragment` points at: the plain `id`, else the `user-content-` id or `<a name>` the sanitiser made. */
220
+ export declare function findAnchorTarget(root: HTMLElement, rawFragment: string): HTMLElement | null;
221
+ /**
222
+ * A long code block or a wide table scrolls sideways, which a keyboard can only do once it takes the focus (WCAG
223
+ * 2.1.1): each one becomes a named stop in the tab order. A table keeps its own role and gets only the stop and the
224
+ * name.
225
+ */
226
+ export declare function makeScrollableBlocksFocusable(container: HTMLElement, names: {
227
+ codeBlock: string;
228
+ table: string;
229
+ }): void;
230
+ /**
231
+ * A task-list checkbox is named by its item's text, so a screen reader says what is done or still to do.
232
+ */
233
+ export declare function nameTaskCheckboxes(container: HTMLElement): void;
234
+ /**
235
+ * Markdown rendered to sanitised HTML, with the reading styles of the design system: headings, lists, code, tables,
236
+ * quotes. Every heading gets a stable id, and the h2–h4 outline is emitted after each render.
237
+ */
238
+ export declare class MarkdownView {
239
+ content: import("@angular/core").InputSignal<string>;
240
+ /** Levels added to every heading (up to h6), so a `# Title` under the page's own headings keeps the outline. */
241
+ headingOffset: import("@angular/core").InputSignal<number>;
242
+ /**
243
+ * Links under this prefix (`/docs` → `/docs/install/configuration#variables`) go through the router instead of
244
+ * reloading the app. Off by default: a link in a README is left to the browser.
245
+ */
246
+ routedLinkPrefix: import("@angular/core").InputSignal<string | null>;
247
+ /** The h2–h4 headings, emitted after each render once their ids are in the DOM. */
248
+ outline: import("@angular/core").OutputEmitterRef<MarkdownOutlineEntry[]>;
249
+ private readonly sanitizer;
250
+ private readonly router;
251
+ private readonly labels;
252
+ private readonly container;
253
+ constructor();
254
+ /**
255
+ * In-content `#anchor` links would resolve against `<base href="/">` and load the home page, so a plain left click
256
+ * scrolls to the target inside this view and focuses it. Modified and middle clicks are left to the browser.
257
+ */
258
+ protected onClick(event: MouseEvent): void;
259
+ /** The `href` of a clicked in-content link under `routedLinkPrefix`, or `null` when the browser should follow it. */
260
+ private routedHref;
261
+ protected readonly renderedHtml: import("@angular/core").Signal<SafeHtml>;
262
+ static ɵfac: i0.ɵɵFactoryDeclaration<MarkdownView, never>;
263
+ static ɵcmp: i0.ɵɵComponentDeclaration<MarkdownView, "gbt-markdown-view", never, {
264
+ "content": {
265
+ "alias": "content";
266
+ "required": true;
267
+ "isSignal": true;
268
+ };
269
+ "headingOffset": {
270
+ "alias": "headingOffset";
271
+ "required": false;
272
+ "isSignal": true;
273
+ };
274
+ "routedLinkPrefix": {
275
+ "alias": "routedLinkPrefix";
276
+ "required": false;
277
+ "isSignal": true;
278
+ };
279
+ }, {
280
+ "outline": "outline";
281
+ }, never, never, true, never>;
282
+ }
283
+ type DocsView = {
284
+ kind: 'loading';
285
+ } | {
286
+ kind: 'failed';
287
+ } | {
288
+ kind: 'not-found';
289
+ firstPage: string[] | null;
290
+ } | {
291
+ kind: 'page';
292
+ location: DocsLocation;
293
+ content: string;
294
+ };
295
+ /**
296
+ * One documentation page (`<root>/<section>/<page>`, read from the route): the navigation, the page with its
297
+ * breadcrumb and neighbours, and on a wide screen the outline beside it. An unknown address gets a "not found" in the
298
+ * same frame.
299
+ */
300
+ export declare class DocsPage {
301
+ private readonly docs;
302
+ private readonly route;
303
+ private readonly setTitle;
304
+ private readonly callouts;
305
+ private readonly host;
306
+ protected readonly labels: import("@angular/core").Signal<import("@masmarino/gabarit/docs").DocsLabels>;
307
+ protected readonly root: string;
308
+ protected readonly skeletonRows: string[];
309
+ private readonly reload$;
310
+ protected readonly index: import("@angular/core").WritableSignal<DocsIndex | null>;
311
+ private readonly params;
312
+ protected readonly sectionSlug: import("@angular/core").Signal<string | null>;
313
+ protected readonly pageSlug: import("@angular/core").Signal<string | null>;
314
+ protected readonly view: import("@angular/core").Signal<DocsView>;
315
+ protected readonly page: import("@angular/core").Signal<{
316
+ kind: "page";
317
+ location: DocsLocation;
318
+ content: string;
319
+ } | null>;
320
+ protected readonly notFound: import("@angular/core").Signal<{
321
+ kind: "not-found";
322
+ firstPage: string[] | null;
323
+ } | null>;
324
+ protected readonly outline: import("@angular/core").WritableSignal<MarkdownOutlineEntry[]>;
325
+ protected readonly showOutline: import("@angular/core").Signal<boolean>;
326
+ private wanted;
327
+ private renderedKey;
328
+ constructor();
329
+ private load;
330
+ protected retry(): void;
331
+ protected sectionLink(location: DocsLocation): string[];
332
+ /** After each render: the outline, the callouts, then the pending navigation. */
333
+ protected onRendered(entries: MarkdownOutlineEntry[]): void;
334
+ private content;
335
+ /** Scrolls to the `#fragment` (an outline `user-content-…` id or the bare slug from a link), or to the top of a new page. */
336
+ private settle;
337
+ private focus;
338
+ static ɵfac: i0.ɵɵFactoryDeclaration<DocsPage, never>;
339
+ static ɵcmp: i0.ɵɵComponentDeclaration<DocsPage, "gbt-docs-page", never, {}, {}, never, never, true, never>;
340
+ }
341
+ /** The search field above the documentation's navigation. Pages load on first focus, since most visits never search. */
342
+ export declare class DocsSearch {
343
+ /** Emitted once a result is opened, so a folded navigation can close. */
344
+ opened: import("@angular/core").OutputEmitterRef<DocsSearchHit>;
345
+ private readonly searchService;
346
+ private readonly router;
347
+ private readonly field;
348
+ protected readonly labels: import("@angular/core").Signal<import("@masmarino/gabarit/docs").DocsLabels>;
349
+ protected readonly search: AutocompleteSearchFn<DocsSearchHit>;
350
+ protected readonly label: (hit: DocsSearchHit) => string;
351
+ protected readonly announce: (count: number) => string;
352
+ protected prepare(): void;
353
+ protected open(hit: DocsSearchHit): void;
354
+ static ɵfac: i0.ɵɵFactoryDeclaration<DocsSearch, never>;
355
+ static ɵcmp: i0.ɵɵComponentDeclaration<DocsSearch, "gbt-docs-search", never, {}, {
356
+ "opened": "opened";
357
+ }, never, never, true, never>;
358
+ }
359
+ /** An outline is worth a panel from two headings on: one heading is no table of contents. */
360
+ export declare function hasOutline(entries: readonly MarkdownOutlineEntry[]): boolean;
361
+ /**
362
+ * The "On this page" panel beside rendered Markdown. Each entry links to `#user-content-…` on the current URL; the
363
+ * router does no anchor scrolling, so the click scrolls to the heading and focuses it itself.
364
+ */
365
+ export declare class MarkdownOutline {
366
+ entries: import("@angular/core").InputSignal<MarkdownOutlineEntry[]>;
367
+ headingLevel: import("@angular/core").InputSignal<PanelHeadingLevel>;
368
+ protected readonly labels: import("@angular/core").Signal<import("@masmarino/gabarit/docs").DocsLabels>;
369
+ protected readonly here: readonly string[];
370
+ protected goTo(id: string): void;
371
+ static ɵfac: i0.ɵɵFactoryDeclaration<MarkdownOutline, never>;
372
+ static ɵcmp: i0.ɵɵComponentDeclaration<MarkdownOutline, "gbt-markdown-outline", never, {
373
+ "entries": {
374
+ "alias": "entries";
375
+ "required": true;
376
+ "isSignal": true;
377
+ };
378
+ "headingLevel": {
379
+ "alias": "headingLevel";
380
+ "required": false;
381
+ "isSignal": true;
382
+ };
383
+ }, {}, never, never, true, never>;
384
+ }
385
+ export type { DocsConfig, DocsIndex, DocsLabels, DocsLink, DocsLocation, DocsPageEntry, DocsSearchHit, DocsSection, MarkdownOutlineEntry };
@@ -2,7 +2,7 @@ import * as i0 from "@angular/core";
2
2
  import { ElementRef, InjectionToken, Injector, OnDestroy, PipeTransform, Provider, Signal, TemplateRef, WritableSignal } from "@angular/core";
3
3
  import { ControlValueAccessor, FormControl } from "@angular/forms";
4
4
  import { Observable } from "rxjs";
5
- export declare const GABARIT_VERSION = "1.3.0";
5
+ export declare const GABARIT_VERSION = "1.4.0";
6
6
  export declare class Icon {
7
7
  private readonly sanitizer;
8
8
  private readonly registry;
@@ -1064,6 +1064,18 @@ type InputSize = 'md' | 'sm';
1064
1064
  type InputInputmode = 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search';
1065
1065
  type InputAutocapitalize = 'off' | 'none' | 'on' | 'sentences' | 'words' | 'characters';
1066
1066
  type InputEnterkeyhint = 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send';
1067
+ /**
1068
+ * The field as the combobox of a list of suggestions it does not render itself: the caller owns the
1069
+ * listbox, the keys (`(keydown)` on the host) and the active option.
1070
+ */
1071
+ interface InputCombobox {
1072
+ /** Whether the listbox is shown. */
1073
+ expanded: boolean;
1074
+ /** The id of the listbox. */
1075
+ controls: string;
1076
+ /** The id of the highlighted option, `null` when none is. */
1077
+ activeDescendant: string | null;
1078
+ }
1067
1079
  export declare class GbtInput implements ControlValueAccessor {
1068
1080
  id: import("@angular/core").InputSignal<string>;
1069
1081
  label: import("@angular/core").InputSignal<string>;
@@ -1085,6 +1097,7 @@ export declare class GbtInput implements ControlValueAccessor {
1085
1097
  maxlength: import("@angular/core").InputSignal<number | null>;
1086
1098
  min: import("@angular/core").InputSignal<string | number | null>;
1087
1099
  max: import("@angular/core").InputSignal<string | number | null>;
1100
+ combobox: import("@angular/core").InputSignal<InputCombobox | null>;
1088
1101
  showPasswordLabel: import("@angular/core").InputSignal<string>;
1089
1102
  hidePasswordLabel: import("@angular/core").InputSignal<string>;
1090
1103
  committed: import("@angular/core").OutputEmitterRef<string>;
@@ -1208,6 +1221,11 @@ export declare class GbtInput implements ControlValueAccessor {
1208
1221
  "required": false;
1209
1222
  "isSignal": true;
1210
1223
  };
1224
+ "combobox": {
1225
+ "alias": "combobox";
1226
+ "required": false;
1227
+ "isSignal": true;
1228
+ };
1211
1229
  "showPasswordLabel": {
1212
1230
  "alias": "showPasswordLabel";
1213
1231
  "required": false;
@@ -5522,7 +5540,8 @@ interface AuthPort {
5522
5540
  authConfig(): Observable<AuthConfig>;
5523
5541
  login(username: string, password: string): Observable<LoginResponse>;
5524
5542
  register(username: string, email: string, password: string): Observable<LoginResponse>;
5525
- activate(token: string, password: string): Observable<void>;
5543
+ /** `username` is passed only when the page lets the invitee choose it (`chooseUsername`). */
5544
+ activate(token: string, password: string, username?: string): Observable<void>;
5526
5545
  resetPassword(token: string, password: string): Observable<void>;
5527
5546
  verifyMfa(mfaToken: string, proof: MfaProof): Observable<void>;
5528
5547
  startPasskeyChallenge(mfaToken: string): Observable<PasskeyChallenge>;
@@ -5721,6 +5740,14 @@ export declare const DEFAULT_REGISTER_LABELS: Readonly<RegisterLabels>;
5721
5740
  interface ActivateLabels extends CommonFailureLabels {
5722
5741
  heading: string;
5723
5742
  intro: string;
5743
+ /** The intro when the invitee chooses their username too (`chooseUsername`). */
5744
+ introWithUsername: string;
5745
+ username: string;
5746
+ usernameHint: string;
5747
+ usernameEmpty: string;
5748
+ usernameInvalid: string;
5749
+ usernameReserved: string;
5750
+ usernameTaken: string;
5724
5751
  password: string;
5725
5752
  passwordHint: (minLength: number) => string;
5726
5753
  confirmation: string;
@@ -5928,7 +5955,7 @@ type PasswordGatedFailure = 'wrong-password' | 'rate-limited' | 'other';
5928
5955
  export declare function classifyPasswordFailure(err: unknown): PasswordGatedFailure;
5929
5956
  export declare function isTooManyPasskeys(err: unknown): boolean;
5930
5957
  type RegisterFailure = 'disabled' | 'invalid' | 'username-invalid' | 'email-invalid' | 'password-weak' | 'username-reserved' | 'username-taken' | 'email-taken' | 'rate-limited' | 'other';
5931
- type ActivateFailure = 'invalid-link' | 'weak-password' | 'rate-limited' | 'other';
5958
+ type ActivateFailure = 'invalid-link' | 'weak-password' | 'username-invalid' | 'username-reserved' | 'username-taken' | 'rate-limited' | 'other';
5932
5959
  export declare function classifyRegisterFailure(err: unknown): RegisterFailure;
5933
5960
  export declare function classifyActivateFailure(err: unknown): ActivateFailure;
5934
5961
  export declare const MIN_PASSWORD_LENGTH = 8;
@@ -6120,6 +6147,8 @@ export declare class MfaEnrollment {
6120
6147
  choosePasskey(): void;
6121
6148
  createPasskey(): void;
6122
6149
  protected back(): void;
6150
+ /** A server that issues no backup codes with this factor has nothing to show: the enrolment ends there. */
6151
+ private enrolled;
6123
6152
  finish(): void;
6124
6153
  private goTo;
6125
6154
  private passkeyFailed;
@@ -6209,7 +6238,7 @@ export declare class AuthLogin {
6209
6238
  };
6210
6239
  }, {
6211
6240
  "loggedIn": "loggedIn";
6212
- }, ["registerLink"], ["[auth-logo]", "[gbtAuthFooterLink]"], true, never>;
6241
+ }, ["registerLink"], ["[auth-logo]", "[auth-notice]", "[gbtAuthFooterLink]"], true, never>;
6213
6242
  }
6214
6243
  type Registration = 'loading' | 'open' | 'closed' | 'created';
6215
6244
  export declare class AuthRegister {
@@ -6283,6 +6312,9 @@ export declare class AuthActivate {
6283
6312
  token: import("@angular/core").InputSignal<string | null>;
6284
6313
  labels: import("@angular/core").InputSignal<Partial<ActivateLabels>>;
6285
6314
  minPasswordLength: import("@angular/core").InputSignal<number>;
6315
+ /** The invitee chooses their username along with the password, for servers that let them. */
6316
+ chooseUsername: import("@angular/core").InputSignal<boolean>;
6317
+ usernamePattern: import("@angular/core").InputSignal<RegExp>;
6286
6318
  activated: import("@angular/core").OutputEmitterRef<void>;
6287
6319
  signIn: import("@angular/core").OutputEmitterRef<void>;
6288
6320
  protected readonly text: import("@angular/core").Signal<Readonly<ActivateLabels>>;
@@ -6291,11 +6323,14 @@ export declare class AuthActivate {
6291
6323
  protected readonly passwordHint: import("@angular/core").Signal<string>;
6292
6324
  private readonly spent;
6293
6325
  view: import("@angular/core").WritableSignal<View$3>;
6326
+ protected username: import("@angular/core").WritableSignal<string>;
6294
6327
  protected password: import("@angular/core").WritableSignal<string>;
6295
6328
  protected confirmation: import("@angular/core").WritableSignal<string>;
6296
6329
  error: import("@angular/core").WritableSignal<string>;
6297
6330
  submitting: import("@angular/core").WritableSignal<boolean>;
6298
6331
  private attempted;
6332
+ protected intro: import("@angular/core").Signal<string>;
6333
+ protected usernameFieldError: import("@angular/core").Signal<string | null>;
6299
6334
  protected passwordFieldError: import("@angular/core").Signal<string | null>;
6300
6335
  protected confirmationFieldError: import("@angular/core").Signal<string | null>;
6301
6336
  constructor();
@@ -6303,6 +6338,7 @@ export declare class AuthActivate {
6303
6338
  private confirmationProblem;
6304
6339
  private clearPasswords;
6305
6340
  private show;
6341
+ private firstField;
6306
6342
  private fail;
6307
6343
  static ɵfac: i0.ɵɵFactoryDeclaration<AuthActivate, never>;
6308
6344
  static ɵcmp: i0.ɵɵComponentDeclaration<AuthActivate, "gbt-auth-activate", never, {
@@ -6321,6 +6357,16 @@ export declare class AuthActivate {
6321
6357
  "required": false;
6322
6358
  "isSignal": true;
6323
6359
  };
6360
+ "chooseUsername": {
6361
+ "alias": "chooseUsername";
6362
+ "required": false;
6363
+ "isSignal": true;
6364
+ };
6365
+ "usernamePattern": {
6366
+ "alias": "usernamePattern";
6367
+ "required": false;
6368
+ "isSignal": true;
6369
+ };
6324
6370
  }, {
6325
6371
  "activated": "activated";
6326
6372
  "signIn": "signIn";
@@ -6556,4 +6602,4 @@ export declare class PasskeySettings {
6556
6602
  "sessionRevoked": "sessionRevoked";
6557
6603
  }, never, never, true, never>;
6558
6604
  }
6559
- export type { AccordionMode, ActivateFailure, ActivateLabels, AlertAppearance, AlertIconAlign, AlertLive, AlertSize, AlertVariant, Arc, AuthConfig, AuthLabels, AuthPort, AuthPortError, AutocompleteSearchFn, AvatarGroupItem, AvatarSize, AxisSpec, BackupCodesLabels, BackupCodesResult, BadgeAppearance, BadgeSize, BadgeVariant, BandScale, ButtonHaspopup, ButtonSize, ButtonVariant, CalendarDay, CardTone, CardVariant, ChartBox, ChartInterval, ChartMargin, ChartPoint, ChartReader, ChartSeries, CheckboxGroupOption, CheckboxGroupSection, ConfirmDangerModalTone, CopyButtonFeedback, CopyOutcome, CopyStatus, CopyValue, DateInput, DateRangeValue, DescriptionListEntry, DescriptionListLayout, DescriptionListResponsive, DescriptionListValueAlign, DimensionRow, DisclosureAppearance, DisclosureHeadingLevel, DividerOrientation, DrawerEdge, EmailProblem, EmptyStateHeadingLevel, EmptyStateIllustration, EmptyStateSize, EmptyStateTone, EnrolledFactor, FlatTreeNode, FormatBytesOptions, FormatDurationOptions, FormatRelativeTimeOptions, FunnelStep, GbtBytesPipeOptions, GbtDateTimePipeOptions, GbtPipeLocale, GbtRelativeTimePipeOptions, GbtToastKind, GbtToastOptions, IconMarkerAppearance, IconMarkerShape, IconMarkerSize, IconMarkerTone, JobGraphJob, JobGraphStage, JobGraphStatus, JobStatusValue, LegendEntry, LinearAxisSpec, ListCardState, ListRowTone, ListToolbarAccessors, ListToolbarDirection, ListToolbarSortOption, ListToolbarSortValue, ListToolbarState, ListToolbarStateConfig, LoginLabels, LoginResponse, MenuItemVariant, MfaEnrollmentLabels, MfaFailure, MfaFormOwner, MfaPort, MfaProof, MfaSettingsLabels, MfaSetupResult, MfaStatus, NavTabsOrientation, NotificationDotVariant, PageHeaderLevel, PageLayoutAsidePosition, PageLayoutAsideWidth, PageLayoutWidth, PanelHeadingLevel, Passkey, PasskeyChallenge, PasskeyFailure, PasskeyNameProblem, PasskeySettingsLabels, PasswordGatedFailure, PasswordProblem, PieSlice, Point, PointValue, PopoverAlign, RadioOption, RegisterFailure, RegisterLabels, ResetPasswordLabels, SaveStatusState, Scale, SearchBarCollapsible, SearchResultCategory, SegmentedControlOption, SegmentedControlSize, SelectOption, SkeletonListLeading, SkeletonVariant, SpinnerSize, StatGridColumns, StatTileTrend, StatTileTrendTone, StepperOrientation, StepperStatus, StepperStep, TableColumn, TimeTicks, TimeUnit, ToastItem, ToastVariant, ToasterPosition, TooltipPoint, TooltipPosition, TooltipRow, TotpEnrollment, TotpQrLabels, TotpQrRenderOptions, TotpQrRenderer, TreeNode, UserChipSize, UsernameProblem, WeekStartsOn };
6605
+ export type { AccordionMode, ActivateFailure, ActivateLabels, AlertAppearance, AlertIconAlign, AlertLive, AlertSize, AlertVariant, Arc, AuthConfig, AuthLabels, AuthPort, AuthPortError, AutocompleteSearchFn, AvatarGroupItem, AvatarSize, AxisSpec, BackupCodesLabels, BackupCodesResult, BadgeAppearance, BadgeSize, BadgeVariant, BandScale, ButtonHaspopup, ButtonSize, ButtonVariant, CalendarDay, CardTone, CardVariant, ChartBox, ChartInterval, ChartMargin, ChartPoint, ChartReader, ChartSeries, CheckboxGroupOption, CheckboxGroupSection, ConfirmDangerModalTone, CopyButtonFeedback, CopyOutcome, CopyStatus, CopyValue, DateInput, DateRangeValue, DescriptionListEntry, DescriptionListLayout, DescriptionListResponsive, DescriptionListValueAlign, DimensionRow, DisclosureAppearance, DisclosureHeadingLevel, DividerOrientation, DrawerEdge, EmailProblem, EmptyStateHeadingLevel, EmptyStateIllustration, EmptyStateSize, EmptyStateTone, EnrolledFactor, FlatTreeNode, FormatBytesOptions, FormatDurationOptions, FormatRelativeTimeOptions, FunnelStep, GbtBytesPipeOptions, GbtDateTimePipeOptions, GbtPipeLocale, GbtRelativeTimePipeOptions, GbtToastKind, GbtToastOptions, IconMarkerAppearance, IconMarkerShape, IconMarkerSize, IconMarkerTone, InputCombobox, JobGraphJob, JobGraphStage, JobGraphStatus, JobStatusValue, LegendEntry, LinearAxisSpec, ListCardState, ListRowTone, ListToolbarAccessors, ListToolbarDirection, ListToolbarSortOption, ListToolbarSortValue, ListToolbarState, ListToolbarStateConfig, LoginLabels, LoginResponse, MenuItemVariant, MfaEnrollmentLabels, MfaFailure, MfaFormOwner, MfaPort, MfaProof, MfaSettingsLabels, MfaSetupResult, MfaStatus, NavTabsOrientation, NotificationDotVariant, PageHeaderLevel, PageLayoutAsidePosition, PageLayoutAsideWidth, PageLayoutWidth, PanelHeadingLevel, Passkey, PasskeyChallenge, PasskeyFailure, PasskeyNameProblem, PasskeySettingsLabels, PasswordGatedFailure, PasswordProblem, PieSlice, Point, PointValue, PopoverAlign, RadioOption, RegisterFailure, RegisterLabels, ResetPasswordLabels, SaveStatusState, Scale, SearchBarCollapsible, SearchResultCategory, SegmentedControlOption, SegmentedControlSize, SelectOption, SkeletonListLeading, SkeletonVariant, SpinnerSize, StatGridColumns, StatTileTrend, StatTileTrendTone, StepperOrientation, StepperStatus, StepperStep, TableColumn, TimeTicks, TimeUnit, ToastItem, ToastVariant, ToasterPosition, TooltipPoint, TooltipPosition, TooltipRow, TotpEnrollment, TotpQrLabels, TotpQrRenderOptions, TotpQrRenderer, TreeNode, UserChipSize, UsernameProblem, WeekStartsOn };