@rblabs-dev/axiom 1.2.1 → 1.2.3

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.
Files changed (73) hide show
  1. package/README.md +39 -13
  2. package/app-shell/package.json +4 -0
  3. package/brand-lockup/package.json +4 -0
  4. package/central-sign-in/package.json +4 -0
  5. package/cli/build-brand-assets.mjs +12 -18
  6. package/cli/project.mjs +6 -0
  7. package/cli/verify-production-assets.mjs +71 -6
  8. package/confirm-dialog/package.json +4 -0
  9. package/core/package.json +4 -0
  10. package/empty-state/package.json +4 -0
  11. package/fesm2022/rblabs-dev-axiom-app-shell.mjs +375 -0
  12. package/fesm2022/rblabs-dev-axiom-app-shell.mjs.map +1 -0
  13. package/fesm2022/rblabs-dev-axiom-brand-lockup.mjs +154 -0
  14. package/fesm2022/rblabs-dev-axiom-brand-lockup.mjs.map +1 -0
  15. package/fesm2022/rblabs-dev-axiom-central-sign-in.mjs +375 -0
  16. package/fesm2022/rblabs-dev-axiom-central-sign-in.mjs.map +1 -0
  17. package/fesm2022/rblabs-dev-axiom-confirm-dialog.mjs +329 -0
  18. package/fesm2022/rblabs-dev-axiom-confirm-dialog.mjs.map +1 -0
  19. package/fesm2022/rblabs-dev-axiom-core.mjs +181 -0
  20. package/fesm2022/rblabs-dev-axiom-core.mjs.map +1 -0
  21. package/fesm2022/rblabs-dev-axiom-empty-state.mjs +252 -0
  22. package/fesm2022/rblabs-dev-axiom-empty-state.mjs.map +1 -0
  23. package/fesm2022/rblabs-dev-axiom-message.mjs +194 -0
  24. package/fesm2022/rblabs-dev-axiom-message.mjs.map +1 -0
  25. package/fesm2022/rblabs-dev-axiom-monogram.mjs +102 -0
  26. package/fesm2022/rblabs-dev-axiom-monogram.mjs.map +1 -0
  27. package/fesm2022/rblabs-dev-axiom-page-header.mjs +199 -0
  28. package/fesm2022/rblabs-dev-axiom-page-header.mjs.map +1 -0
  29. package/fesm2022/rblabs-dev-axiom-panel.mjs +207 -0
  30. package/fesm2022/rblabs-dev-axiom-panel.mjs.map +1 -0
  31. package/fesm2022/rblabs-dev-axiom-public-shell.mjs +165 -0
  32. package/fesm2022/rblabs-dev-axiom-public-shell.mjs.map +1 -0
  33. package/fesm2022/rblabs-dev-axiom-shell-footer.mjs +73 -0
  34. package/fesm2022/rblabs-dev-axiom-shell-footer.mjs.map +1 -0
  35. package/fesm2022/rblabs-dev-axiom-status-chip.mjs +161 -0
  36. package/fesm2022/rblabs-dev-axiom-status-chip.mjs.map +1 -0
  37. package/fesm2022/rblabs-dev-axiom-technical-value.mjs +173 -0
  38. package/fesm2022/rblabs-dev-axiom-technical-value.mjs.map +1 -0
  39. package/fesm2022/rblabs-dev-axiom-theme-toggle.mjs +117 -0
  40. package/fesm2022/rblabs-dev-axiom-theme-toggle.mjs.map +1 -0
  41. package/fesm2022/rblabs-dev-axiom.mjs +15 -2955
  42. package/fonts/LICENSE +93 -0
  43. package/fonts/inter-latin-ext-wght-normal.woff2 +0 -0
  44. package/fonts/inter-latin-wght-normal.woff2 +0 -0
  45. package/message/package.json +4 -0
  46. package/monogram/package.json +4 -0
  47. package/package.json +77 -2
  48. package/page-header/package.json +4 -0
  49. package/panel/package.json +4 -0
  50. package/public-shell/package.json +4 -0
  51. package/shell-footer/package.json +4 -0
  52. package/status-chip/package.json +4 -0
  53. package/styles/_fonts.scss +7 -7
  54. package/styles/_index.scss +1 -1
  55. package/technical-value/package.json +4 -0
  56. package/theme-toggle/package.json +4 -0
  57. package/types/rblabs-dev-axiom-app-shell.d.ts +50 -0
  58. package/types/rblabs-dev-axiom-brand-lockup.d.ts +35 -0
  59. package/types/rblabs-dev-axiom-central-sign-in.d.ts +82 -0
  60. package/types/rblabs-dev-axiom-confirm-dialog.d.ts +76 -0
  61. package/types/rblabs-dev-axiom-core.d.ts +116 -0
  62. package/types/rblabs-dev-axiom-empty-state.d.ts +55 -0
  63. package/types/rblabs-dev-axiom-message.d.ts +48 -0
  64. package/types/rblabs-dev-axiom-monogram.d.ts +12 -0
  65. package/types/rblabs-dev-axiom-page-header.d.ts +44 -0
  66. package/types/rblabs-dev-axiom-panel.d.ts +44 -0
  67. package/types/rblabs-dev-axiom-public-shell.d.ts +28 -0
  68. package/types/rblabs-dev-axiom-shell-footer.d.ts +17 -0
  69. package/types/rblabs-dev-axiom-status-chip.d.ts +40 -0
  70. package/types/rblabs-dev-axiom-technical-value.d.ts +35 -0
  71. package/types/rblabs-dev-axiom-theme-toggle.d.ts +12 -0
  72. package/types/rblabs-dev-axiom.d.ts +15 -675
  73. package/fesm2022/rblabs-dev-axiom.mjs.map +0 -1
@@ -0,0 +1,329 @@
1
+ import * as i0 from "@angular/core";
2
+ import { ChangeDetectionStrategy, Component, Injectable, ViewEncapsulation, inject, signal, viewChild } from "@angular/core";
3
+ import * as i1 from "@angular/forms";
4
+ import { FormControl, ReactiveFormsModule } from "@angular/forms";
5
+ import { MatButton } from "@angular/material/button";
6
+ import { MAT_DIALOG_DATA, MatDialog, MatDialogActions, MatDialogContent, MatDialogRef, MatDialogTitle } from "@angular/material/dialog";
7
+ import { MatIcon } from "@angular/material/icon";
8
+ import { firstValueFrom } from "rxjs";
9
+ let nextId = 0;
10
+ function rbConfirmDialogId() {
11
+ return `rb-confirm-dialog-${nextId++}`;
12
+ }
13
+ var RbConfirmDialogComponent = class RbConfirmDialogComponent {
14
+ data = inject(MAT_DIALOG_DATA);
15
+ dialogRef = inject(MatDialogRef);
16
+ reasonInput = viewChild("reasonInput", ...ngDevMode ? [{ debugName: "reasonInput" }] : /* istanbul ignore next */ []);
17
+ id = rbConfirmDialogId();
18
+ descriptionId = this.data.descriptionId ?? `${this.id}-description`;
19
+ reasonId = `${this.id}-reason`;
20
+ tone = this.data.tone ?? "primary";
21
+ minimumReasonLength = this.data.reason?.minimumLength ?? 3;
22
+ trimmedMinLength = (control) => String(control.value).trim().length >= this.minimumReasonLength ? null : { trimmedMinLength: true };
23
+ reason = new FormControl("", {
24
+ nonNullable: true,
25
+ validators: this.data.reason ? [this.trimmedMinLength] : []
26
+ });
27
+ submitted = signal(false, ...ngDevMode ? [{ debugName: "submitted" }] : /* istanbul ignore next */ []);
28
+ showReasonError() {
29
+ return this.submitted() && this.reason.invalid;
30
+ }
31
+ reasonDescribedBy() {
32
+ const ids = [this.data.reason?.hint ? `${this.reasonId}-hint` : null, this.showReasonError() ? `${this.reasonId}-error` : null].filter((value) => value !== null);
33
+ return ids.length > 0 ? ids.join(" ") : null;
34
+ }
35
+ cancel() {
36
+ this.dialogRef.close({ confirmed: false });
37
+ }
38
+ confirm() {
39
+ if (this.data.reason) {
40
+ this.submitted.set(true);
41
+ if (this.reason.invalid) {
42
+ this.reasonInput()?.nativeElement.focus();
43
+ return;
44
+ }
45
+ }
46
+ this.dialogRef.close({
47
+ confirmed: true,
48
+ ...this.data.reason ? { reason: this.reason.value.trim() } : {}
49
+ });
50
+ }
51
+ static ɵfac = i0.ɵɵngDeclareFactory({
52
+ minVersion: "12.0.0",
53
+ version: "22.2.3",
54
+ ngImport: i0,
55
+ type: RbConfirmDialogComponent,
56
+ deps: [],
57
+ target: i0.ɵɵFactoryTarget.Component
58
+ });
59
+ static ɵcmp = i0.ɵɵngDeclareComponent({
60
+ minVersion: "17.0.0",
61
+ version: "22.2.3",
62
+ type: RbConfirmDialogComponent,
63
+ isStandalone: true,
64
+ selector: "rb-confirm-dialog",
65
+ host: {
66
+ properties: { "attr.data-tone": "tone" },
67
+ classAttribute: "rb-confirm-dialog"
68
+ },
69
+ viewQueries: [{
70
+ propertyName: "reasonInput",
71
+ first: true,
72
+ predicate: ["reasonInput"],
73
+ descendants: true,
74
+ isSignal: true
75
+ }],
76
+ ngImport: i0,
77
+ template: `
78
+ <div class="rb-confirm-dialog__layout">
79
+ <span class="rb-confirm-dialog__icon" aria-hidden="true">
80
+ <mat-icon fontSet="material-symbols-outlined">{{
81
+ tone === 'danger' ? 'warning' : 'help'
82
+ }}</mat-icon>
83
+ </span>
84
+ <div class="rb-confirm-dialog__body">
85
+ <h2 mat-dialog-title class="rb-confirm-dialog__title">{{ data.title }}</h2>
86
+ <mat-dialog-content class="rb-confirm-dialog__content">
87
+ <p class="rb-confirm-dialog__description" [id]="descriptionId">{{ data.description }}</p>
88
+ @if (data.reason) {
89
+ <div class="rb-field" [class.rb-field--invalid]="showReasonError()">
90
+ <label class="rb-field__label" [for]="reasonId">{{
91
+ data.reason.label ?? 'Reason'
92
+ }}</label>
93
+ <input
94
+ #reasonInput
95
+ class="rb-field__control"
96
+ type="text"
97
+ autocomplete="off"
98
+ [id]="reasonId"
99
+ [formControl]="reason"
100
+ [attr.aria-invalid]="showReasonError() ? 'true' : null"
101
+ [attr.aria-describedby]="reasonDescribedBy()"
102
+ />
103
+ @if (data.reason.hint) {
104
+ <p class="rb-field__hint" [id]="reasonId + '-hint'">{{ data.reason.hint }}</p>
105
+ }
106
+ @if (showReasonError()) {
107
+ <p class="rb-field__error" [id]="reasonId + '-error'">
108
+ Enter at least {{ minimumReasonLength }} characters.
109
+ </p>
110
+ }
111
+ </div>
112
+ }
113
+ </mat-dialog-content>
114
+ </div>
115
+ </div>
116
+ <mat-dialog-actions align="end" class="rb-confirm-dialog__actions">
117
+ <button matButton type="button" (click)="cancel()">{{ data.cancelLabel ?? 'Cancel' }}</button>
118
+ <button
119
+ matButton="filled"
120
+ type="button"
121
+ [color]="tone === 'danger' ? 'warn' : 'primary'"
122
+ (click)="confirm()"
123
+ >
124
+ {{ data.confirmLabel }}
125
+ </button>
126
+ </mat-dialog-actions>
127
+ `,
128
+ isInline: true,
129
+ styles: ["rb-confirm-dialog{--mat-dialog-headline-padding: 0;--mat-dialog-content-padding: 0;--mat-dialog-with-actions-content-padding: 0;--mat-dialog-actions-padding: var(--rb-space-6);--mat-dialog-subhead-color: var(--rb-color-text-strong);--mat-dialog-subhead-font: var(--rb-font-sans);--mat-dialog-subhead-size: var(--rb-type-title-large-size);--mat-dialog-subhead-line-height: var(--rb-type-title-large-line-height);--mat-dialog-subhead-weight: var(--rb-type-title-large-weight);--mat-dialog-subhead-tracking: var(--rb-type-title-large-tracking);--mat-dialog-supporting-text-color: var(--rb-color-text-muted);--mat-dialog-supporting-text-font: var(--rb-font-sans);--mat-dialog-supporting-text-size: var(--rb-type-body-medium-size);--mat-dialog-supporting-text-line-height: var(--rb-type-body-medium-line-height);--mat-dialog-supporting-text-weight: var(--rb-type-body-medium-weight);--mat-dialog-supporting-text-tracking: var(--rb-type-body-medium-tracking)}rb-confirm-dialog .rb-confirm-dialog__layout{display:grid;grid-template-columns:auto minmax(0,1fr);gap:var(--rb-space-4);min-height:0;padding:var(--rb-space-6) var(--rb-space-6) 0}@media(width<30rem){rb-confirm-dialog .rb-confirm-dialog__layout{gap:var(--rb-space-3);padding-inline:var(--rb-space-4)}}rb-confirm-dialog .rb-confirm-dialog__icon{display:grid;width:var(--rb-size-touch-target);height:var(--rb-size-touch-target);place-items:center;border-radius:var(--rb-radius-full);background-color:var(--rb-color-primary-soft);color:var(--rb-color-on-primary-soft)}rb-confirm-dialog[data-tone=danger] .rb-confirm-dialog__icon{background-color:var(--rb-color-danger-soft);color:var(--rb-color-danger)}rb-confirm-dialog .rb-confirm-dialog__body{display:grid;gap:var(--rb-space-1);min-width:0}rb-confirm-dialog .rb-confirm-dialog__title{overflow-wrap:anywhere}rb-confirm-dialog .rb-confirm-dialog__content{display:grid;gap:var(--rb-space-5);overflow-wrap:anywhere}rb-confirm-dialog .rb-confirm-dialog__description{margin:0}rb-confirm-dialog .rb-confirm-dialog__actions{gap:var(--rb-space-2);min-height:0}@media(width<30rem){rb-confirm-dialog .rb-confirm-dialog__actions{padding-inline:var(--rb-space-4)}}\n"],
130
+ dependencies: [
131
+ {
132
+ kind: "component",
133
+ type: MatButton,
134
+ selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ",
135
+ inputs: ["matButton"],
136
+ exportAs: ["matButton", "matAnchor"]
137
+ },
138
+ {
139
+ kind: "directive",
140
+ type: MatDialogActions,
141
+ selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]",
142
+ inputs: ["align"]
143
+ },
144
+ {
145
+ kind: "directive",
146
+ type: MatDialogContent,
147
+ selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]"
148
+ },
149
+ {
150
+ kind: "directive",
151
+ type: MatDialogTitle,
152
+ selector: "[mat-dialog-title], [matDialogTitle]",
153
+ inputs: ["id"],
154
+ exportAs: ["matDialogTitle"]
155
+ },
156
+ {
157
+ kind: "component",
158
+ type: MatIcon,
159
+ selector: "mat-icon",
160
+ inputs: [
161
+ "color",
162
+ "inline",
163
+ "svgIcon",
164
+ "fontSet",
165
+ "fontIcon"
166
+ ],
167
+ exportAs: ["matIcon"]
168
+ },
169
+ {
170
+ kind: "ngmodule",
171
+ type: ReactiveFormsModule
172
+ },
173
+ {
174
+ kind: "directive",
175
+ type: i1.DefaultValueAccessor,
176
+ selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]"
177
+ },
178
+ {
179
+ kind: "directive",
180
+ type: i1.NgControlStatus,
181
+ selector: "[formControlName],[ngModel],[formControl]"
182
+ },
183
+ {
184
+ kind: "directive",
185
+ type: i1.FormControlDirective,
186
+ selector: "[formControl]",
187
+ inputs: [
188
+ "formControl",
189
+ "disabled",
190
+ "ngModel"
191
+ ],
192
+ outputs: ["ngModelChange"],
193
+ exportAs: ["ngForm"]
194
+ }
195
+ ],
196
+ changeDetection: i0.ChangeDetectionStrategy.OnPush,
197
+ encapsulation: i0.ViewEncapsulation.None
198
+ });
199
+ };
200
+ i0.ɵɵngDeclareClassMetadata({
201
+ minVersion: "12.0.0",
202
+ version: "22.2.3",
203
+ ngImport: i0,
204
+ type: RbConfirmDialogComponent,
205
+ decorators: [{
206
+ type: Component,
207
+ args: [{
208
+ selector: "rb-confirm-dialog",
209
+ imports: [
210
+ MatButton,
211
+ MatDialogActions,
212
+ MatDialogContent,
213
+ MatDialogTitle,
214
+ MatIcon,
215
+ ReactiveFormsModule
216
+ ],
217
+ changeDetection: ChangeDetectionStrategy.OnPush,
218
+ encapsulation: ViewEncapsulation.None,
219
+ host: {
220
+ class: "rb-confirm-dialog",
221
+ "[attr.data-tone]": "tone"
222
+ },
223
+ template: `
224
+ <div class="rb-confirm-dialog__layout">
225
+ <span class="rb-confirm-dialog__icon" aria-hidden="true">
226
+ <mat-icon fontSet="material-symbols-outlined">{{
227
+ tone === 'danger' ? 'warning' : 'help'
228
+ }}</mat-icon>
229
+ </span>
230
+ <div class="rb-confirm-dialog__body">
231
+ <h2 mat-dialog-title class="rb-confirm-dialog__title">{{ data.title }}</h2>
232
+ <mat-dialog-content class="rb-confirm-dialog__content">
233
+ <p class="rb-confirm-dialog__description" [id]="descriptionId">{{ data.description }}</p>
234
+ @if (data.reason) {
235
+ <div class="rb-field" [class.rb-field--invalid]="showReasonError()">
236
+ <label class="rb-field__label" [for]="reasonId">{{
237
+ data.reason.label ?? 'Reason'
238
+ }}</label>
239
+ <input
240
+ #reasonInput
241
+ class="rb-field__control"
242
+ type="text"
243
+ autocomplete="off"
244
+ [id]="reasonId"
245
+ [formControl]="reason"
246
+ [attr.aria-invalid]="showReasonError() ? 'true' : null"
247
+ [attr.aria-describedby]="reasonDescribedBy()"
248
+ />
249
+ @if (data.reason.hint) {
250
+ <p class="rb-field__hint" [id]="reasonId + '-hint'">{{ data.reason.hint }}</p>
251
+ }
252
+ @if (showReasonError()) {
253
+ <p class="rb-field__error" [id]="reasonId + '-error'">
254
+ Enter at least {{ minimumReasonLength }} characters.
255
+ </p>
256
+ }
257
+ </div>
258
+ }
259
+ </mat-dialog-content>
260
+ </div>
261
+ </div>
262
+ <mat-dialog-actions align="end" class="rb-confirm-dialog__actions">
263
+ <button matButton type="button" (click)="cancel()">{{ data.cancelLabel ?? 'Cancel' }}</button>
264
+ <button
265
+ matButton="filled"
266
+ type="button"
267
+ [color]="tone === 'danger' ? 'warn' : 'primary'"
268
+ (click)="confirm()"
269
+ >
270
+ {{ data.confirmLabel }}
271
+ </button>
272
+ </mat-dialog-actions>
273
+ `,
274
+ styles: ["rb-confirm-dialog{--mat-dialog-headline-padding: 0;--mat-dialog-content-padding: 0;--mat-dialog-with-actions-content-padding: 0;--mat-dialog-actions-padding: var(--rb-space-6);--mat-dialog-subhead-color: var(--rb-color-text-strong);--mat-dialog-subhead-font: var(--rb-font-sans);--mat-dialog-subhead-size: var(--rb-type-title-large-size);--mat-dialog-subhead-line-height: var(--rb-type-title-large-line-height);--mat-dialog-subhead-weight: var(--rb-type-title-large-weight);--mat-dialog-subhead-tracking: var(--rb-type-title-large-tracking);--mat-dialog-supporting-text-color: var(--rb-color-text-muted);--mat-dialog-supporting-text-font: var(--rb-font-sans);--mat-dialog-supporting-text-size: var(--rb-type-body-medium-size);--mat-dialog-supporting-text-line-height: var(--rb-type-body-medium-line-height);--mat-dialog-supporting-text-weight: var(--rb-type-body-medium-weight);--mat-dialog-supporting-text-tracking: var(--rb-type-body-medium-tracking)}rb-confirm-dialog .rb-confirm-dialog__layout{display:grid;grid-template-columns:auto minmax(0,1fr);gap:var(--rb-space-4);min-height:0;padding:var(--rb-space-6) var(--rb-space-6) 0}@media(width<30rem){rb-confirm-dialog .rb-confirm-dialog__layout{gap:var(--rb-space-3);padding-inline:var(--rb-space-4)}}rb-confirm-dialog .rb-confirm-dialog__icon{display:grid;width:var(--rb-size-touch-target);height:var(--rb-size-touch-target);place-items:center;border-radius:var(--rb-radius-full);background-color:var(--rb-color-primary-soft);color:var(--rb-color-on-primary-soft)}rb-confirm-dialog[data-tone=danger] .rb-confirm-dialog__icon{background-color:var(--rb-color-danger-soft);color:var(--rb-color-danger)}rb-confirm-dialog .rb-confirm-dialog__body{display:grid;gap:var(--rb-space-1);min-width:0}rb-confirm-dialog .rb-confirm-dialog__title{overflow-wrap:anywhere}rb-confirm-dialog .rb-confirm-dialog__content{display:grid;gap:var(--rb-space-5);overflow-wrap:anywhere}rb-confirm-dialog .rb-confirm-dialog__description{margin:0}rb-confirm-dialog .rb-confirm-dialog__actions{gap:var(--rb-space-2);min-height:0}@media(width<30rem){rb-confirm-dialog .rb-confirm-dialog__actions{padding-inline:var(--rb-space-4)}}\n"]
275
+ }]
276
+ }],
277
+ propDecorators: { reasonInput: [{
278
+ type: i0.ViewChild,
279
+ args: ["reasonInput", { isSignal: true }]
280
+ }] }
281
+ });
282
+ var RbConfirmDialogService = class RbConfirmDialogService {
283
+ dialog = inject(MatDialog);
284
+ async confirm(data) {
285
+ const descriptionId = `${rbConfirmDialogId()}-description`;
286
+ const dialogRef = this.dialog.open(RbConfirmDialogComponent, {
287
+ data: {
288
+ ...data,
289
+ descriptionId
290
+ },
291
+ role: data.tone === "danger" ? "alertdialog" : "dialog",
292
+ ariaDescribedBy: descriptionId,
293
+ autoFocus: "first-tabbable",
294
+ restoreFocus: true,
295
+ width: "min(var(--rb-size-card-wide), calc(100vw - 2 * var(--rb-space-4)))",
296
+ maxWidth: "100vw",
297
+ panelClass: ["rb-confirm-dialog-panel", "rb-scope"]
298
+ });
299
+ return await firstValueFrom(dialogRef.afterClosed()) ?? { confirmed: false };
300
+ }
301
+ static ɵfac = i0.ɵɵngDeclareFactory({
302
+ minVersion: "12.0.0",
303
+ version: "22.2.3",
304
+ ngImport: i0,
305
+ type: RbConfirmDialogService,
306
+ deps: [],
307
+ target: i0.ɵɵFactoryTarget.Injectable
308
+ });
309
+ static ɵprov = i0.ɵɵngDeclareInjectable({
310
+ minVersion: "12.0.0",
311
+ version: "22.2.3",
312
+ ngImport: i0,
313
+ type: RbConfirmDialogService,
314
+ providedIn: "root"
315
+ });
316
+ };
317
+ i0.ɵɵngDeclareClassMetadata({
318
+ minVersion: "12.0.0",
319
+ version: "22.2.3",
320
+ ngImport: i0,
321
+ type: RbConfirmDialogService,
322
+ decorators: [{
323
+ type: Injectable,
324
+ args: [{ providedIn: "root" }]
325
+ }]
326
+ });
327
+ export { RbConfirmDialogComponent, RbConfirmDialogService, rbConfirmDialogId };
328
+
329
+ //# sourceMappingURL=rblabs-dev-axiom-confirm-dialog.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rblabs-dev-axiom-confirm-dialog.mjs","names":[],"sources":["../../../projects/axiom/confirm-dialog/src/confirm-dialog.ts","../../../projects/axiom/confirm-dialog/src/confirm-dialog.service.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n inject,\n signal,\n viewChild,\n} from '@angular/core';\nimport { FormControl, ReactiveFormsModule, ValidatorFn } from '@angular/forms';\nimport { MatButton } from '@angular/material/button';\nimport {\n MAT_DIALOG_DATA,\n MatDialogActions,\n MatDialogContent,\n MatDialogRef,\n MatDialogTitle,\n} from '@angular/material/dialog';\nimport { MatIcon } from '@angular/material/icon';\n\nexport type RbConfirmDialogTone = 'primary' | 'danger';\n\nexport interface RbConfirmDialogReason {\n /** Visible label of the reason field. Defaults to \"Reason\". */\n label?: string;\n /** Helper text under the field. */\n hint?: string;\n /** Minimum length of the trimmed reason. Defaults to 3. */\n minimumLength?: number;\n}\n\nexport interface RbConfirmDialogData {\n title: string;\n description: string;\n confirmLabel: string;\n /** Defaults to \"Cancel\". */\n cancelLabel?: string;\n /** `danger` is for destructive or irreversible actions. Defaults to `primary`. */\n tone?: RbConfirmDialogTone;\n /** Asks for a required reason, returned trimmed in the result. */\n reason?: RbConfirmDialogReason;\n}\n\nexport interface RbConfirmDialogResult {\n confirmed: boolean;\n reason?: string;\n}\n\n/** Data the service adds so the dialog container can reference the description. */\nexport interface RbConfirmDialogInternalData extends RbConfirmDialogData {\n descriptionId?: string;\n}\n\nlet nextId = 0;\n\n/** Generates the ids shared by the service (dialog config) and the dialog content. */\nexport function rbConfirmDialogId(): string {\n return `rb-confirm-dialog-${nextId++}`;\n}\n\n/**\n * Confirmation content opened by `RbConfirmDialogService` (docs/design-system.md, section 15.7).\n * Use the service rather than opening this component directly.\n */\n@Component({\n selector: 'rb-confirm-dialog',\n imports: [\n MatButton,\n MatDialogActions,\n MatDialogContent,\n MatDialogTitle,\n MatIcon,\n ReactiveFormsModule,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'rb-confirm-dialog',\n '[attr.data-tone]': 'tone',\n },\n template: `\n <div class=\"rb-confirm-dialog__layout\">\n <span class=\"rb-confirm-dialog__icon\" aria-hidden=\"true\">\n <mat-icon fontSet=\"material-symbols-outlined\">{{\n tone === 'danger' ? 'warning' : 'help'\n }}</mat-icon>\n </span>\n <div class=\"rb-confirm-dialog__body\">\n <h2 mat-dialog-title class=\"rb-confirm-dialog__title\">{{ data.title }}</h2>\n <mat-dialog-content class=\"rb-confirm-dialog__content\">\n <p class=\"rb-confirm-dialog__description\" [id]=\"descriptionId\">{{ data.description }}</p>\n @if (data.reason) {\n <div class=\"rb-field\" [class.rb-field--invalid]=\"showReasonError()\">\n <label class=\"rb-field__label\" [for]=\"reasonId\">{{\n data.reason.label ?? 'Reason'\n }}</label>\n <input\n #reasonInput\n class=\"rb-field__control\"\n type=\"text\"\n autocomplete=\"off\"\n [id]=\"reasonId\"\n [formControl]=\"reason\"\n [attr.aria-invalid]=\"showReasonError() ? 'true' : null\"\n [attr.aria-describedby]=\"reasonDescribedBy()\"\n />\n @if (data.reason.hint) {\n <p class=\"rb-field__hint\" [id]=\"reasonId + '-hint'\">{{ data.reason.hint }}</p>\n }\n @if (showReasonError()) {\n <p class=\"rb-field__error\" [id]=\"reasonId + '-error'\">\n Enter at least {{ minimumReasonLength }} characters.\n </p>\n }\n </div>\n }\n </mat-dialog-content>\n </div>\n </div>\n <mat-dialog-actions align=\"end\" class=\"rb-confirm-dialog__actions\">\n <button matButton type=\"button\" (click)=\"cancel()\">{{ data.cancelLabel ?? 'Cancel' }}</button>\n <button\n matButton=\"filled\"\n type=\"button\"\n [color]=\"tone === 'danger' ? 'warn' : 'primary'\"\n (click)=\"confirm()\"\n >\n {{ data.confirmLabel }}\n </button>\n </mat-dialog-actions>\n `,\n styleUrl: './confirm-dialog.scss',\n})\nexport class RbConfirmDialogComponent {\n protected readonly data = inject<RbConfirmDialogInternalData>(MAT_DIALOG_DATA);\n private readonly dialogRef =\n inject<MatDialogRef<RbConfirmDialogComponent, RbConfirmDialogResult>>(MatDialogRef);\n private readonly reasonInput = viewChild<ElementRef<HTMLInputElement>>('reasonInput');\n\n private readonly id = rbConfirmDialogId();\n protected readonly descriptionId = this.data.descriptionId ?? `${this.id}-description`;\n protected readonly reasonId = `${this.id}-reason`;\n protected readonly tone: RbConfirmDialogTone = this.data.tone ?? 'primary';\n protected readonly minimumReasonLength = this.data.reason?.minimumLength ?? 3;\n\n private readonly trimmedMinLength: ValidatorFn = (control) =>\n String(control.value).trim().length >= this.minimumReasonLength\n ? null\n : { trimmedMinLength: true };\n\n protected readonly reason = new FormControl('', {\n nonNullable: true,\n validators: this.data.reason ? [this.trimmedMinLength] : [],\n });\n\n private readonly submitted = signal(false);\n\n protected showReasonError(): boolean {\n return this.submitted() && this.reason.invalid;\n }\n\n protected reasonDescribedBy(): string | null {\n const ids = [\n this.data.reason?.hint ? `${this.reasonId}-hint` : null,\n this.showReasonError() ? `${this.reasonId}-error` : null,\n ].filter((value): value is string => value !== null);\n return ids.length > 0 ? ids.join(' ') : null;\n }\n\n cancel(): void {\n this.dialogRef.close({ confirmed: false });\n }\n\n confirm(): void {\n if (this.data.reason) {\n this.submitted.set(true);\n if (this.reason.invalid) {\n // Focus returns to the field, which now announces its error through aria-describedby.\n this.reasonInput()?.nativeElement.focus();\n return;\n }\n }\n\n this.dialogRef.close({\n confirmed: true,\n ...(this.data.reason ? { reason: this.reason.value.trim() } : {}),\n });\n }\n}\n","import { Injectable, inject } from '@angular/core';\nimport { MatDialog } from '@angular/material/dialog';\nimport { firstValueFrom } from 'rxjs';\n\nimport {\n RbConfirmDialogComponent,\n RbConfirmDialogData,\n RbConfirmDialogInternalData,\n RbConfirmDialogResult,\n rbConfirmDialogId,\n} from './confirm-dialog';\n\n/**\n * Asks the user to confirm an action (docs/design-system.md, section 15.7):\n *\n * ```ts\n * const { confirmed, reason } = await confirmDialog.confirm({\n * title: 'Revoke credential?',\n * description: 'Clients using it stop working immediately.',\n * confirmLabel: 'Revoke credential',\n * tone: 'danger',\n * reason: { label: 'Reason for revoking' },\n * });\n * ```\n *\n * Closing the dialog in any other way (Cancel, Escape, the backdrop) resolves `confirmed: false`.\n */\n@Injectable({ providedIn: 'root' })\nexport class RbConfirmDialogService {\n private readonly dialog = inject(MatDialog);\n\n async confirm(data: RbConfirmDialogData): Promise<RbConfirmDialogResult> {\n const descriptionId = `${rbConfirmDialogId()}-description`;\n const dialogRef = this.dialog.open<\n RbConfirmDialogComponent,\n RbConfirmDialogInternalData,\n RbConfirmDialogResult\n >(RbConfirmDialogComponent, {\n data: { ...data, descriptionId },\n // A destructive confirmation interrupts the task, so it is announced as an alert dialog.\n role: data.tone === 'danger' ? 'alertdialog' : 'dialog',\n ariaDescribedBy: descriptionId,\n // The reason field when there is one, otherwise Cancel: never the destructive button.\n autoFocus: 'first-tabbable',\n restoreFocus: true,\n width: 'min(var(--rb-size-card-wide), calc(100vw - 2 * var(--rb-space-4)))',\n maxWidth: '100vw',\n // `rb-scope` gives the pane the kit's tokens while the kit is applied scoped (14).\n panelClass: ['rb-confirm-dialog-panel', 'rb-scope'],\n });\n\n return (await firstValueFrom(dialogRef.afterClosed())) ?? { confirmed: false };\n }\n}\n"],"mappings":";;;;;;;;AAqDA,IAAI,SAAS;AAGb,SAAgB,oBAAiB;CAC/B,OAAO,qBAAqB;AAC9B;AA2EA,IAAa,2BAAb,MAAa,yBAAwB;CAChB,OAAO,OAAoC,eAAe;CAC5D,YACf,OAAsE,YAAY;CACnE,cAAc,UAAwC,eAAc,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAEpE,KAAK,kBAAiB;CACpB,gBAAgB,KAAK,KAAK,iBAAiB,GAAG,KAAK,GAAE;CACrD,WAAW,GAAG,KAAK,GAAE;CACrB,OAA4B,KAAK,KAAK,QAAQ;CAC9C,sBAAsB,KAAK,KAAK,QAAQ,iBAAiB;CAE3D,oBAAiC,YAChD,OAAO,QAAQ,KAAK,CAAC,CAAC,KAAI,CAAE,CAAC,UAAU,KAAK,sBACxC,OACA,EAAE,kBAAkB,KAAI;CAEX,SAAS,IAAI,YAAY,IAAI;EAC9C,aAAa;EACb,YAAY,KAAK,KAAK,SAAS,CAAC,KAAK,gBAAgB,IAAI,CAAA;CAC1D,CAAA;CAEgB,YAAY,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAEhC,kBAAe;EACvB,OAAO,KAAK,UAAS,KAAM,KAAK,OAAO;CACzC;CAEU,oBAAiB;EACzB,MAAM,MAAM,CACV,KAAK,KAAK,QAAQ,OAAO,GAAG,KAAK,SAAQ,SAAU,MACnD,KAAK,gBAAe,IAAK,GAAG,KAAK,SAAQ,UAAW,IACrD,CAAA,CAAC,QAAQ,UAA2B,UAAU,IAAI;EACnD,OAAO,IAAI,SAAS,IAAI,IAAI,KAAK,GAAG,IAAI;CAC1C;CAEA,SAAM;EACJ,KAAK,UAAU,MAAM,EAAE,WAAW,MAAK,CAAE;CAC3C;CAEA,UAAO;EACL,IAAI,KAAK,KAAK,QAAQ;GACpB,KAAK,UAAU,IAAI,IAAI;GACvB,IAAI,KAAK,OAAO,SAAS;IAEvB,KAAK,YAAW,CAAE,EAAE,cAAc,MAAK;IACvC;GACF;EACF;EAEA,KAAK,UAAU,MAAM;GACnB,WAAW;GACX,GAAI,KAAK,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,MAAM,KAAI,EAAE,IAAK,CAAA;EAC/D,CAAA;CACH;CAtDW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAwB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAxB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAwB,cAAA;EAAA,UAAA;EAAA,MAAA;GAAA,YAAA,EAAA,kBAAA,OAAA;GAAA,gBAAA;EAAA;EAAA,aAAA,CAAA;GAAA,cAAA;GAAA,OAAA;GAAA,WAAA,CAAA,aAAA;GAAA,aAAA;GAAA,UAAA;EAAA,CAAA;EAAA,UAAA;EAAA,UArDzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkDT,UAAA;EAAA,QAAA,CAAA,8mEAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MA/DC;IAAS,UAAA;IAAA,QAAA,CAAA,WAAA;IAAA,UAAA,CAAA,aAAA,WAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACT;IAAgB,UAAA;IAAA,QAAA,CAAA,OAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAChB;IAAgB,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAChB;IAAc,UAAA;IAAA,QAAA,CAAA,IAAA;IAAA,UAAA,CAAA,gBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACd;IAAO,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,UAAA,CAAA,SAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACP;GAAmB;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA,CAAA,eAAA;IAAA,UAAA,CAAA,QAAA;GAAA;EAAA;EAAA,iBAAA,GAAA,wBAAA;EAAA,eAAA,GAAA,kBAAA;CAAA,CAAA;;AA6DV,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAwB,YAAA,CAAA;EArEpC,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAmB,SACpB;IACP;IACA;IACA;IACA;IACA;IACA;GACD;GAAA,iBACgB,wBAAwB;GAAM,eAChC,kBAAkB;GAAI,MAC/B;IACJ,OAAO;IACP,oBAAoB;GACrB;GAAA,UACS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDT,QAAA,CAAA,8mEAAA;EAAA,CAAA;CAOsE,CAAA;CAAA,gBAAA,EAAA,aAAA,CAAA;EAAA,MAAA,GAAA;EAAA,MAAA,CAAA,eAAa,EAAA,UAAA,KAAA,CAAA;CAAA,CAAA,EAAA;AAAA,CAAA;AC7GtF,IAAa,yBAAb,MAAa,uBAAsB;CAChB,SAAS,OAAO,SAAS;CAE1C,MAAM,QAAQ,MAAyB;EACrC,MAAM,gBAAgB,GAAG,kBAAiB,EAAE;EAC5C,MAAM,YAAY,KAAK,OAAO,KAI5B,0BAA0B;GAC1B,MAAM;IAAE,GAAG;IAAM;GAAa;GAE9B,MAAM,KAAK,SAAS,WAAW,gBAAgB;GAC/C,iBAAiB;GAEjB,WAAW;GACX,cAAc;GACd,OAAO;GACP,UAAU;GAEV,YAAY,CAAC,2BAA2B,UAAU;EACnD,CAAA;EAED,OAAQ,MAAM,eAAe,UAAU,YAAW,CAAE,KAAM,EAAE,WAAW,MAAK;CAC9E;CAxBW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAsB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAtB,OAAA,QAAA,GAAA,sBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAsB,YADT;CAAM,CAAA;;AACnB,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAsB,YAAA,CAAA;EADlC,MAAA;EAAW,MAAA,CAAA,EAAE,YAAY,OAAM,CAAE"}
@@ -0,0 +1,181 @@
1
+ import * as i0 from "@angular/core";
2
+ import { DestroyRef, Injectable, InjectionToken, computed, inject, makeEnvironmentProviders, provideAppInitializer, signal } from "@angular/core";
3
+ import { MatIconRegistry } from "@angular/material/icon";
4
+ import { DOCUMENT } from "@angular/common";
5
+ const RB_BREAKPOINT_WIDTHS = {
6
+ xs: "30rem",
7
+ sm: "40rem",
8
+ md: "48rem",
9
+ lg: "60rem",
10
+ xl: "75rem",
11
+ "2xl": "87.5rem"
12
+ };
13
+ const RB_BREAKPOINTS = {
14
+ belowXs: "(width < 30rem)",
15
+ belowSm: "(width < 40rem)",
16
+ belowMd: "(width < 48rem)",
17
+ belowLg: "(width < 60rem)",
18
+ belowXl: "(width < 75rem)",
19
+ below2xl: "(width < 87.5rem)",
20
+ aboveXs: "(width >= 30rem)",
21
+ aboveSm: "(width >= 40rem)",
22
+ aboveMd: "(width >= 48rem)",
23
+ aboveLg: "(width >= 60rem)",
24
+ aboveXl: "(width >= 75rem)",
25
+ above2xl: "(width >= 87.5rem)"
26
+ };
27
+ const RB_THEME_STORAGE_KEY = "rb-theme";
28
+ const RB_THEME_COLORS = {
29
+ light: "#f4f7fb",
30
+ dark: "#08111d"
31
+ };
32
+ const RB_THEME_OPTIONS = new InjectionToken("RB_THEME_OPTIONS", {
33
+ providedIn: "root",
34
+ factory: () => ({})
35
+ });
36
+ const DARK_SCHEME_QUERY = "(prefers-color-scheme: dark)";
37
+ function isTheme(value) {
38
+ return value === "light" || value === "dark";
39
+ }
40
+ var ThemeService = class ThemeService {
41
+ document = inject(DOCUMENT);
42
+ options = inject(RB_THEME_OPTIONS);
43
+ window = this.document.defaultView;
44
+ darkScheme = this.window?.matchMedia?.(DARK_SCHEME_QUERY) ?? null;
45
+ systemTheme = signal(this.darkScheme?.matches ? "dark" : "light", ...ngDevMode ? [{ debugName: "systemTheme" }] : /* istanbul ignore next */ []);
46
+ storedTheme = signal(null, ...ngDevMode ? [{ debugName: "storedTheme" }] : /* istanbul ignore next */ []);
47
+ forcedTheme = signal(this.options.forcedTheme ?? null, ...ngDevMode ? [{ debugName: "forcedTheme" }] : /* istanbul ignore next */ []);
48
+ initialized = false;
49
+ preference = this.storedTheme.asReadonly();
50
+ theme = computed(() => this.forcedTheme() ?? this.storedTheme() ?? this.systemTheme(), ...ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []);
51
+ isDark = computed(() => this.theme() === "dark", ...ngDevMode ? [{ debugName: "isDark" }] : /* istanbul ignore next */ []);
52
+ isForced = computed(() => this.forcedTheme() !== null, ...ngDevMode ? [{ debugName: "isForced" }] : /* istanbul ignore next */ []);
53
+ constructor() {
54
+ const onSystemChange = (event) => {
55
+ this.systemTheme.set(event.matches ? "dark" : "light");
56
+ this.apply();
57
+ };
58
+ this.darkScheme?.addEventListener("change", onSystemChange);
59
+ inject(DestroyRef).onDestroy(() => this.darkScheme?.removeEventListener("change", onSystemChange));
60
+ }
61
+ initialize() {
62
+ if (!this.initialized) {
63
+ this.initialized = true;
64
+ this.storedTheme.set(this.readStoredTheme());
65
+ }
66
+ this.apply();
67
+ }
68
+ toggle() {
69
+ this.setTheme(this.theme() === "dark" ? "light" : "dark");
70
+ }
71
+ setTheme(theme) {
72
+ this.initialized = true;
73
+ this.storedTheme.set(theme);
74
+ this.write(RB_THEME_STORAGE_KEY, theme);
75
+ this.apply();
76
+ }
77
+ clearPreference() {
78
+ this.initialized = true;
79
+ this.storedTheme.set(null);
80
+ this.remove(RB_THEME_STORAGE_KEY);
81
+ this.apply();
82
+ }
83
+ forceTheme(theme) {
84
+ this.forcedTheme.set(theme);
85
+ this.apply();
86
+ }
87
+ apply() {
88
+ const root = this.document.documentElement;
89
+ const theme = this.theme();
90
+ const explicit = this.forcedTheme() ?? this.storedTheme();
91
+ root.dataset["theme"] = theme;
92
+ if (explicit) root.style.colorScheme = explicit;
93
+ else root.style.removeProperty("color-scheme");
94
+ for (const meta of Array.from(this.document.querySelectorAll("meta[name=\"theme-color\"]"))) meta.content = RB_THEME_COLORS[theme];
95
+ }
96
+ readStoredTheme() {
97
+ const stored = this.read(RB_THEME_STORAGE_KEY);
98
+ let theme = isTheme(stored) ? stored : null;
99
+ for (const legacyKey of this.options.legacyStorageKeys ?? []) {
100
+ const legacy = this.read(legacyKey);
101
+ if (theme === null && isTheme(legacy)) {
102
+ theme = legacy;
103
+ this.write(RB_THEME_STORAGE_KEY, legacy);
104
+ }
105
+ if (legacy !== null) this.remove(legacyKey);
106
+ }
107
+ return theme;
108
+ }
109
+ read(key) {
110
+ try {
111
+ return this.window?.localStorage.getItem(key) ?? null;
112
+ } catch {
113
+ return null;
114
+ }
115
+ }
116
+ write(key, value) {
117
+ try {
118
+ this.window?.localStorage.setItem(key, value);
119
+ } catch {}
120
+ }
121
+ remove(key) {
122
+ try {
123
+ this.window?.localStorage.removeItem(key);
124
+ } catch {}
125
+ }
126
+ static ɵfac = i0.ɵɵngDeclareFactory({
127
+ minVersion: "12.0.0",
128
+ version: "22.2.3",
129
+ ngImport: i0,
130
+ type: ThemeService,
131
+ deps: [],
132
+ target: i0.ɵɵFactoryTarget.Injectable
133
+ });
134
+ static ɵprov = i0.ɵɵngDeclareInjectable({
135
+ minVersion: "12.0.0",
136
+ version: "22.2.3",
137
+ ngImport: i0,
138
+ type: ThemeService,
139
+ providedIn: "root"
140
+ });
141
+ };
142
+ i0.ɵɵngDeclareClassMetadata({
143
+ minVersion: "12.0.0",
144
+ version: "22.2.3",
145
+ ngImport: i0,
146
+ type: ThemeService,
147
+ decorators: [{
148
+ type: Injectable,
149
+ args: [{ providedIn: "root" }]
150
+ }],
151
+ ctorParameters: () => []
152
+ });
153
+ const RB_ICON_FONT_SET = "material-symbols-outlined";
154
+ function provideRbDesignSystem(options = {}) {
155
+ return makeEnvironmentProviders([{
156
+ provide: RB_THEME_OPTIONS,
157
+ useValue: options
158
+ }, provideAppInitializer(() => {
159
+ inject(ThemeService).initialize();
160
+ inject(MatIconRegistry).setDefaultFontSetClass(RB_ICON_FONT_SET);
161
+ })]);
162
+ }
163
+ const RB_TONE_ICONS = {
164
+ neutral: null,
165
+ info: "info",
166
+ active: "autorenew",
167
+ success: "check_circle",
168
+ warning: "warning",
169
+ danger: "error"
170
+ };
171
+ const RB_MESSAGE_TONE_LABELS = {
172
+ neutral: null,
173
+ info: "Information",
174
+ success: "Success",
175
+ warning: "Warning",
176
+ danger: "Error"
177
+ };
178
+ const RB_DESIGN_SYSTEM_VERSION = "1.2.3";
179
+ export { RB_BREAKPOINTS, RB_BREAKPOINT_WIDTHS, RB_DESIGN_SYSTEM_VERSION, RB_ICON_FONT_SET, RB_MESSAGE_TONE_LABELS, RB_THEME_COLORS, RB_THEME_OPTIONS, RB_THEME_STORAGE_KEY, RB_TONE_ICONS, ThemeService, provideRbDesignSystem };
180
+
181
+ //# sourceMappingURL=rblabs-dev-axiom-core.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rblabs-dev-axiom-core.mjs","names":[],"sources":["../../../projects/axiom/core/src/breakpoints.ts","../../../projects/axiom/core/src/theme.service.ts","../../../projects/axiom/core/src/provide-design-system.ts","../../../projects/axiom/core/src/tones.ts","../../../projects/axiom/core/src/version.ts"],"sourcesContent":["/** Breakpoint widths (docs/design-system.md, section 8). Mirrors `$breakpoints` in _breakpoints.scss. */\nexport const RB_BREAKPOINT_WIDTHS = {\n xs: '30rem',\n sm: '40rem',\n md: '48rem',\n lg: '60rem',\n xl: '75rem',\n '2xl': '87.5rem',\n} as const;\n\nexport type RbBreakpoint = keyof typeof RB_BREAKPOINT_WIDTHS;\n\n/** Media queries for the CDK `BreakpointObserver`, e.g. `observe(RB_BREAKPOINTS.belowLg)`. */\nexport const RB_BREAKPOINTS = {\n belowXs: '(width < 30rem)',\n belowSm: '(width < 40rem)',\n belowMd: '(width < 48rem)',\n belowLg: '(width < 60rem)',\n belowXl: '(width < 75rem)',\n below2xl: '(width < 87.5rem)',\n aboveXs: '(width >= 30rem)',\n aboveSm: '(width >= 40rem)',\n aboveMd: '(width >= 48rem)',\n aboveLg: '(width >= 60rem)',\n aboveXl: '(width >= 75rem)',\n above2xl: '(width >= 87.5rem)',\n} as const;\n","import { DOCUMENT } from '@angular/common';\nimport { DestroyRef, Injectable, InjectionToken, computed, inject, signal } from '@angular/core';\n\nexport type RbTheme = 'light' | 'dark';\n\n/** localStorage key holding the user's explicit choice (docs/design-system.md, section 11). */\nexport const RB_THEME_STORAGE_KEY = 'rb-theme';\n\n/** `--rb-color-bg` per theme; also the `<meta name=\"theme-color\">` value. */\nexport const RB_THEME_COLORS: Readonly<Record<RbTheme, string>> = {\n light: '#f4f7fb',\n dark: '#08111d',\n};\n\nexport interface RbThemeOptions {\n /**\n * Forces a theme regardless of the stored choice and the OS, without persisting anything. Used by\n * apps that only support one theme until their migration is done. The theme toggle hides itself\n * while a theme is forced.\n */\n forcedTheme?: RbTheme | null;\n /** Storage keys an app used before adopting the kit; a valid value is moved to `rb-theme` once. */\n legacyStorageKeys?: readonly string[];\n}\n\nexport const RB_THEME_OPTIONS = new InjectionToken<RbThemeOptions>('RB_THEME_OPTIONS', {\n providedIn: 'root',\n factory: () => ({}),\n});\n\nconst DARK_SCHEME_QUERY = '(prefers-color-scheme: dark)';\n\nfunction isTheme(value: unknown): value is RbTheme {\n return value === 'light' || value === 'dark';\n}\n\n/**\n * Owns the light/dark theme contract (docs/design-system.md, section 11):\n *\n * - an explicit choice is stored under `rb-theme` and wins over the OS;\n * - without one, the theme follows `prefers-color-scheme` and tracks OS changes live;\n * - the resolved theme is written to `<html>` as `data-theme`, and every\n * `<meta name=\"theme-color\">` is kept in sync;\n * - `color-scheme` is only set inline for an explicit or forced theme; otherwise the stylesheet's\n * `color-scheme: light dark` already follows the OS before any script runs.\n *\n * `provideRbDesignSystem()` calls `initialize()` from an app initializer, before first paint.\n */\n@Injectable({ providedIn: 'root' })\nexport class ThemeService {\n private readonly document = inject(DOCUMENT);\n private readonly options = inject(RB_THEME_OPTIONS);\n private readonly window = this.document.defaultView;\n private readonly darkScheme = this.window?.matchMedia?.(DARK_SCHEME_QUERY) ?? null;\n\n private readonly systemTheme = signal<RbTheme>(this.darkScheme?.matches ? 'dark' : 'light');\n private readonly storedTheme = signal<RbTheme | null>(null);\n private readonly forcedTheme = signal<RbTheme | null>(this.options.forcedTheme ?? null);\n private initialized = false;\n\n /** The user's explicit choice, or `null` while the theme follows the OS. */\n readonly preference = this.storedTheme.asReadonly();\n /** The theme in effect: forced, then stored, then the OS preference. */\n readonly theme = computed<RbTheme>(\n () => this.forcedTheme() ?? this.storedTheme() ?? this.systemTheme(),\n );\n readonly isDark = computed(() => this.theme() === 'dark');\n /** True while a theme is forced; the toggle is hidden then. */\n readonly isForced = computed(() => this.forcedTheme() !== null);\n\n constructor() {\n const onSystemChange = (event: MediaQueryListEvent): void => {\n this.systemTheme.set(event.matches ? 'dark' : 'light');\n this.apply();\n };\n this.darkScheme?.addEventListener('change', onSystemChange);\n inject(DestroyRef).onDestroy(() =>\n this.darkScheme?.removeEventListener('change', onSystemChange),\n );\n }\n\n /** Reads the stored choice and applies the theme to the document. Safe to call more than once. */\n initialize(): void {\n if (!this.initialized) {\n this.initialized = true;\n this.storedTheme.set(this.readStoredTheme());\n }\n this.apply();\n }\n\n /** Switches between light and dark and stores the result as an explicit choice. */\n toggle(): void {\n this.setTheme(this.theme() === 'dark' ? 'light' : 'dark');\n }\n\n /** Stores an explicit choice; OS changes are ignored from now on. */\n setTheme(theme: RbTheme): void {\n this.initialized = true;\n this.storedTheme.set(theme);\n this.write(RB_THEME_STORAGE_KEY, theme);\n this.apply();\n }\n\n /** Forgets the explicit choice, so the theme follows the OS again. */\n clearPreference(): void {\n this.initialized = true;\n this.storedTheme.set(null);\n this.remove(RB_THEME_STORAGE_KEY);\n this.apply();\n }\n\n /** Forces a theme (or releases it with `null`) without touching the stored choice. */\n forceTheme(theme: RbTheme | null): void {\n this.forcedTheme.set(theme);\n this.apply();\n }\n\n private apply(): void {\n const root = this.document.documentElement;\n const theme = this.theme();\n const explicit = this.forcedTheme() ?? this.storedTheme();\n\n root.dataset['theme'] = theme;\n if (explicit) {\n root.style.colorScheme = explicit;\n } else {\n root.style.removeProperty('color-scheme');\n }\n\n for (const meta of Array.from(\n this.document.querySelectorAll<HTMLMetaElement>('meta[name=\"theme-color\"]'),\n )) {\n meta.content = RB_THEME_COLORS[theme];\n }\n }\n\n private readStoredTheme(): RbTheme | null {\n const stored = this.read(RB_THEME_STORAGE_KEY);\n let theme: RbTheme | null = isTheme(stored) ? stored : null;\n\n for (const legacyKey of this.options.legacyStorageKeys ?? []) {\n const legacy = this.read(legacyKey);\n if (theme === null && isTheme(legacy)) {\n theme = legacy;\n this.write(RB_THEME_STORAGE_KEY, legacy);\n }\n if (legacy !== null) this.remove(legacyKey);\n }\n\n return theme;\n }\n\n // Storage can be unavailable (privacy modes, disabled storage); the theme then follows the OS.\n private read(key: string): string | null {\n try {\n return this.window?.localStorage.getItem(key) ?? null;\n } catch {\n return null;\n }\n }\n\n private write(key: string, value: string): void {\n try {\n this.window?.localStorage.setItem(key, value);\n } catch {\n // Ignore: the choice still applies for this session.\n }\n }\n\n private remove(key: string): void {\n try {\n this.window?.localStorage.removeItem(key);\n } catch {\n // Ignore: nothing to clean up without storage.\n }\n }\n}\n","import {\n EnvironmentProviders,\n inject,\n makeEnvironmentProviders,\n provideAppInitializer,\n} from '@angular/core';\nimport { MatIconRegistry } from '@angular/material/icon';\n\nimport { RB_THEME_OPTIONS, RbThemeOptions, ThemeService } from './theme.service';\n\n/** Font set class of the self-hosted Material Symbols subset (docs/design-system.md, section 10). */\nexport const RB_ICON_FONT_SET = 'material-symbols-outlined';\n\nexport type RbDesignSystemOptions = RbThemeOptions;\n\n/**\n * Registers the kit's runtime pieces in `app.config.ts`:\n *\n * - applies the theme before the root component renders (no flash for a stored choice);\n * - makes `material-symbols-outlined` the default `<mat-icon>` font set.\n */\nexport function provideRbDesignSystem(options: RbDesignSystemOptions = {}): EnvironmentProviders {\n return makeEnvironmentProviders([\n { provide: RB_THEME_OPTIONS, useValue: options },\n provideAppInitializer(() => {\n inject(ThemeService).initialize();\n inject(MatIconRegistry).setDefaultFontSetClass(RB_ICON_FONT_SET);\n }),\n ]);\n}\n","/** Tones of `rb-message` (docs/design-system.md, section 15.3). */\nexport type RbMessageTone = 'neutral' | 'info' | 'success' | 'warning' | 'danger';\n\n/** Tones of `rb-status-chip` and page header metrics (15.1, 15.5). `active` means in progress. */\nexport type RbStatusTone = 'neutral' | 'active' | 'success' | 'warning' | 'danger';\n\n/**\n * Default icon per tone, so state is never carried by color alone (section 9.4). Neutral status\n * chips and metrics have no default icon: their label is the whole message.\n */\nexport const RB_TONE_ICONS: Readonly<Record<RbMessageTone | RbStatusTone, string | null>> = {\n neutral: null,\n info: 'info',\n active: 'autorenew',\n success: 'check_circle',\n warning: 'warning',\n danger: 'error',\n};\n\n/** Visually hidden prefix that names a message's tone for screen reader users. */\nexport const RB_MESSAGE_TONE_LABELS: Readonly<Record<RbMessageTone, string | null>> = {\n neutral: null,\n info: 'Information',\n success: 'Success',\n warning: 'Warning',\n danger: 'Error',\n};\n","/**\n * Kit version. The build stamps it from projects/axiom/package.json (scripts/stamp-version.mjs);\n * source and development builds show the placeholder.\n */\nexport const RB_DESIGN_SYSTEM_VERSION: string = '1.2.3';\n"],"mappings":"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"}