@joanroucoux/cairn-ui 0.5.0 → 0.6.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/fesm2022/joanroucoux-cairn-ui.mjs +1284 -467
- package/fesm2022/joanroucoux-cairn-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/styles/tokens.css +18 -6
- package/types/joanroucoux-cairn-ui.d.ts +274 -56
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, signal, input, inject, LOCALE_ID, booleanAttribute, computed, Component, output, ElementRef, DestroyRef,
|
|
3
|
-
import { pie, arc, curveMonotoneX, line } from 'd3-shape';
|
|
2
|
+
import { InjectionToken, signal, input, inject, LOCALE_ID, booleanAttribute, computed, Component, output, ElementRef, DestroyRef, forwardRef, Directive, model, viewChildren, afterRenderEffect, contentChild, viewChild, afterNextRender, effect, contentChildren } from '@angular/core';
|
|
4
3
|
import { scaleLinear } from 'd3-scale';
|
|
4
|
+
import { curveMonotoneX, line } from 'd3-shape';
|
|
5
5
|
|
|
6
6
|
const MINUS = '−';
|
|
7
7
|
const EM_DASH = '—';
|
|
@@ -108,9 +108,125 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
108
108
|
}]
|
|
109
109
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], currency: [{ type: i0.Input, args: [{ isSignal: true, alias: "currency", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], signed: [{ type: i0.Input, args: [{ isSignal: true, alias: "signed", required: false }] }], fractionDigits: [{ type: i0.Input, args: [{ isSignal: true, alias: "fractionDigits", required: false }] }], numeric: [{ type: i0.Input, args: [{ isSignal: true, alias: "numeric", required: false }] }], whenMasked: [{ type: i0.Input, args: [{ isSignal: true, alias: "whenMasked", required: false }] }] } });
|
|
110
110
|
|
|
111
|
+
const ALERT_VARIANTS = ['error', 'warning'];
|
|
112
|
+
const BASE_CLASSES$7 = 'flex items-start gap-2.5 text-left text-label';
|
|
113
|
+
const VARIANT_CLASSES$3 = {
|
|
114
|
+
error: 'rounded-control bg-(--card) px-3.5 py-3 shadow-[inset_0_0_0_1px_var(--border)]',
|
|
115
|
+
warning: 'text-(--foreground)',
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Inline message explaining a failure or a consequence: an icon, an optional heading and a text.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* <ui-alert heading="Sign-in failed">Try again.</ui-alert>
|
|
122
|
+
*/
|
|
123
|
+
class UiAlert {
|
|
124
|
+
variant = input('error', /* @ts-ignore */
|
|
125
|
+
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
126
|
+
heading = input(/* @ts-ignore */
|
|
127
|
+
...(ngDevMode ? [undefined, { debugName: "heading" }] : /* istanbul ignore next */ []));
|
|
128
|
+
classes = computed(() => `${BASE_CLASSES$7} ${VARIANT_CLASSES$3[this.variant()]}`, /* @ts-ignore */
|
|
129
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
130
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAlert, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
131
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiAlert, isStandalone: true, selector: "ui-alert", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.role": "variant() === 'warning' ? 'status' : 'alert'" } }, ngImport: i0, template: `
|
|
132
|
+
@if (variant() === 'warning') {
|
|
133
|
+
<svg
|
|
134
|
+
aria-hidden="true"
|
|
135
|
+
class="mt-px block flex-none stroke-(--negative)"
|
|
136
|
+
fill="none"
|
|
137
|
+
height="18"
|
|
138
|
+
stroke-linecap="round"
|
|
139
|
+
stroke-linejoin="round"
|
|
140
|
+
stroke-width="1.75"
|
|
141
|
+
viewBox="0 0 24 24"
|
|
142
|
+
width="18"
|
|
143
|
+
>
|
|
144
|
+
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" />
|
|
145
|
+
<path d="M12 9v4" />
|
|
146
|
+
<path d="M12 17h.01" />
|
|
147
|
+
</svg>
|
|
148
|
+
} @else {
|
|
149
|
+
<svg
|
|
150
|
+
aria-hidden="true"
|
|
151
|
+
class="block flex-none stroke-(--negative)"
|
|
152
|
+
fill="none"
|
|
153
|
+
height="18"
|
|
154
|
+
stroke-linecap="round"
|
|
155
|
+
stroke-linejoin="round"
|
|
156
|
+
stroke-width="1.75"
|
|
157
|
+
viewBox="0 0 24 24"
|
|
158
|
+
width="18"
|
|
159
|
+
[class.mt-px]="heading()"
|
|
160
|
+
>
|
|
161
|
+
<circle cx="12" cy="12" r="10" />
|
|
162
|
+
<line x1="12" x2="12" y1="8" y2="12" />
|
|
163
|
+
<line x1="12" x2="12.01" y1="16" y2="16" />
|
|
164
|
+
</svg>
|
|
165
|
+
}
|
|
166
|
+
<div class="flex flex-col gap-0.5">
|
|
167
|
+
@if (heading()) {
|
|
168
|
+
<span class="font-medium">{{ heading() }}</span>
|
|
169
|
+
}
|
|
170
|
+
<span class="text-pretty" [class.text-(--muted-foreground)]="heading()"><ng-content /></span>
|
|
171
|
+
</div>
|
|
172
|
+
`, isInline: true });
|
|
173
|
+
}
|
|
174
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAlert, decorators: [{
|
|
175
|
+
type: Component,
|
|
176
|
+
args: [{
|
|
177
|
+
selector: 'ui-alert',
|
|
178
|
+
template: `
|
|
179
|
+
@if (variant() === 'warning') {
|
|
180
|
+
<svg
|
|
181
|
+
aria-hidden="true"
|
|
182
|
+
class="mt-px block flex-none stroke-(--negative)"
|
|
183
|
+
fill="none"
|
|
184
|
+
height="18"
|
|
185
|
+
stroke-linecap="round"
|
|
186
|
+
stroke-linejoin="round"
|
|
187
|
+
stroke-width="1.75"
|
|
188
|
+
viewBox="0 0 24 24"
|
|
189
|
+
width="18"
|
|
190
|
+
>
|
|
191
|
+
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" />
|
|
192
|
+
<path d="M12 9v4" />
|
|
193
|
+
<path d="M12 17h.01" />
|
|
194
|
+
</svg>
|
|
195
|
+
} @else {
|
|
196
|
+
<svg
|
|
197
|
+
aria-hidden="true"
|
|
198
|
+
class="block flex-none stroke-(--negative)"
|
|
199
|
+
fill="none"
|
|
200
|
+
height="18"
|
|
201
|
+
stroke-linecap="round"
|
|
202
|
+
stroke-linejoin="round"
|
|
203
|
+
stroke-width="1.75"
|
|
204
|
+
viewBox="0 0 24 24"
|
|
205
|
+
width="18"
|
|
206
|
+
[class.mt-px]="heading()"
|
|
207
|
+
>
|
|
208
|
+
<circle cx="12" cy="12" r="10" />
|
|
209
|
+
<line x1="12" x2="12" y1="8" y2="12" />
|
|
210
|
+
<line x1="12" x2="12.01" y1="16" y2="16" />
|
|
211
|
+
</svg>
|
|
212
|
+
}
|
|
213
|
+
<div class="flex flex-col gap-0.5">
|
|
214
|
+
@if (heading()) {
|
|
215
|
+
<span class="font-medium">{{ heading() }}</span>
|
|
216
|
+
}
|
|
217
|
+
<span class="text-pretty" [class.text-(--muted-foreground)]="heading()"><ng-content /></span>
|
|
218
|
+
</div>
|
|
219
|
+
`,
|
|
220
|
+
host: {
|
|
221
|
+
'[class]': 'classes()',
|
|
222
|
+
'[attr.role]': "variant() === 'warning' ? 'status' : 'alert'",
|
|
223
|
+
},
|
|
224
|
+
}]
|
|
225
|
+
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }] } });
|
|
226
|
+
|
|
111
227
|
/** Available async block states. `AsyncState` is derived from this tuple. */
|
|
112
228
|
const ASYNC_STATES = ['loading', 'error', 'empty', 'ready'];
|
|
113
|
-
const RETRY_BUTTON_CLASSES = 'mt-2 relative inline-flex items-center justify-center gap-2 rounded-control font-medium whitespace-nowrap cursor-pointer select-none touch-manipulation transition-[transform,background-color,opacity] duration-(--duration-press) ease-out active:scale-(--press-scale) focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring) min-h-(--row-min)
|
|
229
|
+
const RETRY_BUTTON_CLASSES = 'mt-2 relative inline-flex items-center justify-center gap-2 rounded-control font-medium whitespace-nowrap cursor-pointer select-none touch-manipulation transition-[transform,background-color,opacity] duration-(--duration-press) ease-out active:scale-(--press-scale) focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring) min-h-(--row-min) pl-3 pr-4 text-label bg-(--card) text-(--foreground) shadow-[inset_0_0_0_1px_var(--border)] hover:bg-(--glow)';
|
|
114
230
|
/**
|
|
115
231
|
* The three states of a block that depends on a service call, next to the ready content.
|
|
116
232
|
*
|
|
@@ -141,12 +257,25 @@ class UiAsync {
|
|
|
141
257
|
@case ('error') {
|
|
142
258
|
<div
|
|
143
259
|
aria-live="polite"
|
|
144
|
-
class="rounded-control flex flex-col items-start gap-1 bg-(--elevated) p-
|
|
260
|
+
class="rounded-control flex flex-col items-start gap-1 bg-(--elevated) p-4"
|
|
145
261
|
role="alert"
|
|
146
262
|
>
|
|
147
263
|
<span class="text-body font-medium">{{ errorTitle() }}</span>
|
|
148
264
|
<span class="text-label text-(--muted-foreground)">{{ errorMessage() }}</span>
|
|
149
265
|
<button type="button" [class]="retryButtonClasses" (click)="retry.emit()">
|
|
266
|
+
<svg
|
|
267
|
+
aria-hidden="true"
|
|
268
|
+
class="block flex-none fill-none stroke-current"
|
|
269
|
+
height="18"
|
|
270
|
+
stroke-linecap="round"
|
|
271
|
+
stroke-linejoin="round"
|
|
272
|
+
stroke-width="1.75"
|
|
273
|
+
viewBox="0 0 24 24"
|
|
274
|
+
width="18"
|
|
275
|
+
>
|
|
276
|
+
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
|
277
|
+
<path d="M21 3v5h-5" />
|
|
278
|
+
</svg>
|
|
150
279
|
{{ retryLabel() }}
|
|
151
280
|
</button>
|
|
152
281
|
</div>
|
|
@@ -172,12 +301,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
172
301
|
@case ('error') {
|
|
173
302
|
<div
|
|
174
303
|
aria-live="polite"
|
|
175
|
-
class="rounded-control flex flex-col items-start gap-1 bg-(--elevated) p-
|
|
304
|
+
class="rounded-control flex flex-col items-start gap-1 bg-(--elevated) p-4"
|
|
176
305
|
role="alert"
|
|
177
306
|
>
|
|
178
307
|
<span class="text-body font-medium">{{ errorTitle() }}</span>
|
|
179
308
|
<span class="text-label text-(--muted-foreground)">{{ errorMessage() }}</span>
|
|
180
309
|
<button type="button" [class]="retryButtonClasses" (click)="retry.emit()">
|
|
310
|
+
<svg
|
|
311
|
+
aria-hidden="true"
|
|
312
|
+
class="block flex-none fill-none stroke-current"
|
|
313
|
+
height="18"
|
|
314
|
+
stroke-linecap="round"
|
|
315
|
+
stroke-linejoin="round"
|
|
316
|
+
stroke-width="1.75"
|
|
317
|
+
viewBox="0 0 24 24"
|
|
318
|
+
width="18"
|
|
319
|
+
>
|
|
320
|
+
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
|
321
|
+
<path d="M21 3v5h-5" />
|
|
322
|
+
</svg>
|
|
181
323
|
{{ retryLabel() }}
|
|
182
324
|
</button>
|
|
183
325
|
</div>
|
|
@@ -197,11 +339,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
197
339
|
}], propDecorators: { state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: true }] }], errorTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorTitle", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], retryLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "retryLabel", required: false }] }], retry: [{ type: i0.Output, args: ["retry"] }] } });
|
|
198
340
|
|
|
199
341
|
/** Available avatar sizes. `AvatarSize` is derived from this tuple. */
|
|
200
|
-
const AVATAR_SIZES = ['sm', 'md'];
|
|
201
|
-
const BASE_CLASSES$6 = 'inline-flex items-center justify-center rounded-pill
|
|
202
|
-
const SIZE_CLASSES$
|
|
342
|
+
const AVATAR_SIZES = ['sm', 'md', 'lg'];
|
|
343
|
+
const BASE_CLASSES$6 = 'inline-flex items-center justify-center rounded-pill bg-(--muted) font-medium tabular-nums';
|
|
344
|
+
const SIZE_CLASSES$3 = {
|
|
203
345
|
sm: 'size-8 text-caption',
|
|
204
|
-
md: 'size-
|
|
346
|
+
md: 'size-[34px] text-label',
|
|
347
|
+
lg: 'size-14 text-title',
|
|
205
348
|
};
|
|
206
349
|
/**
|
|
207
350
|
* Initials in a disc, standing in for a person. Single-user application: there is exactly one.
|
|
@@ -216,7 +359,7 @@ class UiAvatar {
|
|
|
216
359
|
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
217
360
|
size = input('md', /* @ts-ignore */
|
|
218
361
|
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
219
|
-
classes = computed(() => `${BASE_CLASSES$6} ${SIZE_CLASSES$
|
|
362
|
+
classes = computed(() => `${BASE_CLASSES$6} ${SIZE_CLASSES$3[this.size()]}`, /* @ts-ignore */
|
|
220
363
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
221
364
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAvatar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
222
365
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: UiAvatar, isStandalone: true, selector: "ui-avatar", inputs: { initials: { classPropertyName: "initials", publicName: "initials", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "img" }, properties: { "attr.aria-label": "label()", "class": "classes()" } }, ngImport: i0, template: '<span aria-hidden="true">{{ initials() }}</span>', isInline: true });
|
|
@@ -236,7 +379,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
236
379
|
|
|
237
380
|
/** Available badge variants. `BadgeVariant` is derived from this tuple. */
|
|
238
381
|
const BADGE_VARIANTS = ['neutral', 'outline'];
|
|
239
|
-
const
|
|
382
|
+
const BADGE_SIZES = ['md', 'sm'];
|
|
383
|
+
const BASE_CLASSES$5 = 'inline-flex items-center rounded-pill text-caption font-medium';
|
|
384
|
+
const SIZE_CLASSES$2 = {
|
|
385
|
+
md: 'h-6 px-2.5',
|
|
386
|
+
sm: 'h-[22px] px-2',
|
|
387
|
+
};
|
|
240
388
|
const VARIANT_CLASSES$2 = {
|
|
241
389
|
neutral: 'bg-(--muted) text-(--foreground)',
|
|
242
390
|
outline: 'shadow-[inset_0_0_0_1px_var(--border)] text-(--foreground)',
|
|
@@ -250,10 +398,12 @@ const VARIANT_CLASSES$2 = {
|
|
|
250
398
|
class UiBadge {
|
|
251
399
|
variant = input('neutral', /* @ts-ignore */
|
|
252
400
|
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
253
|
-
|
|
401
|
+
size = input('md', /* @ts-ignore */
|
|
402
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
403
|
+
classes = computed(() => `${BASE_CLASSES$5} ${SIZE_CLASSES$2[this.size()]} ${VARIANT_CLASSES$2[this.variant()]}`, /* @ts-ignore */
|
|
254
404
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
255
405
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiBadge, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
256
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: UiBadge, isStandalone: true, selector: "ui-badge", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: '<ng-content />', isInline: true });
|
|
406
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: UiBadge, isStandalone: true, selector: "ui-badge", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: '<ng-content />', isInline: true });
|
|
257
407
|
}
|
|
258
408
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiBadge, decorators: [{
|
|
259
409
|
type: Component,
|
|
@@ -264,24 +414,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
264
414
|
'[class]': 'classes()',
|
|
265
415
|
},
|
|
266
416
|
}]
|
|
267
|
-
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }] } });
|
|
417
|
+
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
268
418
|
|
|
269
419
|
/** Available button variants. `ButtonVariant` is derived from this tuple. */
|
|
270
420
|
const BUTTON_VARIANTS = ['primary', 'outline', 'ghost', 'destructive'];
|
|
271
|
-
/** Available button sizes.
|
|
272
|
-
const BUTTON_SIZES = ['md', 'lg', 'xl', 'icon'];
|
|
273
|
-
const BASE_CLASSES$4 = 'relative inline-flex items-center justify-center
|
|
421
|
+
/** Available button sizes. */
|
|
422
|
+
const BUTTON_SIZES = ['md', 'lg', 'xl', 'xxl', 'icon'];
|
|
423
|
+
const BASE_CLASSES$4 = 'relative inline-flex items-center justify-center rounded-control font-medium whitespace-nowrap cursor-pointer select-none touch-manipulation transition-[transform,background-color,opacity] duration-(--duration-press) ease-out active:scale-(--press-scale) focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring) disabled:pointer-events-none disabled:opacity-40 aria-disabled:not-aria-busy:opacity-40';
|
|
274
424
|
const VARIANT_CLASSES$1 = {
|
|
275
|
-
primary: 'bg-(--primary) text-(--primary-foreground) hover:
|
|
276
|
-
outline: 'bg-(--card) text-(--foreground) shadow-[inset_0_0_0_1px_var(--border)] hover:bg-(--glow)',
|
|
277
|
-
ghost: 'bg-transparent text-(--foreground) hover:bg-(--glow)',
|
|
278
|
-
destructive: 'bg-(--destructive) text-(--destructive-foreground)
|
|
425
|
+
primary: 'bg-(--primary) text-(--primary-foreground) hover:bg-(--primary-to)',
|
|
426
|
+
outline: 'bg-(--card) text-(--foreground) shadow-[inset_0_0_0_1px_var(--border)] hover:bg-(--glow) active:bg-(--soft)',
|
|
427
|
+
ghost: 'bg-transparent text-(--foreground) hover:bg-(--glow) active:bg-(--soft)',
|
|
428
|
+
destructive: 'bg-(--destructive) text-(--destructive-foreground)',
|
|
279
429
|
};
|
|
280
|
-
const SIZE_CLASSES = {
|
|
281
|
-
md: 'min-h-(--row-min) px-4 text-label',
|
|
282
|
-
lg: 'h-11 px-[18px] text-label',
|
|
283
|
-
xl: 'h-[50px] px-6 text-body',
|
|
284
|
-
|
|
430
|
+
const SIZE_CLASSES$1 = {
|
|
431
|
+
md: 'min-h-(--row-min) gap-2 px-4 text-label has-[>svg:first-child]:pl-3',
|
|
432
|
+
lg: 'h-11 gap-2 px-[18px] text-label',
|
|
433
|
+
xl: 'h-[50px] gap-2 px-6 text-body',
|
|
434
|
+
xxl: 'h-[52px] gap-2.5 px-6 text-body',
|
|
435
|
+
icon: 'size-(--row-min) gap-2 p-0',
|
|
285
436
|
};
|
|
286
437
|
/**
|
|
287
438
|
* Styled native button or anchor, applied as an attribute so the host keeps every native behavior.
|
|
@@ -296,7 +447,7 @@ class UiButton {
|
|
|
296
447
|
size = input('md', /* @ts-ignore */
|
|
297
448
|
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
298
449
|
loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
299
|
-
classes = computed(() => `${BASE_CLASSES$4} ${VARIANT_CLASSES$1[this.variant()]} ${SIZE_CLASSES[this.size()]}${this.loading() ? ' pointer-events-none opacity-70' : ''}`, /* @ts-ignore */
|
|
450
|
+
classes = computed(() => `${BASE_CLASSES$4} ${VARIANT_CLASSES$1[this.variant()]} ${SIZE_CLASSES$1[this.size()]}${this.loading() ? ' pointer-events-none opacity-70' : ''}`, /* @ts-ignore */
|
|
300
451
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
301
452
|
constructor() {
|
|
302
453
|
const host = inject(ElementRef).nativeElement;
|
|
@@ -344,16 +495,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
344
495
|
/** Available card variants. `CardVariant` is derived from this tuple. */
|
|
345
496
|
const CARD_VARIANTS = ['default', 'elevated'];
|
|
346
497
|
/** Available card paddings. `CardPadding` is derived from this tuple. */
|
|
347
|
-
const CARD_PADDINGS = ['none', 'sm', 'md'];
|
|
348
|
-
const BASE_CLASSES$3 = 'block rounded-container
|
|
498
|
+
const CARD_PADDINGS = ['none', 'sm', 'md', 'list'];
|
|
499
|
+
const BASE_CLASSES$3 = 'block rounded-container';
|
|
349
500
|
const VARIANT_CLASSES = {
|
|
350
|
-
default: 'bg-(--card)
|
|
351
|
-
elevated: 'bg-(--elevated)
|
|
501
|
+
default: 'bg-(--card) shadow-[inset_0_0_0_1px_var(--border)] text-(--card-foreground)',
|
|
502
|
+
elevated: 'bg-(--elevated) shadow-[inset_0_0_0_1px_var(--hairline)] text-(--foreground)',
|
|
352
503
|
};
|
|
353
|
-
const PADDING_CLASSES = {
|
|
504
|
+
const PADDING_CLASSES$1 = {
|
|
354
505
|
none: 'p-0',
|
|
355
506
|
sm: 'p-3',
|
|
356
|
-
md: 'p-
|
|
507
|
+
md: 'p-(--inset-card)',
|
|
508
|
+
list: 'px-2 py-3',
|
|
357
509
|
};
|
|
358
510
|
/**
|
|
359
511
|
* Surface that groups related content: a summary block, a table, a side panel.
|
|
@@ -366,7 +518,7 @@ class UiCard {
|
|
|
366
518
|
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
367
519
|
padding = input('md', /* @ts-ignore */
|
|
368
520
|
...(ngDevMode ? [{ debugName: "padding" }] : /* istanbul ignore next */ []));
|
|
369
|
-
classes = computed(() => `${BASE_CLASSES$3} ${VARIANT_CLASSES[this.variant()]} ${PADDING_CLASSES[this.padding()]}`, /* @ts-ignore */
|
|
521
|
+
classes = computed(() => `${BASE_CLASSES$3} ${VARIANT_CLASSES[this.variant()]} ${PADDING_CLASSES$1[this.padding()]}`, /* @ts-ignore */
|
|
370
522
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
371
523
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiCard, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
372
524
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: UiCard, isStandalone: true, selector: "ui-card", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, padding: { classPropertyName: "padding", publicName: "padding", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: '<ng-content />', isInline: true });
|
|
@@ -392,6 +544,244 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
392
544
|
*/
|
|
393
545
|
const UI_CONTROL = new InjectionToken('UI_CONTROL');
|
|
394
546
|
|
|
547
|
+
/** Available control sizes. `md` is the 44/40px touch target. */
|
|
548
|
+
const CONTROL_SIZES = ['sm', 'md'];
|
|
549
|
+
const CONTROL_BASE_CLASSES = 'w-full rounded-control px-3 text-body text-(--foreground) shadow-[inset_0_0_0_1px_var(--border)] transition-shadow duration-(--duration-fast) ease-out placeholder:text-(--muted-foreground) focus-visible:shadow-[inset_0_0_0_2px_var(--ring)] aria-invalid:shadow-[inset_0_0_0_2px_var(--negative)] disabled:cursor-not-allowed disabled:opacity-50';
|
|
550
|
+
const CONTROL_SURFACES = ['background', 'card'];
|
|
551
|
+
const CONTROL_SURFACE_CLASSES = {
|
|
552
|
+
background: 'bg-(--background)',
|
|
553
|
+
card: 'bg-(--card)',
|
|
554
|
+
};
|
|
555
|
+
const CONTROL_SIZE_CLASSES = {
|
|
556
|
+
sm: 'h-9',
|
|
557
|
+
md: 'min-h-(--row-min)',
|
|
558
|
+
};
|
|
559
|
+
/**
|
|
560
|
+
* Styled native text input. A directive (not a wrapper component) so the host
|
|
561
|
+
* stays a plain <input>: every forms flavor (ngModel, reactive, signal forms)
|
|
562
|
+
* and every native attribute keep working without any plumbing.
|
|
563
|
+
*
|
|
564
|
+
* Declares the `errors` and `touched` inputs Angular's `[formField]` fills, so a `ui-field` around
|
|
565
|
+
* it can show the message without any binding here.
|
|
566
|
+
*
|
|
567
|
+
* @example
|
|
568
|
+
* <input uiInput type="email" placeholder="you@example.com" />
|
|
569
|
+
*/
|
|
570
|
+
class UiInput {
|
|
571
|
+
size = input('md', /* @ts-ignore */
|
|
572
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
573
|
+
surface = input('background', /* @ts-ignore */
|
|
574
|
+
...(ngDevMode ? [{ debugName: "surface" }] : /* istanbul ignore next */ []));
|
|
575
|
+
errors = input([], /* @ts-ignore */
|
|
576
|
+
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
577
|
+
touched = input(false, /* @ts-ignore */
|
|
578
|
+
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
579
|
+
classes = computed(() => `${CONTROL_BASE_CLASSES} ${CONTROL_SURFACE_CLASSES[this.surface()]} ${CONTROL_SIZE_CLASSES[this.size()]}`, /* @ts-ignore */
|
|
580
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
581
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiInput, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
582
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiInput, isStandalone: true, selector: "input[uiInput]", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, surface: { classPropertyName: "surface", publicName: "surface", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, providers: [{ provide: UI_CONTROL, useExisting: forwardRef(() => UiInput) }], ngImport: i0 });
|
|
583
|
+
}
|
|
584
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiInput, decorators: [{
|
|
585
|
+
type: Directive,
|
|
586
|
+
args: [{
|
|
587
|
+
selector: 'input[uiInput]',
|
|
588
|
+
host: {
|
|
589
|
+
'[class]': 'classes()',
|
|
590
|
+
},
|
|
591
|
+
providers: [{ provide: UI_CONTROL, useExisting: forwardRef(() => UiInput) }],
|
|
592
|
+
}]
|
|
593
|
+
}], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], surface: [{ type: i0.Input, args: [{ isSignal: true, alias: "surface", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }] } });
|
|
594
|
+
/**
|
|
595
|
+
* Styled native textarea. Lives beside the input because it shares every one of its
|
|
596
|
+
* classes; it takes no size, since a textarea grows from a floor instead of sitting
|
|
597
|
+
* at a fixed height.
|
|
598
|
+
*
|
|
599
|
+
* Declares the `errors` and `touched` inputs Angular's `[formField]` fills, so a `ui-field` around
|
|
600
|
+
* it can show the message without any binding here.
|
|
601
|
+
*
|
|
602
|
+
* @example
|
|
603
|
+
* <textarea uiTextarea maxlength="280"></textarea>
|
|
604
|
+
*/
|
|
605
|
+
class UiTextarea {
|
|
606
|
+
errors = input([], /* @ts-ignore */
|
|
607
|
+
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
608
|
+
touched = input(false, /* @ts-ignore */
|
|
609
|
+
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
610
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTextarea, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
611
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiTextarea, isStandalone: true, selector: "textarea[uiTextarea]", inputs: { errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "w-full rounded-control px-3 text-body text-(--foreground) shadow-[inset_0_0_0_1px_var(--border)] transition-shadow duration-(--duration-fast) ease-out placeholder:text-(--muted-foreground) focus-visible:shadow-[inset_0_0_0_2px_var(--ring)] aria-invalid:shadow-[inset_0_0_0_2px_var(--negative)] disabled:cursor-not-allowed disabled:opacity-50 bg-(--background) min-h-24 py-2" }, providers: [{ provide: UI_CONTROL, useExisting: forwardRef(() => UiTextarea) }], ngImport: i0 });
|
|
612
|
+
}
|
|
613
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTextarea, decorators: [{
|
|
614
|
+
type: Directive,
|
|
615
|
+
args: [{
|
|
616
|
+
selector: 'textarea[uiTextarea]',
|
|
617
|
+
host: {
|
|
618
|
+
class: `${CONTROL_BASE_CLASSES} bg-(--background) min-h-24 py-2`,
|
|
619
|
+
},
|
|
620
|
+
providers: [{ provide: UI_CONTROL, useExisting: forwardRef(() => UiTextarea) }],
|
|
621
|
+
}]
|
|
622
|
+
}], propDecorators: { errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }] } });
|
|
623
|
+
|
|
624
|
+
const CHIP_CLASSES = 'h-10 px-3.5 pointer-fine:h-8 pointer-fine:px-3 rounded-pill text-label font-medium cursor-pointer transition-transform duration-(--duration-press) ease-out active:scale-(--press-scale) disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring)';
|
|
625
|
+
const SELECTED_CLASSES$2 = 'bg-(--primary) text-(--primary-foreground)';
|
|
626
|
+
const UNSELECTED_CLASSES$1 = 'text-(--foreground) shadow-[inset_0_0_0_1px_var(--border)]';
|
|
627
|
+
const nextId$3 = (() => {
|
|
628
|
+
let count = 0;
|
|
629
|
+
return () => `ui-choice-chips-${++count}`;
|
|
630
|
+
})();
|
|
631
|
+
/**
|
|
632
|
+
* Exclusive choice among a handful of named options, shown as wrapping pills: an account envelope,
|
|
633
|
+
* a category, a frequency. Binds to Signal Forms with `[formField]`.
|
|
634
|
+
*
|
|
635
|
+
* @example
|
|
636
|
+
* <ui-choice-chips label="Envelope" [options]="envelopes" [(value)]="envelope" />
|
|
637
|
+
*
|
|
638
|
+
* @example
|
|
639
|
+
* <ui-choice-chips label="Envelope" [options]="envelopes" [formField]="form.envelope" />
|
|
640
|
+
*/
|
|
641
|
+
class UiChoiceChips {
|
|
642
|
+
options = input.required(/* @ts-ignore */
|
|
643
|
+
...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
|
|
644
|
+
value = model.required(/* @ts-ignore */
|
|
645
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
646
|
+
label = input(/* @ts-ignore */
|
|
647
|
+
...(ngDevMode ? [undefined, { debugName: "label" }] : /* istanbul ignore next */ []));
|
|
648
|
+
ariaLabel = input(/* @ts-ignore */
|
|
649
|
+
...(ngDevMode ? [undefined, { debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
650
|
+
ariaLabelledby = input(/* @ts-ignore */
|
|
651
|
+
...(ngDevMode ? [undefined, { debugName: "ariaLabelledby" }] : /* istanbul ignore next */ []));
|
|
652
|
+
surface = input('background', /* @ts-ignore */
|
|
653
|
+
...(ngDevMode ? [{ debugName: "surface" }] : /* istanbul ignore next */ []));
|
|
654
|
+
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
655
|
+
errors = input([], /* @ts-ignore */
|
|
656
|
+
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
657
|
+
invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
658
|
+
required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
659
|
+
touched = input(false, /* @ts-ignore */
|
|
660
|
+
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
661
|
+
touch = output();
|
|
662
|
+
labelId = nextId$3();
|
|
663
|
+
#host = inject(ElementRef);
|
|
664
|
+
radios = viewChildren('radio', /* @ts-ignore */
|
|
665
|
+
...(ngDevMode ? [{ debugName: "radios" }] : /* istanbul ignore next */ []));
|
|
666
|
+
labelledBy = computed(() => this.ariaLabelledby() ?? (this.label() ? this.labelId : null), /* @ts-ignore */
|
|
667
|
+
...(ngDevMode ? [{ debugName: "labelledBy" }] : /* istanbul ignore next */ []));
|
|
668
|
+
chipClasses(optionValue) {
|
|
669
|
+
const state = optionValue === this.value()
|
|
670
|
+
? SELECTED_CLASSES$2
|
|
671
|
+
: `${CONTROL_SURFACE_CLASSES[this.surface()]} ${UNSELECTED_CLASSES$1}`;
|
|
672
|
+
return `${CHIP_CLASSES} ${state}`;
|
|
673
|
+
}
|
|
674
|
+
tabIndexFor(optionValue) {
|
|
675
|
+
const opts = this.options();
|
|
676
|
+
const tabStopValue = opts.some((option) => option.value === this.value()) ? this.value() : opts[0]?.value;
|
|
677
|
+
return optionValue === tabStopValue ? 0 : -1;
|
|
678
|
+
}
|
|
679
|
+
select(optionValue) {
|
|
680
|
+
this.value.set(optionValue);
|
|
681
|
+
}
|
|
682
|
+
onFocusOut(event) {
|
|
683
|
+
if (!this.#host.nativeElement.contains(event.relatedTarget)) {
|
|
684
|
+
this.touch.emit();
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
onKeydown(event, index) {
|
|
688
|
+
const opts = this.options();
|
|
689
|
+
const target = {
|
|
690
|
+
ArrowRight: index + 1,
|
|
691
|
+
ArrowDown: index + 1,
|
|
692
|
+
ArrowLeft: index - 1,
|
|
693
|
+
ArrowUp: index - 1,
|
|
694
|
+
Home: 0,
|
|
695
|
+
End: opts.length - 1,
|
|
696
|
+
}[event.key];
|
|
697
|
+
if (target === undefined) {
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
event.preventDefault();
|
|
701
|
+
const nextIndex = ((target % opts.length) + opts.length) % opts.length;
|
|
702
|
+
this.value.set(opts[nextIndex].value);
|
|
703
|
+
this.radios()[nextIndex].nativeElement.focus();
|
|
704
|
+
}
|
|
705
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiChoiceChips, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
706
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiChoiceChips, isStandalone: true, selector: "ui-choice-chips", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "ariaLabelledby", isSignal: true, isRequired: false, transformFunction: null }, surface: { classPropertyName: "surface", publicName: "surface", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, providers: [{ provide: UI_CONTROL, useExisting: forwardRef(() => UiChoiceChips) }], viewQueries: [{ propertyName: "radios", predicate: ["radio"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
707
|
+
<div
|
|
708
|
+
class="flex flex-col gap-1.5"
|
|
709
|
+
role="radiogroup"
|
|
710
|
+
[attr.aria-invalid]="invalid() || null"
|
|
711
|
+
[attr.aria-label]="ariaLabel() ?? null"
|
|
712
|
+
[attr.aria-labelledby]="labelledBy()"
|
|
713
|
+
[attr.aria-required]="required() || null"
|
|
714
|
+
(focusout)="onFocusOut($event)"
|
|
715
|
+
>
|
|
716
|
+
@if (label()) {
|
|
717
|
+
<span class="text-label leading-[17px] font-medium text-(--muted-foreground)" [id]="labelId">{{
|
|
718
|
+
label()
|
|
719
|
+
}}</span>
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
<div class="flex flex-wrap gap-1.5">
|
|
723
|
+
@for (option of options(); track option.value; let index = $index) {
|
|
724
|
+
<button
|
|
725
|
+
#radio
|
|
726
|
+
role="radio"
|
|
727
|
+
type="button"
|
|
728
|
+
[attr.aria-checked]="option.value === value()"
|
|
729
|
+
[attr.tabindex]="tabIndexFor(option.value)"
|
|
730
|
+
[class]="chipClasses(option.value)"
|
|
731
|
+
[disabled]="disabled()"
|
|
732
|
+
(click)="select(option.value)"
|
|
733
|
+
(keydown)="onKeydown($event, index)"
|
|
734
|
+
>
|
|
735
|
+
{{ option.label }}
|
|
736
|
+
</button>
|
|
737
|
+
}
|
|
738
|
+
</div>
|
|
739
|
+
</div>
|
|
740
|
+
`, isInline: true });
|
|
741
|
+
}
|
|
742
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiChoiceChips, decorators: [{
|
|
743
|
+
type: Component,
|
|
744
|
+
args: [{
|
|
745
|
+
selector: 'ui-choice-chips',
|
|
746
|
+
template: `
|
|
747
|
+
<div
|
|
748
|
+
class="flex flex-col gap-1.5"
|
|
749
|
+
role="radiogroup"
|
|
750
|
+
[attr.aria-invalid]="invalid() || null"
|
|
751
|
+
[attr.aria-label]="ariaLabel() ?? null"
|
|
752
|
+
[attr.aria-labelledby]="labelledBy()"
|
|
753
|
+
[attr.aria-required]="required() || null"
|
|
754
|
+
(focusout)="onFocusOut($event)"
|
|
755
|
+
>
|
|
756
|
+
@if (label()) {
|
|
757
|
+
<span class="text-label leading-[17px] font-medium text-(--muted-foreground)" [id]="labelId">{{
|
|
758
|
+
label()
|
|
759
|
+
}}</span>
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
<div class="flex flex-wrap gap-1.5">
|
|
763
|
+
@for (option of options(); track option.value; let index = $index) {
|
|
764
|
+
<button
|
|
765
|
+
#radio
|
|
766
|
+
role="radio"
|
|
767
|
+
type="button"
|
|
768
|
+
[attr.aria-checked]="option.value === value()"
|
|
769
|
+
[attr.tabindex]="tabIndexFor(option.value)"
|
|
770
|
+
[class]="chipClasses(option.value)"
|
|
771
|
+
[disabled]="disabled()"
|
|
772
|
+
(click)="select(option.value)"
|
|
773
|
+
(keydown)="onKeydown($event, index)"
|
|
774
|
+
>
|
|
775
|
+
{{ option.label }}
|
|
776
|
+
</button>
|
|
777
|
+
}
|
|
778
|
+
</div>
|
|
779
|
+
</div>
|
|
780
|
+
`,
|
|
781
|
+
providers: [{ provide: UI_CONTROL, useExisting: forwardRef(() => UiChoiceChips) }],
|
|
782
|
+
}]
|
|
783
|
+
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }, { type: i0.Output, args: ["valueChange"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaLabelledby: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabelledby", required: false }] }], surface: [{ type: i0.Input, args: [{ isSignal: true, alias: "surface", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], radios: [{ type: i0.ViewChildren, args: ['radio', { isSignal: true }] }] } });
|
|
784
|
+
|
|
395
785
|
/** Available delta emphases. `DeltaEmphasis` is derived from this tuple. */
|
|
396
786
|
const DELTA_EMPHASES = ['text', 'pill'];
|
|
397
787
|
const BASE_CLASSES$2 = 'inline-flex items-center gap-1 text-label font-medium tabular-nums';
|
|
@@ -402,7 +792,7 @@ const TEXT_CLASSES = {
|
|
|
402
792
|
neutral: 'text-(--muted-foreground)',
|
|
403
793
|
unknown: 'text-(--subtle-foreground)',
|
|
404
794
|
};
|
|
405
|
-
const PILL_BACKGROUND_CLASS = 'bg-(--
|
|
795
|
+
const PILL_BACKGROUND_CLASS = 'bg-(--soft)';
|
|
406
796
|
/**
|
|
407
797
|
* Signed amount whose sign carries meaning: a gain, a loss, or an unknown.
|
|
408
798
|
*
|
|
@@ -470,24 +860,68 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
470
860
|
}]
|
|
471
861
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], unknownLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "unknownLabel", required: true }] }], emphasis: [{ type: i0.Input, args: [{ isSignal: true, alias: "emphasis", required: false }] }] } });
|
|
472
862
|
|
|
473
|
-
/**
|
|
863
|
+
/** Named dialog widths; any other CSS length is accepted as is. `DialogWidth` is derived from this tuple. */
|
|
474
864
|
const DIALOG_WIDTHS = ['md', 'lg'];
|
|
475
|
-
const
|
|
476
|
-
md: '
|
|
477
|
-
lg: '
|
|
865
|
+
const WIDTH_VALUES = {
|
|
866
|
+
md: '28rem',
|
|
867
|
+
lg: '560px',
|
|
868
|
+
};
|
|
869
|
+
/** Spacing presets. `DialogLayout` is derived from this tuple. */
|
|
870
|
+
const DIALOG_LAYOUTS = ['trade', 'form', 'list', 'confirm'];
|
|
871
|
+
const LAYOUTS = {
|
|
872
|
+
trade: {
|
|
873
|
+
dialog: '',
|
|
874
|
+
header: 'items-start lg:pt-6',
|
|
875
|
+
title: 'pt-1 lg:pt-0',
|
|
876
|
+
cross: 'lg:-mt-1.5',
|
|
877
|
+
icon: 'lg:size-5',
|
|
878
|
+
handle: 'pt-[7.5px]',
|
|
879
|
+
body: 'pt-3 pb-4 lg:pt-5 lg:pb-5',
|
|
880
|
+
footer: 'max-lg:pb-[calc(8px+env(safe-area-inset-bottom))] lg:pb-6',
|
|
881
|
+
},
|
|
882
|
+
form: {
|
|
883
|
+
dialog: '',
|
|
884
|
+
header: 'items-center lg:pt-6',
|
|
885
|
+
title: '',
|
|
886
|
+
cross: '',
|
|
887
|
+
icon: 'lg:size-[22px]',
|
|
888
|
+
handle: 'pt-[7.5px]',
|
|
889
|
+
body: 'pt-2 pb-5 lg:pt-4 lg:pb-5',
|
|
890
|
+
footer: 'max-lg:pb-[calc(12px+env(safe-area-inset-bottom))] lg:pb-5',
|
|
891
|
+
},
|
|
892
|
+
list: {
|
|
893
|
+
dialog: 'max-lg:h-[calc(100dvh-58px)] lg:mt-24 lg:mb-auto lg:max-h-[min(760px,calc(100dvh-96px-32px))]',
|
|
894
|
+
header: 'items-center lg:pt-5',
|
|
895
|
+
title: '',
|
|
896
|
+
cross: '',
|
|
897
|
+
icon: 'lg:size-[22px]',
|
|
898
|
+
handle: 'pt-[7.5px]',
|
|
899
|
+
body: 'pt-2 pb-4 lg:pt-4 lg:pb-5',
|
|
900
|
+
footer: 'pt-3 shadow-[0_-1px_0_var(--hairline)] max-lg:pb-[calc(8px+env(safe-area-inset-bottom))] lg:pt-4 lg:pb-4',
|
|
901
|
+
},
|
|
902
|
+
confirm: {
|
|
903
|
+
dialog: '',
|
|
904
|
+
header: 'items-center pt-3 lg:pt-6',
|
|
905
|
+
title: '',
|
|
906
|
+
cross: '',
|
|
907
|
+
icon: 'lg:size-[22px]',
|
|
908
|
+
handle: 'pt-[11.5px]',
|
|
909
|
+
body: 'pt-3 pb-5 lg:pt-3 lg:pb-6',
|
|
910
|
+
footer: 'max-lg:pb-[calc(8px+env(safe-area-inset-bottom))] lg:pb-6',
|
|
911
|
+
},
|
|
478
912
|
};
|
|
479
913
|
const nextId$2 = (() => {
|
|
480
914
|
let count = 0;
|
|
481
915
|
return () => `ui-dialog-${++count}`;
|
|
482
916
|
})();
|
|
483
917
|
/**
|
|
484
|
-
* Modal dialog on the native <dialog>: a sheet
|
|
485
|
-
* above it. Two projection slots - the body, and [dialogActions] for the footer.
|
|
918
|
+
* Modal dialog on the native <dialog>: a bottom sheet under `64rem`, centered above it.
|
|
486
919
|
*
|
|
487
920
|
* @example
|
|
488
|
-
* <ui-dialog heading="
|
|
489
|
-
* <p>
|
|
490
|
-
* <button dialogActions ui-button variant="outline" (click)="
|
|
921
|
+
* <ui-dialog heading="Buy" description="Ferrari" closeLabel="Close" width="528px" [open]="buying()" (dismissed)="buying.set(false)">
|
|
922
|
+
* <p>Body</p>
|
|
923
|
+
* <button dialogActions ui-button variant="outline" class="max-lg:hidden" (click)="buying.set(false)">Cancel</button>
|
|
924
|
+
* <button dialogActions ui-button>Buy 40 shares</button>
|
|
491
925
|
* </ui-dialog>
|
|
492
926
|
*/
|
|
493
927
|
class UiDialog {
|
|
@@ -495,17 +929,39 @@ class UiDialog {
|
|
|
495
929
|
...(ngDevMode ? [{ debugName: "heading" }] : /* istanbul ignore next */ []));
|
|
496
930
|
description = input(/* @ts-ignore */
|
|
497
931
|
...(ngDevMode ? [undefined, { debugName: "description" }] : /* istanbul ignore next */ []));
|
|
932
|
+
closeLabel = input(/* @ts-ignore */
|
|
933
|
+
...(ngDevMode ? [undefined, { debugName: "closeLabel" }] : /* istanbul ignore next */ []));
|
|
934
|
+
layout = input('trade', /* @ts-ignore */
|
|
935
|
+
...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
|
|
936
|
+
truncateDescription = input(false, { ...(ngDevMode ? { debugName: "truncateDescription" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
498
937
|
width = input('lg', /* @ts-ignore */
|
|
499
938
|
...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
|
|
500
939
|
open = input(false, { ...(ngDevMode ? { debugName: "open" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
501
940
|
dismissed = output();
|
|
502
941
|
headingId = nextId$2();
|
|
503
942
|
descriptionId = `${this.headingId}-description`;
|
|
504
|
-
|
|
943
|
+
widthValue = computed(() => {
|
|
944
|
+
const width = this.width();
|
|
945
|
+
return Object.hasOwn(WIDTH_VALUES, width) ? WIDTH_VALUES[width] : width;
|
|
946
|
+
}, /* @ts-ignore */
|
|
947
|
+
...(ngDevMode ? [{ debugName: "widthValue" }] : /* istanbul ignore next */ []));
|
|
948
|
+
spec = computed(() => LAYOUTS[this.layout()], /* @ts-ignore */
|
|
949
|
+
...(ngDevMode ? [{ debugName: "spec" }] : /* istanbul ignore next */ []));
|
|
950
|
+
headerClasses = computed(() => `flex gap-2 pl-4 lg:gap-3 lg:pl-6 ${this.spec().header} ${this.closeLabel() ? 'pr-2 lg:pr-4' : 'pr-4 lg:pr-6'}`, /* @ts-ignore */
|
|
951
|
+
...(ngDevMode ? [{ debugName: "headerClasses" }] : /* istanbul ignore next */ []));
|
|
952
|
+
titleClasses = computed(() => this.spec().title, /* @ts-ignore */
|
|
953
|
+
...(ngDevMode ? [{ debugName: "titleClasses" }] : /* istanbul ignore next */ []));
|
|
954
|
+
crossClasses = computed(() => `rounded-pill lg:rounded-control grid size-11 flex-none cursor-pointer place-items-center text-(--muted-foreground) transition-[transform,background-color,color] duration-(--duration-press) ease-out outline-none focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-(--ring) active:scale-(--press-scale) active:bg-(--soft) lg:size-9 lg:hover:bg-(--glow) lg:hover:text-(--foreground) ${this.spec().cross}`, /* @ts-ignore */
|
|
955
|
+
...(ngDevMode ? [{ debugName: "crossClasses" }] : /* istanbul ignore next */ []));
|
|
956
|
+
iconClasses = computed(() => this.spec().icon, /* @ts-ignore */
|
|
957
|
+
...(ngDevMode ? [{ debugName: "iconClasses" }] : /* istanbul ignore next */ []));
|
|
958
|
+
footerClasses = computed(() => `max-lg:[&>[ui-button]]:text-body flex justify-end gap-2 px-4 empty:hidden max-lg:flex-col-reverse max-lg:[&>[ui-button]]:h-[50px] max-lg:[&>[ui-button]]:w-full lg:px-6 ${this.spec().footer}`, /* @ts-ignore */
|
|
959
|
+
...(ngDevMode ? [{ debugName: "footerClasses" }] : /* istanbul ignore next */ []));
|
|
960
|
+
classes = computed(() => `open:flex w-full flex-col overflow-hidden m-auto mt-auto max-h-[calc(100dvh-2rem)] max-lg:mb-0 max-lg:max-w-none max-lg:rounded-b-none lg:max-w-(--dialog-width) rounded-container bg-(--card) text-(--foreground) shadow-[0_0_0_1px_var(--border),0_24px_64px_rgb(0_0_0/0.24)] max-lg:shadow-[0_-1px_0_var(--border),0_-12px_32px_rgb(0_0_0/0.16)] backdrop:bg-black/[0.36] ${this.spec().dialog}`, /* @ts-ignore */
|
|
505
961
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
506
962
|
#host = inject(ElementRef);
|
|
507
963
|
constructor() {
|
|
508
|
-
|
|
964
|
+
afterRenderEffect(() => {
|
|
509
965
|
// viewChild.required can't target a #private field (NG1053); safe because the template has exactly one <dialog>.
|
|
510
966
|
const dialog = this.#host.nativeElement.querySelector('dialog');
|
|
511
967
|
if (this.open() && !dialog.open) {
|
|
@@ -516,6 +972,23 @@ class UiDialog {
|
|
|
516
972
|
}
|
|
517
973
|
});
|
|
518
974
|
}
|
|
975
|
+
#pressedOnBackdrop = false;
|
|
976
|
+
onPointerDown(event) {
|
|
977
|
+
this.#pressedOnBackdrop = event.target === this.#dialog && this.#outside(event);
|
|
978
|
+
}
|
|
979
|
+
onClick(event) {
|
|
980
|
+
if (this.#pressedOnBackdrop && event.target === this.#dialog && this.#outside(event)) {
|
|
981
|
+
this.#dialog.close();
|
|
982
|
+
}
|
|
983
|
+
this.#pressedOnBackdrop = false;
|
|
984
|
+
}
|
|
985
|
+
get #dialog() {
|
|
986
|
+
return this.#host.nativeElement.querySelector('dialog');
|
|
987
|
+
}
|
|
988
|
+
#outside(event) {
|
|
989
|
+
const rect = this.#dialog.getBoundingClientRect();
|
|
990
|
+
return (event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom);
|
|
991
|
+
}
|
|
519
992
|
onNativeClose() {
|
|
520
993
|
// The owner already knows about a close it asked for; only a close it did not ask for is news.
|
|
521
994
|
if (this.open()) {
|
|
@@ -523,87 +996,145 @@ class UiDialog {
|
|
|
523
996
|
}
|
|
524
997
|
}
|
|
525
998
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
526
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiDialog, isStandalone: true, selector: "ui-dialog", inputs: { heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: true, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dismissed: "dismissed" }, ngImport: i0, template: `
|
|
999
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiDialog, isStandalone: true, selector: "ui-dialog", inputs: { heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: true, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, closeLabel: { classPropertyName: "closeLabel", publicName: "closeLabel", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null }, truncateDescription: { classPropertyName: "truncateDescription", publicName: "truncateDescription", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dismissed: "dismissed" }, host: { listeners: { "pointerdown": "onPointerDown($event)", "click": "onClick($event)" } }, ngImport: i0, template: `
|
|
527
1000
|
<dialog
|
|
1001
|
+
#dlg
|
|
528
1002
|
[attr.aria-describedby]="description() ? descriptionId : null"
|
|
529
1003
|
[attr.aria-labelledby]="headingId"
|
|
1004
|
+
[attr.role]="layout() === 'confirm' ? 'alertdialog' : 'dialog'"
|
|
530
1005
|
[class]="classes()"
|
|
1006
|
+
[style.--dialog-width]="widthValue()"
|
|
531
1007
|
(close)="onNativeClose()"
|
|
532
1008
|
>
|
|
533
|
-
<div aria-hidden="true" class="flex h-
|
|
534
|
-
<span class="rounded-pill h-
|
|
1009
|
+
<div aria-hidden="true" class="flex h-5 justify-center lg:hidden" data-dialog-handle [class]="spec().handle">
|
|
1010
|
+
<span class="rounded-pill h-[5px] w-9 bg-(--border)"></span>
|
|
535
1011
|
</div>
|
|
536
1012
|
|
|
537
|
-
<div
|
|
538
|
-
<
|
|
1013
|
+
<div data-dialog-header [class]="headerClasses()">
|
|
1014
|
+
<div class="flex min-w-0 flex-1 flex-col" [class]="titleClasses()">
|
|
1015
|
+
<h2 class="text-title font-semibold" [id]="headingId">{{ heading() }}</h2>
|
|
1016
|
+
|
|
1017
|
+
@if (description()) {
|
|
1018
|
+
<p
|
|
1019
|
+
class="text-label text-(--muted-foreground)"
|
|
1020
|
+
[class.truncate]="truncateDescription()"
|
|
1021
|
+
[id]="descriptionId"
|
|
1022
|
+
>
|
|
1023
|
+
{{ description() }}
|
|
1024
|
+
</p>
|
|
1025
|
+
}
|
|
1026
|
+
</div>
|
|
539
1027
|
|
|
540
|
-
@if (
|
|
541
|
-
<
|
|
1028
|
+
@if (closeLabel()) {
|
|
1029
|
+
<button type="button" [attr.aria-label]="closeLabel()" [class]="crossClasses()" (click)="dlg.close()">
|
|
1030
|
+
<svg
|
|
1031
|
+
aria-hidden="true"
|
|
1032
|
+
class="block size-[22px] fill-none stroke-current stroke-[1.75]"
|
|
1033
|
+
stroke-linecap="round"
|
|
1034
|
+
stroke-linejoin="round"
|
|
1035
|
+
viewBox="0 0 24 24"
|
|
1036
|
+
[class]="iconClasses()"
|
|
1037
|
+
>
|
|
1038
|
+
<path d="M18 6 6 18" />
|
|
1039
|
+
<path d="m6 6 12 12" />
|
|
1040
|
+
</svg>
|
|
1041
|
+
</button>
|
|
542
1042
|
}
|
|
543
1043
|
</div>
|
|
544
1044
|
|
|
545
|
-
<div class="min-h-0 flex-1 overflow-y-auto px-6" data-dialog-body
|
|
546
|
-
<!-- empty:hidden keeps a body-less dialog from carrying the body's
|
|
547
|
-
<div class="
|
|
1045
|
+
<div class="min-h-0 flex-1 overflow-y-auto px-4 lg:px-6" data-dialog-body>
|
|
1046
|
+
<!-- empty:hidden keeps a body-less dialog from carrying the body's vertical padding. -->
|
|
1047
|
+
<div class="flex flex-col gap-4 empty:hidden" [class]="spec().body">
|
|
548
1048
|
<ng-content />
|
|
549
1049
|
</div>
|
|
550
1050
|
</div>
|
|
551
1051
|
|
|
552
|
-
<div
|
|
553
|
-
class="flex justify-end gap-3 px-6 pt-6 pb-6 max-lg:pb-[calc(1rem+env(safe-area-inset-bottom))]"
|
|
554
|
-
data-dialog-footer
|
|
555
|
-
>
|
|
1052
|
+
<div data-dialog-footer [class]="footerClasses()">
|
|
556
1053
|
<ng-content select="[dialogActions]" />
|
|
557
1054
|
</div>
|
|
558
1055
|
</dialog>
|
|
559
|
-
`, isInline: true, styles: ["dialog{transition:opacity var(--duration-base) var(--ease
|
|
1056
|
+
`, isInline: true, styles: ["dialog{--dialog-ease: var(--ease-sheet);transition:opacity var(--duration-base) var(--dialog-ease),transform var(--duration-base) var(--dialog-ease),overlay var(--duration-base) allow-discrete,display var(--duration-base) allow-discrete;opacity:1;transform:translateY(0)}dialog:not([open]){opacity:0;transform:translateY(100%);transition-duration:var(--duration-exit)}@starting-style{dialog[open]{opacity:0;transform:translateY(100%)}}@media(min-width:64rem){dialog{--dialog-ease: var(--ease-out);transform:scale(1)}dialog:not([open]){transform:scale(var(--enter-scale))}@starting-style{dialog[open]{transform:scale(var(--enter-scale))}}}dialog::backdrop{transition:opacity var(--duration-base) var(--ease-out);opacity:1}dialog:not([open])::backdrop{opacity:0;transition-duration:var(--duration-exit)}@starting-style{dialog[open]::backdrop{opacity:0}}\n"] });
|
|
560
1057
|
}
|
|
561
1058
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiDialog, decorators: [{
|
|
562
1059
|
type: Component,
|
|
563
|
-
args: [{ selector: 'ui-dialog', template: `
|
|
1060
|
+
args: [{ selector: 'ui-dialog', host: { '(pointerdown)': 'onPointerDown($event)', '(click)': 'onClick($event)' }, template: `
|
|
564
1061
|
<dialog
|
|
1062
|
+
#dlg
|
|
565
1063
|
[attr.aria-describedby]="description() ? descriptionId : null"
|
|
566
1064
|
[attr.aria-labelledby]="headingId"
|
|
1065
|
+
[attr.role]="layout() === 'confirm' ? 'alertdialog' : 'dialog'"
|
|
567
1066
|
[class]="classes()"
|
|
1067
|
+
[style.--dialog-width]="widthValue()"
|
|
568
1068
|
(close)="onNativeClose()"
|
|
569
1069
|
>
|
|
570
|
-
<div aria-hidden="true" class="flex h-
|
|
571
|
-
<span class="rounded-pill h-
|
|
1070
|
+
<div aria-hidden="true" class="flex h-5 justify-center lg:hidden" data-dialog-handle [class]="spec().handle">
|
|
1071
|
+
<span class="rounded-pill h-[5px] w-9 bg-(--border)"></span>
|
|
572
1072
|
</div>
|
|
573
1073
|
|
|
574
|
-
<div
|
|
575
|
-
<
|
|
1074
|
+
<div data-dialog-header [class]="headerClasses()">
|
|
1075
|
+
<div class="flex min-w-0 flex-1 flex-col" [class]="titleClasses()">
|
|
1076
|
+
<h2 class="text-title font-semibold" [id]="headingId">{{ heading() }}</h2>
|
|
1077
|
+
|
|
1078
|
+
@if (description()) {
|
|
1079
|
+
<p
|
|
1080
|
+
class="text-label text-(--muted-foreground)"
|
|
1081
|
+
[class.truncate]="truncateDescription()"
|
|
1082
|
+
[id]="descriptionId"
|
|
1083
|
+
>
|
|
1084
|
+
{{ description() }}
|
|
1085
|
+
</p>
|
|
1086
|
+
}
|
|
1087
|
+
</div>
|
|
576
1088
|
|
|
577
|
-
@if (
|
|
578
|
-
<
|
|
1089
|
+
@if (closeLabel()) {
|
|
1090
|
+
<button type="button" [attr.aria-label]="closeLabel()" [class]="crossClasses()" (click)="dlg.close()">
|
|
1091
|
+
<svg
|
|
1092
|
+
aria-hidden="true"
|
|
1093
|
+
class="block size-[22px] fill-none stroke-current stroke-[1.75]"
|
|
1094
|
+
stroke-linecap="round"
|
|
1095
|
+
stroke-linejoin="round"
|
|
1096
|
+
viewBox="0 0 24 24"
|
|
1097
|
+
[class]="iconClasses()"
|
|
1098
|
+
>
|
|
1099
|
+
<path d="M18 6 6 18" />
|
|
1100
|
+
<path d="m6 6 12 12" />
|
|
1101
|
+
</svg>
|
|
1102
|
+
</button>
|
|
579
1103
|
}
|
|
580
1104
|
</div>
|
|
581
1105
|
|
|
582
|
-
<div class="min-h-0 flex-1 overflow-y-auto px-6" data-dialog-body
|
|
583
|
-
<!-- empty:hidden keeps a body-less dialog from carrying the body's
|
|
584
|
-
<div class="
|
|
1106
|
+
<div class="min-h-0 flex-1 overflow-y-auto px-4 lg:px-6" data-dialog-body>
|
|
1107
|
+
<!-- empty:hidden keeps a body-less dialog from carrying the body's vertical padding. -->
|
|
1108
|
+
<div class="flex flex-col gap-4 empty:hidden" [class]="spec().body">
|
|
585
1109
|
<ng-content />
|
|
586
1110
|
</div>
|
|
587
1111
|
</div>
|
|
588
1112
|
|
|
589
|
-
<div
|
|
590
|
-
class="flex justify-end gap-3 px-6 pt-6 pb-6 max-lg:pb-[calc(1rem+env(safe-area-inset-bottom))]"
|
|
591
|
-
data-dialog-footer
|
|
592
|
-
>
|
|
1113
|
+
<div data-dialog-footer [class]="footerClasses()">
|
|
593
1114
|
<ng-content select="[dialogActions]" />
|
|
594
1115
|
</div>
|
|
595
1116
|
</dialog>
|
|
596
|
-
`, styles: ["dialog{transition:opacity var(--duration-base) var(--ease
|
|
597
|
-
}], ctorParameters: () => [], propDecorators: { heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: true }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }], dismissed: [{ type: i0.Output, args: ["dismissed"] }] } });
|
|
598
|
-
|
|
599
|
-
const
|
|
600
|
-
const
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
const arcGenerator = arc().innerRadius(INNER_RADIUS).outerRadius(OUTER_RADIUS);
|
|
1117
|
+
`, styles: ["dialog{--dialog-ease: var(--ease-sheet);transition:opacity var(--duration-base) var(--dialog-ease),transform var(--duration-base) var(--dialog-ease),overlay var(--duration-base) allow-discrete,display var(--duration-base) allow-discrete;opacity:1;transform:translateY(0)}dialog:not([open]){opacity:0;transform:translateY(100%);transition-duration:var(--duration-exit)}@starting-style{dialog[open]{opacity:0;transform:translateY(100%)}}@media(min-width:64rem){dialog{--dialog-ease: var(--ease-out);transform:scale(1)}dialog:not([open]){transform:scale(var(--enter-scale))}@starting-style{dialog[open]{transform:scale(var(--enter-scale))}}}dialog::backdrop{transition:opacity var(--duration-base) var(--ease-out);opacity:1}dialog:not([open])::backdrop{opacity:0;transition-duration:var(--duration-exit)}@starting-style{dialog[open]::backdrop{opacity:0}}\n"] }]
|
|
1118
|
+
}], ctorParameters: () => [], propDecorators: { heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: true }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], closeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeLabel", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }], truncateDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "truncateDescription", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }], dismissed: [{ type: i0.Output, args: ["dismissed"] }] } });
|
|
1119
|
+
|
|
1120
|
+
const RADIUS = 78;
|
|
1121
|
+
const RING_WIDTH = 30;
|
|
1122
|
+
const ACTIVE_RING_WIDTH = 38;
|
|
1123
|
+
const CIRCUMFERENCE = 2 * Math.PI * RADIUS;
|
|
1124
|
+
const GAP = 2;
|
|
605
1125
|
function positionSlices(slices) {
|
|
606
|
-
|
|
1126
|
+
let travelled = 0;
|
|
1127
|
+
return slices.map((slice) => {
|
|
1128
|
+
const length = slice.share * CIRCUMFERENCE;
|
|
1129
|
+
const drawn = Math.max(0, length - GAP);
|
|
1130
|
+
const positioned = {
|
|
1131
|
+
...slice,
|
|
1132
|
+
dash: `${drawn.toFixed(2)} ${(CIRCUMFERENCE - drawn).toFixed(2)}`,
|
|
1133
|
+
offset: (-travelled).toFixed(2),
|
|
1134
|
+
};
|
|
1135
|
+
travelled += length;
|
|
1136
|
+
return positioned;
|
|
1137
|
+
});
|
|
607
1138
|
}
|
|
608
1139
|
|
|
609
1140
|
const MAX_RAMP = 6;
|
|
@@ -635,16 +1166,7 @@ function rankSlices(slices, othersLabel) {
|
|
|
635
1166
|
|
|
636
1167
|
const identityValue$1 = (value) => `${value}`;
|
|
637
1168
|
const identityShare = (share) => `${Math.round(share * 100)}%`;
|
|
638
|
-
const
|
|
639
|
-
const ROW_CLASSES = 'flex w-full items-center gap-3 min-h-12 px-2 rounded-control text-left transition-colors duration-(--duration-fast) ease-out hover:bg-(--glow) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring)';
|
|
640
|
-
const RAMP_FILL_CLASSES = {
|
|
641
|
-
1: 'fill-(--ramp-1)',
|
|
642
|
-
2: 'fill-(--ramp-2)',
|
|
643
|
-
3: 'fill-(--ramp-3)',
|
|
644
|
-
4: 'fill-(--ramp-4)',
|
|
645
|
-
5: 'fill-(--ramp-5)',
|
|
646
|
-
6: 'fill-(--ramp-6)',
|
|
647
|
-
};
|
|
1169
|
+
const ROW_CLASSES$1 = 'flex w-full items-center gap-3 min-h-14 px-2 py-1 [font-variant-numeric:var(--numeric)] rounded-control text-left transition-colors duration-(--duration-fast) ease-out hover:bg-(--glow) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring)';
|
|
648
1170
|
const RAMP_DOT_CLASSES = {
|
|
649
1171
|
1: 'bg-(--ramp-1)',
|
|
650
1172
|
2: 'bg-(--ramp-2)',
|
|
@@ -691,22 +1213,23 @@ class UiDonut {
|
|
|
691
1213
|
return detail ? `${this.label()} : ${detail}` : this.label();
|
|
692
1214
|
}, /* @ts-ignore */
|
|
693
1215
|
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
694
|
-
|
|
695
|
-
|
|
1216
|
+
radius = RADIUS;
|
|
1217
|
+
ringWidth = RING_WIDTH;
|
|
1218
|
+
strokeColor(slice) {
|
|
1219
|
+
return `var(--ramp-${slice.ramp})`;
|
|
1220
|
+
}
|
|
1221
|
+
strokeWidth(slice) {
|
|
1222
|
+
return this.isActive(slice) ? ACTIVE_RING_WIDTH : RING_WIDTH;
|
|
696
1223
|
}
|
|
697
1224
|
dotClasses(slice) {
|
|
698
1225
|
return `size-3 flex-none rounded-pill shadow-[inset_0_0_0_1px_var(--border)] ${RAMP_DOT_CLASSES[slice.ramp]}`;
|
|
699
1226
|
}
|
|
700
1227
|
rowClasses(slice) {
|
|
701
|
-
return `${ROW_CLASSES}${this.isActive(slice) ? ' bg-(--soft)' : ''}`;
|
|
1228
|
+
return `${ROW_CLASSES$1}${this.isActive(slice) ? ' bg-(--soft)' : ''}`;
|
|
702
1229
|
}
|
|
703
1230
|
subLabel(slice) {
|
|
704
1231
|
return slice.members.length > 0 ? slice.members.join(', ') : (slice.sublabel ?? '');
|
|
705
1232
|
}
|
|
706
|
-
arcTransform(slice) {
|
|
707
|
-
const scale = this.isActive(slice) ? ACTIVE_SCALE : 1;
|
|
708
|
-
return `translate(100px, 100px) scale(${scale})`;
|
|
709
|
-
}
|
|
710
1233
|
isActive(slice) {
|
|
711
1234
|
return this.active()?.id === slice.id;
|
|
712
1235
|
}
|
|
@@ -723,36 +1246,53 @@ class UiDonut {
|
|
|
723
1246
|
this.sliceSelect.emit(slice.id);
|
|
724
1247
|
}
|
|
725
1248
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiDonut, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
726
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiDonut, isStandalone: true, selector: "ui-donut", inputs: { slices: { classPropertyName: "slices", publicName: "slices", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, othersLabel: { classPropertyName: "othersLabel", publicName: "othersLabel", isSignal: true, isRequired: true, transformFunction: null }, valueFormat: { classPropertyName: "valueFormat", publicName: "valueFormat", isSignal: true, isRequired: false, transformFunction: null }, shareFormat: { classPropertyName: "shareFormat", publicName: "shareFormat", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sliceSelect: "sliceSelect" }, host: { classAttribute: "flex flex-col items-center gap-
|
|
1249
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiDonut, isStandalone: true, selector: "ui-donut", inputs: { slices: { classPropertyName: "slices", publicName: "slices", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, othersLabel: { classPropertyName: "othersLabel", publicName: "othersLabel", isSignal: true, isRequired: true, transformFunction: null }, valueFormat: { classPropertyName: "valueFormat", publicName: "valueFormat", isSignal: true, isRequired: false, transformFunction: null }, shareFormat: { classPropertyName: "shareFormat", publicName: "shareFormat", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sliceSelect: "sliceSelect" }, host: { classAttribute: "flex flex-col items-center gap-3 sm:flex-row sm:items-center sm:gap-8" }, ngImport: i0, template: `
|
|
727
1250
|
<div class="relative size-[232px] flex-none sm:size-60">
|
|
728
|
-
<svg class="block h-full w-full" role="img" viewBox="0 0 200 200" [attr.aria-label]="ariaLabel()">
|
|
1251
|
+
<svg class="block h-full w-full -rotate-90" role="img" viewBox="0 0 200 200" [attr.aria-label]="ariaLabel()">
|
|
1252
|
+
<circle
|
|
1253
|
+
class="stroke-(--muted)"
|
|
1254
|
+
cx="100"
|
|
1255
|
+
cy="100"
|
|
1256
|
+
fill="none"
|
|
1257
|
+
[attr.r]="radius"
|
|
1258
|
+
[attr.stroke-width]="ringWidth"
|
|
1259
|
+
/>
|
|
729
1260
|
@for (slice of positioned(); track slice.id) {
|
|
730
|
-
<
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
1261
|
+
<circle
|
|
1262
|
+
class="cursor-pointer transition-[stroke-width] duration-(--duration-fast) ease-out"
|
|
1263
|
+
cx="100"
|
|
1264
|
+
cy="100"
|
|
1265
|
+
data-slice
|
|
1266
|
+
fill="none"
|
|
1267
|
+
[attr.r]="radius"
|
|
1268
|
+
[attr.stroke-dasharray]="slice.dash"
|
|
1269
|
+
[attr.stroke-dashoffset]="slice.offset"
|
|
1270
|
+
[style.stroke]="strokeColor(slice)"
|
|
1271
|
+
[style.stroke-width.px]="strokeWidth(slice)"
|
|
1272
|
+
(click)="select(slice)"
|
|
1273
|
+
(pointerenter)="highlight(slice.id)"
|
|
1274
|
+
(pointerleave)="clearHighlight(slice.id)"
|
|
1275
|
+
/>
|
|
740
1276
|
}
|
|
741
1277
|
</svg>
|
|
742
1278
|
|
|
743
1279
|
@if (active(); as slice) {
|
|
744
1280
|
<div
|
|
745
|
-
class="pointer-events-none absolute inset-0 flex flex-col items-center justify-center px-
|
|
1281
|
+
class="pointer-events-none absolute inset-0 flex flex-col items-center justify-center px-12 text-center"
|
|
746
1282
|
data-testid="donut-centre"
|
|
747
1283
|
>
|
|
748
|
-
<span class="text-
|
|
749
|
-
|
|
750
|
-
|
|
1284
|
+
<span class="text-label max-w-full truncate font-medium whitespace-nowrap text-(--muted-foreground)">{{
|
|
1285
|
+
slice.label
|
|
1286
|
+
}}</span>
|
|
1287
|
+
<span class="text-heading font-semibold tracking-(--tracking-display)">{{ shareFormat()(slice.share) }}</span>
|
|
1288
|
+
<span class="text-caption tracking-normal text-(--muted-foreground) [font-variant-numeric:var(--numeric)]">{{
|
|
1289
|
+
valueFormat()(slice.value)
|
|
1290
|
+
}}</span>
|
|
751
1291
|
</div>
|
|
752
1292
|
}
|
|
753
1293
|
</div>
|
|
754
1294
|
|
|
755
|
-
<div class="flex min-w-0 flex-1 flex-col">
|
|
1295
|
+
<div class="flex w-full min-w-0 flex-1 flex-col sm:w-auto" data-testid="donut-legend">
|
|
756
1296
|
@for (slice of ranked(); track slice.id) {
|
|
757
1297
|
<button
|
|
758
1298
|
type="button"
|
|
@@ -766,11 +1306,13 @@ class UiDonut {
|
|
|
766
1306
|
<span [class]="dotClasses(slice)"></span>
|
|
767
1307
|
<span class="flex min-w-0 flex-1 flex-col">
|
|
768
1308
|
<span class="text-body truncate font-medium">{{ slice.label }}</span>
|
|
769
|
-
<span class="text-caption truncate text-(--
|
|
1309
|
+
<span class="text-caption truncate tracking-(--tracking-caption) text-(--subtle-foreground)">{{
|
|
1310
|
+
subLabel(slice)
|
|
1311
|
+
}}</span>
|
|
770
1312
|
</span>
|
|
771
1313
|
<span class="flex flex-none flex-col items-end whitespace-nowrap">
|
|
772
1314
|
<span class="text-body font-medium">{{ shareFormat()(slice.share) }}</span>
|
|
773
|
-
<span class="text-caption text-(--muted-foreground)">{{ valueFormat()(slice.value) }}</span>
|
|
1315
|
+
<span class="text-caption tracking-normal text-(--muted-foreground)">{{ valueFormat()(slice.value) }}</span>
|
|
774
1316
|
</span>
|
|
775
1317
|
</button>
|
|
776
1318
|
}
|
|
@@ -783,34 +1325,51 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
783
1325
|
selector: 'ui-donut',
|
|
784
1326
|
template: `
|
|
785
1327
|
<div class="relative size-[232px] flex-none sm:size-60">
|
|
786
|
-
<svg class="block h-full w-full" role="img" viewBox="0 0 200 200" [attr.aria-label]="ariaLabel()">
|
|
1328
|
+
<svg class="block h-full w-full -rotate-90" role="img" viewBox="0 0 200 200" [attr.aria-label]="ariaLabel()">
|
|
1329
|
+
<circle
|
|
1330
|
+
class="stroke-(--muted)"
|
|
1331
|
+
cx="100"
|
|
1332
|
+
cy="100"
|
|
1333
|
+
fill="none"
|
|
1334
|
+
[attr.r]="radius"
|
|
1335
|
+
[attr.stroke-width]="ringWidth"
|
|
1336
|
+
/>
|
|
787
1337
|
@for (slice of positioned(); track slice.id) {
|
|
788
|
-
<
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
1338
|
+
<circle
|
|
1339
|
+
class="cursor-pointer transition-[stroke-width] duration-(--duration-fast) ease-out"
|
|
1340
|
+
cx="100"
|
|
1341
|
+
cy="100"
|
|
1342
|
+
data-slice
|
|
1343
|
+
fill="none"
|
|
1344
|
+
[attr.r]="radius"
|
|
1345
|
+
[attr.stroke-dasharray]="slice.dash"
|
|
1346
|
+
[attr.stroke-dashoffset]="slice.offset"
|
|
1347
|
+
[style.stroke]="strokeColor(slice)"
|
|
1348
|
+
[style.stroke-width.px]="strokeWidth(slice)"
|
|
1349
|
+
(click)="select(slice)"
|
|
1350
|
+
(pointerenter)="highlight(slice.id)"
|
|
1351
|
+
(pointerleave)="clearHighlight(slice.id)"
|
|
1352
|
+
/>
|
|
798
1353
|
}
|
|
799
1354
|
</svg>
|
|
800
1355
|
|
|
801
1356
|
@if (active(); as slice) {
|
|
802
1357
|
<div
|
|
803
|
-
class="pointer-events-none absolute inset-0 flex flex-col items-center justify-center px-
|
|
1358
|
+
class="pointer-events-none absolute inset-0 flex flex-col items-center justify-center px-12 text-center"
|
|
804
1359
|
data-testid="donut-centre"
|
|
805
1360
|
>
|
|
806
|
-
<span class="text-
|
|
807
|
-
|
|
808
|
-
|
|
1361
|
+
<span class="text-label max-w-full truncate font-medium whitespace-nowrap text-(--muted-foreground)">{{
|
|
1362
|
+
slice.label
|
|
1363
|
+
}}</span>
|
|
1364
|
+
<span class="text-heading font-semibold tracking-(--tracking-display)">{{ shareFormat()(slice.share) }}</span>
|
|
1365
|
+
<span class="text-caption tracking-normal text-(--muted-foreground) [font-variant-numeric:var(--numeric)]">{{
|
|
1366
|
+
valueFormat()(slice.value)
|
|
1367
|
+
}}</span>
|
|
809
1368
|
</div>
|
|
810
1369
|
}
|
|
811
1370
|
</div>
|
|
812
1371
|
|
|
813
|
-
<div class="flex min-w-0 flex-1 flex-col">
|
|
1372
|
+
<div class="flex w-full min-w-0 flex-1 flex-col sm:w-auto" data-testid="donut-legend">
|
|
814
1373
|
@for (slice of ranked(); track slice.id) {
|
|
815
1374
|
<button
|
|
816
1375
|
type="button"
|
|
@@ -824,18 +1383,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
824
1383
|
<span [class]="dotClasses(slice)"></span>
|
|
825
1384
|
<span class="flex min-w-0 flex-1 flex-col">
|
|
826
1385
|
<span class="text-body truncate font-medium">{{ slice.label }}</span>
|
|
827
|
-
<span class="text-caption truncate text-(--
|
|
1386
|
+
<span class="text-caption truncate tracking-(--tracking-caption) text-(--subtle-foreground)">{{
|
|
1387
|
+
subLabel(slice)
|
|
1388
|
+
}}</span>
|
|
828
1389
|
</span>
|
|
829
1390
|
<span class="flex flex-none flex-col items-end whitespace-nowrap">
|
|
830
1391
|
<span class="text-body font-medium">{{ shareFormat()(slice.share) }}</span>
|
|
831
|
-
<span class="text-caption text-(--muted-foreground)">{{ valueFormat()(slice.value) }}</span>
|
|
1392
|
+
<span class="text-caption tracking-normal text-(--muted-foreground)">{{ valueFormat()(slice.value) }}</span>
|
|
832
1393
|
</span>
|
|
833
1394
|
</button>
|
|
834
1395
|
}
|
|
835
1396
|
</div>
|
|
836
1397
|
`,
|
|
837
1398
|
host: {
|
|
838
|
-
class: 'flex flex-col items-center gap-
|
|
1399
|
+
class: 'flex flex-col items-center gap-3 sm:flex-row sm:items-center sm:gap-8',
|
|
839
1400
|
},
|
|
840
1401
|
}]
|
|
841
1402
|
}], propDecorators: { slices: [{ type: i0.Input, args: [{ isSignal: true, alias: "slices", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], othersLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "othersLabel", required: true }] }], valueFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueFormat", required: false }] }], shareFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "shareFormat", required: false }] }], sliceSelect: [{ type: i0.Output, args: ["sliceSelect"] }] } });
|
|
@@ -844,6 +1405,31 @@ const nextId$1 = (() => {
|
|
|
844
1405
|
let count = 0;
|
|
845
1406
|
return () => `ui-field-${++count}`;
|
|
846
1407
|
})();
|
|
1408
|
+
/**
|
|
1409
|
+
* Marks an element, typically an 18px svg icon, as the leading content of a `ui-field`: it sits
|
|
1410
|
+
* inside the control's left edge and the control's text is inset to clear it. Decorative, so hidden
|
|
1411
|
+
* from assistive technologies.
|
|
1412
|
+
*
|
|
1413
|
+
* @example
|
|
1414
|
+
* <ui-field label="Search" labelHidden>
|
|
1415
|
+
* <svg uiFieldLeading width="18" height="18" viewBox="0 0 24 24">...</svg>
|
|
1416
|
+
* <input uiInput type="search" />
|
|
1417
|
+
* </ui-field>
|
|
1418
|
+
*/
|
|
1419
|
+
class UiFieldLeading {
|
|
1420
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFieldLeading, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1421
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.7", type: UiFieldLeading, isStandalone: true, selector: "[uiFieldLeading]", host: { attributes: { "aria-hidden": "true" }, classAttribute: "pointer-events-none absolute left-3 flex text-(--muted-foreground)" }, ngImport: i0 });
|
|
1422
|
+
}
|
|
1423
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFieldLeading, decorators: [{
|
|
1424
|
+
type: Directive,
|
|
1425
|
+
args: [{
|
|
1426
|
+
selector: '[uiFieldLeading]',
|
|
1427
|
+
host: {
|
|
1428
|
+
class: 'pointer-events-none absolute left-3 flex text-(--muted-foreground)',
|
|
1429
|
+
'aria-hidden': 'true',
|
|
1430
|
+
},
|
|
1431
|
+
}]
|
|
1432
|
+
}] });
|
|
847
1433
|
/**
|
|
848
1434
|
* Label, control, hint and error as one unit. The control stays a plain native element:
|
|
849
1435
|
* the field finds it in its own projected content and wires the ARIA attributes onto it.
|
|
@@ -882,7 +1468,11 @@ class UiField {
|
|
|
882
1468
|
#host = inject(ElementRef);
|
|
883
1469
|
control = contentChild(UI_CONTROL, /* @ts-ignore */
|
|
884
1470
|
...(ngDevMode ? [{ debugName: "control" }] : /* istanbul ignore next */ []));
|
|
885
|
-
|
|
1471
|
+
leading = contentChild(UiFieldLeading, /* @ts-ignore */
|
|
1472
|
+
...(ngDevMode ? [{ debugName: "leading" }] : /* istanbul ignore next */ []));
|
|
1473
|
+
rowClasses = computed(() => this.leading() ? 'relative flex items-center [&>input]:pl-[38px]' : 'relative flex items-center', /* @ts-ignore */
|
|
1474
|
+
...(ngDevMode ? [{ debugName: "rowClasses" }] : /* istanbul ignore next */ []));
|
|
1475
|
+
labelClasses = computed(() => this.labelHidden() ? 'sr-only' : 'text-label leading-[17px] font-medium text-(--muted-foreground)', /* @ts-ignore */
|
|
886
1476
|
...(ngDevMode ? [{ debugName: "labelClasses" }] : /* istanbul ignore next */ []));
|
|
887
1477
|
/**
|
|
888
1478
|
* The caller's own `error` wins: it is the only way to report something the control does not
|
|
@@ -925,12 +1515,13 @@ class UiField {
|
|
|
925
1515
|
});
|
|
926
1516
|
}
|
|
927
1517
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiField, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
928
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiField, isStandalone: true, selector: "ui-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, labelHidden: { classPropertyName: "labelHidden", publicName: "labelHidden", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, unit: { classPropertyName: "unit", publicName: "unit", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "control", first: true, predicate: UI_CONTROL, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1518
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiField, isStandalone: true, selector: "ui-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, labelHidden: { classPropertyName: "labelHidden", publicName: "labelHidden", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, unit: { classPropertyName: "unit", publicName: "unit", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "control", first: true, predicate: UI_CONTROL, descendants: true, isSignal: true }, { propertyName: "leading", first: true, predicate: UiFieldLeading, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
929
1519
|
<div class="group flex flex-col gap-1.5">
|
|
930
1520
|
<!-- eslint-disable-next-line @angular-eslint/template/label-has-associated-control -- htmlFor is wired at runtime, once the projected control's id is known -->
|
|
931
1521
|
<label [class]="labelClasses()">{{ label() }}</label>
|
|
932
1522
|
|
|
933
|
-
<div class="
|
|
1523
|
+
<div [class]="rowClasses()">
|
|
1524
|
+
<ng-content select="[uiFieldLeading]" />
|
|
934
1525
|
<ng-content />
|
|
935
1526
|
|
|
936
1527
|
@if (unit()) {
|
|
@@ -957,7 +1548,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
957
1548
|
<!-- eslint-disable-next-line @angular-eslint/template/label-has-associated-control -- htmlFor is wired at runtime, once the projected control's id is known -->
|
|
958
1549
|
<label [class]="labelClasses()">{{ label() }}</label>
|
|
959
1550
|
|
|
960
|
-
<div class="
|
|
1551
|
+
<div [class]="rowClasses()">
|
|
1552
|
+
<ng-content select="[uiFieldLeading]" />
|
|
961
1553
|
<ng-content />
|
|
962
1554
|
|
|
963
1555
|
@if (unit()) {
|
|
@@ -975,77 +1567,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
975
1567
|
</div>
|
|
976
1568
|
`,
|
|
977
1569
|
}]
|
|
978
|
-
}], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], labelHidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelHidden", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], unit: [{ type: i0.Input, args: [{ isSignal: true, alias: "unit", required: false }] }], control: [{ type: i0.ContentChild, args: [i0.forwardRef(() => UI_CONTROL), { isSignal: true }] }] } });
|
|
979
|
-
|
|
980
|
-
/** Available control sizes. `md` is the 44/40px touch target. */
|
|
981
|
-
const CONTROL_SIZES = ['sm', 'md'];
|
|
982
|
-
const CONTROL_BASE_CLASSES = 'w-full rounded-control bg-(--background) px-3 text-body text-(--foreground) shadow-[inset_0_0_0_1px_var(--border)] transition-shadow duration-(--duration-fast) ease-out placeholder:text-(--muted-foreground) focus-visible:shadow-[inset_0_0_0_2px_var(--ring)] aria-invalid:shadow-[inset_0_0_0_2px_var(--negative)] disabled:cursor-not-allowed disabled:opacity-40';
|
|
983
|
-
const CONTROL_SIZE_CLASSES = {
|
|
984
|
-
sm: 'h-9',
|
|
985
|
-
md: 'min-h-(--row-min)',
|
|
986
|
-
};
|
|
987
|
-
/**
|
|
988
|
-
* Styled native text input. A directive (not a wrapper component) so the host
|
|
989
|
-
* stays a plain <input>: every forms flavor (ngModel, reactive, signal forms)
|
|
990
|
-
* and every native attribute keep working without any plumbing.
|
|
991
|
-
*
|
|
992
|
-
* Declares the `errors` and `touched` inputs Angular's `[formField]` fills, so a `ui-field` around
|
|
993
|
-
* it can show the message without any binding here.
|
|
994
|
-
*
|
|
995
|
-
* @example
|
|
996
|
-
* <input uiInput type="email" placeholder="you@example.com" />
|
|
997
|
-
*/
|
|
998
|
-
class UiInput {
|
|
999
|
-
size = input('md', /* @ts-ignore */
|
|
1000
|
-
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
1001
|
-
errors = input([], /* @ts-ignore */
|
|
1002
|
-
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
1003
|
-
touched = input(false, /* @ts-ignore */
|
|
1004
|
-
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
1005
|
-
classes = computed(() => `${CONTROL_BASE_CLASSES} ${CONTROL_SIZE_CLASSES[this.size()]}`, /* @ts-ignore */
|
|
1006
|
-
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
1007
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiInput, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1008
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiInput, isStandalone: true, selector: "input[uiInput]", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, providers: [{ provide: UI_CONTROL, useExisting: forwardRef(() => UiInput) }], ngImport: i0 });
|
|
1009
|
-
}
|
|
1010
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiInput, decorators: [{
|
|
1011
|
-
type: Directive,
|
|
1012
|
-
args: [{
|
|
1013
|
-
selector: 'input[uiInput]',
|
|
1014
|
-
host: {
|
|
1015
|
-
'[class]': 'classes()',
|
|
1016
|
-
},
|
|
1017
|
-
providers: [{ provide: UI_CONTROL, useExisting: forwardRef(() => UiInput) }],
|
|
1018
|
-
}]
|
|
1019
|
-
}], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }] } });
|
|
1020
|
-
/**
|
|
1021
|
-
* Styled native textarea. Lives beside the input because it shares every one of its
|
|
1022
|
-
* classes; it takes no size, since a textarea grows from a floor instead of sitting
|
|
1023
|
-
* at a fixed height.
|
|
1024
|
-
*
|
|
1025
|
-
* Declares the `errors` and `touched` inputs Angular's `[formField]` fills, so a `ui-field` around
|
|
1026
|
-
* it can show the message without any binding here.
|
|
1027
|
-
*
|
|
1028
|
-
* @example
|
|
1029
|
-
* <textarea uiTextarea maxlength="280"></textarea>
|
|
1030
|
-
*/
|
|
1031
|
-
class UiTextarea {
|
|
1032
|
-
errors = input([], /* @ts-ignore */
|
|
1033
|
-
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
1034
|
-
touched = input(false, /* @ts-ignore */
|
|
1035
|
-
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
1036
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTextarea, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1037
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiTextarea, isStandalone: true, selector: "textarea[uiTextarea]", inputs: { errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "w-full rounded-control bg-(--background) px-3 text-body text-(--foreground) shadow-[inset_0_0_0_1px_var(--border)] transition-shadow duration-(--duration-fast) ease-out placeholder:text-(--muted-foreground) focus-visible:shadow-[inset_0_0_0_2px_var(--ring)] aria-invalid:shadow-[inset_0_0_0_2px_var(--negative)] disabled:cursor-not-allowed disabled:opacity-40 min-h-24 py-2" }, providers: [{ provide: UI_CONTROL, useExisting: forwardRef(() => UiTextarea) }], ngImport: i0 });
|
|
1038
|
-
}
|
|
1039
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTextarea, decorators: [{
|
|
1040
|
-
type: Directive,
|
|
1041
|
-
args: [{
|
|
1042
|
-
selector: 'textarea[uiTextarea]',
|
|
1043
|
-
host: {
|
|
1044
|
-
class: `${CONTROL_BASE_CLASSES} min-h-24 py-2`,
|
|
1045
|
-
},
|
|
1046
|
-
providers: [{ provide: UI_CONTROL, useExisting: forwardRef(() => UiTextarea) }],
|
|
1047
|
-
}]
|
|
1048
|
-
}], propDecorators: { errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }] } });
|
|
1570
|
+
}], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], labelHidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelHidden", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], unit: [{ type: i0.Input, args: [{ isSignal: true, alias: "unit", required: false }] }], control: [{ type: i0.ContentChild, args: [i0.forwardRef(() => UI_CONTROL), { isSignal: true }] }], leading: [{ type: i0.ContentChild, args: [i0.forwardRef(() => UiFieldLeading), { isSignal: true }] }] } });
|
|
1049
1571
|
|
|
1050
1572
|
const axisTicks = (points, maxTicks = 5) => {
|
|
1051
1573
|
if (points.length <= maxTicks) {
|
|
@@ -1059,6 +1581,13 @@ const axisTicks = (points, maxTicks = 5) => {
|
|
|
1059
1581
|
}
|
|
1060
1582
|
return [...indexes].sort((a, b) => a - b).map((index) => points[index]);
|
|
1061
1583
|
};
|
|
1584
|
+
const isCoreTick = (index, count) => {
|
|
1585
|
+
if (count <= 3) {
|
|
1586
|
+
return true;
|
|
1587
|
+
}
|
|
1588
|
+
const middle = Math.floor((count - 1) / 2);
|
|
1589
|
+
return index === 0 || index === count - 1 || index === middle;
|
|
1590
|
+
};
|
|
1062
1591
|
|
|
1063
1592
|
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
|
|
1064
1593
|
const nearestPointIndex = (points, x) => {
|
|
@@ -1090,6 +1619,36 @@ const navigateIndex = (key, current, last) => {
|
|
|
1090
1619
|
}
|
|
1091
1620
|
};
|
|
1092
1621
|
|
|
1622
|
+
const START_LABEL_HEIGHT = 16;
|
|
1623
|
+
const AXIS_ROW = 17;
|
|
1624
|
+
const TOOLTIP_SIZES = ['compact', 'large'];
|
|
1625
|
+
const TOOLTIP_CLASSES = {
|
|
1626
|
+
compact: { box: '-top-3 px-2.5', value: 'text-label', delta: 'text-caption' },
|
|
1627
|
+
large: { box: 'top-0 px-3', value: 'text-body', delta: 'text-label' },
|
|
1628
|
+
};
|
|
1629
|
+
const PLOT_PADDING_RATIO = 16 / 240;
|
|
1630
|
+
const SPARKLINE_PADDING = 4;
|
|
1631
|
+
const START_LABEL_BASELINE_OFFSET = 4;
|
|
1632
|
+
const TOOLTIP_OFFSET = 14;
|
|
1633
|
+
const TOOLTIP_FLIP_RATIO = 0.55;
|
|
1634
|
+
const plotHeightFor = (height, sparkline, axisGap, wide) => sparkline ? height : Math.max(height - resolveGap(axisGap, wide) - AXIS_ROW, 1);
|
|
1635
|
+
const plotPaddingFor = (plotHeight, sparkline) => sparkline ? SPARKLINE_PADDING : plotHeight * PLOT_PADDING_RATIO;
|
|
1636
|
+
const startLabelBaseline = (boxBottom) => boxBottom - START_LABEL_BASELINE_OFFSET;
|
|
1637
|
+
const tooltipPlacement = (ratio) => {
|
|
1638
|
+
const flipped = ratio > TOOLTIP_FLIP_RATIO;
|
|
1639
|
+
return `left: calc(${ratio * 100}% ${flipped ? '-' : '+'} ${TOOLTIP_OFFSET}px); transform: ${flipped ? 'translateX(-100%)' : 'none'}`;
|
|
1640
|
+
};
|
|
1641
|
+
const deltaTone = (delta) => delta > 0 ? 'text-(--positive)' : delta < 0 ? 'text-(--negative)' : 'text-(--muted-foreground)';
|
|
1642
|
+
const DEFAULT_WIDTH = 640;
|
|
1643
|
+
const DEFAULT_HEIGHT = 240;
|
|
1644
|
+
const identityValue = (value) => `${value}`;
|
|
1645
|
+
const identityDelta = (delta) => `${delta > 0 ? '+' : ''}${delta}`;
|
|
1646
|
+
const identityTime = (time) => new Date(time).toISOString();
|
|
1647
|
+
const parseAxisTicks = (value) => value === 'auto' ? 'auto' : Number(value);
|
|
1648
|
+
const resolveGap = (gap, wide) => (gap === 'auto' ? (wide ? 16 : 12) : gap);
|
|
1649
|
+
const resolveTooltip = (size, wide) => size === 'auto' ? (wide ? 'large' : 'compact') : size;
|
|
1650
|
+
const tooltipClassesFor = (size, wide) => TOOLTIP_CLASSES[resolveTooltip(size, wide)];
|
|
1651
|
+
|
|
1093
1652
|
const CURVE = curveMonotoneX;
|
|
1094
1653
|
const buildGeometry = (points, width, height, padding = {}) => {
|
|
1095
1654
|
if (points.length === 0) {
|
|
@@ -1125,8 +1684,8 @@ const buildGeometry = (points, width, height, padding = {}) => {
|
|
|
1125
1684
|
};
|
|
1126
1685
|
};
|
|
1127
1686
|
|
|
1128
|
-
const LINE_GAP =
|
|
1129
|
-
const COLLISION_MARGIN =
|
|
1687
|
+
const LINE_GAP = 6;
|
|
1688
|
+
const COLLISION_MARGIN = 6;
|
|
1130
1689
|
const EDGE_TOLERANCE = 3;
|
|
1131
1690
|
const candidateSlots = (startY, box, label) => {
|
|
1132
1691
|
const aboveTop = startY - LINE_GAP - label.height;
|
|
@@ -1163,6 +1722,9 @@ const placeStartLabel = (points, startY, box, label) => {
|
|
|
1163
1722
|
break;
|
|
1164
1723
|
}
|
|
1165
1724
|
}
|
|
1725
|
+
if (!best) {
|
|
1726
|
+
return { anchor: 'end', x: box.width, y: label.height };
|
|
1727
|
+
}
|
|
1166
1728
|
const { anchor, x, y } = best.slot;
|
|
1167
1729
|
return { anchor, x, y };
|
|
1168
1730
|
};
|
|
@@ -1236,13 +1798,19 @@ const interpolateLine = (from, to, progress) => {
|
|
|
1236
1798
|
return buildPolyline(samples, fromYs.map((fromY, index) => fromY + (toYs[index] - fromY) * progress));
|
|
1237
1799
|
};
|
|
1238
1800
|
|
|
1239
|
-
const
|
|
1240
|
-
const
|
|
1241
|
-
const
|
|
1242
|
-
const
|
|
1243
|
-
|
|
1244
|
-
const
|
|
1245
|
-
|
|
1801
|
+
const WIDE_QUERY = '(min-width: 64rem)';
|
|
1802
|
+
const wideViewport = () => {
|
|
1803
|
+
const query = typeof matchMedia === 'function' ? matchMedia(WIDE_QUERY) : null;
|
|
1804
|
+
const wide = signal(query?.matches ?? false, /* @ts-ignore */
|
|
1805
|
+
...(ngDevMode ? [{ debugName: "wide" }] : /* istanbul ignore next */ []));
|
|
1806
|
+
const onChange = (event) => wide.set(event.matches);
|
|
1807
|
+
if (query) {
|
|
1808
|
+
query.onchange = onChange;
|
|
1809
|
+
inject(DestroyRef).onDestroy(() => (query.onchange = null));
|
|
1810
|
+
}
|
|
1811
|
+
return wide;
|
|
1812
|
+
};
|
|
1813
|
+
|
|
1246
1814
|
/**
|
|
1247
1815
|
* Value over time: a monotone curve with a dashed line at the starting value and a tooltip.
|
|
1248
1816
|
*
|
|
@@ -1268,10 +1836,19 @@ class UiLineChart {
|
|
|
1268
1836
|
...(ngDevMode ? [{ debugName: "timeColumnLabel" }] : /* istanbul ignore next */ []));
|
|
1269
1837
|
valueColumnLabel = input('Value', /* @ts-ignore */
|
|
1270
1838
|
...(ngDevMode ? [{ debugName: "valueColumnLabel" }] : /* istanbul ignore next */ []));
|
|
1839
|
+
sparkline = input(false, { ...(ngDevMode ? { debugName: "sparkline" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1840
|
+
tooltip = input('compact', /* @ts-ignore */
|
|
1841
|
+
...(ngDevMode ? [{ debugName: "tooltip" }] : /* istanbul ignore next */ []));
|
|
1842
|
+
tooltipDelta = input(true, { ...(ngDevMode ? { debugName: "tooltipDelta" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1843
|
+
axisGap = input(12, /* @ts-ignore */
|
|
1844
|
+
...(ngDevMode ? [{ debugName: "axisGap" }] : /* istanbul ignore next */ []));
|
|
1845
|
+
axisTicks = input('auto', { ...(ngDevMode ? { debugName: "axisTicks" } : /* istanbul ignore next */ {}), transform: parseAxisTicks });
|
|
1271
1846
|
#destroyRef = inject(DestroyRef);
|
|
1847
|
+
#wide = wideViewport();
|
|
1272
1848
|
#frame = null;
|
|
1273
1849
|
#hasRenderedOnce = false;
|
|
1274
1850
|
#previousGeometry = null;
|
|
1851
|
+
isCoreTick = isCoreTick;
|
|
1275
1852
|
svgRef = viewChild.required('svgRef', /* @ts-ignore */
|
|
1276
1853
|
...(ngDevMode ? [{ debugName: "svgRef" }] : /* istanbul ignore next */ []));
|
|
1277
1854
|
activeIndex = signal(null, /* @ts-ignore */
|
|
@@ -1284,7 +1861,16 @@ class UiLineChart {
|
|
|
1284
1861
|
...(ngDevMode ? [{ debugName: "effectiveWidth" }] : /* istanbul ignore next */ []));
|
|
1285
1862
|
effectiveHeight = computed(() => this.measuredSize()?.height ?? DEFAULT_HEIGHT, /* @ts-ignore */
|
|
1286
1863
|
...(ngDevMode ? [{ debugName: "effectiveHeight" }] : /* istanbul ignore next */ []));
|
|
1287
|
-
|
|
1864
|
+
plotHeight = computed(() => plotHeightFor(this.effectiveHeight(), this.sparkline(), this.axisGap(), this.#wide()), /* @ts-ignore */
|
|
1865
|
+
...(ngDevMode ? [{ debugName: "plotHeight" }] : /* istanbul ignore next */ []));
|
|
1866
|
+
tooltipStyle = (point) => tooltipPlacement(point.x / this.effectiveWidth());
|
|
1867
|
+
tooltipClasses = computed(() => tooltipClassesFor(this.tooltip(), this.#wide()), /* @ts-ignore */
|
|
1868
|
+
...(ngDevMode ? [{ debugName: "tooltipClasses" }] : /* istanbul ignore next */ []));
|
|
1869
|
+
geometry = computed(() => {
|
|
1870
|
+
const plotHeight = this.plotHeight();
|
|
1871
|
+
const padding = plotPaddingFor(plotHeight, this.sparkline());
|
|
1872
|
+
return buildGeometry(this.points(), this.effectiveWidth(), plotHeight, { x: 0, top: padding, bottom: padding });
|
|
1873
|
+
}, /* @ts-ignore */
|
|
1288
1874
|
...(ngDevMode ? [{ debugName: "geometry" }] : /* istanbul ignore next */ []));
|
|
1289
1875
|
displayLine = computed(() => this.animatedLine() ?? this.geometry().line, /* @ts-ignore */
|
|
1290
1876
|
...(ngDevMode ? [{ debugName: "displayLine" }] : /* istanbul ignore next */ []));
|
|
@@ -1304,8 +1890,8 @@ class UiLineChart {
|
|
|
1304
1890
|
}
|
|
1305
1891
|
const label = `${text} ${this.valueFormat()(geometry.points[0].v)}`;
|
|
1306
1892
|
const size = { width: label.length * 0.56 * 12 + 8, height: START_LABEL_HEIGHT };
|
|
1307
|
-
const placement = placeStartLabel(geometry.points, geometry.start.y, { width: this.effectiveWidth(), height: this.
|
|
1308
|
-
return { label, placement };
|
|
1893
|
+
const placement = placeStartLabel(geometry.points, geometry.start.y, { width: this.effectiveWidth(), height: this.plotHeight() }, size);
|
|
1894
|
+
return { label, placement: { ...placement, y: startLabelBaseline(placement.y) } };
|
|
1309
1895
|
}, /* @ts-ignore */
|
|
1310
1896
|
...(ngDevMode ? [{ debugName: "startLabelInfo" }] : /* istanbul ignore next */ []));
|
|
1311
1897
|
#renderRef = afterNextRender(() => this.#observeSize());
|
|
@@ -1350,10 +1936,8 @@ class UiLineChart {
|
|
|
1350
1936
|
this.#destroyRef.onDestroy(() => observer.disconnect());
|
|
1351
1937
|
}
|
|
1352
1938
|
#cancelAnimation() {
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
this.#frame = null;
|
|
1356
|
-
}
|
|
1939
|
+
cancelAnimationFrame(this.#frame ?? 0);
|
|
1940
|
+
this.#frame = null;
|
|
1357
1941
|
}
|
|
1358
1942
|
#animate(from, to) {
|
|
1359
1943
|
if (from.points.length < 2 || to.points.length < 2) {
|
|
@@ -1363,37 +1947,20 @@ class UiLineChart {
|
|
|
1363
1947
|
const startTime = performance.now();
|
|
1364
1948
|
const step = (now) => {
|
|
1365
1949
|
const t = Math.min(1, (now - startTime) / TRANSITION_DURATION);
|
|
1366
|
-
this.animatedLine.set(interpolateLine(from, to, easeOutQuint(t)));
|
|
1367
|
-
|
|
1368
|
-
this.#frame = requestAnimationFrame(step);
|
|
1369
|
-
}
|
|
1370
|
-
else {
|
|
1371
|
-
this.#frame = null;
|
|
1372
|
-
this.animatedLine.set(null);
|
|
1373
|
-
}
|
|
1950
|
+
this.animatedLine.set(t < 1 ? interpolateLine(from, to, easeOutQuint(t)) : null);
|
|
1951
|
+
this.#frame = t < 1 ? requestAnimationFrame(step) : null;
|
|
1374
1952
|
};
|
|
1375
1953
|
this.#frame = requestAnimationFrame(step);
|
|
1376
1954
|
}
|
|
1377
|
-
coreTick(index, count) {
|
|
1378
|
-
if (count <= 3) {
|
|
1379
|
-
return true;
|
|
1380
|
-
}
|
|
1381
|
-
const middle = Math.floor((count - 1) / 2);
|
|
1382
|
-
return index === 0 || index === count - 1 || index === middle;
|
|
1383
|
-
}
|
|
1384
1955
|
deltaFor(point) {
|
|
1385
1956
|
return point.v - this.points()[0].v;
|
|
1386
1957
|
}
|
|
1387
1958
|
deltaClasses(point) {
|
|
1388
|
-
|
|
1389
|
-
return delta > 0 ? 'text-(--positive)' : delta < 0 ? 'text-(--negative)' : 'text-(--muted-foreground)';
|
|
1390
|
-
}
|
|
1391
|
-
tooltipStyle(point) {
|
|
1392
|
-
return `left: ${(point.x / this.effectiveWidth()) * 100}%; top: ${(point.y / this.effectiveHeight()) * 100}%`;
|
|
1959
|
+
return `${this.tooltipClasses().delta} ${deltaTone(this.deltaFor(point))}`;
|
|
1393
1960
|
}
|
|
1394
1961
|
onPointerMove(event) {
|
|
1395
1962
|
const geometry = this.geometry();
|
|
1396
|
-
if (!geometry || geometry.points.length === 0) {
|
|
1963
|
+
if (this.sparkline() || !geometry || geometry.points.length === 0) {
|
|
1397
1964
|
return;
|
|
1398
1965
|
}
|
|
1399
1966
|
const rect = this.svgRef().nativeElement.getBoundingClientRect();
|
|
@@ -1406,7 +1973,7 @@ class UiLineChart {
|
|
|
1406
1973
|
}
|
|
1407
1974
|
onKeydown(event) {
|
|
1408
1975
|
const geometry = this.geometry();
|
|
1409
|
-
if (!geometry || geometry.points.length === 0) {
|
|
1976
|
+
if (this.sparkline() || !geometry || geometry.points.length === 0) {
|
|
1410
1977
|
return;
|
|
1411
1978
|
}
|
|
1412
1979
|
const navigation = navigateIndex(event.key, this.activeIndex(), geometry.points.length - 1);
|
|
@@ -1419,15 +1986,15 @@ class UiLineChart {
|
|
|
1419
1986
|
this.activeIndex.set(navigation.index);
|
|
1420
1987
|
}
|
|
1421
1988
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiLineChart, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1422
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiLineChart, isStandalone: true, selector: "ui-line-chart", inputs: { points: { classPropertyName: "points", publicName: "points", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, valueFormat: { classPropertyName: "valueFormat", publicName: "valueFormat", isSignal: true, isRequired: false, transformFunction: null }, deltaFormat: { classPropertyName: "deltaFormat", publicName: "deltaFormat", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, axisFormat: { classPropertyName: "axisFormat", publicName: "axisFormat", isSignal: true, isRequired: false, transformFunction: null }, startLabel: { classPropertyName: "startLabel", publicName: "startLabel", isSignal: true, isRequired: false, transformFunction: null }, timeColumnLabel: { classPropertyName: "timeColumnLabel", publicName: "timeColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, valueColumnLabel: { classPropertyName: "valueColumnLabel", publicName: "valueColumnLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "block h-full" }, viewQueries: [{ propertyName: "svgRef", first: true, predicate: ["svgRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1989
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiLineChart, isStandalone: true, selector: "ui-line-chart", inputs: { points: { classPropertyName: "points", publicName: "points", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, valueFormat: { classPropertyName: "valueFormat", publicName: "valueFormat", isSignal: true, isRequired: false, transformFunction: null }, deltaFormat: { classPropertyName: "deltaFormat", publicName: "deltaFormat", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, axisFormat: { classPropertyName: "axisFormat", publicName: "axisFormat", isSignal: true, isRequired: false, transformFunction: null }, startLabel: { classPropertyName: "startLabel", publicName: "startLabel", isSignal: true, isRequired: false, transformFunction: null }, timeColumnLabel: { classPropertyName: "timeColumnLabel", publicName: "timeColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, valueColumnLabel: { classPropertyName: "valueColumnLabel", publicName: "valueColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, sparkline: { classPropertyName: "sparkline", publicName: "sparkline", isSignal: true, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: true, isRequired: false, transformFunction: null }, tooltipDelta: { classPropertyName: "tooltipDelta", publicName: "tooltipDelta", isSignal: true, isRequired: false, transformFunction: null }, axisGap: { classPropertyName: "axisGap", publicName: "axisGap", isSignal: true, isRequired: false, transformFunction: null }, axisTicks: { classPropertyName: "axisTicks", publicName: "axisTicks", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "block h-full" }, viewQueries: [{ propertyName: "svgRef", first: true, predicate: ["svgRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1423
1990
|
<div class="relative h-full">
|
|
1424
1991
|
<svg
|
|
1425
1992
|
#svgRef
|
|
1426
|
-
class="block h-full w-full touch-pan-y"
|
|
1993
|
+
class="block h-full w-full touch-pan-y overflow-visible"
|
|
1427
1994
|
role="img"
|
|
1428
|
-
tabindex="0"
|
|
1429
1995
|
[attr.aria-label]="label()"
|
|
1430
1996
|
[attr.height]="effectiveHeight()"
|
|
1997
|
+
[attr.tabindex]="sparkline() ? null : 0"
|
|
1431
1998
|
[attr.viewBox]="'0 0 ' + effectiveWidth() + ' ' + effectiveHeight()"
|
|
1432
1999
|
[attr.width]="effectiveWidth()"
|
|
1433
2000
|
(keydown)="onKeydown($event)"
|
|
@@ -1441,94 +2008,100 @@ class UiLineChart {
|
|
|
1441
2008
|
fill="none"
|
|
1442
2009
|
stroke-linecap="round"
|
|
1443
2010
|
stroke-linejoin="round"
|
|
1444
|
-
stroke-width="2"
|
|
1445
2011
|
[attr.d]="displayLine()"
|
|
2012
|
+
[attr.stroke-width]="sparkline() ? 1.5 : 2"
|
|
1446
2013
|
/>
|
|
1447
2014
|
|
|
1448
|
-
|
|
1449
|
-
class="stroke-(--border)"
|
|
1450
|
-
data-chart-start-line
|
|
1451
|
-
stroke-dasharray="4 4"
|
|
1452
|
-
stroke-width="1"
|
|
1453
|
-
x1="0"
|
|
1454
|
-
[attr.x2]="effectiveWidth()"
|
|
1455
|
-
[attr.y1]="geometry.start.y"
|
|
1456
|
-
[attr.y2]="geometry.start.y"
|
|
1457
|
-
/>
|
|
1458
|
-
|
|
1459
|
-
@if (startLabelInfo(); as info) {
|
|
1460
|
-
<text
|
|
1461
|
-
class="text-caption fill-(--subtle-foreground)"
|
|
1462
|
-
data-chart-start-label
|
|
1463
|
-
[attr.text-anchor]="info.placement.anchor"
|
|
1464
|
-
[attr.x]="info.placement.x"
|
|
1465
|
-
[attr.y]="info.placement.y"
|
|
1466
|
-
>
|
|
1467
|
-
{{ info.label }}
|
|
1468
|
-
</text>
|
|
1469
|
-
}
|
|
1470
|
-
|
|
1471
|
-
<circle
|
|
1472
|
-
class="fill-(--foreground) stroke-(--card)"
|
|
1473
|
-
data-chart-end
|
|
1474
|
-
r="4"
|
|
1475
|
-
stroke-width="2"
|
|
1476
|
-
[attr.cx]="geometry.end.x"
|
|
1477
|
-
[attr.cy]="geometry.end.y"
|
|
1478
|
-
/>
|
|
1479
|
-
|
|
1480
|
-
@for (
|
|
1481
|
-
tick of ticks();
|
|
1482
|
-
track tick.t;
|
|
1483
|
-
let index = $index;
|
|
1484
|
-
let count = $count;
|
|
1485
|
-
let first = $first;
|
|
1486
|
-
let last = $last
|
|
1487
|
-
) {
|
|
1488
|
-
<text
|
|
1489
|
-
class="text-caption fill-(--subtle-foreground)"
|
|
1490
|
-
data-chart-axis-tick
|
|
1491
|
-
[attr.text-anchor]="first ? 'start' : last ? 'end' : 'middle'"
|
|
1492
|
-
[attr.x]="tick.x"
|
|
1493
|
-
[attr.y]="effectiveHeight() - 4"
|
|
1494
|
-
[class.max-sm:hidden]="!coreTick(index, count)"
|
|
1495
|
-
>
|
|
1496
|
-
{{ axisFormat()(tick.t) }}
|
|
1497
|
-
</text>
|
|
1498
|
-
}
|
|
1499
|
-
|
|
1500
|
-
@if (active(); as point) {
|
|
2015
|
+
@if (!sparkline()) {
|
|
1501
2016
|
<line
|
|
1502
2017
|
class="stroke-(--border)"
|
|
1503
|
-
data-chart-
|
|
2018
|
+
data-chart-start-line
|
|
2019
|
+
stroke-dasharray="3 4"
|
|
1504
2020
|
stroke-width="1"
|
|
1505
|
-
|
|
1506
|
-
[attr.
|
|
1507
|
-
[attr.
|
|
1508
|
-
[attr.y2]="
|
|
2021
|
+
x1="0"
|
|
2022
|
+
[attr.x2]="effectiveWidth()"
|
|
2023
|
+
[attr.y1]="geometry.start.y"
|
|
2024
|
+
[attr.y2]="geometry.start.y"
|
|
1509
2025
|
/>
|
|
2026
|
+
|
|
2027
|
+
@if (startLabelInfo(); as info) {
|
|
2028
|
+
<text
|
|
2029
|
+
class="text-caption fill-(--subtle-foreground) tabular-nums"
|
|
2030
|
+
data-chart-start-label
|
|
2031
|
+
[attr.text-anchor]="info.placement.anchor"
|
|
2032
|
+
[attr.x]="info.placement.x"
|
|
2033
|
+
[attr.y]="info.placement.y"
|
|
2034
|
+
>
|
|
2035
|
+
{{ info.label }}
|
|
2036
|
+
</text>
|
|
2037
|
+
}
|
|
2038
|
+
|
|
1510
2039
|
<circle
|
|
1511
|
-
class="fill-(--foreground) stroke-(--card)"
|
|
1512
|
-
data-chart-
|
|
2040
|
+
class="fill-(--foreground) stroke-(--card) [paint-order:stroke]"
|
|
2041
|
+
data-chart-end
|
|
1513
2042
|
r="4"
|
|
1514
|
-
stroke-width="
|
|
1515
|
-
[attr.cx]="
|
|
1516
|
-
[attr.cy]="
|
|
2043
|
+
stroke-width="6"
|
|
2044
|
+
[attr.cx]="geometry.end.x"
|
|
2045
|
+
[attr.cy]="geometry.end.y"
|
|
1517
2046
|
/>
|
|
2047
|
+
|
|
2048
|
+
@for (
|
|
2049
|
+
tick of ticks();
|
|
2050
|
+
track tick.t;
|
|
2051
|
+
let index = $index;
|
|
2052
|
+
let count = $count;
|
|
2053
|
+
let first = $first;
|
|
2054
|
+
let last = $last
|
|
2055
|
+
) {
|
|
2056
|
+
<text
|
|
2057
|
+
class="text-caption fill-(--subtle-foreground) tabular-nums"
|
|
2058
|
+
data-chart-axis-tick
|
|
2059
|
+
[attr.text-anchor]="first ? 'start' : last ? 'end' : 'middle'"
|
|
2060
|
+
[attr.x]="tick.x"
|
|
2061
|
+
[attr.y]="effectiveHeight() - 4"
|
|
2062
|
+
[class.hidden]="axisTicks() === 3 && !isCoreTick(index, count)"
|
|
2063
|
+
[class.max-sm:hidden]="axisTicks() === 'auto' && !isCoreTick(index, count)"
|
|
2064
|
+
>
|
|
2065
|
+
{{ axisFormat()(tick.t) }}
|
|
2066
|
+
</text>
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
@if (active(); as point) {
|
|
2070
|
+
<line
|
|
2071
|
+
class="stroke-(--border)"
|
|
2072
|
+
data-chart-crosshair
|
|
2073
|
+
stroke-width="1"
|
|
2074
|
+
y1="0"
|
|
2075
|
+
[attr.x1]="point.x"
|
|
2076
|
+
[attr.x2]="point.x"
|
|
2077
|
+
[attr.y2]="plotHeight()"
|
|
2078
|
+
/>
|
|
2079
|
+
<circle
|
|
2080
|
+
class="fill-(--foreground) stroke-(--card) [paint-order:stroke]"
|
|
2081
|
+
data-chart-active
|
|
2082
|
+
r="5"
|
|
2083
|
+
stroke-width="6"
|
|
2084
|
+
[attr.cx]="point.x"
|
|
2085
|
+
[attr.cy]="point.y"
|
|
2086
|
+
/>
|
|
2087
|
+
}
|
|
1518
2088
|
}
|
|
1519
2089
|
}
|
|
1520
2090
|
</svg>
|
|
1521
2091
|
|
|
1522
2092
|
@if (active(); as point) {
|
|
1523
2093
|
<div
|
|
1524
|
-
class="rounded-container
|
|
2094
|
+
class="rounded-container pointer-events-none absolute bg-(--elevated) py-2 whitespace-nowrap [font-variant-numeric:var(--numeric)] shadow-[0_4px_16px_rgb(0_0_0/0.12),inset_0_0_0_1px_var(--border)]"
|
|
1525
2095
|
data-testid="chart-tooltip"
|
|
1526
2096
|
role="status"
|
|
2097
|
+
[class]="tooltipClasses().box"
|
|
1527
2098
|
[style]="tooltipStyle(point)"
|
|
1528
2099
|
>
|
|
1529
|
-
<p class="font-medium text-(--foreground)">{{ valueFormat()(point.v) }}</p>
|
|
1530
|
-
|
|
1531
|
-
|
|
2100
|
+
<p class="font-medium text-(--foreground)" [class]="tooltipClasses().value">{{ valueFormat()(point.v) }}</p>
|
|
2101
|
+
@if (tooltipDelta()) {
|
|
2102
|
+
<p data-chart-delta [class]="deltaClasses(point)">{{ deltaFormat()(deltaFor(point)) }}</p>
|
|
2103
|
+
}
|
|
2104
|
+
<p class="text-caption text-(--subtle-foreground)" data-chart-date>{{ timeFormat()(point.t) }}</p>
|
|
1532
2105
|
</div>
|
|
1533
2106
|
}
|
|
1534
2107
|
|
|
@@ -1566,11 +2139,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1566
2139
|
<div class="relative h-full">
|
|
1567
2140
|
<svg
|
|
1568
2141
|
#svgRef
|
|
1569
|
-
class="block h-full w-full touch-pan-y"
|
|
2142
|
+
class="block h-full w-full touch-pan-y overflow-visible"
|
|
1570
2143
|
role="img"
|
|
1571
|
-
tabindex="0"
|
|
1572
2144
|
[attr.aria-label]="label()"
|
|
1573
2145
|
[attr.height]="effectiveHeight()"
|
|
2146
|
+
[attr.tabindex]="sparkline() ? null : 0"
|
|
1574
2147
|
[attr.viewBox]="'0 0 ' + effectiveWidth() + ' ' + effectiveHeight()"
|
|
1575
2148
|
[attr.width]="effectiveWidth()"
|
|
1576
2149
|
(keydown)="onKeydown($event)"
|
|
@@ -1584,94 +2157,100 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1584
2157
|
fill="none"
|
|
1585
2158
|
stroke-linecap="round"
|
|
1586
2159
|
stroke-linejoin="round"
|
|
1587
|
-
stroke-width="2"
|
|
1588
2160
|
[attr.d]="displayLine()"
|
|
2161
|
+
[attr.stroke-width]="sparkline() ? 1.5 : 2"
|
|
1589
2162
|
/>
|
|
1590
2163
|
|
|
1591
|
-
|
|
1592
|
-
class="stroke-(--border)"
|
|
1593
|
-
data-chart-start-line
|
|
1594
|
-
stroke-dasharray="4 4"
|
|
1595
|
-
stroke-width="1"
|
|
1596
|
-
x1="0"
|
|
1597
|
-
[attr.x2]="effectiveWidth()"
|
|
1598
|
-
[attr.y1]="geometry.start.y"
|
|
1599
|
-
[attr.y2]="geometry.start.y"
|
|
1600
|
-
/>
|
|
1601
|
-
|
|
1602
|
-
@if (startLabelInfo(); as info) {
|
|
1603
|
-
<text
|
|
1604
|
-
class="text-caption fill-(--subtle-foreground)"
|
|
1605
|
-
data-chart-start-label
|
|
1606
|
-
[attr.text-anchor]="info.placement.anchor"
|
|
1607
|
-
[attr.x]="info.placement.x"
|
|
1608
|
-
[attr.y]="info.placement.y"
|
|
1609
|
-
>
|
|
1610
|
-
{{ info.label }}
|
|
1611
|
-
</text>
|
|
1612
|
-
}
|
|
1613
|
-
|
|
1614
|
-
<circle
|
|
1615
|
-
class="fill-(--foreground) stroke-(--card)"
|
|
1616
|
-
data-chart-end
|
|
1617
|
-
r="4"
|
|
1618
|
-
stroke-width="2"
|
|
1619
|
-
[attr.cx]="geometry.end.x"
|
|
1620
|
-
[attr.cy]="geometry.end.y"
|
|
1621
|
-
/>
|
|
1622
|
-
|
|
1623
|
-
@for (
|
|
1624
|
-
tick of ticks();
|
|
1625
|
-
track tick.t;
|
|
1626
|
-
let index = $index;
|
|
1627
|
-
let count = $count;
|
|
1628
|
-
let first = $first;
|
|
1629
|
-
let last = $last
|
|
1630
|
-
) {
|
|
1631
|
-
<text
|
|
1632
|
-
class="text-caption fill-(--subtle-foreground)"
|
|
1633
|
-
data-chart-axis-tick
|
|
1634
|
-
[attr.text-anchor]="first ? 'start' : last ? 'end' : 'middle'"
|
|
1635
|
-
[attr.x]="tick.x"
|
|
1636
|
-
[attr.y]="effectiveHeight() - 4"
|
|
1637
|
-
[class.max-sm:hidden]="!coreTick(index, count)"
|
|
1638
|
-
>
|
|
1639
|
-
{{ axisFormat()(tick.t) }}
|
|
1640
|
-
</text>
|
|
1641
|
-
}
|
|
1642
|
-
|
|
1643
|
-
@if (active(); as point) {
|
|
2164
|
+
@if (!sparkline()) {
|
|
1644
2165
|
<line
|
|
1645
2166
|
class="stroke-(--border)"
|
|
1646
|
-
data-chart-
|
|
2167
|
+
data-chart-start-line
|
|
2168
|
+
stroke-dasharray="3 4"
|
|
1647
2169
|
stroke-width="1"
|
|
1648
|
-
|
|
1649
|
-
[attr.
|
|
1650
|
-
[attr.
|
|
1651
|
-
[attr.y2]="
|
|
2170
|
+
x1="0"
|
|
2171
|
+
[attr.x2]="effectiveWidth()"
|
|
2172
|
+
[attr.y1]="geometry.start.y"
|
|
2173
|
+
[attr.y2]="geometry.start.y"
|
|
1652
2174
|
/>
|
|
2175
|
+
|
|
2176
|
+
@if (startLabelInfo(); as info) {
|
|
2177
|
+
<text
|
|
2178
|
+
class="text-caption fill-(--subtle-foreground) tabular-nums"
|
|
2179
|
+
data-chart-start-label
|
|
2180
|
+
[attr.text-anchor]="info.placement.anchor"
|
|
2181
|
+
[attr.x]="info.placement.x"
|
|
2182
|
+
[attr.y]="info.placement.y"
|
|
2183
|
+
>
|
|
2184
|
+
{{ info.label }}
|
|
2185
|
+
</text>
|
|
2186
|
+
}
|
|
2187
|
+
|
|
1653
2188
|
<circle
|
|
1654
|
-
class="fill-(--foreground) stroke-(--card)"
|
|
1655
|
-
data-chart-
|
|
2189
|
+
class="fill-(--foreground) stroke-(--card) [paint-order:stroke]"
|
|
2190
|
+
data-chart-end
|
|
1656
2191
|
r="4"
|
|
1657
|
-
stroke-width="
|
|
1658
|
-
[attr.cx]="
|
|
1659
|
-
[attr.cy]="
|
|
2192
|
+
stroke-width="6"
|
|
2193
|
+
[attr.cx]="geometry.end.x"
|
|
2194
|
+
[attr.cy]="geometry.end.y"
|
|
1660
2195
|
/>
|
|
2196
|
+
|
|
2197
|
+
@for (
|
|
2198
|
+
tick of ticks();
|
|
2199
|
+
track tick.t;
|
|
2200
|
+
let index = $index;
|
|
2201
|
+
let count = $count;
|
|
2202
|
+
let first = $first;
|
|
2203
|
+
let last = $last
|
|
2204
|
+
) {
|
|
2205
|
+
<text
|
|
2206
|
+
class="text-caption fill-(--subtle-foreground) tabular-nums"
|
|
2207
|
+
data-chart-axis-tick
|
|
2208
|
+
[attr.text-anchor]="first ? 'start' : last ? 'end' : 'middle'"
|
|
2209
|
+
[attr.x]="tick.x"
|
|
2210
|
+
[attr.y]="effectiveHeight() - 4"
|
|
2211
|
+
[class.hidden]="axisTicks() === 3 && !isCoreTick(index, count)"
|
|
2212
|
+
[class.max-sm:hidden]="axisTicks() === 'auto' && !isCoreTick(index, count)"
|
|
2213
|
+
>
|
|
2214
|
+
{{ axisFormat()(tick.t) }}
|
|
2215
|
+
</text>
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
@if (active(); as point) {
|
|
2219
|
+
<line
|
|
2220
|
+
class="stroke-(--border)"
|
|
2221
|
+
data-chart-crosshair
|
|
2222
|
+
stroke-width="1"
|
|
2223
|
+
y1="0"
|
|
2224
|
+
[attr.x1]="point.x"
|
|
2225
|
+
[attr.x2]="point.x"
|
|
2226
|
+
[attr.y2]="plotHeight()"
|
|
2227
|
+
/>
|
|
2228
|
+
<circle
|
|
2229
|
+
class="fill-(--foreground) stroke-(--card) [paint-order:stroke]"
|
|
2230
|
+
data-chart-active
|
|
2231
|
+
r="5"
|
|
2232
|
+
stroke-width="6"
|
|
2233
|
+
[attr.cx]="point.x"
|
|
2234
|
+
[attr.cy]="point.y"
|
|
2235
|
+
/>
|
|
2236
|
+
}
|
|
1661
2237
|
}
|
|
1662
2238
|
}
|
|
1663
2239
|
</svg>
|
|
1664
2240
|
|
|
1665
2241
|
@if (active(); as point) {
|
|
1666
2242
|
<div
|
|
1667
|
-
class="rounded-container
|
|
2243
|
+
class="rounded-container pointer-events-none absolute bg-(--elevated) py-2 whitespace-nowrap [font-variant-numeric:var(--numeric)] shadow-[0_4px_16px_rgb(0_0_0/0.12),inset_0_0_0_1px_var(--border)]"
|
|
1668
2244
|
data-testid="chart-tooltip"
|
|
1669
2245
|
role="status"
|
|
2246
|
+
[class]="tooltipClasses().box"
|
|
1670
2247
|
[style]="tooltipStyle(point)"
|
|
1671
2248
|
>
|
|
1672
|
-
<p class="font-medium text-(--foreground)">{{ valueFormat()(point.v) }}</p>
|
|
1673
|
-
|
|
1674
|
-
|
|
2249
|
+
<p class="font-medium text-(--foreground)" [class]="tooltipClasses().value">{{ valueFormat()(point.v) }}</p>
|
|
2250
|
+
@if (tooltipDelta()) {
|
|
2251
|
+
<p data-chart-delta [class]="deltaClasses(point)">{{ deltaFormat()(deltaFor(point)) }}</p>
|
|
2252
|
+
}
|
|
2253
|
+
<p class="text-caption text-(--subtle-foreground)" data-chart-date>{{ timeFormat()(point.t) }}</p>
|
|
1675
2254
|
</div>
|
|
1676
2255
|
}
|
|
1677
2256
|
|
|
@@ -1704,10 +2283,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1704
2283
|
class: 'block h-full',
|
|
1705
2284
|
},
|
|
1706
2285
|
}]
|
|
1707
|
-
}], ctorParameters: () => [], propDecorators: { points: [{ type: i0.Input, args: [{ isSignal: true, alias: "points", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], valueFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueFormat", required: false }] }], deltaFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "deltaFormat", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], axisFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "axisFormat", required: false }] }], startLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "startLabel", required: false }] }], timeColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeColumnLabel", required: false }] }], valueColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueColumnLabel", required: false }] }], svgRef: [{ type: i0.ViewChild, args: ['svgRef', { isSignal: true }] }] } });
|
|
2286
|
+
}], ctorParameters: () => [], propDecorators: { points: [{ type: i0.Input, args: [{ isSignal: true, alias: "points", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], valueFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueFormat", required: false }] }], deltaFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "deltaFormat", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], axisFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "axisFormat", required: false }] }], startLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "startLabel", required: false }] }], timeColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeColumnLabel", required: false }] }], valueColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueColumnLabel", required: false }] }], sparkline: [{ type: i0.Input, args: [{ isSignal: true, alias: "sparkline", required: false }] }], tooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltip", required: false }] }], tooltipDelta: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipDelta", required: false }] }], axisGap: [{ type: i0.Input, args: [{ isSignal: true, alias: "axisGap", required: false }] }], axisTicks: [{ type: i0.Input, args: [{ isSignal: true, alias: "axisTicks", required: false }] }], svgRef: [{ type: i0.ViewChild, args: ['svgRef', { isSignal: true }] }] } });
|
|
1708
2287
|
|
|
1709
|
-
const MENU_CLASSES = 'm-0 min-w-44 p-1 rounded-container bg-(--elevated) shadow-[0_8px_24px_rgb(0_0_0/0.16)] text-(--foreground) transition-[opacity,transform,overlay,display] transition-discrete duration-(--duration-fast) ease-out starting:open:opacity-0 starting:open:scale-(--enter-scale) opacity-0 scale-(--enter-scale) open:opacity-100 open:scale-100';
|
|
1710
|
-
const ITEM_CLASSES = 'flex w-full items-center gap-2 min-h-
|
|
2288
|
+
const MENU_CLASSES = 'm-0 min-w-44 p-1 rounded-container bg-(--elevated) shadow-[0_8px_24px_rgb(0_0_0/0.16),inset_0_0_0_1px_var(--border)] text-(--foreground) transition-[opacity,transform,overlay,display] transition-discrete duration-(--duration-fast) ease-out starting:open:opacity-0 starting:open:scale-(--enter-scale) opacity-0 scale-(--enter-scale) open:opacity-100 open:scale-100';
|
|
2289
|
+
const ITEM_CLASSES = 'flex w-full items-center gap-3 pointer-fine:gap-2.5 min-h-11 pointer-fine:min-h-9 px-3 pointer-fine:px-2.5 rounded-[calc(var(--radius-container)-4px)] text-body pointer-fine:text-label hover:bg-(--glow) focus-visible:bg-(--glow) outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring)';
|
|
1711
2290
|
const nextId = (() => {
|
|
1712
2291
|
let count = 0;
|
|
1713
2292
|
return () => `ui-menu-${++count}`;
|
|
@@ -1920,12 +2499,12 @@ class UiMeter {
|
|
|
1920
2499
|
...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
|
|
1921
2500
|
percent = computed(() => Math.min(100, Math.max(0, this.value() * 100)), /* @ts-ignore */
|
|
1922
2501
|
...(ngDevMode ? [{ debugName: "percent" }] : /* istanbul ignore next */ []));
|
|
1923
|
-
fillClasses = computed(() => `h-full rounded-
|
|
2502
|
+
fillClasses = computed(() => `h-full rounded-pill ${TONE_CLASSES[this.tone()]}`, /* @ts-ignore */
|
|
1924
2503
|
...(ngDevMode ? [{ debugName: "fillClasses" }] : /* istanbul ignore next */ []));
|
|
1925
2504
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiMeter, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1926
2505
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: UiMeter, isStandalone: true, selector: "ui-meter", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, valueText: { classPropertyName: "valueText", publicName: "valueText", isSignal: true, isRequired: true, transformFunction: null }, tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
1927
2506
|
<div
|
|
1928
|
-
class="rounded-
|
|
2507
|
+
class="rounded-pill h-1.5 w-full overflow-hidden bg-(--muted)"
|
|
1929
2508
|
role="meter"
|
|
1930
2509
|
[attr.aria-label]="label()"
|
|
1931
2510
|
[attr.aria-valuemax]="1"
|
|
@@ -1943,7 +2522,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1943
2522
|
selector: 'ui-meter',
|
|
1944
2523
|
template: `
|
|
1945
2524
|
<div
|
|
1946
|
-
class="rounded-
|
|
2525
|
+
class="rounded-pill h-1.5 w-full overflow-hidden bg-(--muted)"
|
|
1947
2526
|
role="meter"
|
|
1948
2527
|
[attr.aria-label]="label()"
|
|
1949
2528
|
[attr.aria-valuemax]="1"
|
|
@@ -1957,8 +2536,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1957
2536
|
}]
|
|
1958
2537
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], valueText: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueText", required: true }] }], tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }] } });
|
|
1959
2538
|
|
|
1960
|
-
const BASE_CLASSES$1 = 'flex items-center gap-3 h-10 px-3 rounded-control text-label font-medium
|
|
2539
|
+
const BASE_CLASSES$1 = 'flex items-center gap-3 h-10 px-3 rounded-control text-label font-medium transition-colors duration-(--duration-press) hover:bg-(--glow) hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring)';
|
|
1961
2540
|
const ACTIVE_CLASSES = 'bg-(--soft) text-(--foreground)';
|
|
2541
|
+
const IDLE_CLASSES = 'text-(--muted-foreground)';
|
|
1962
2542
|
/**
|
|
1963
2543
|
* One destination of the sidebar navigation (Portfolio, Holdings, Allocation, Accounts).
|
|
1964
2544
|
*
|
|
@@ -1970,7 +2550,7 @@ const ACTIVE_CLASSES = 'bg-(--soft) text-(--foreground)';
|
|
|
1970
2550
|
*/
|
|
1971
2551
|
class UiNavItem {
|
|
1972
2552
|
active = input(false, { ...(ngDevMode ? { debugName: "active" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1973
|
-
classes = computed(() => `${BASE_CLASSES$1}${this.active() ?
|
|
2553
|
+
classes = computed(() => `${BASE_CLASSES$1} ${this.active() ? ACTIVE_CLASSES : IDLE_CLASSES}`, /* @ts-ignore */
|
|
1974
2554
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
1975
2555
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiNavItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1976
2556
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: UiNavItem, isStandalone: true, selector: "a[ui-nav-item]", inputs: { active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.aria-current": "active() ? 'page' : null" } }, ngImport: i0, template: '<ng-content select="[navIcon]" /><ng-content />', isInline: true });
|
|
@@ -1987,7 +2567,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1987
2567
|
}]
|
|
1988
2568
|
}], propDecorators: { active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }] } });
|
|
1989
2569
|
|
|
1990
|
-
const
|
|
2570
|
+
const ROW_SIZES = ['md', 'lg', 'xl'];
|
|
2571
|
+
const ROW_PADDINGS = ['md', 'sm', 'none'];
|
|
2572
|
+
const SIZE_CLASSES = {
|
|
2573
|
+
md: 'min-h-14 gap-2.5',
|
|
2574
|
+
lg: 'min-h-15 gap-2.5',
|
|
2575
|
+
xl: 'min-h-18 pointer-fine:min-h-17 gap-3',
|
|
2576
|
+
};
|
|
2577
|
+
const PADDING_CLASSES = { md: 'px-2.5', sm: 'px-2', none: 'px-0' };
|
|
2578
|
+
const BASE_CLASSES = 'flex w-full items-center py-1.5 rounded-control text-left select-none touch-manipulation transition-colors duration-(--duration-press) hover:bg-(--glow) active:bg-(--soft) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring)';
|
|
1991
2579
|
const SELECTED_CLASSES$1 = 'bg-(--soft)';
|
|
1992
2580
|
/**
|
|
1993
2581
|
* Clickable row of a list: a holding, an envelope, an account.
|
|
@@ -1999,10 +2587,14 @@ const SELECTED_CLASSES$1 = 'bg-(--soft)';
|
|
|
1999
2587
|
*/
|
|
2000
2588
|
class UiRow {
|
|
2001
2589
|
selected = input(false, { ...(ngDevMode ? { debugName: "selected" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2002
|
-
|
|
2590
|
+
size = input('md', /* @ts-ignore */
|
|
2591
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
2592
|
+
padding = input('md', /* @ts-ignore */
|
|
2593
|
+
...(ngDevMode ? [{ debugName: "padding" }] : /* istanbul ignore next */ []));
|
|
2594
|
+
classes = computed(() => `${BASE_CLASSES} ${SIZE_CLASSES[this.size()]} ${PADDING_CLASSES[this.padding()]}${this.selected() ? ` ${SELECTED_CLASSES$1}` : ''}`, /* @ts-ignore */
|
|
2003
2595
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
2004
2596
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRow, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2005
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: UiRow, isStandalone: true, selector: "a[ui-row], button[ui-row]", inputs: { selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.aria-current": "selected() ? 'true' : null" } }, ngImport: i0, template: '<ng-content />', isInline: true });
|
|
2597
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: UiRow, isStandalone: true, selector: "a[ui-row], button[ui-row]", inputs: { selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, padding: { classPropertyName: "padding", publicName: "padding", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.aria-current": "selected() ? 'true' : null" } }, ngImport: i0, template: '<ng-content />', isInline: true });
|
|
2006
2598
|
}
|
|
2007
2599
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRow, decorators: [{
|
|
2008
2600
|
type: Component,
|
|
@@ -2014,9 +2606,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2014
2606
|
'[attr.aria-current]': "selected() ? 'true' : null",
|
|
2015
2607
|
},
|
|
2016
2608
|
}]
|
|
2017
|
-
}], propDecorators: { selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }] } });
|
|
2609
|
+
}], propDecorators: { selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], padding: [{ type: i0.Input, args: [{ isSignal: true, alias: "padding", required: false }] }] } });
|
|
2018
2610
|
|
|
2019
|
-
const OPTION_CLASSES = "relative z-10
|
|
2611
|
+
const OPTION_CLASSES = "relative z-10 h-10 pointer-fine:h-8 flex-1 cursor-pointer px-3 text-label font-medium transition-colors after:absolute after:inset-x-0 after:top-1/2 after:h-(--row-min) after:-translate-y-1/2 after:content-[''] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring) active:scale-(--press-scale)";
|
|
2020
2612
|
const SELECTED_CLASSES = 'text-(--foreground)';
|
|
2021
2613
|
const UNSELECTED_CLASSES = 'text-(--muted-foreground) hover:text-(--foreground)';
|
|
2022
2614
|
/**
|
|
@@ -2075,10 +2667,10 @@ class UiSegmented {
|
|
|
2075
2667
|
@if (thumbIndex(); as index) {
|
|
2076
2668
|
<span
|
|
2077
2669
|
aria-hidden="true"
|
|
2078
|
-
class="absolute top-0.5 bottom-0.5 left-0.5 rounded-[calc(var(--radius-control)-2px)] bg-(--card) shadow-[0_1px_2px_rgb(0_0_0/0.08)] transition-transform duration-(--duration-fast) ease-out"
|
|
2670
|
+
class="absolute top-0.5 bottom-0.5 left-0.5 rounded-[calc(var(--radius-control)-2px)] bg-(--card) shadow-[0_1px_2px_rgb(0_0_0/0.08),inset_0_0_0_1px_var(--border)] transition-transform duration-(--duration-fast) ease-out"
|
|
2079
2671
|
data-thumb
|
|
2080
2672
|
[style.transform]="'translateX(' + (index - 1) * 100 + '%)'"
|
|
2081
|
-
[style.width]="'calc(100% / ' + options().length + ')'"
|
|
2673
|
+
[style.width]="'calc((100% - 4px) / ' + options().length + ')'"
|
|
2082
2674
|
></span>
|
|
2083
2675
|
}
|
|
2084
2676
|
|
|
@@ -2113,10 +2705,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2113
2705
|
@if (thumbIndex(); as index) {
|
|
2114
2706
|
<span
|
|
2115
2707
|
aria-hidden="true"
|
|
2116
|
-
class="absolute top-0.5 bottom-0.5 left-0.5 rounded-[calc(var(--radius-control)-2px)] bg-(--card) shadow-[0_1px_2px_rgb(0_0_0/0.08)] transition-transform duration-(--duration-fast) ease-out"
|
|
2708
|
+
class="absolute top-0.5 bottom-0.5 left-0.5 rounded-[calc(var(--radius-control)-2px)] bg-(--card) shadow-[0_1px_2px_rgb(0_0_0/0.08),inset_0_0_0_1px_var(--border)] transition-transform duration-(--duration-fast) ease-out"
|
|
2117
2709
|
data-thumb
|
|
2118
2710
|
[style.transform]="'translateX(' + (index - 1) * 100 + '%)'"
|
|
2119
|
-
[style.width]="'calc(100% / ' + options().length + ')'"
|
|
2711
|
+
[style.width]="'calc((100% - 4px) / ' + options().length + ')'"
|
|
2120
2712
|
></span>
|
|
2121
2713
|
}
|
|
2122
2714
|
|
|
@@ -2139,13 +2731,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2139
2731
|
}]
|
|
2140
2732
|
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }, { type: i0.Output, args: ["valueChange"] }], radios: [{ type: i0.ViewChildren, args: ['radio', { isSignal: true }] }] } });
|
|
2141
2733
|
|
|
2142
|
-
const SELECT_CLASSES = 'cursor-pointer pr-
|
|
2734
|
+
const SELECT_CLASSES = 'cursor-pointer appearance-none pr-10 bg-(image:--chevron-down) bg-no-repeat bg-[position:right_0.75rem_center] bg-[size:1.125rem]';
|
|
2143
2735
|
// Spelled out prefix included: Tailwind scans for literal strings, so a prefix applied in code
|
|
2144
|
-
// emits nothing.
|
|
2736
|
+
// emits nothing.
|
|
2145
2737
|
const PICKER_CLASSES = [
|
|
2146
2738
|
'pointer-fine:supports-[appearance:base-select]:[appearance:base-select]',
|
|
2147
2739
|
'pointer-fine:supports-[appearance:base-select]:items-center',
|
|
2148
|
-
'pointer-fine:supports-[appearance:base-select]:pr-3',
|
|
2149
2740
|
'pointer-fine:supports-[appearance:base-select]:[&_option]:cursor-pointer',
|
|
2150
2741
|
'pointer-fine:supports-[appearance:base-select]:[&_option]:rounded-control',
|
|
2151
2742
|
'pointer-fine:supports-[appearance:base-select]:[&_option]:px-2.5',
|
|
@@ -2153,8 +2744,7 @@ const PICKER_CLASSES = [
|
|
|
2153
2744
|
'pointer-fine:supports-[appearance:base-select]:[&_option:hover]:bg-(--soft)',
|
|
2154
2745
|
'pointer-fine:supports-[appearance:base-select]:[&_option:focus]:bg-(--soft)',
|
|
2155
2746
|
'pointer-fine:supports-[appearance:base-select]:[&_option:checked]:font-medium',
|
|
2156
|
-
'[&::picker-icon]:
|
|
2157
|
-
'[&::picker-icon]:text-(--muted-foreground)',
|
|
2747
|
+
'[&::picker-icon]:hidden',
|
|
2158
2748
|
'[&::picker(select)]:[appearance:base-select]',
|
|
2159
2749
|
'[&::picker(select)]:my-1.5',
|
|
2160
2750
|
'[&::picker(select)]:rounded-control',
|
|
@@ -2183,7 +2773,7 @@ class UiSelect {
|
|
|
2183
2773
|
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
2184
2774
|
touched = input(false, /* @ts-ignore */
|
|
2185
2775
|
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
2186
|
-
classes = computed(() => `${CONTROL_BASE_CLASSES} ${SELECT_CLASSES} ${PICKER_CLASSES} ${CONTROL_SIZE_CLASSES[this.size()]}`, /* @ts-ignore */
|
|
2776
|
+
classes = computed(() => `${CONTROL_BASE_CLASSES} bg-(--background) ${SELECT_CLASSES} ${PICKER_CLASSES} ${CONTROL_SIZE_CLASSES[this.size()]}`, /* @ts-ignore */
|
|
2187
2777
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
2188
2778
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiSelect, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2189
2779
|
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiSelect, isStandalone: true, selector: "select[uiSelect]", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, providers: [{ provide: UI_CONTROL, useExisting: forwardRef(() => UiSelect) }], ngImport: i0 });
|
|
@@ -2219,6 +2809,8 @@ class UiSkeleton {
|
|
|
2219
2809
|
...(ngDevMode ? [{ debugName: "lines" }] : /* istanbul ignore next */ []));
|
|
2220
2810
|
height = input(12, /* @ts-ignore */
|
|
2221
2811
|
...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
|
|
2812
|
+
size = input(232, /* @ts-ignore */
|
|
2813
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
2222
2814
|
animation = PULSE_ANIMATION;
|
|
2223
2815
|
bars = computed(() => {
|
|
2224
2816
|
const count = Math.max(1, this.lines());
|
|
@@ -2226,28 +2818,33 @@ class UiSkeleton {
|
|
|
2226
2818
|
}, /* @ts-ignore */
|
|
2227
2819
|
...(ngDevMode ? [{ debugName: "bars" }] : /* istanbul ignore next */ []));
|
|
2228
2820
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiSkeleton, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2229
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiSkeleton, isStandalone: true, selector: "ui-skeleton", inputs: { shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null }, lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-hidden": "true" }, classAttribute: "flex flex-col gap-2" }, ngImport: i0, template: "\n @switch (shape()) {\n @case ('figure') {\n <span class=\"block rounded-control bg-(--muted) h-
|
|
2821
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiSkeleton, isStandalone: true, selector: "ui-skeleton", inputs: { shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null }, lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-hidden": "true" }, classAttribute: "flex flex-col gap-2" }, ngImport: i0, template: "\n @switch (shape()) {\n @case ('figure') {\n <span class=\"block rounded-control bg-(--muted) h-10 w-65\" [style.animation]=\"animation\"></span>\n }\n @case ('row') {\n <span class=\"flex h-14 items-center justify-between gap-4\">\n <span class=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <span class=\"block rounded-control bg-(--muted) h-4 w-3/5\" [style.animation]=\"animation\"></span>\n <span class=\"block rounded-control bg-(--muted) h-3 w-20\" [style.animation]=\"animation\"></span>\n </span>\n <span class=\"block rounded-control bg-(--muted) h-4 w-[90px] flex-none\" [style.animation]=\"animation\"></span>\n </span>\n }\n @case ('chart') {\n <span class=\"rounded-control min-h-50 w-full flex-1 bg-(--muted)\" [style.animation]=\"animation\"></span>\n }\n @case ('ring') {\n <span\n class=\"rounded-pill shadow-[inset_0_0_0_30px_var(--muted)]\"\n [style.animation]=\"animation\"\n [style.height.px]=\"size()\"\n [style.width.px]=\"size()\"\n ></span>\n }\n @default {\n @for (line of bars(); track $index) {\n <span\n class=\"block rounded-control bg-(--muted)\"\n [style.animation]=\"animation\"\n [style.height.px]=\"height()\"\n [style.width]=\"line\"\n ></span>\n }\n }\n }\n ", isInline: true, styles: ["@keyframes cairn-pulse{0%{opacity:1}to{opacity:.45}}\n"] });
|
|
2230
2822
|
}
|
|
2231
2823
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiSkeleton, decorators: [{
|
|
2232
2824
|
type: Component,
|
|
2233
2825
|
args: [{ selector: 'ui-skeleton', template: `
|
|
2234
2826
|
@switch (shape()) {
|
|
2235
2827
|
@case ('figure') {
|
|
2236
|
-
<span class="${BAR_CLASSES} h-
|
|
2828
|
+
<span class="${BAR_CLASSES} h-10 w-65" [style.animation]="animation"></span>
|
|
2237
2829
|
}
|
|
2238
2830
|
@case ('row') {
|
|
2239
|
-
<span class="flex h-14
|
|
2240
|
-
<span class="
|
|
2241
|
-
|
|
2831
|
+
<span class="flex h-14 items-center justify-between gap-4">
|
|
2832
|
+
<span class="flex min-w-0 flex-1 flex-col gap-1.5">
|
|
2833
|
+
<span class="${BAR_CLASSES} h-4 w-3/5" [style.animation]="animation"></span>
|
|
2834
|
+
<span class="${BAR_CLASSES} h-3 w-20" [style.animation]="animation"></span>
|
|
2835
|
+
</span>
|
|
2836
|
+
<span class="${BAR_CLASSES} h-4 w-[90px] flex-none" [style.animation]="animation"></span>
|
|
2242
2837
|
</span>
|
|
2243
2838
|
}
|
|
2244
2839
|
@case ('chart') {
|
|
2245
|
-
<span class="rounded-
|
|
2840
|
+
<span class="rounded-control min-h-50 w-full flex-1 bg-(--muted)" [style.animation]="animation"></span>
|
|
2246
2841
|
}
|
|
2247
2842
|
@case ('ring') {
|
|
2248
2843
|
<span
|
|
2249
|
-
class="rounded-pill
|
|
2844
|
+
class="rounded-pill shadow-[inset_0_0_0_30px_var(--muted)]"
|
|
2250
2845
|
[style.animation]="animation"
|
|
2846
|
+
[style.height.px]="size()"
|
|
2847
|
+
[style.width.px]="size()"
|
|
2251
2848
|
></span>
|
|
2252
2849
|
}
|
|
2253
2850
|
@default {
|
|
@@ -2265,15 +2862,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2265
2862
|
'aria-hidden': 'true',
|
|
2266
2863
|
class: 'flex flex-col gap-2',
|
|
2267
2864
|
}, styles: ["@keyframes cairn-pulse{0%{opacity:1}to{opacity:.45}}\n"] }]
|
|
2268
|
-
}], propDecorators: { shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }], lines: [{ type: i0.Input, args: [{ isSignal: true, alias: "lines", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }] } });
|
|
2865
|
+
}], propDecorators: { shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }], lines: [{ type: i0.Input, args: [{ isSignal: true, alias: "lines", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
2269
2866
|
|
|
2270
2867
|
/** Available stat sizes. `StatSize` is derived from this tuple. */
|
|
2271
2868
|
const STAT_SIZES = ['hero', 'tile'];
|
|
2272
2869
|
const VALUE_CLASSES = {
|
|
2273
|
-
hero: 'text-display font-semibold text-(--foreground)',
|
|
2274
|
-
tile: 'text-title font-semibold text-(--foreground)',
|
|
2870
|
+
hero: 'text-display font-semibold tracking-(--tracking-display) text-(--foreground)',
|
|
2871
|
+
tile: 'text-title font-semibold tabular-nums text-(--foreground)',
|
|
2872
|
+
};
|
|
2873
|
+
const LABEL_CLASSES = {
|
|
2874
|
+
hero: 'text-label font-medium text-(--muted-foreground)',
|
|
2875
|
+
tile: 'text-label font-normal text-(--muted-foreground)',
|
|
2876
|
+
};
|
|
2877
|
+
const STACK_CLASSES = {
|
|
2878
|
+
hero: 'flex flex-col gap-1',
|
|
2879
|
+
tile: 'flex flex-col gap-0.5',
|
|
2275
2880
|
};
|
|
2276
|
-
const LABEL_CLASSES = 'text-label font-medium text-(--subtle-foreground)';
|
|
2277
2881
|
/**
|
|
2278
2882
|
* Label, figure and a named period of change, at two sizes: a `hero` for a screen's single
|
|
2279
2883
|
* headline number, or a smaller `tile` repeated in a grid. The figure itself, its delta and its
|
|
@@ -2294,21 +2898,24 @@ class UiStat {
|
|
|
2294
2898
|
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
2295
2899
|
size = input('tile', /* @ts-ignore */
|
|
2296
2900
|
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
2297
|
-
labelClasses = LABEL_CLASSES
|
|
2901
|
+
labelClasses = computed(() => LABEL_CLASSES[this.size()], /* @ts-ignore */
|
|
2902
|
+
...(ngDevMode ? [{ debugName: "labelClasses" }] : /* istanbul ignore next */ []));
|
|
2903
|
+
stackClasses = computed(() => STACK_CLASSES[this.size()], /* @ts-ignore */
|
|
2904
|
+
...(ngDevMode ? [{ debugName: "stackClasses" }] : /* istanbul ignore next */ []));
|
|
2298
2905
|
valueClasses = computed(() => VALUE_CLASSES[this.size()], /* @ts-ignore */
|
|
2299
2906
|
...(ngDevMode ? [{ debugName: "valueClasses" }] : /* istanbul ignore next */ []));
|
|
2300
2907
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiStat, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2301
2908
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: UiStat, isStandalone: true, selector: "ui-stat", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
2302
2909
|
<div class="flex items-start justify-between gap-4">
|
|
2303
|
-
<div class="
|
|
2304
|
-
<dl>
|
|
2305
|
-
<dt [class]="labelClasses">{{ label() }}</dt>
|
|
2910
|
+
<div [class]="stackClasses()">
|
|
2911
|
+
<dl [class]="stackClasses()">
|
|
2912
|
+
<dt [class]="labelClasses()">{{ label() }}</dt>
|
|
2306
2913
|
<dd [class]="valueClasses()">
|
|
2307
2914
|
<ng-content select="[uiStatValue]" />
|
|
2308
2915
|
</dd>
|
|
2309
2916
|
</dl>
|
|
2310
2917
|
|
|
2311
|
-
<div class="text-label flex flex-wrap items-center gap-x-
|
|
2918
|
+
<div class="text-label flex flex-wrap items-center gap-x-1.5 gap-y-1 text-(--muted-foreground)">
|
|
2312
2919
|
<ng-content select="[uiStatDelta]" />
|
|
2313
2920
|
<ng-content select="[uiStatCaption]" />
|
|
2314
2921
|
</div>
|
|
@@ -2324,15 +2931,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2324
2931
|
selector: 'ui-stat',
|
|
2325
2932
|
template: `
|
|
2326
2933
|
<div class="flex items-start justify-between gap-4">
|
|
2327
|
-
<div class="
|
|
2328
|
-
<dl>
|
|
2329
|
-
<dt [class]="labelClasses">{{ label() }}</dt>
|
|
2934
|
+
<div [class]="stackClasses()">
|
|
2935
|
+
<dl [class]="stackClasses()">
|
|
2936
|
+
<dt [class]="labelClasses()">{{ label() }}</dt>
|
|
2330
2937
|
<dd [class]="valueClasses()">
|
|
2331
2938
|
<ng-content select="[uiStatValue]" />
|
|
2332
2939
|
</dd>
|
|
2333
2940
|
</dl>
|
|
2334
2941
|
|
|
2335
|
-
<div class="text-label flex flex-wrap items-center gap-x-
|
|
2942
|
+
<div class="text-label flex flex-wrap items-center gap-x-1.5 gap-y-1 text-(--muted-foreground)">
|
|
2336
2943
|
<ng-content select="[uiStatDelta]" />
|
|
2337
2944
|
<ng-content select="[uiStatCaption]" />
|
|
2338
2945
|
</div>
|
|
@@ -2344,9 +2951,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2344
2951
|
}]
|
|
2345
2952
|
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
2346
2953
|
|
|
2347
|
-
const CLASSES = "relative shrink-0 w-[51px] h-[31px] appearance-none cursor-pointer rounded-pill bg-(--muted) checked:bg-(--primary) transition-colors duration-(--duration-fast) ease-out disabled:pointer-events-none disabled:opacity-40 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring) before:absolute before:inset-x-0 before:top-1/2 before:-translate-y-1/2 before:h-(--row-min) before:content-[''] after:absolute after:top-0.5 after:left-0.5 after:size-[27px] after:rounded-pill after:bg-(--card) after:shadow-[0_1px_3px_rgb(0_0_0/0.2)] after:transition-transform after:duration-(--duration-fast) after:ease-out after:content-[''] checked:after:translate-x-[20px]";
|
|
2954
|
+
const CLASSES = "relative shrink-0 w-[51px] h-[31px] pointer-fine:w-10 pointer-fine:h-6 appearance-none cursor-pointer rounded-pill bg-(--muted) checked:bg-(--primary) transition-colors duration-(--duration-fast) ease-out disabled:pointer-events-none disabled:opacity-40 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring) before:absolute before:inset-x-0 before:top-1/2 before:-translate-y-1/2 before:h-(--row-min) before:content-[''] after:absolute after:top-0.5 after:left-0.5 after:size-[27px] pointer-fine:after:size-5 after:rounded-pill after:bg-(--card) after:shadow-[0_1px_3px_rgb(0_0_0/0.2)] after:transition-transform after:duration-(--duration-fast) after:ease-out after:content-[''] checked:after:translate-x-[20px] pointer-fine:checked:after:translate-x-4";
|
|
2348
2955
|
/**
|
|
2349
2956
|
* Native checkbox styled as an iOS-style switch, exposed to assistive technology as `role="switch"`.
|
|
2957
|
+
* 51 by 31 on touch, 40 by 24 with a mouse.
|
|
2350
2958
|
*
|
|
2351
2959
|
* @example
|
|
2352
2960
|
* <input type="checkbox" uiSwitch [checked]="hidden()" (change)="toggle()" aria-label="Hide amounts" />
|
|
@@ -2369,42 +2977,96 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2369
2977
|
|
|
2370
2978
|
/** Breakpoints a secondary column can be held back until. */
|
|
2371
2979
|
const CELL_BREAKPOINTS = ['md', 'lg'];
|
|
2980
|
+
/** Body row heights. */
|
|
2981
|
+
const TABLE_ROWS = ['48', '52', '60'];
|
|
2982
|
+
const ROW_CLASSES = {
|
|
2983
|
+
'48': '[--table-row:3rem]',
|
|
2984
|
+
'52': '[--table-row:3.25rem]',
|
|
2985
|
+
'60': '[--table-row:3.75rem]',
|
|
2986
|
+
};
|
|
2372
2987
|
const FROM_CLASSES = {
|
|
2373
2988
|
md: 'hidden md:table-cell',
|
|
2374
2989
|
lg: 'hidden lg:table-cell',
|
|
2375
2990
|
};
|
|
2376
|
-
const TH_CLASSES = 'h-
|
|
2377
|
-
const TD_CLASSES = 'h-
|
|
2378
|
-
const NUMERIC_CLASSES = 'text-right tabular-nums';
|
|
2991
|
+
const TH_CLASSES = 'h-[calc(var(--table-head)+var(--table-head-gap))] border-b-(length:--table-head-gap) border-transparent px-2 align-middle text-caption font-medium text-(--subtle-foreground) shadow-(--table-rule)';
|
|
2992
|
+
const TD_CLASSES = 'h-(--table-row) px-2 align-middle text-body';
|
|
2993
|
+
const NUMERIC_CLASSES = 'text-right tabular-nums whitespace-nowrap';
|
|
2379
2994
|
const TEXTUAL_CLASSES = 'text-left';
|
|
2380
|
-
|
|
2995
|
+
const PRIMARY_CLASSES = 'w-full max-w-0';
|
|
2996
|
+
/**
|
|
2997
|
+
* Styled native table. The rows and cells stay plain <tr> and <td>. `row` sets the height of every
|
|
2998
|
+
* body row, `rule` draws or drops the hairline under the header, `spaced` leaves 4px between the
|
|
2999
|
+
* header and the first row.
|
|
3000
|
+
*
|
|
3001
|
+
* @example
|
|
3002
|
+
* <table uiTable row="60" [rule]="false">
|
|
3003
|
+
*/
|
|
2381
3004
|
class UiTable {
|
|
3005
|
+
row = input('48', /* @ts-ignore */
|
|
3006
|
+
...(ngDevMode ? [{ debugName: "row" }] : /* istanbul ignore next */ []));
|
|
3007
|
+
rule = input(true, { ...(ngDevMode ? { debugName: "rule" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3008
|
+
spaced = input(false, { ...(ngDevMode ? { debugName: "spaced" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3009
|
+
classes = computed(() => [
|
|
3010
|
+
'w-full border-separate border-spacing-0',
|
|
3011
|
+
ROW_CLASSES[this.row()],
|
|
3012
|
+
this.rule() ? '[--table-rule:inset_0_-1px_0_var(--hairline)]' : '[--table-rule:none]',
|
|
3013
|
+
this.spaced() ? '[--table-head-gap:0.25rem]' : '[--table-head-gap:0px]',
|
|
3014
|
+
].join(' '), /* @ts-ignore */
|
|
3015
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
2382
3016
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTable, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2383
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "
|
|
3017
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiTable, isStandalone: true, selector: "table[uiTable]", inputs: { row: { classPropertyName: "row", publicName: "row", isSignal: true, isRequired: false, transformFunction: null }, rule: { classPropertyName: "rule", publicName: "rule", isSignal: true, isRequired: false, transformFunction: null }, spaced: { classPropertyName: "spaced", publicName: "spaced", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0 });
|
|
2384
3018
|
}
|
|
2385
3019
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTable, decorators: [{
|
|
2386
3020
|
type: Directive,
|
|
2387
3021
|
args: [{
|
|
2388
3022
|
selector: 'table[uiTable]',
|
|
2389
3023
|
host: {
|
|
2390
|
-
class: '
|
|
3024
|
+
'[class]': 'classes()',
|
|
2391
3025
|
},
|
|
2392
3026
|
}]
|
|
3027
|
+
}], propDecorators: { row: [{ type: i0.Input, args: [{ isSignal: true, alias: "row", required: false }] }], rule: [{ type: i0.Input, args: [{ isSignal: true, alias: "rule", required: false }] }], spaced: [{ type: i0.Input, args: [{ isSignal: true, alias: "spaced", required: false }] }] } });
|
|
3028
|
+
/** Body of one group of rows: leaves a 4px tail after its last row. */
|
|
3029
|
+
class UiGroup {
|
|
3030
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3031
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.7", type: UiGroup, isStandalone: true, selector: "tbody[uiGroup]", host: { classAttribute: "after:table-row after:h-1 after:content-[\"\"]" }, ngImport: i0 });
|
|
3032
|
+
}
|
|
3033
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiGroup, decorators: [{
|
|
3034
|
+
type: Directive,
|
|
3035
|
+
args: [{
|
|
3036
|
+
selector: 'tbody[uiGroup]',
|
|
3037
|
+
host: { class: 'after:table-row after:h-1 after:content-[""]' },
|
|
3038
|
+
}]
|
|
2393
3039
|
}] });
|
|
2394
3040
|
/**
|
|
2395
|
-
* Body or group row.
|
|
2396
|
-
*
|
|
3041
|
+
* Body or group row. An ordinary row glows on hover and takes the soft fill when `selected`; an
|
|
3042
|
+
* `interactive` row (one that opens something) also presses to the soft fill. A row with no action keeps a
|
|
3043
|
+
* plain name: `<td uiTd primary class="truncate font-medium">`.
|
|
3044
|
+
* `group` marks the row that holds a group band: it carries no hover state.
|
|
2397
3045
|
*
|
|
2398
3046
|
* @example
|
|
2399
|
-
* <tr uiTr>...
|
|
2400
|
-
* <tr uiTr group>...
|
|
3047
|
+
* <tr uiTr [selected]="open">...
|
|
3048
|
+
* <tr uiTr group><td ui-group-cell name="Brokerage">...
|
|
2401
3049
|
*/
|
|
2402
3050
|
class UiTr {
|
|
2403
3051
|
group = input(false, { ...(ngDevMode ? { debugName: "group" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2404
|
-
|
|
3052
|
+
selected = input(false, { ...(ngDevMode ? { debugName: "selected" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3053
|
+
interactive = input(false, { ...(ngDevMode ? { debugName: "interactive" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3054
|
+
classes = computed(() => {
|
|
3055
|
+
if (this.group()) {
|
|
3056
|
+
return '';
|
|
3057
|
+
}
|
|
3058
|
+
return [
|
|
3059
|
+
'relative [&>td:first-child]:rounded-l-control [&>td:last-child]:rounded-r-control',
|
|
3060
|
+
this.selected() ? '[&>td]:bg-(--soft)' : '',
|
|
3061
|
+
'hover:[&>td]:bg-(--glow)',
|
|
3062
|
+
this.interactive() ? 'active:[&>td]:bg-(--soft)' : '',
|
|
3063
|
+
]
|
|
3064
|
+
.filter(Boolean)
|
|
3065
|
+
.join(' ');
|
|
3066
|
+
}, /* @ts-ignore */
|
|
2405
3067
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
2406
3068
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTr, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2407
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiTr, isStandalone: true, selector: "tr[uiTr]", inputs: { group: { classPropertyName: "group", publicName: "group", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0 });
|
|
3069
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiTr, isStandalone: true, selector: "tr[uiTr]", inputs: { group: { classPropertyName: "group", publicName: "group", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.aria-selected": "selected() ? \"true\" : null" } }, ngImport: i0 });
|
|
2408
3070
|
}
|
|
2409
3071
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTr, decorators: [{
|
|
2410
3072
|
type: Directive,
|
|
@@ -2412,25 +3074,42 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2412
3074
|
selector: 'tr[uiTr]',
|
|
2413
3075
|
host: {
|
|
2414
3076
|
'[class]': 'classes()',
|
|
3077
|
+
'[attr.aria-selected]': 'selected() ? "true" : null',
|
|
2415
3078
|
},
|
|
2416
3079
|
}]
|
|
2417
|
-
}], propDecorators: { group: [{ type: i0.Input, args: [{ isSignal: true, alias: "group", required: false }] }] } });
|
|
2418
|
-
const cellClasses = (base, numeric,
|
|
3080
|
+
}], propDecorators: { group: [{ type: i0.Input, args: [{ isSignal: true, alias: "group", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }] } });
|
|
3081
|
+
const cellClasses = (base, numeric, primary, from, secondary) => {
|
|
3082
|
+
const breakpoint = from ?? (secondary ? 'lg' : null);
|
|
3083
|
+
return [
|
|
3084
|
+
base,
|
|
3085
|
+
numeric ? NUMERIC_CLASSES : TEXTUAL_CLASSES,
|
|
3086
|
+
primary ? PRIMARY_CLASSES : '',
|
|
3087
|
+
breakpoint ? FROM_CLASSES[breakpoint] : '',
|
|
3088
|
+
]
|
|
3089
|
+
.filter(Boolean)
|
|
3090
|
+
.join(' ');
|
|
3091
|
+
};
|
|
2419
3092
|
/**
|
|
2420
|
-
* Column header. `numeric` right-aligns and lines the digits up; `
|
|
2421
|
-
*
|
|
3093
|
+
* Column header, centred in its 36px. `numeric` right-aligns and lines the digits up; `secondary`
|
|
3094
|
+
* (or `from`) holds a column back until the viewport is wide enough for it; `primary` makes it
|
|
3095
|
+
* the column that absorbs the free width and truncates; `tall` is a 40px header; `width` fixes the column width and keeps it from shrinking.
|
|
2422
3096
|
*
|
|
2423
3097
|
* @example
|
|
2424
|
-
* <th uiTh numeric
|
|
3098
|
+
* <th uiTh numeric secondary width="108px">Quantity</th>
|
|
2425
3099
|
*/
|
|
2426
3100
|
class UiTh {
|
|
3101
|
+
width = input(null, /* @ts-ignore */
|
|
3102
|
+
...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
|
|
2427
3103
|
numeric = input(false, { ...(ngDevMode ? { debugName: "numeric" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3104
|
+
primary = input(false, { ...(ngDevMode ? { debugName: "primary" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3105
|
+
secondary = input(false, { ...(ngDevMode ? { debugName: "secondary" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3106
|
+
tall = input(false, { ...(ngDevMode ? { debugName: "tall" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2428
3107
|
from = input(null, /* @ts-ignore */
|
|
2429
3108
|
...(ngDevMode ? [{ debugName: "from" }] : /* istanbul ignore next */ []));
|
|
2430
|
-
classes = computed(() => cellClasses(TH_CLASSES
|
|
3109
|
+
classes = computed(() => cellClasses(`${this.tall() ? '[--table-head:2.5rem]' : '[--table-head:2.25rem]'} ${TH_CLASSES}`, this.numeric(), this.primary(), this.from(), this.secondary()), /* @ts-ignore */
|
|
2431
3110
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
2432
3111
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTh, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2433
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiTh, isStandalone: true, selector: "th[uiTh]", inputs: { numeric: { classPropertyName: "numeric", publicName: "numeric", isSignal: true, isRequired: false, transformFunction: null }, from: { classPropertyName: "from", publicName: "from", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0 });
|
|
3112
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiTh, isStandalone: true, selector: "th[uiTh]", inputs: { width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, numeric: { classPropertyName: "numeric", publicName: "numeric", isSignal: true, isRequired: false, transformFunction: null }, primary: { classPropertyName: "primary", publicName: "primary", isSignal: true, isRequired: false, transformFunction: null }, secondary: { classPropertyName: "secondary", publicName: "secondary", isSignal: true, isRequired: false, transformFunction: null }, tall: { classPropertyName: "tall", publicName: "tall", isSignal: true, isRequired: false, transformFunction: null }, from: { classPropertyName: "from", publicName: "from", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "style.width": "width()", "style.min-width": "width()" } }, ngImport: i0 });
|
|
2434
3113
|
}
|
|
2435
3114
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTh, decorators: [{
|
|
2436
3115
|
type: Directive,
|
|
@@ -2438,18 +3117,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2438
3117
|
selector: 'th[uiTh]',
|
|
2439
3118
|
host: {
|
|
2440
3119
|
'[class]': 'classes()',
|
|
3120
|
+
'[style.width]': 'width()',
|
|
3121
|
+
'[style.min-width]': 'width()',
|
|
2441
3122
|
},
|
|
2442
3123
|
}]
|
|
2443
|
-
}], propDecorators: { numeric: [{ type: i0.Input, args: [{ isSignal: true, alias: "numeric", required: false }] }], from: [{ type: i0.Input, args: [{ isSignal: true, alias: "from", required: false }] }] } });
|
|
2444
|
-
/** Body cell. Same
|
|
3124
|
+
}], propDecorators: { width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], numeric: [{ type: i0.Input, args: [{ isSignal: true, alias: "numeric", required: false }] }], primary: [{ type: i0.Input, args: [{ isSignal: true, alias: "primary", required: false }] }], secondary: [{ type: i0.Input, args: [{ isSignal: true, alias: "secondary", required: false }] }], tall: [{ type: i0.Input, args: [{ isSignal: true, alias: "tall", required: false }] }], from: [{ type: i0.Input, args: [{ isSignal: true, alias: "from", required: false }] }] } });
|
|
3125
|
+
/** Body cell. Same inputs as `UiTh` (bar `tall` and `width`), and they must be set on both to match. */
|
|
2445
3126
|
class UiTd {
|
|
2446
3127
|
numeric = input(false, { ...(ngDevMode ? { debugName: "numeric" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3128
|
+
primary = input(false, { ...(ngDevMode ? { debugName: "primary" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3129
|
+
secondary = input(false, { ...(ngDevMode ? { debugName: "secondary" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2447
3130
|
from = input(null, /* @ts-ignore */
|
|
2448
3131
|
...(ngDevMode ? [{ debugName: "from" }] : /* istanbul ignore next */ []));
|
|
2449
|
-
classes = computed(() => cellClasses(TD_CLASSES, this.numeric(), this.from()), /* @ts-ignore */
|
|
3132
|
+
classes = computed(() => cellClasses(TD_CLASSES, this.numeric(), this.primary(), this.from(), this.secondary()), /* @ts-ignore */
|
|
2450
3133
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
2451
3134
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTd, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2452
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiTd, isStandalone: true, selector: "td[uiTd]", inputs: { numeric: { classPropertyName: "numeric", publicName: "numeric", isSignal: true, isRequired: false, transformFunction: null }, from: { classPropertyName: "from", publicName: "from", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0 });
|
|
3135
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiTd, isStandalone: true, selector: "td[uiTd]", inputs: { numeric: { classPropertyName: "numeric", publicName: "numeric", isSignal: true, isRequired: false, transformFunction: null }, primary: { classPropertyName: "primary", publicName: "primary", isSignal: true, isRequired: false, transformFunction: null }, secondary: { classPropertyName: "secondary", publicName: "secondary", isSignal: true, isRequired: false, transformFunction: null }, from: { classPropertyName: "from", publicName: "from", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0 });
|
|
2453
3136
|
}
|
|
2454
3137
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTd, decorators: [{
|
|
2455
3138
|
type: Directive,
|
|
@@ -2459,9 +3142,143 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2459
3142
|
'[class]': 'classes()',
|
|
2460
3143
|
},
|
|
2461
3144
|
}]
|
|
2462
|
-
}], propDecorators: { numeric: [{ type: i0.Input, args: [{ isSignal: true, alias: "numeric", required: false }] }], from: [{ type: i0.Input, args: [{ isSignal: true, alias: "from", required: false }] }] } });
|
|
3145
|
+
}], propDecorators: { numeric: [{ type: i0.Input, args: [{ isSignal: true, alias: "numeric", required: false }] }], primary: [{ type: i0.Input, args: [{ isSignal: true, alias: "primary", required: false }] }], secondary: [{ type: i0.Input, args: [{ isSignal: true, alias: "secondary", required: false }] }], from: [{ type: i0.Input, args: [{ isSignal: true, alias: "from", required: false }] }] } });
|
|
3146
|
+
/** Group band sizes. */
|
|
3147
|
+
const GROUP_SIZES = ['md', 'lg'];
|
|
3148
|
+
/**
|
|
3149
|
+
* The band that opens a group of rows: name in 600 (a heading), meta beside it, the projected
|
|
3150
|
+
* total pinned to the right. Spans the whole row through `colspan`.
|
|
3151
|
+
*
|
|
3152
|
+
* @example
|
|
3153
|
+
* <tr uiTr group><td ui-group-cell colspan="4" name="Brokerage" meta="Savings plan">...total...</td></tr>
|
|
3154
|
+
*/
|
|
3155
|
+
class UiGroupCell {
|
|
3156
|
+
name = input.required(/* @ts-ignore */
|
|
3157
|
+
...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
|
|
3158
|
+
meta = input(/* @ts-ignore */
|
|
3159
|
+
...(ngDevMode ? [undefined, { debugName: "meta" }] : /* istanbul ignore next */ []));
|
|
3160
|
+
size = input('md', /* @ts-ignore */
|
|
3161
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
3162
|
+
hostClasses = computed(() => `px-0 ${this.size() === 'lg' ? 'pt-3' : 'pt-2.5'} pb-1 align-middle text-body`, /* @ts-ignore */
|
|
3163
|
+
...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
|
|
3164
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiGroupCell, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3165
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiGroupCell, isStandalone: true, selector: "td[ui-group-cell]", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: `
|
|
3166
|
+
<div
|
|
3167
|
+
class="rounded-control flex items-center justify-between gap-4 bg-(--muted) px-2"
|
|
3168
|
+
[class]="size() === 'lg' ? 'min-h-12' : 'min-h-11'"
|
|
3169
|
+
>
|
|
3170
|
+
<div class="flex min-w-0 items-baseline gap-3">
|
|
3171
|
+
<h2 class="text-body m-0 font-semibold whitespace-nowrap">{{ name() }}</h2>
|
|
3172
|
+
@if (meta()) {
|
|
3173
|
+
<span class="text-label truncate text-(--muted-foreground)">{{ meta() }}</span>
|
|
3174
|
+
}
|
|
3175
|
+
</div>
|
|
3176
|
+
<span class="font-semibold whitespace-nowrap tabular-nums"><ng-content /></span>
|
|
3177
|
+
</div>
|
|
3178
|
+
`, isInline: true });
|
|
3179
|
+
}
|
|
3180
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiGroupCell, decorators: [{
|
|
3181
|
+
type: Component,
|
|
3182
|
+
args: [{
|
|
3183
|
+
selector: 'td[ui-group-cell]',
|
|
3184
|
+
host: {
|
|
3185
|
+
'[class]': 'hostClasses()',
|
|
3186
|
+
},
|
|
3187
|
+
template: `
|
|
3188
|
+
<div
|
|
3189
|
+
class="rounded-control flex items-center justify-between gap-4 bg-(--muted) px-2"
|
|
3190
|
+
[class]="size() === 'lg' ? 'min-h-12' : 'min-h-11'"
|
|
3191
|
+
>
|
|
3192
|
+
<div class="flex min-w-0 items-baseline gap-3">
|
|
3193
|
+
<h2 class="text-body m-0 font-semibold whitespace-nowrap">{{ name() }}</h2>
|
|
3194
|
+
@if (meta()) {
|
|
3195
|
+
<span class="text-label truncate text-(--muted-foreground)">{{ meta() }}</span>
|
|
3196
|
+
}
|
|
3197
|
+
</div>
|
|
3198
|
+
<span class="font-semibold whitespace-nowrap tabular-nums"><ng-content /></span>
|
|
3199
|
+
</div>
|
|
3200
|
+
`,
|
|
3201
|
+
}]
|
|
3202
|
+
}], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], meta: [{ type: i0.Input, args: [{ isSignal: true, alias: "meta", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
3203
|
+
/**
|
|
3204
|
+
* Makes a link or button the way into its row. By default an invisible layer stretches over the
|
|
3205
|
+
* whole row, so the row is one target for the pointer, the keyboard and a screen reader, and its
|
|
3206
|
+
* focus ring wraps the row. With `[stretch]="false"` only the name is the
|
|
3207
|
+
* target: it underlines on hover and takes its own ring. `current` marks the open line.
|
|
3208
|
+
*
|
|
3209
|
+
* @example
|
|
3210
|
+
* <td uiTd primary><a uiRowLink href="/lines/42">Ferrari</a></td>
|
|
3211
|
+
* <td uiTd primary><a uiRowLink [stretch]="false" href="/accounts/3">Brokerage</a></td>
|
|
3212
|
+
*/
|
|
3213
|
+
class UiRowLink {
|
|
3214
|
+
stretch = input(true, { ...(ngDevMode ? { debugName: "stretch" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3215
|
+
current = input(false, { ...(ngDevMode ? { debugName: "current" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3216
|
+
classes = computed(() => this.stretch()
|
|
3217
|
+
? 'block max-w-full truncate rounded-control text-left font-medium outline-none after:absolute after:inset-0 after:rounded-control after:content-[""] focus-visible:after:outline-2 focus-visible:after:-outline-offset-2 focus-visible:after:outline-(--ring)'
|
|
3218
|
+
: 'block max-w-full truncate rounded-sm text-left font-medium underline-offset-[3px] outline-none hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring)', /* @ts-ignore */
|
|
3219
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
3220
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRowLink, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3221
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiRowLink, isStandalone: true, selector: "a[uiRowLink], button[uiRowLink]", inputs: { stretch: { classPropertyName: "stretch", publicName: "stretch", isSignal: true, isRequired: false, transformFunction: null }, current: { classPropertyName: "current", publicName: "current", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.aria-current": "current() ? \"true\" : null" } }, ngImport: i0 });
|
|
3222
|
+
}
|
|
3223
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRowLink, decorators: [{
|
|
3224
|
+
type: Directive,
|
|
3225
|
+
args: [{
|
|
3226
|
+
selector: 'a[uiRowLink], button[uiRowLink]',
|
|
3227
|
+
host: {
|
|
3228
|
+
'[class]': 'classes()',
|
|
3229
|
+
'[attr.aria-current]': 'current() ? "true" : null',
|
|
3230
|
+
},
|
|
3231
|
+
}]
|
|
3232
|
+
}], propDecorators: { stretch: [{ type: i0.Input, args: [{ isSignal: true, alias: "stretch", required: false }] }], current: [{ type: i0.Input, args: [{ isSignal: true, alias: "current", required: false }] }] } });
|
|
3233
|
+
/** A control in another cell of a stretched-link row: lifts it above the layer that covers the row. */
|
|
3234
|
+
class UiRowAction {
|
|
3235
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRowAction, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3236
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.7", type: UiRowAction, isStandalone: true, selector: "[uiRowAction]", host: { classAttribute: "relative z-1" }, ngImport: i0 });
|
|
3237
|
+
}
|
|
3238
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRowAction, decorators: [{
|
|
3239
|
+
type: Directive,
|
|
3240
|
+
args: [{
|
|
3241
|
+
selector: '[uiRowAction]',
|
|
3242
|
+
host: { class: 'relative z-1' },
|
|
3243
|
+
}]
|
|
3244
|
+
}] });
|
|
3245
|
+
/** Tones of a subtitle: subtle (default), `--stale` at 500, or the color of the cell. */
|
|
3246
|
+
const SUB_TONES = ['subtle', 'stale', 'inherit'];
|
|
3247
|
+
const SUB_TONE_CLASSES = {
|
|
3248
|
+
subtle: 'font-normal text-(--subtle-foreground)',
|
|
3249
|
+
stale: 'font-medium text-(--stale)',
|
|
3250
|
+
inherit: 'font-normal',
|
|
3251
|
+
};
|
|
3252
|
+
/**
|
|
3253
|
+
* A second line under a cell's main text. `narrow` shows it only under 1024px, where it carries
|
|
3254
|
+
* the quantity, average cost and quote that were held back. Its amounts go through `ui-amount`
|
|
3255
|
+
* so they mask.
|
|
3256
|
+
*
|
|
3257
|
+
* @example
|
|
3258
|
+
* <span uiCellSub narrow>10 × 421.26 € · cost 388.10 €</span>
|
|
3259
|
+
* <span uiCellSub tone="stale">Quote of 24/09</span>
|
|
3260
|
+
*/
|
|
3261
|
+
class UiCellSub {
|
|
3262
|
+
narrow = input(false, { ...(ngDevMode ? { debugName: "narrow" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3263
|
+
tone = input('subtle', /* @ts-ignore */
|
|
3264
|
+
...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
|
|
3265
|
+
classes = computed(() => `${this.narrow() ? 'lg:hidden ' : ''}block truncate text-caption tabular-nums ${SUB_TONE_CLASSES[this.tone()]}`, /* @ts-ignore */
|
|
3266
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
3267
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiCellSub, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3268
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiCellSub, isStandalone: true, selector: "[uiCellSub]", inputs: { narrow: { classPropertyName: "narrow", publicName: "narrow", isSignal: true, isRequired: false, transformFunction: null }, tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0 });
|
|
3269
|
+
}
|
|
3270
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiCellSub, decorators: [{
|
|
3271
|
+
type: Directive,
|
|
3272
|
+
args: [{
|
|
3273
|
+
selector: '[uiCellSub]',
|
|
3274
|
+
host: {
|
|
3275
|
+
'[class]': 'classes()',
|
|
3276
|
+
},
|
|
3277
|
+
}]
|
|
3278
|
+
}], propDecorators: { narrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "narrow", required: false }] }], tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }] } });
|
|
2463
3279
|
|
|
2464
|
-
const TAB_CLASSES = 'flex h-[52px] flex-col items-center justify-center gap-
|
|
3280
|
+
const TAB_CLASSES = 'flex h-[52px] flex-col items-center justify-center gap-[3px] touch-manipulation select-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring)';
|
|
3281
|
+
const INACTIVE_TAB_CLASSES = 'font-medium text-(--muted-foreground)';
|
|
2465
3282
|
const ACTIVE_TAB_CLASSES = 'font-semibold text-(--foreground)';
|
|
2466
3283
|
/**
|
|
2467
3284
|
* Bottom navigation bar for iPhone: 52px of tabs plus the home indicator's safe area.
|
|
@@ -2493,12 +3310,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2493
3310
|
*/
|
|
2494
3311
|
class UiTab {
|
|
2495
3312
|
active = input(false, { ...(ngDevMode ? { debugName: "active" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2496
|
-
classes = computed(() => `${TAB_CLASSES}${this.active() ?
|
|
3313
|
+
classes = computed(() => `${TAB_CLASSES} ${this.active() ? ACTIVE_TAB_CLASSES : INACTIVE_TAB_CLASSES}`, /* @ts-ignore */
|
|
2497
3314
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
2498
3315
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTab, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2499
3316
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: UiTab, isStandalone: true, selector: "a[ui-tab]", inputs: { active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.aria-current": "active() ? 'page' : null" } }, ngImport: i0, template: `
|
|
2500
3317
|
<span class="size-6" data-tab-icon><ng-content select="[tabIcon]" /></span>
|
|
2501
|
-
<span class="text-caption" data-tab-label><ng-content /></span>
|
|
3318
|
+
<span class="text-caption leading-none" data-tab-label><ng-content /></span>
|
|
2502
3319
|
`, isInline: true });
|
|
2503
3320
|
}
|
|
2504
3321
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTab, decorators: [{
|
|
@@ -2507,7 +3324,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2507
3324
|
selector: 'a[ui-tab]',
|
|
2508
3325
|
template: `
|
|
2509
3326
|
<span class="size-6" data-tab-icon><ng-content select="[tabIcon]" /></span>
|
|
2510
|
-
<span class="text-caption" data-tab-label><ng-content /></span>
|
|
3327
|
+
<span class="text-caption leading-none" data-tab-label><ng-content /></span>
|
|
2511
3328
|
`,
|
|
2512
3329
|
host: {
|
|
2513
3330
|
'[class]': 'classes()',
|
|
@@ -2524,5 +3341,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2524
3341
|
* Generated bundle index. Do not edit.
|
|
2525
3342
|
*/
|
|
2526
3343
|
|
|
2527
|
-
export { AMOUNT_MASKINGS, AMOUNT_NUMERICS, ASYNC_STATES, AVATAR_SIZES, BADGE_VARIANTS, BUTTON_SIZES, BUTTON_VARIANTS, CARD_PADDINGS, CARD_VARIANTS, CELL_BREAKPOINTS, CONTROL_SIZES, DELTA_EMPHASES, DIALOG_WIDTHS, METER_TONES, STAT_SIZES, UI_AMOUNT_MASKED, UiAmount, UiAsync, UiAvatar, UiBadge, UiButton, UiCard, UiDelta, UiDialog, UiDonut, UiField, UiInput, UiLineChart, UiMenu, UiMenuItem, UiMenuTrigger, UiMeter, UiNavItem, UiRow, UiSegmented, UiSelect, UiSkeleton, UiStat, UiSwitch, UiTab, UiTabBar, UiTable, UiTd, UiTextarea, UiTh, UiTr, formatAmount };
|
|
3344
|
+
export { ALERT_VARIANTS, AMOUNT_MASKINGS, AMOUNT_NUMERICS, ASYNC_STATES, AVATAR_SIZES, BADGE_SIZES, BADGE_VARIANTS, BUTTON_SIZES, BUTTON_VARIANTS, CARD_PADDINGS, CARD_VARIANTS, CELL_BREAKPOINTS, CONTROL_SIZES, CONTROL_SURFACES, DELTA_EMPHASES, DIALOG_LAYOUTS, DIALOG_WIDTHS, GROUP_SIZES, METER_TONES, ROW_PADDINGS, ROW_SIZES, STAT_SIZES, SUB_TONES, TABLE_ROWS, UI_AMOUNT_MASKED, UiAlert, UiAmount, UiAsync, UiAvatar, UiBadge, UiButton, UiCard, UiCellSub, UiChoiceChips, UiDelta, UiDialog, UiDonut, UiField, UiFieldLeading, UiGroup, UiGroupCell, UiInput, UiLineChart, UiMenu, UiMenuItem, UiMenuTrigger, UiMeter, UiNavItem, UiRow, UiRowAction, UiRowLink, UiSegmented, UiSelect, UiSkeleton, UiStat, UiSwitch, UiTab, UiTabBar, UiTable, UiTd, UiTextarea, UiTh, UiTr, formatAmount };
|
|
2528
3345
|
//# sourceMappingURL=joanroucoux-cairn-ui.mjs.map
|