@joanroucoux/cairn-ui 0.5.1 → 0.6.1
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 +2299 -676
- 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 +544 -88
|
@@ -1,7 +1,151 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, signal,
|
|
3
|
-
import {
|
|
2
|
+
import { Component, input, computed, InjectionToken, signal, inject, LOCALE_ID, booleanAttribute, output, Directive, ElementRef, DestroyRef, forwardRef, model, viewChildren, afterNextRender, afterRenderEffect, contentChild, viewChild, effect, numberAttribute, contentChildren } from '@angular/core';
|
|
3
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
4
4
|
import { scaleLinear } from 'd3-scale';
|
|
5
|
+
import { curveMonotoneX, line } from 'd3-shape';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Bar of actions fixed above the tab bar on iPhone: the primary actions of a detail screen, within
|
|
9
|
+
* thumb reach. It sits 52px plus the safe area above the bottom edge, so it clears `ui-tab-bar`, and
|
|
10
|
+
* it is hidden from `64rem`, where the same actions live in the page itself. Its children share the
|
|
11
|
+
* width equally.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* <ui-action-bar>
|
|
15
|
+
* <button ui-button variant="outline" size="tall">Sell</button>
|
|
16
|
+
* <button ui-button size="tall">Buy</button>
|
|
17
|
+
* </ui-action-bar>
|
|
18
|
+
*/
|
|
19
|
+
class UiActionBar {
|
|
20
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiActionBar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
21
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.7", type: UiActionBar, isStandalone: true, selector: "ui-action-bar", host: { classAttribute: "fixed inset-x-0 bottom-[calc(52px+env(safe-area-inset-bottom))] z-40 grid grid-flow-col auto-cols-fr gap-2 bg-(--background) px-(--gutter) py-3 shadow-[0_-1px_0_var(--hairline)] lg:hidden" }, ngImport: i0, template: '<ng-content />', isInline: true });
|
|
22
|
+
}
|
|
23
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiActionBar, decorators: [{
|
|
24
|
+
type: Component,
|
|
25
|
+
args: [{
|
|
26
|
+
selector: 'ui-action-bar',
|
|
27
|
+
template: '<ng-content />',
|
|
28
|
+
host: {
|
|
29
|
+
class: 'fixed inset-x-0 bottom-[calc(52px+env(safe-area-inset-bottom))] z-40 grid grid-flow-col auto-cols-fr gap-2 bg-(--background) px-(--gutter) py-3 shadow-[0_-1px_0_var(--hairline)] lg:hidden',
|
|
30
|
+
},
|
|
31
|
+
}]
|
|
32
|
+
}] });
|
|
33
|
+
|
|
34
|
+
const ALERT_VARIANTS = ['error', 'warning'];
|
|
35
|
+
const BASE_CLASSES$8 = 'flex items-start gap-2.5 text-left text-label';
|
|
36
|
+
const VARIANT_CLASSES$3 = {
|
|
37
|
+
error: 'rounded-control bg-(--card) px-3.5 py-3 shadow-[inset_0_0_0_1px_var(--border)]',
|
|
38
|
+
warning: 'text-(--foreground)',
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Inline message explaining a failure or a consequence: an icon, an optional heading and a text.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* <ui-alert heading="Sign-in failed">Try again.</ui-alert>
|
|
45
|
+
*/
|
|
46
|
+
class UiAlert {
|
|
47
|
+
variant = input('error', /* @ts-ignore */
|
|
48
|
+
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
49
|
+
heading = input(/* @ts-ignore */
|
|
50
|
+
...(ngDevMode ? [undefined, { debugName: "heading" }] : /* istanbul ignore next */ []));
|
|
51
|
+
classes = computed(() => `${BASE_CLASSES$8} ${VARIANT_CLASSES$3[this.variant()]}`, /* @ts-ignore */
|
|
52
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
53
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAlert, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
54
|
+
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: `
|
|
55
|
+
@if (variant() === 'warning') {
|
|
56
|
+
<svg
|
|
57
|
+
aria-hidden="true"
|
|
58
|
+
class="mt-px block flex-none stroke-(--negative)"
|
|
59
|
+
fill="none"
|
|
60
|
+
height="18"
|
|
61
|
+
stroke-linecap="round"
|
|
62
|
+
stroke-linejoin="round"
|
|
63
|
+
stroke-width="1.75"
|
|
64
|
+
viewBox="0 0 24 24"
|
|
65
|
+
width="18"
|
|
66
|
+
>
|
|
67
|
+
<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" />
|
|
68
|
+
<path d="M12 9v4" />
|
|
69
|
+
<path d="M12 17h.01" />
|
|
70
|
+
</svg>
|
|
71
|
+
} @else {
|
|
72
|
+
<svg
|
|
73
|
+
aria-hidden="true"
|
|
74
|
+
class="block flex-none stroke-(--negative)"
|
|
75
|
+
fill="none"
|
|
76
|
+
height="18"
|
|
77
|
+
stroke-linecap="round"
|
|
78
|
+
stroke-linejoin="round"
|
|
79
|
+
stroke-width="1.75"
|
|
80
|
+
viewBox="0 0 24 24"
|
|
81
|
+
width="18"
|
|
82
|
+
[class.mt-px]="heading()"
|
|
83
|
+
>
|
|
84
|
+
<circle cx="12" cy="12" r="10" />
|
|
85
|
+
<line x1="12" x2="12" y1="8" y2="12" />
|
|
86
|
+
<line x1="12" x2="12.01" y1="16" y2="16" />
|
|
87
|
+
</svg>
|
|
88
|
+
}
|
|
89
|
+
<div class="flex flex-col gap-0.5">
|
|
90
|
+
@if (heading()) {
|
|
91
|
+
<span class="font-medium">{{ heading() }}</span>
|
|
92
|
+
}
|
|
93
|
+
<span class="text-pretty" [class.text-(--muted-foreground)]="heading()"><ng-content /></span>
|
|
94
|
+
</div>
|
|
95
|
+
`, isInline: true });
|
|
96
|
+
}
|
|
97
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAlert, decorators: [{
|
|
98
|
+
type: Component,
|
|
99
|
+
args: [{
|
|
100
|
+
selector: 'ui-alert',
|
|
101
|
+
template: `
|
|
102
|
+
@if (variant() === 'warning') {
|
|
103
|
+
<svg
|
|
104
|
+
aria-hidden="true"
|
|
105
|
+
class="mt-px block flex-none stroke-(--negative)"
|
|
106
|
+
fill="none"
|
|
107
|
+
height="18"
|
|
108
|
+
stroke-linecap="round"
|
|
109
|
+
stroke-linejoin="round"
|
|
110
|
+
stroke-width="1.75"
|
|
111
|
+
viewBox="0 0 24 24"
|
|
112
|
+
width="18"
|
|
113
|
+
>
|
|
114
|
+
<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" />
|
|
115
|
+
<path d="M12 9v4" />
|
|
116
|
+
<path d="M12 17h.01" />
|
|
117
|
+
</svg>
|
|
118
|
+
} @else {
|
|
119
|
+
<svg
|
|
120
|
+
aria-hidden="true"
|
|
121
|
+
class="block flex-none stroke-(--negative)"
|
|
122
|
+
fill="none"
|
|
123
|
+
height="18"
|
|
124
|
+
stroke-linecap="round"
|
|
125
|
+
stroke-linejoin="round"
|
|
126
|
+
stroke-width="1.75"
|
|
127
|
+
viewBox="0 0 24 24"
|
|
128
|
+
width="18"
|
|
129
|
+
[class.mt-px]="heading()"
|
|
130
|
+
>
|
|
131
|
+
<circle cx="12" cy="12" r="10" />
|
|
132
|
+
<line x1="12" x2="12" y1="8" y2="12" />
|
|
133
|
+
<line x1="12" x2="12.01" y1="16" y2="16" />
|
|
134
|
+
</svg>
|
|
135
|
+
}
|
|
136
|
+
<div class="flex flex-col gap-0.5">
|
|
137
|
+
@if (heading()) {
|
|
138
|
+
<span class="font-medium">{{ heading() }}</span>
|
|
139
|
+
}
|
|
140
|
+
<span class="text-pretty" [class.text-(--muted-foreground)]="heading()"><ng-content /></span>
|
|
141
|
+
</div>
|
|
142
|
+
`,
|
|
143
|
+
host: {
|
|
144
|
+
'[class]': 'classes()',
|
|
145
|
+
'[attr.role]': "variant() === 'warning' ? 'status' : 'alert'",
|
|
146
|
+
},
|
|
147
|
+
}]
|
|
148
|
+
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }] } });
|
|
5
149
|
|
|
6
150
|
const MINUS = '−';
|
|
7
151
|
const EM_DASH = '—';
|
|
@@ -110,7 +254,60 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
110
254
|
|
|
111
255
|
/** Available async block states. `AsyncState` is derived from this tuple. */
|
|
112
256
|
const ASYNC_STATES = ['loading', 'error', 'empty', 'ready'];
|
|
113
|
-
|
|
257
|
+
/** Looks of the error block. `AsyncVariant` is derived from this tuple. */
|
|
258
|
+
const ASYNC_VARIANTS = ['elevated', 'plain', 'emphasis', 'inline'];
|
|
259
|
+
/** Alignments of the error block; `auto` is centred from 64rem. `AsyncAlign` is derived from this tuple. */
|
|
260
|
+
const ASYNC_ALIGNS = ['start', 'center', 'auto'];
|
|
261
|
+
const RETRY_BASE_CLASSES = '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) text-label';
|
|
262
|
+
const RETRY_OUTLINE_CLASSES = 'bg-(--card) text-(--foreground) shadow-[inset_0_0_0_1px_var(--border)] hover:bg-(--glow)';
|
|
263
|
+
const RETRY_PRIMARY_CLASSES = 'bg-(--primary) text-(--primary-foreground) hover:bg-(--primary-to)';
|
|
264
|
+
const RETRY_BLOCK_CLASSES = 'min-h-(--row-min) gap-2 pl-3 pr-4';
|
|
265
|
+
const RETRY_INLINE_CLASSES = 'h-11 pointer-fine:h-8 flex-none gap-1.5 pl-2.5 pr-3';
|
|
266
|
+
const ELEVATED_SURFACE_CLASSES = 'rounded-control bg-(--elevated)';
|
|
267
|
+
const CARD_SURFACE_CLASSES = 'rounded-container bg-(--card) shadow-[inset_0_0_0_1px_var(--border)]';
|
|
268
|
+
const BLOCK_SPECS = {
|
|
269
|
+
elevated: {
|
|
270
|
+
surface: ELEVATED_SURFACE_CLASSES,
|
|
271
|
+
gap: 'gap-1',
|
|
272
|
+
padding: { start: 'p-4', center: 'px-4 py-10', auto: 'p-4 lg:py-10' },
|
|
273
|
+
title: 'text-body font-medium',
|
|
274
|
+
message: { start: 'text-label', center: 'text-label', auto: 'text-label' },
|
|
275
|
+
retryMargin: { start: 'mt-2', center: 'mt-2', auto: 'mt-2' },
|
|
276
|
+
retry: RETRY_OUTLINE_CLASSES,
|
|
277
|
+
},
|
|
278
|
+
plain: {
|
|
279
|
+
surface: '',
|
|
280
|
+
gap: 'gap-1',
|
|
281
|
+
padding: { start: 'px-4 py-5', center: 'px-4 py-12', auto: 'px-4 py-5 lg:py-12' },
|
|
282
|
+
title: 'text-body leading-[normal] font-medium',
|
|
283
|
+
message: {
|
|
284
|
+
start: 'text-label leading-[normal]',
|
|
285
|
+
center: 'text-label leading-[normal]',
|
|
286
|
+
auto: 'text-label leading-[normal]',
|
|
287
|
+
},
|
|
288
|
+
retryMargin: { start: 'mt-2', center: 'mt-2', auto: 'mt-2' },
|
|
289
|
+
retry: RETRY_OUTLINE_CLASSES,
|
|
290
|
+
},
|
|
291
|
+
emphasis: {
|
|
292
|
+
surface: '',
|
|
293
|
+
gap: 'gap-3',
|
|
294
|
+
padding: { start: 'px-4 py-6', center: 'px-4 py-14', auto: 'px-4 py-6 lg:py-14' },
|
|
295
|
+
title: 'text-title font-semibold',
|
|
296
|
+
message: {
|
|
297
|
+
start: 'text-label',
|
|
298
|
+
center: 'text-body leading-[normal]',
|
|
299
|
+
auto: 'text-label lg:text-body lg:leading-[normal]',
|
|
300
|
+
},
|
|
301
|
+
retryMargin: { start: 'mt-1', center: 'mt-2', auto: 'mt-1 lg:mt-2' },
|
|
302
|
+
retry: RETRY_PRIMARY_CLASSES,
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
const ALIGN_CLASSES = {
|
|
306
|
+
start: 'items-start',
|
|
307
|
+
center: 'items-center text-center',
|
|
308
|
+
auto: 'items-start lg:items-center lg:text-center',
|
|
309
|
+
};
|
|
310
|
+
const INLINE_BOX_CLASSES = 'flex-row items-center justify-between gap-3 pt-1.5 pr-1.5 pb-2 pl-2.5';
|
|
114
311
|
/**
|
|
115
312
|
* The three states of a block that depends on a service call, next to the ready content.
|
|
116
313
|
*
|
|
@@ -130,23 +327,76 @@ class UiAsync {
|
|
|
130
327
|
...(ngDevMode ? [undefined, { debugName: "errorMessage" }] : /* istanbul ignore next */ []));
|
|
131
328
|
retryLabel = input(/* @ts-ignore */
|
|
132
329
|
...(ngDevMode ? [undefined, { debugName: "retryLabel" }] : /* istanbul ignore next */ []));
|
|
330
|
+
variant = input('elevated', /* @ts-ignore */
|
|
331
|
+
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
332
|
+
align = input('start', /* @ts-ignore */
|
|
333
|
+
...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
|
|
334
|
+
card = input(false, { ...(ngDevMode ? { debugName: "card" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
335
|
+
fill = input(false, { ...(ngDevMode ? { debugName: "fill" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
133
336
|
retry = output();
|
|
134
|
-
|
|
337
|
+
filling = computed(() => this.fill() && this.state() === 'error', /* @ts-ignore */
|
|
338
|
+
...(ngDevMode ? [{ debugName: "filling" }] : /* istanbul ignore next */ []));
|
|
339
|
+
iconSize = computed(() => (this.variant() === 'inline' ? 16 : 18), /* @ts-ignore */
|
|
340
|
+
...(ngDevMode ? [{ debugName: "iconSize" }] : /* istanbul ignore next */ []));
|
|
341
|
+
#spec = computed(() => {
|
|
342
|
+
const variant = this.variant();
|
|
343
|
+
return variant === 'inline' ? null : BLOCK_SPECS[variant];
|
|
344
|
+
}, /* @ts-ignore */
|
|
345
|
+
...(ngDevMode ? [{ debugName: "#spec" }] : /* istanbul ignore next */ []));
|
|
346
|
+
boxClasses = computed(() => {
|
|
347
|
+
const spec = this.#spec();
|
|
348
|
+
const fill = this.fill() ? ' flex-1 justify-center' : '';
|
|
349
|
+
if (spec === null) {
|
|
350
|
+
return `flex ${INLINE_BOX_CLASSES}${this.card() ? ` ${CARD_SURFACE_CLASSES}` : ''}${this.fill() ? ' flex-1' : ''}`;
|
|
351
|
+
}
|
|
352
|
+
const surface = this.card() ? CARD_SURFACE_CLASSES : spec.surface;
|
|
353
|
+
return `flex flex-col ${surface} ${spec.gap} ${ALIGN_CLASSES[this.align()]} ${spec.padding[this.align()]}${fill}`;
|
|
354
|
+
}, /* @ts-ignore */
|
|
355
|
+
...(ngDevMode ? [{ debugName: "boxClasses" }] : /* istanbul ignore next */ []));
|
|
356
|
+
titleClasses = computed(() => this.#spec()?.title ?? '', /* @ts-ignore */
|
|
357
|
+
...(ngDevMode ? [{ debugName: "titleClasses" }] : /* istanbul ignore next */ []));
|
|
358
|
+
messageClasses = computed(() => this.#spec()?.message[this.align()] ?? '', /* @ts-ignore */
|
|
359
|
+
...(ngDevMode ? [{ debugName: "messageClasses" }] : /* istanbul ignore next */ []));
|
|
360
|
+
retryButtonClasses = computed(() => {
|
|
361
|
+
const spec = this.#spec();
|
|
362
|
+
if (spec === null) {
|
|
363
|
+
return `${RETRY_BASE_CLASSES} ${RETRY_OUTLINE_CLASSES} ${RETRY_INLINE_CLASSES}`;
|
|
364
|
+
}
|
|
365
|
+
return `${RETRY_BASE_CLASSES} ${spec.retry} ${RETRY_BLOCK_CLASSES} ${spec.retryMargin[this.align()]}`;
|
|
366
|
+
}, /* @ts-ignore */
|
|
367
|
+
...(ngDevMode ? [{ debugName: "retryButtonClasses" }] : /* istanbul ignore next */ []));
|
|
135
368
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAsync, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
136
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiAsync, isStandalone: true, selector: "ui-async", inputs: { state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: true, transformFunction: null }, errorTitle: { classPropertyName: "errorTitle", publicName: "errorTitle", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, retryLabel: { classPropertyName: "retryLabel", publicName: "retryLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { retry: "retry" }, host: { properties: { "attr.aria-busy": "state() === 'loading' || null" } }, ngImport: i0, template: `
|
|
369
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiAsync, isStandalone: true, selector: "ui-async", inputs: { state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: true, transformFunction: null }, errorTitle: { classPropertyName: "errorTitle", publicName: "errorTitle", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, retryLabel: { classPropertyName: "retryLabel", publicName: "retryLabel", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, card: { classPropertyName: "card", publicName: "card", isSignal: true, isRequired: false, transformFunction: null }, fill: { classPropertyName: "fill", publicName: "fill", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { retry: "retry" }, host: { properties: { "attr.aria-busy": "state() === 'loading' || null", "class.flex": "filling()", "class.flex-col": "filling()" } }, ngImport: i0, template: `
|
|
137
370
|
@switch (state()) {
|
|
138
371
|
@case ('loading') {
|
|
139
372
|
<ng-content select="[asyncLoading]" />
|
|
140
373
|
}
|
|
141
374
|
@case ('error') {
|
|
142
|
-
<div
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
375
|
+
<div aria-live="polite" role="alert" [class]="boxClasses()">
|
|
376
|
+
@if (variant() === 'inline') {
|
|
377
|
+
<span class="text-label text-(--muted-foreground)">{{ errorMessage() }}</span>
|
|
378
|
+
} @else {
|
|
379
|
+
@if (variant() === 'emphasis') {
|
|
380
|
+
<h2 [class]="titleClasses()">{{ errorTitle() }}</h2>
|
|
381
|
+
} @else {
|
|
382
|
+
<span [class]="titleClasses()">{{ errorTitle() }}</span>
|
|
383
|
+
}
|
|
384
|
+
<span class="text-(--muted-foreground)" [class]="messageClasses()">{{ errorMessage() }}</span>
|
|
385
|
+
}
|
|
386
|
+
<button type="button" [class]="retryButtonClasses()" (click)="retry.emit()">
|
|
387
|
+
<svg
|
|
388
|
+
aria-hidden="true"
|
|
389
|
+
class="block flex-none fill-none stroke-current"
|
|
390
|
+
stroke-linecap="round"
|
|
391
|
+
stroke-linejoin="round"
|
|
392
|
+
stroke-width="1.75"
|
|
393
|
+
viewBox="0 0 24 24"
|
|
394
|
+
[attr.height]="iconSize()"
|
|
395
|
+
[attr.width]="iconSize()"
|
|
396
|
+
>
|
|
397
|
+
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
|
398
|
+
<path d="M21 3v5h-5" />
|
|
399
|
+
</svg>
|
|
150
400
|
{{ retryLabel() }}
|
|
151
401
|
</button>
|
|
152
402
|
</div>
|
|
@@ -170,14 +420,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
170
420
|
<ng-content select="[asyncLoading]" />
|
|
171
421
|
}
|
|
172
422
|
@case ('error') {
|
|
173
|
-
<div
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
423
|
+
<div aria-live="polite" role="alert" [class]="boxClasses()">
|
|
424
|
+
@if (variant() === 'inline') {
|
|
425
|
+
<span class="text-label text-(--muted-foreground)">{{ errorMessage() }}</span>
|
|
426
|
+
} @else {
|
|
427
|
+
@if (variant() === 'emphasis') {
|
|
428
|
+
<h2 [class]="titleClasses()">{{ errorTitle() }}</h2>
|
|
429
|
+
} @else {
|
|
430
|
+
<span [class]="titleClasses()">{{ errorTitle() }}</span>
|
|
431
|
+
}
|
|
432
|
+
<span class="text-(--muted-foreground)" [class]="messageClasses()">{{ errorMessage() }}</span>
|
|
433
|
+
}
|
|
434
|
+
<button type="button" [class]="retryButtonClasses()" (click)="retry.emit()">
|
|
435
|
+
<svg
|
|
436
|
+
aria-hidden="true"
|
|
437
|
+
class="block flex-none fill-none stroke-current"
|
|
438
|
+
stroke-linecap="round"
|
|
439
|
+
stroke-linejoin="round"
|
|
440
|
+
stroke-width="1.75"
|
|
441
|
+
viewBox="0 0 24 24"
|
|
442
|
+
[attr.height]="iconSize()"
|
|
443
|
+
[attr.width]="iconSize()"
|
|
444
|
+
>
|
|
445
|
+
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" />
|
|
446
|
+
<path d="M21 3v5h-5" />
|
|
447
|
+
</svg>
|
|
181
448
|
{{ retryLabel() }}
|
|
182
449
|
</button>
|
|
183
450
|
</div>
|
|
@@ -192,16 +459,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
192
459
|
`,
|
|
193
460
|
host: {
|
|
194
461
|
'[attr.aria-busy]': "state() === 'loading' || null",
|
|
462
|
+
'[class.flex]': 'filling()',
|
|
463
|
+
'[class.flex-col]': 'filling()',
|
|
195
464
|
},
|
|
196
465
|
}]
|
|
197
|
-
}], 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"] }] } });
|
|
466
|
+
}], 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 }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], card: [{ type: i0.Input, args: [{ isSignal: true, alias: "card", required: false }] }], fill: [{ type: i0.Input, args: [{ isSignal: true, alias: "fill", required: false }] }], retry: [{ type: i0.Output, args: ["retry"] }] } });
|
|
198
467
|
|
|
199
468
|
/** Available avatar sizes. `AvatarSize` is derived from this tuple. */
|
|
200
|
-
const AVATAR_SIZES = ['sm', 'md'];
|
|
201
|
-
const BASE_CLASSES$
|
|
202
|
-
const SIZE_CLASSES$
|
|
469
|
+
const AVATAR_SIZES = ['sm', 'md', 'lg', 'auto'];
|
|
470
|
+
const BASE_CLASSES$7 = 'inline-flex items-center justify-center rounded-pill bg-(--muted) font-medium tabular-nums';
|
|
471
|
+
const SIZE_CLASSES$7 = {
|
|
203
472
|
sm: 'size-8 text-caption',
|
|
204
|
-
md: 'size-
|
|
473
|
+
md: 'size-[34px] text-label',
|
|
474
|
+
lg: 'size-14 text-title',
|
|
475
|
+
auto: 'size-[34px] text-label lg:size-8 lg:text-caption',
|
|
205
476
|
};
|
|
206
477
|
/**
|
|
207
478
|
* Initials in a disc, standing in for a person. Single-user application: there is exactly one.
|
|
@@ -216,7 +487,7 @@ class UiAvatar {
|
|
|
216
487
|
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
217
488
|
size = input('md', /* @ts-ignore */
|
|
218
489
|
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
219
|
-
classes = computed(() => `${BASE_CLASSES$
|
|
490
|
+
classes = computed(() => `${BASE_CLASSES$7} ${SIZE_CLASSES$7[this.size()]}`, /* @ts-ignore */
|
|
220
491
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
221
492
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAvatar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
222
493
|
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 });
|
|
@@ -233,10 +504,101 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
233
504
|
},
|
|
234
505
|
}]
|
|
235
506
|
}], propDecorators: { initials: [{ type: i0.Input, args: [{ isSignal: true, alias: "initials", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
507
|
+
/**
|
|
508
|
+
* Round hit area around a `ui-avatar` that links somewhere: 44px on touch, 40px from 64rem, with a
|
|
509
|
+
* glow on hover and the press scale. The avatar itself keeps its own size.
|
|
510
|
+
*
|
|
511
|
+
* @example
|
|
512
|
+
* <a uiAvatarLink routerLink="/profile"><ui-avatar initials="JR" label="Profile" size="auto" /></a>
|
|
513
|
+
*/
|
|
514
|
+
class UiAvatarLink {
|
|
515
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAvatarLink, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
516
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.7", type: UiAvatarLink, isStandalone: true, selector: "a[uiAvatarLink], button[uiAvatarLink]", host: { classAttribute: "rounded-pill grid size-11 lg:size-10 place-items-center cursor-pointer select-none touch-manipulation transition-[transform,background-color] duration-(--duration-press) ease-out hover:bg-(--glow) active:scale-(--press-scale) focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring)" }, ngImport: i0 });
|
|
517
|
+
}
|
|
518
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAvatarLink, decorators: [{
|
|
519
|
+
type: Directive,
|
|
520
|
+
args: [{
|
|
521
|
+
selector: 'a[uiAvatarLink], button[uiAvatarLink]',
|
|
522
|
+
host: {
|
|
523
|
+
class: 'rounded-pill grid size-11 lg:size-10 place-items-center cursor-pointer select-none touch-manipulation transition-[transform,background-color] duration-(--duration-press) ease-out hover:bg-(--glow) active:scale-(--press-scale) focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring)',
|
|
524
|
+
},
|
|
525
|
+
}]
|
|
526
|
+
}] });
|
|
527
|
+
|
|
528
|
+
/** Available back link sizes. `BackLinkSize` is derived from this tuple. */
|
|
529
|
+
const BACK_LINK_SIZES = ['md', 'sm', 'header'];
|
|
530
|
+
const BASE_CLASSES$6 = 'inline-flex items-center gap-0.5 rounded-control text-body font-medium whitespace-nowrap cursor-pointer select-none touch-manipulation transition-[transform,background-color,color] duration-(--duration-press) ease-out active:scale-(--press-scale) focus-visible:outline-2 focus-visible:outline-(--ring)';
|
|
531
|
+
const SIZE_CLASSES$6 = {
|
|
532
|
+
md: 'h-11 pr-3 pl-1 text-(--foreground) focus-visible:outline-offset-2',
|
|
533
|
+
sm: 'h-9 pr-2 pl-0.5 text-(--muted-foreground) hover:bg-(--glow) hover:text-(--foreground) focus-visible:outline-offset-2',
|
|
534
|
+
header: 'h-11 pr-3 pl-1 text-(--foreground) focus-visible:-outline-offset-2',
|
|
535
|
+
};
|
|
536
|
+
const CHEVRON = { md: 22, sm: 22, header: 24 };
|
|
537
|
+
/**
|
|
538
|
+
* Link back to the parent screen: a chevron and the name of the destination.
|
|
539
|
+
*
|
|
540
|
+
* @example
|
|
541
|
+
* <a ui-back-link routerLink="/accounts">Accounts</a>
|
|
542
|
+
*/
|
|
543
|
+
class UiBackLink {
|
|
544
|
+
size = input('md', /* @ts-ignore */
|
|
545
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
546
|
+
chevron = computed(() => CHEVRON[this.size()], /* @ts-ignore */
|
|
547
|
+
...(ngDevMode ? [{ debugName: "chevron" }] : /* istanbul ignore next */ []));
|
|
548
|
+
classes = computed(() => `${BASE_CLASSES$6} ${SIZE_CLASSES$6[this.size()]}`, /* @ts-ignore */
|
|
549
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
550
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiBackLink, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
551
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: UiBackLink, isStandalone: true, selector: "a[ui-back-link]", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: `
|
|
552
|
+
<svg
|
|
553
|
+
aria-hidden="true"
|
|
554
|
+
fill="none"
|
|
555
|
+
stroke="currentColor"
|
|
556
|
+
stroke-linecap="round"
|
|
557
|
+
stroke-linejoin="round"
|
|
558
|
+
stroke-width="1.75"
|
|
559
|
+
viewBox="0 0 24 24"
|
|
560
|
+
[attr.height]="chevron()"
|
|
561
|
+
[attr.width]="chevron()"
|
|
562
|
+
>
|
|
563
|
+
<path d="m15 18-6-6 6-6" />
|
|
564
|
+
</svg>
|
|
565
|
+
<ng-content />
|
|
566
|
+
`, isInline: true });
|
|
567
|
+
}
|
|
568
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiBackLink, decorators: [{
|
|
569
|
+
type: Component,
|
|
570
|
+
args: [{
|
|
571
|
+
selector: 'a[ui-back-link]',
|
|
572
|
+
template: `
|
|
573
|
+
<svg
|
|
574
|
+
aria-hidden="true"
|
|
575
|
+
fill="none"
|
|
576
|
+
stroke="currentColor"
|
|
577
|
+
stroke-linecap="round"
|
|
578
|
+
stroke-linejoin="round"
|
|
579
|
+
stroke-width="1.75"
|
|
580
|
+
viewBox="0 0 24 24"
|
|
581
|
+
[attr.height]="chevron()"
|
|
582
|
+
[attr.width]="chevron()"
|
|
583
|
+
>
|
|
584
|
+
<path d="m15 18-6-6 6-6" />
|
|
585
|
+
</svg>
|
|
586
|
+
<ng-content />
|
|
587
|
+
`,
|
|
588
|
+
host: {
|
|
589
|
+
'[class]': 'classes()',
|
|
590
|
+
},
|
|
591
|
+
}]
|
|
592
|
+
}], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
236
593
|
|
|
237
594
|
/** Available badge variants. `BadgeVariant` is derived from this tuple. */
|
|
238
595
|
const BADGE_VARIANTS = ['neutral', 'outline'];
|
|
239
|
-
const
|
|
596
|
+
const BADGE_SIZES = ['md', 'sm'];
|
|
597
|
+
const BASE_CLASSES$5 = 'inline-flex items-center rounded-pill text-caption font-medium';
|
|
598
|
+
const SIZE_CLASSES$5 = {
|
|
599
|
+
md: 'h-6 px-2.5',
|
|
600
|
+
sm: 'h-[22px] px-2',
|
|
601
|
+
};
|
|
240
602
|
const VARIANT_CLASSES$2 = {
|
|
241
603
|
neutral: 'bg-(--muted) text-(--foreground)',
|
|
242
604
|
outline: 'shadow-[inset_0_0_0_1px_var(--border)] text-(--foreground)',
|
|
@@ -250,10 +612,12 @@ const VARIANT_CLASSES$2 = {
|
|
|
250
612
|
class UiBadge {
|
|
251
613
|
variant = input('neutral', /* @ts-ignore */
|
|
252
614
|
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
253
|
-
|
|
615
|
+
size = input('md', /* @ts-ignore */
|
|
616
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
617
|
+
classes = computed(() => `${BASE_CLASSES$5} ${SIZE_CLASSES$5[this.size()]} ${VARIANT_CLASSES$2[this.variant()]}`, /* @ts-ignore */
|
|
254
618
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
255
619
|
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 });
|
|
620
|
+
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
621
|
}
|
|
258
622
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiBadge, decorators: [{
|
|
259
623
|
type: Component,
|
|
@@ -264,24 +628,63 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
264
628
|
'[class]': 'classes()',
|
|
265
629
|
},
|
|
266
630
|
}]
|
|
267
|
-
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }] } });
|
|
631
|
+
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
268
632
|
|
|
269
633
|
/** Available button variants. `ButtonVariant` is derived from this tuple. */
|
|
270
|
-
const BUTTON_VARIANTS = [
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
634
|
+
const BUTTON_VARIANTS = [
|
|
635
|
+
'primary',
|
|
636
|
+
'outline',
|
|
637
|
+
'ghost',
|
|
638
|
+
'destructive',
|
|
639
|
+
'quiet',
|
|
640
|
+
'quiet-destructive',
|
|
641
|
+
'outline-destructive',
|
|
642
|
+
'quiet-glow',
|
|
643
|
+
'tonal',
|
|
644
|
+
];
|
|
645
|
+
/** Available button sizes. */
|
|
646
|
+
const BUTTON_SIZES = [
|
|
647
|
+
'compact',
|
|
648
|
+
'slim',
|
|
649
|
+
'xs',
|
|
650
|
+
'sm',
|
|
651
|
+
'md',
|
|
652
|
+
'lg',
|
|
653
|
+
'xl',
|
|
654
|
+
'xxl',
|
|
655
|
+
'tall',
|
|
656
|
+
'block',
|
|
657
|
+
'icon',
|
|
658
|
+
'icon-sm',
|
|
659
|
+
];
|
|
660
|
+
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-(--ring) disabled:pointer-events-none disabled:opacity-40 aria-disabled:not-aria-busy:opacity-40';
|
|
661
|
+
const RING_OUTSIDE = 'focus-visible:outline-offset-2';
|
|
662
|
+
const RING_INSIDE = 'focus-visible:-outline-offset-2';
|
|
663
|
+
const OUTLINE = 'bg-(--card) shadow-[inset_0_0_0_1px_var(--border)] hover:bg-(--glow) active:bg-(--soft)';
|
|
274
664
|
const VARIANT_CLASSES$1 = {
|
|
275
|
-
primary:
|
|
276
|
-
outline:
|
|
277
|
-
ghost:
|
|
278
|
-
destructive:
|
|
665
|
+
primary: `${RING_OUTSIDE} bg-(--primary) text-(--primary-foreground) hover:bg-(--primary-to)`,
|
|
666
|
+
outline: `${RING_OUTSIDE} ${OUTLINE} text-(--foreground)`,
|
|
667
|
+
ghost: `${RING_OUTSIDE} bg-transparent text-(--foreground) hover:bg-(--glow) active:bg-(--soft)`,
|
|
668
|
+
destructive: `${RING_OUTSIDE} bg-(--destructive) text-(--destructive-foreground)`,
|
|
669
|
+
tonal: `${RING_OUTSIDE} bg-(--muted) text-(--foreground) lg:bg-transparent lg:hover:bg-(--glow)`,
|
|
670
|
+
'quiet-glow': `${RING_INSIDE} bg-transparent text-(--muted-foreground) hover:bg-(--glow) hover:text-(--foreground)`,
|
|
671
|
+
quiet: `${RING_INSIDE} bg-transparent text-(--muted-foreground) hover:bg-(--soft) hover:text-(--foreground) active:bg-(--soft)`,
|
|
672
|
+
'quiet-destructive': `${RING_INSIDE} bg-transparent text-(--muted-foreground) hover:bg-(--glow) hover:text-(--negative) active:bg-(--soft)`,
|
|
673
|
+
'outline-destructive': `${RING_OUTSIDE} ${OUTLINE} text-(--negative)`,
|
|
279
674
|
};
|
|
280
|
-
const SIZE_CLASSES = {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
675
|
+
const SIZE_CLASSES$4 = {
|
|
676
|
+
compact: 'h-8 lg:h-7 gap-1.5 px-2.5 lg:px-2 text-label before:absolute before:-inset-x-1 before:-inset-y-1.5 lg:before:hidden',
|
|
677
|
+
slim: 'h-11 lg:h-8 gap-1.5 px-2.5 text-label',
|
|
678
|
+
xs: 'h-8 gap-1.5 px-2.5 text-label',
|
|
679
|
+
sm: 'h-9 gap-2 px-3 text-label',
|
|
680
|
+
md: 'min-h-(--row-min) gap-2 px-4 text-label has-[>svg:first-child]:pl-3',
|
|
681
|
+
lg: 'h-11 gap-2 px-[18px] text-label',
|
|
682
|
+
xl: 'h-[50px] gap-2 px-6 text-body',
|
|
683
|
+
xxl: 'h-[52px] lg:h-11 gap-2.5 px-6 lg:px-5 text-body lg:has-[>svg:first-child]:pl-4',
|
|
684
|
+
tall: 'h-12 lg:h-10 gap-2 px-4 text-body',
|
|
685
|
+
block: 'h-[50px] lg:h-11 gap-2 px-4 text-body',
|
|
686
|
+
icon: 'size-(--row-min) gap-2 p-0',
|
|
687
|
+
'icon-sm': 'size-11 pointer-fine:size-9 gap-2 p-0',
|
|
285
688
|
};
|
|
286
689
|
/**
|
|
287
690
|
* Styled native button or anchor, applied as an attribute so the host keeps every native behavior.
|
|
@@ -296,12 +699,15 @@ class UiButton {
|
|
|
296
699
|
size = input('md', /* @ts-ignore */
|
|
297
700
|
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
298
701
|
loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
299
|
-
|
|
702
|
+
busy = input(false, { ...(ngDevMode ? { debugName: "busy" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
703
|
+
inactive = computed(() => this.loading() || this.busy(), /* @ts-ignore */
|
|
704
|
+
...(ngDevMode ? [{ debugName: "inactive" }] : /* istanbul ignore next */ []));
|
|
705
|
+
classes = computed(() => `${BASE_CLASSES$4} ${VARIANT_CLASSES$1[this.variant()]} ${SIZE_CLASSES$4[this.size()]}${this.inactive() ? ' pointer-events-none opacity-70' : ''}`, /* @ts-ignore */
|
|
300
706
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
301
707
|
constructor() {
|
|
302
708
|
const host = inject(ElementRef).nativeElement;
|
|
303
709
|
const guard = (event) => {
|
|
304
|
-
if (this.
|
|
710
|
+
if (this.inactive()) {
|
|
305
711
|
event.preventDefault();
|
|
306
712
|
event.stopImmediatePropagation();
|
|
307
713
|
}
|
|
@@ -310,7 +716,7 @@ class UiButton {
|
|
|
310
716
|
inject(DestroyRef).onDestroy(() => host.removeEventListener('click', guard, { capture: true }));
|
|
311
717
|
}
|
|
312
718
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiButton, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
313
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiButton, isStandalone: true, selector: "button[ui-button], a[ui-button]", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.aria-busy": "
|
|
719
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiButton, isStandalone: true, selector: "button[ui-button], a[ui-button]", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, busy: { classPropertyName: "busy", publicName: "busy", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.aria-busy": "inactive() || null", "attr.aria-disabled": "inactive() || null" } }, ngImport: i0, template: `
|
|
314
720
|
@if (loading()) {
|
|
315
721
|
<span
|
|
316
722
|
aria-hidden="true"
|
|
@@ -335,41 +741,78 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
335
741
|
`,
|
|
336
742
|
host: {
|
|
337
743
|
'[class]': 'classes()',
|
|
338
|
-
'[attr.aria-busy]': '
|
|
339
|
-
'[attr.aria-disabled]': '
|
|
744
|
+
'[attr.aria-busy]': 'inactive() || null',
|
|
745
|
+
'[attr.aria-disabled]': 'inactive() || null',
|
|
340
746
|
},
|
|
341
747
|
}]
|
|
342
|
-
}], ctorParameters: () => [], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }] } });
|
|
748
|
+
}], ctorParameters: () => [], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], busy: [{ type: i0.Input, args: [{ isSignal: true, alias: "busy", required: false }] }] } });
|
|
343
749
|
|
|
344
750
|
/** Available card variants. `CardVariant` is derived from this tuple. */
|
|
345
751
|
const CARD_VARIANTS = ['default', 'elevated'];
|
|
346
752
|
/** Available card paddings. `CardPadding` is derived from this tuple. */
|
|
347
|
-
const CARD_PADDINGS = ['none', 'sm', 'md'];
|
|
348
|
-
|
|
753
|
+
const CARD_PADDINGS = ['none', 'sm', 'md', 'list', 'rows'];
|
|
754
|
+
/** Where the card surface (fill, border, radius) and its padding apply. `CardSurface` is derived from this tuple. */
|
|
755
|
+
const CARD_SURFACES = ['always', 'lg', 'max-lg'];
|
|
756
|
+
const BASE_CLASSES$3 = 'block';
|
|
349
757
|
const VARIANT_CLASSES = {
|
|
350
|
-
default:
|
|
351
|
-
|
|
758
|
+
default: {
|
|
759
|
+
always: 'rounded-container bg-(--card) shadow-[inset_0_0_0_1px_var(--border)] text-(--card-foreground)',
|
|
760
|
+
lg: 'lg:rounded-container lg:bg-(--card) lg:shadow-[inset_0_0_0_1px_var(--border)] lg:text-(--card-foreground)',
|
|
761
|
+
'max-lg': 'max-lg:rounded-container max-lg:bg-(--card) max-lg:shadow-[inset_0_0_0_1px_var(--border)] max-lg:text-(--card-foreground)',
|
|
762
|
+
},
|
|
763
|
+
elevated: {
|
|
764
|
+
always: 'rounded-container bg-(--elevated) shadow-[inset_0_0_0_1px_var(--hairline)] text-(--foreground)',
|
|
765
|
+
lg: 'lg:rounded-container lg:bg-(--elevated) lg:shadow-[inset_0_0_0_1px_var(--hairline)] lg:text-(--foreground)',
|
|
766
|
+
'max-lg': 'max-lg:rounded-container max-lg:bg-(--elevated) max-lg:shadow-[inset_0_0_0_1px_var(--hairline)] max-lg:text-(--foreground)',
|
|
767
|
+
},
|
|
352
768
|
};
|
|
353
|
-
const PADDING_CLASSES = {
|
|
354
|
-
none:
|
|
355
|
-
|
|
356
|
-
|
|
769
|
+
const PADDING_CLASSES$1 = {
|
|
770
|
+
none: {
|
|
771
|
+
always: 'p-0',
|
|
772
|
+
lg: 'lg:p-0',
|
|
773
|
+
'max-lg': 'max-lg:p-0',
|
|
774
|
+
},
|
|
775
|
+
sm: {
|
|
776
|
+
always: 'p-3',
|
|
777
|
+
lg: 'lg:p-3',
|
|
778
|
+
'max-lg': 'max-lg:p-3',
|
|
779
|
+
},
|
|
780
|
+
md: {
|
|
781
|
+
always: 'p-(--inset-card)',
|
|
782
|
+
lg: 'lg:p-(--inset-card)',
|
|
783
|
+
'max-lg': 'max-lg:p-(--inset-card)',
|
|
784
|
+
},
|
|
785
|
+
list: {
|
|
786
|
+
always: 'px-2 py-3',
|
|
787
|
+
lg: 'lg:px-2 lg:py-3',
|
|
788
|
+
'max-lg': 'max-lg:px-2 max-lg:py-3',
|
|
789
|
+
},
|
|
790
|
+
rows: {
|
|
791
|
+
always: 'px-(--inset-card) py-1',
|
|
792
|
+
lg: 'lg:px-(--inset-card) lg:py-1',
|
|
793
|
+
'max-lg': 'max-lg:px-(--inset-card) max-lg:py-1',
|
|
794
|
+
},
|
|
357
795
|
};
|
|
358
796
|
/**
|
|
359
|
-
* Surface that groups related content: a summary block, a table, a side panel.
|
|
797
|
+
* Surface that groups related content: a summary block, a table, a side panel. `surface` limits the
|
|
798
|
+
* fill, border, radius and padding to one side of `64rem`, for a block that is a card on a desktop and
|
|
799
|
+
* plain on an iPhone, or the reverse.
|
|
360
800
|
*
|
|
361
801
|
* @example
|
|
362
802
|
* <ui-card variant="elevated" padding="sm">Total</ui-card>
|
|
803
|
+
* <ui-card surface="max-lg">Card on an iPhone, plain on a desktop</ui-card>
|
|
363
804
|
*/
|
|
364
805
|
class UiCard {
|
|
365
806
|
variant = input('default', /* @ts-ignore */
|
|
366
807
|
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
367
808
|
padding = input('md', /* @ts-ignore */
|
|
368
809
|
...(ngDevMode ? [{ debugName: "padding" }] : /* istanbul ignore next */ []));
|
|
369
|
-
|
|
810
|
+
surface = input('always', /* @ts-ignore */
|
|
811
|
+
...(ngDevMode ? [{ debugName: "surface" }] : /* istanbul ignore next */ []));
|
|
812
|
+
classes = computed(() => `${BASE_CLASSES$3} ${VARIANT_CLASSES[this.variant()][this.surface()]} ${PADDING_CLASSES$1[this.padding()][this.surface()]}`, /* @ts-ignore */
|
|
370
813
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
371
814
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiCard, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
372
|
-
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 });
|
|
815
|
+
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 }, surface: { classPropertyName: "surface", publicName: "surface", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: '<ng-content />', isInline: true });
|
|
373
816
|
}
|
|
374
817
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiCard, decorators: [{
|
|
375
818
|
type: Component,
|
|
@@ -380,7 +823,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
380
823
|
'[class]': 'classes()',
|
|
381
824
|
},
|
|
382
825
|
}]
|
|
383
|
-
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], padding: [{ type: i0.Input, args: [{ isSignal: true, alias: "padding", required: false }] }] } });
|
|
826
|
+
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], padding: [{ type: i0.Input, args: [{ isSignal: true, alias: "padding", required: false }] }], surface: [{ type: i0.Input, args: [{ isSignal: true, alias: "surface", required: false }] }] } });
|
|
384
827
|
|
|
385
828
|
/**
|
|
386
829
|
* Resolves to the styled control projected into a field.
|
|
@@ -392,17 +835,270 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
392
835
|
*/
|
|
393
836
|
const UI_CONTROL = new InjectionToken('UI_CONTROL');
|
|
394
837
|
|
|
838
|
+
/** Available control sizes. `md` is the 44/40px touch target; `lg` and `xl` are the 48px sheet and sign-in fields. */
|
|
839
|
+
const CONTROL_SIZES = ['sm', 'md', 'lg', 'xl'];
|
|
840
|
+
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';
|
|
841
|
+
const CONTROL_SURFACES = ['background', 'card'];
|
|
842
|
+
const CONTROL_SURFACE_CLASSES = {
|
|
843
|
+
background: 'bg-(--background)',
|
|
844
|
+
card: 'bg-(--card)',
|
|
845
|
+
};
|
|
846
|
+
const CONTROL_SIZE_CLASSES = {
|
|
847
|
+
sm: 'h-9',
|
|
848
|
+
md: 'min-h-(--row-min)',
|
|
849
|
+
lg: 'min-h-12 lg:min-h-(--row-min)',
|
|
850
|
+
xl: 'h-12 lg:h-11',
|
|
851
|
+
};
|
|
852
|
+
const SEARCH_CLASSES = '[&::-webkit-search-cancel-button]:appearance-none';
|
|
853
|
+
/**
|
|
854
|
+
* Styled native text input. A directive (not a wrapper component) so the host
|
|
855
|
+
* stays a plain <input>: every forms flavor (ngModel, reactive, signal forms)
|
|
856
|
+
* and every native attribute keep working without any plumbing.
|
|
857
|
+
*
|
|
858
|
+
* Declares the `errors` and `touched` inputs Angular's `[formField]` fills, so a `ui-field` around
|
|
859
|
+
* it can show the message without any binding here.
|
|
860
|
+
*
|
|
861
|
+
* @example
|
|
862
|
+
* <input uiInput type="email" placeholder="you@example.com" />
|
|
863
|
+
*/
|
|
864
|
+
class UiInput {
|
|
865
|
+
size = input('md', /* @ts-ignore */
|
|
866
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
867
|
+
surface = input('background', /* @ts-ignore */
|
|
868
|
+
...(ngDevMode ? [{ debugName: "surface" }] : /* istanbul ignore next */ []));
|
|
869
|
+
errors = input([], /* @ts-ignore */
|
|
870
|
+
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
871
|
+
touched = input(false, /* @ts-ignore */
|
|
872
|
+
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
873
|
+
classes = computed(() => `${CONTROL_BASE_CLASSES} ${SEARCH_CLASSES} ${CONTROL_SURFACE_CLASSES[this.surface()]} ${CONTROL_SIZE_CLASSES[this.size()]}`, /* @ts-ignore */
|
|
874
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
875
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiInput, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
876
|
+
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 });
|
|
877
|
+
}
|
|
878
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiInput, decorators: [{
|
|
879
|
+
type: Directive,
|
|
880
|
+
args: [{
|
|
881
|
+
selector: 'input[uiInput]',
|
|
882
|
+
host: {
|
|
883
|
+
'[class]': 'classes()',
|
|
884
|
+
},
|
|
885
|
+
providers: [{ provide: UI_CONTROL, useExisting: forwardRef(() => UiInput) }],
|
|
886
|
+
}]
|
|
887
|
+
}], 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 }] }] } });
|
|
888
|
+
/**
|
|
889
|
+
* Styled native textarea. Lives beside the input because it shares every one of its
|
|
890
|
+
* classes; it takes no size, since a textarea grows from a floor instead of sitting
|
|
891
|
+
* at a fixed height.
|
|
892
|
+
*
|
|
893
|
+
* Declares the `errors` and `touched` inputs Angular's `[formField]` fills, so a `ui-field` around
|
|
894
|
+
* it can show the message without any binding here.
|
|
895
|
+
*
|
|
896
|
+
* @example
|
|
897
|
+
* <textarea uiTextarea maxlength="280"></textarea>
|
|
898
|
+
*/
|
|
899
|
+
class UiTextarea {
|
|
900
|
+
errors = input([], /* @ts-ignore */
|
|
901
|
+
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
902
|
+
touched = input(false, /* @ts-ignore */
|
|
903
|
+
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
904
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTextarea, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
905
|
+
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 });
|
|
906
|
+
}
|
|
907
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTextarea, decorators: [{
|
|
908
|
+
type: Directive,
|
|
909
|
+
args: [{
|
|
910
|
+
selector: 'textarea[uiTextarea]',
|
|
911
|
+
host: {
|
|
912
|
+
class: `${CONTROL_BASE_CLASSES} bg-(--background) min-h-24 py-2`,
|
|
913
|
+
},
|
|
914
|
+
providers: [{ provide: UI_CONTROL, useExisting: forwardRef(() => UiTextarea) }],
|
|
915
|
+
}]
|
|
916
|
+
}], propDecorators: { errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }] } });
|
|
917
|
+
|
|
918
|
+
const CHIP_CLASSES$1 = '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)';
|
|
919
|
+
const SELECTED_CLASSES$2 = 'bg-(--primary) text-(--primary-foreground)';
|
|
920
|
+
const UNSELECTED_CLASSES$1 = 'text-(--foreground) shadow-[inset_0_0_0_1px_var(--border)]';
|
|
921
|
+
const nextId$4 = (() => {
|
|
922
|
+
let count = 0;
|
|
923
|
+
return () => `ui-choice-chips-${++count}`;
|
|
924
|
+
})();
|
|
925
|
+
/**
|
|
926
|
+
* Exclusive choice among a handful of named options, shown as wrapping pills: an account envelope,
|
|
927
|
+
* a category, a frequency. Binds to Signal Forms with `[formField]`.
|
|
928
|
+
*
|
|
929
|
+
* @example
|
|
930
|
+
* <ui-choice-chips label="Envelope" [options]="envelopes" [(value)]="envelope" />
|
|
931
|
+
*
|
|
932
|
+
* @example
|
|
933
|
+
* <ui-choice-chips label="Envelope" [options]="envelopes" [formField]="form.envelope" />
|
|
934
|
+
*/
|
|
935
|
+
class UiChoiceChips {
|
|
936
|
+
options = input.required(/* @ts-ignore */
|
|
937
|
+
...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
|
|
938
|
+
value = model.required(/* @ts-ignore */
|
|
939
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
940
|
+
label = input(/* @ts-ignore */
|
|
941
|
+
...(ngDevMode ? [undefined, { debugName: "label" }] : /* istanbul ignore next */ []));
|
|
942
|
+
ariaLabel = input(/* @ts-ignore */
|
|
943
|
+
...(ngDevMode ? [undefined, { debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
944
|
+
ariaLabelledby = input(/* @ts-ignore */
|
|
945
|
+
...(ngDevMode ? [undefined, { debugName: "ariaLabelledby" }] : /* istanbul ignore next */ []));
|
|
946
|
+
surface = input('background', /* @ts-ignore */
|
|
947
|
+
...(ngDevMode ? [{ debugName: "surface" }] : /* istanbul ignore next */ []));
|
|
948
|
+
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
949
|
+
errors = input([], /* @ts-ignore */
|
|
950
|
+
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
951
|
+
invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
952
|
+
required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
953
|
+
touched = input(false, /* @ts-ignore */
|
|
954
|
+
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
955
|
+
touch = output();
|
|
956
|
+
labelId = nextId$4();
|
|
957
|
+
#host = inject(ElementRef);
|
|
958
|
+
radios = viewChildren('radio', /* @ts-ignore */
|
|
959
|
+
...(ngDevMode ? [{ debugName: "radios" }] : /* istanbul ignore next */ []));
|
|
960
|
+
labelledBy = computed(() => this.ariaLabelledby() ?? (this.label() ? this.labelId : null), /* @ts-ignore */
|
|
961
|
+
...(ngDevMode ? [{ debugName: "labelledBy" }] : /* istanbul ignore next */ []));
|
|
962
|
+
chipClasses(optionValue) {
|
|
963
|
+
const state = optionValue === this.value()
|
|
964
|
+
? SELECTED_CLASSES$2
|
|
965
|
+
: `${CONTROL_SURFACE_CLASSES[this.surface()]} ${UNSELECTED_CLASSES$1}`;
|
|
966
|
+
return `${CHIP_CLASSES$1} ${state}`;
|
|
967
|
+
}
|
|
968
|
+
tabIndexFor(optionValue) {
|
|
969
|
+
const opts = this.options();
|
|
970
|
+
const tabStopValue = opts.some((option) => option.value === this.value()) ? this.value() : opts[0]?.value;
|
|
971
|
+
return optionValue === tabStopValue ? 0 : -1;
|
|
972
|
+
}
|
|
973
|
+
select(optionValue) {
|
|
974
|
+
this.value.set(optionValue);
|
|
975
|
+
}
|
|
976
|
+
onFocusOut(event) {
|
|
977
|
+
if (!this.#host.nativeElement.contains(event.relatedTarget)) {
|
|
978
|
+
this.touch.emit();
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
onKeydown(event, index) {
|
|
982
|
+
const opts = this.options();
|
|
983
|
+
const target = {
|
|
984
|
+
ArrowRight: index + 1,
|
|
985
|
+
ArrowDown: index + 1,
|
|
986
|
+
ArrowLeft: index - 1,
|
|
987
|
+
ArrowUp: index - 1,
|
|
988
|
+
Home: 0,
|
|
989
|
+
End: opts.length - 1,
|
|
990
|
+
}[event.key];
|
|
991
|
+
if (target === undefined) {
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
event.preventDefault();
|
|
995
|
+
const nextIndex = ((target % opts.length) + opts.length) % opts.length;
|
|
996
|
+
this.value.set(opts[nextIndex].value);
|
|
997
|
+
this.radios()[nextIndex].nativeElement.focus();
|
|
998
|
+
}
|
|
999
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiChoiceChips, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1000
|
+
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: `
|
|
1001
|
+
<div
|
|
1002
|
+
class="flex flex-col gap-1.5"
|
|
1003
|
+
role="radiogroup"
|
|
1004
|
+
[attr.aria-invalid]="invalid() || null"
|
|
1005
|
+
[attr.aria-label]="ariaLabel() ?? null"
|
|
1006
|
+
[attr.aria-labelledby]="labelledBy()"
|
|
1007
|
+
[attr.aria-required]="required() || null"
|
|
1008
|
+
(focusout)="onFocusOut($event)"
|
|
1009
|
+
>
|
|
1010
|
+
@if (label()) {
|
|
1011
|
+
<span class="text-label leading-[17px] font-medium text-(--muted-foreground)" [id]="labelId">{{
|
|
1012
|
+
label()
|
|
1013
|
+
}}</span>
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
<div class="flex flex-wrap gap-1.5">
|
|
1017
|
+
@for (option of options(); track option.value; let index = $index) {
|
|
1018
|
+
<button
|
|
1019
|
+
#radio
|
|
1020
|
+
role="radio"
|
|
1021
|
+
type="button"
|
|
1022
|
+
[attr.aria-checked]="option.value === value()"
|
|
1023
|
+
[attr.tabindex]="tabIndexFor(option.value)"
|
|
1024
|
+
[class]="chipClasses(option.value)"
|
|
1025
|
+
[disabled]="disabled()"
|
|
1026
|
+
(click)="select(option.value)"
|
|
1027
|
+
(keydown)="onKeydown($event, index)"
|
|
1028
|
+
>
|
|
1029
|
+
{{ option.label }}
|
|
1030
|
+
</button>
|
|
1031
|
+
}
|
|
1032
|
+
</div>
|
|
1033
|
+
</div>
|
|
1034
|
+
`, isInline: true });
|
|
1035
|
+
}
|
|
1036
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiChoiceChips, decorators: [{
|
|
1037
|
+
type: Component,
|
|
1038
|
+
args: [{
|
|
1039
|
+
selector: 'ui-choice-chips',
|
|
1040
|
+
template: `
|
|
1041
|
+
<div
|
|
1042
|
+
class="flex flex-col gap-1.5"
|
|
1043
|
+
role="radiogroup"
|
|
1044
|
+
[attr.aria-invalid]="invalid() || null"
|
|
1045
|
+
[attr.aria-label]="ariaLabel() ?? null"
|
|
1046
|
+
[attr.aria-labelledby]="labelledBy()"
|
|
1047
|
+
[attr.aria-required]="required() || null"
|
|
1048
|
+
(focusout)="onFocusOut($event)"
|
|
1049
|
+
>
|
|
1050
|
+
@if (label()) {
|
|
1051
|
+
<span class="text-label leading-[17px] font-medium text-(--muted-foreground)" [id]="labelId">{{
|
|
1052
|
+
label()
|
|
1053
|
+
}}</span>
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
<div class="flex flex-wrap gap-1.5">
|
|
1057
|
+
@for (option of options(); track option.value; let index = $index) {
|
|
1058
|
+
<button
|
|
1059
|
+
#radio
|
|
1060
|
+
role="radio"
|
|
1061
|
+
type="button"
|
|
1062
|
+
[attr.aria-checked]="option.value === value()"
|
|
1063
|
+
[attr.tabindex]="tabIndexFor(option.value)"
|
|
1064
|
+
[class]="chipClasses(option.value)"
|
|
1065
|
+
[disabled]="disabled()"
|
|
1066
|
+
(click)="select(option.value)"
|
|
1067
|
+
(keydown)="onKeydown($event, index)"
|
|
1068
|
+
>
|
|
1069
|
+
{{ option.label }}
|
|
1070
|
+
</button>
|
|
1071
|
+
}
|
|
1072
|
+
</div>
|
|
1073
|
+
</div>
|
|
1074
|
+
`,
|
|
1075
|
+
providers: [{ provide: UI_CONTROL, useExisting: forwardRef(() => UiChoiceChips) }],
|
|
1076
|
+
}]
|
|
1077
|
+
}], 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 }] }] } });
|
|
1078
|
+
|
|
395
1079
|
/** Available delta emphases. `DeltaEmphasis` is derived from this tuple. */
|
|
396
1080
|
const DELTA_EMPHASES = ['text', 'pill'];
|
|
397
|
-
|
|
398
|
-
const
|
|
1081
|
+
/** Type sizes. `DeltaSize` is derived from this tuple. */
|
|
1082
|
+
const DELTA_SIZES = ['label', 'inherit'];
|
|
1083
|
+
/** Font weights. `DeltaWeight` is derived from this tuple. */
|
|
1084
|
+
const DELTA_WEIGHTS = ['medium', 'regular'];
|
|
1085
|
+
const BASE_CLASSES$2 = 'inline-flex items-center gap-1 tabular-nums';
|
|
1086
|
+
const SIZE_CLASSES$3 = {
|
|
1087
|
+
label: 'text-label',
|
|
1088
|
+
inherit: '',
|
|
1089
|
+
};
|
|
1090
|
+
const WEIGHT_CLASSES = {
|
|
1091
|
+
medium: 'font-medium',
|
|
1092
|
+
regular: 'font-normal',
|
|
1093
|
+
};
|
|
1094
|
+
const PILL_CLASSES$1 = 'h-6 rounded-pill px-2';
|
|
399
1095
|
const TEXT_CLASSES = {
|
|
400
1096
|
positive: 'text-(--positive)',
|
|
401
1097
|
negative: 'text-(--negative)',
|
|
402
1098
|
neutral: 'text-(--muted-foreground)',
|
|
403
1099
|
unknown: 'text-(--subtle-foreground)',
|
|
404
1100
|
};
|
|
405
|
-
const PILL_BACKGROUND_CLASS = 'bg-(--
|
|
1101
|
+
const PILL_BACKGROUND_CLASS = 'bg-(--soft)';
|
|
406
1102
|
/**
|
|
407
1103
|
* Signed amount whose sign carries meaning: a gain, a loss, or an unknown.
|
|
408
1104
|
*
|
|
@@ -422,6 +1118,10 @@ class UiDelta {
|
|
|
422
1118
|
...(ngDevMode ? [{ debugName: "unknownLabel" }] : /* istanbul ignore next */ []));
|
|
423
1119
|
emphasis = input('text', /* @ts-ignore */
|
|
424
1120
|
...(ngDevMode ? [{ debugName: "emphasis" }] : /* istanbul ignore next */ []));
|
|
1121
|
+
size = input('label', /* @ts-ignore */
|
|
1122
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
1123
|
+
weight = input('medium', /* @ts-ignore */
|
|
1124
|
+
...(ngDevMode ? [{ debugName: "weight" }] : /* istanbul ignore next */ []));
|
|
425
1125
|
sign = computed(() => {
|
|
426
1126
|
const value = this.value();
|
|
427
1127
|
if (value === null || value === undefined) {
|
|
@@ -438,12 +1138,12 @@ class UiDelta {
|
|
|
438
1138
|
...(ngDevMode ? [{ debugName: "sign" }] : /* istanbul ignore next */ []));
|
|
439
1139
|
classes = computed(() => {
|
|
440
1140
|
const sign = this.sign();
|
|
441
|
-
const background = this.emphasis() === 'pill' ? `${PILL_CLASSES} ${PILL_BACKGROUND_CLASS}` : 'bg-transparent';
|
|
442
|
-
return `${BASE_CLASSES$2} ${TEXT_CLASSES[sign]} ${background}`;
|
|
1141
|
+
const background = this.emphasis() === 'pill' ? `${PILL_CLASSES$1} ${PILL_BACKGROUND_CLASS}` : 'bg-transparent';
|
|
1142
|
+
return `${BASE_CLASSES$2} ${SIZE_CLASSES$3[this.size()]} ${WEIGHT_CLASSES[this.weight()]} ${TEXT_CLASSES[sign]} ${background}`;
|
|
443
1143
|
}, /* @ts-ignore */
|
|
444
1144
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
445
1145
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiDelta, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
446
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiDelta, isStandalone: true, selector: "ui-delta", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, unknownLabel: { classPropertyName: "unknownLabel", publicName: "unknownLabel", isSignal: true, isRequired: true, transformFunction: null }, emphasis: { classPropertyName: "emphasis", publicName: "emphasis", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: `
|
|
1146
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiDelta, isStandalone: true, selector: "ui-delta", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, unknownLabel: { classPropertyName: "unknownLabel", publicName: "unknownLabel", isSignal: true, isRequired: true, transformFunction: null }, emphasis: { classPropertyName: "emphasis", publicName: "emphasis", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, weight: { classPropertyName: "weight", publicName: "weight", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: `
|
|
447
1147
|
@if (sign() === 'unknown') {
|
|
448
1148
|
<span aria-hidden="true">—</span>
|
|
449
1149
|
<span class="sr-only">{{ unknownLabel() }}</span>
|
|
@@ -468,26 +1168,70 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
468
1168
|
'[class]': 'classes()',
|
|
469
1169
|
},
|
|
470
1170
|
}]
|
|
471
|
-
}], 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 }] }] } });
|
|
1171
|
+
}], 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 }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], weight: [{ type: i0.Input, args: [{ isSignal: true, alias: "weight", required: false }] }] } });
|
|
472
1172
|
|
|
473
|
-
/**
|
|
1173
|
+
/** Named dialog widths; any other CSS length is accepted as is. `DialogWidth` is derived from this tuple. */
|
|
474
1174
|
const DIALOG_WIDTHS = ['md', 'lg'];
|
|
475
|
-
const
|
|
476
|
-
md: '
|
|
477
|
-
lg: '
|
|
1175
|
+
const WIDTH_VALUES = {
|
|
1176
|
+
md: '28rem',
|
|
1177
|
+
lg: '560px',
|
|
478
1178
|
};
|
|
479
|
-
|
|
1179
|
+
/** Spacing presets. `DialogLayout` is derived from this tuple. */
|
|
1180
|
+
const DIALOG_LAYOUTS = ['trade', 'form', 'list', 'confirm'];
|
|
1181
|
+
const LAYOUTS = {
|
|
1182
|
+
trade: {
|
|
1183
|
+
dialog: '',
|
|
1184
|
+
header: 'items-start lg:pt-6',
|
|
1185
|
+
title: 'pt-1 lg:pt-0',
|
|
1186
|
+
cross: 'lg:-mt-1.5',
|
|
1187
|
+
icon: 'lg:size-5',
|
|
1188
|
+
handle: 'pt-[7.5px]',
|
|
1189
|
+
body: 'pt-3 pb-4 lg:pt-5 lg:pb-5',
|
|
1190
|
+
footer: 'max-lg:pb-[calc(8px+env(safe-area-inset-bottom))] lg:pb-6',
|
|
1191
|
+
},
|
|
1192
|
+
form: {
|
|
1193
|
+
dialog: '',
|
|
1194
|
+
header: 'items-center lg:pt-6',
|
|
1195
|
+
title: '',
|
|
1196
|
+
cross: '',
|
|
1197
|
+
icon: 'lg:size-[22px]',
|
|
1198
|
+
handle: 'pt-[7.5px]',
|
|
1199
|
+
body: 'pt-2 pb-5 lg:pt-4 lg:pb-5',
|
|
1200
|
+
footer: 'max-lg:pb-[calc(12px+env(safe-area-inset-bottom))] lg:pb-5',
|
|
1201
|
+
},
|
|
1202
|
+
list: {
|
|
1203
|
+
dialog: 'max-lg:h-[calc(100dvh-58px)] lg:mt-24 lg:mb-auto lg:max-h-[min(760px,calc(100dvh-96px-32px))]',
|
|
1204
|
+
header: 'items-center lg:pt-5',
|
|
1205
|
+
title: '',
|
|
1206
|
+
cross: '',
|
|
1207
|
+
icon: 'lg:size-[22px]',
|
|
1208
|
+
handle: 'pt-[7.5px]',
|
|
1209
|
+
body: 'pt-2 pb-4 lg:pt-4 lg:pb-5',
|
|
1210
|
+
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',
|
|
1211
|
+
},
|
|
1212
|
+
confirm: {
|
|
1213
|
+
dialog: '',
|
|
1214
|
+
header: 'items-center pt-3 lg:pt-6',
|
|
1215
|
+
title: '',
|
|
1216
|
+
cross: '',
|
|
1217
|
+
icon: 'lg:size-[22px]',
|
|
1218
|
+
handle: 'pt-[11.5px]',
|
|
1219
|
+
body: 'pt-3 pb-5 lg:pt-3 lg:pb-6',
|
|
1220
|
+
footer: 'max-lg:pb-[calc(8px+env(safe-area-inset-bottom))] lg:pb-6',
|
|
1221
|
+
},
|
|
1222
|
+
};
|
|
1223
|
+
const nextId$3 = (() => {
|
|
480
1224
|
let count = 0;
|
|
481
1225
|
return () => `ui-dialog-${++count}`;
|
|
482
1226
|
})();
|
|
483
1227
|
/**
|
|
484
|
-
* Modal dialog on the native <dialog>: a sheet
|
|
485
|
-
* above it. Two projection slots - the body, and [dialogActions] for the footer.
|
|
1228
|
+
* Modal dialog on the native <dialog>: a bottom sheet under `64rem`, centered above it.
|
|
486
1229
|
*
|
|
487
1230
|
* @example
|
|
488
|
-
* <ui-dialog heading="
|
|
489
|
-
* <p>
|
|
490
|
-
* <button dialogActions ui-button variant="outline" (click)="
|
|
1231
|
+
* <ui-dialog heading="Buy" description="Ferrari" closeLabel="Close" width="528px" [open]="buying()" (dismissed)="buying.set(false)">
|
|
1232
|
+
* <p>Body</p>
|
|
1233
|
+
* <button dialogActions ui-button variant="outline" class="max-lg:hidden" (click)="buying.set(false)">Cancel</button>
|
|
1234
|
+
* <button dialogActions ui-button>Buy 40 shares</button>
|
|
491
1235
|
* </ui-dialog>
|
|
492
1236
|
*/
|
|
493
1237
|
class UiDialog {
|
|
@@ -495,17 +1239,60 @@ class UiDialog {
|
|
|
495
1239
|
...(ngDevMode ? [{ debugName: "heading" }] : /* istanbul ignore next */ []));
|
|
496
1240
|
description = input(/* @ts-ignore */
|
|
497
1241
|
...(ngDevMode ? [undefined, { debugName: "description" }] : /* istanbul ignore next */ []));
|
|
1242
|
+
closeLabel = input(/* @ts-ignore */
|
|
1243
|
+
...(ngDevMode ? [undefined, { debugName: "closeLabel" }] : /* istanbul ignore next */ []));
|
|
1244
|
+
layout = input('trade', /* @ts-ignore */
|
|
1245
|
+
...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
|
|
1246
|
+
truncateDescription = input(false, { ...(ngDevMode ? { debugName: "truncateDescription" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
498
1247
|
width = input('lg', /* @ts-ignore */
|
|
499
1248
|
...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
|
|
500
1249
|
open = input(false, { ...(ngDevMode ? { debugName: "open" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
501
1250
|
dismissed = output();
|
|
502
|
-
headingId = nextId$
|
|
1251
|
+
headingId = nextId$3();
|
|
503
1252
|
descriptionId = `${this.headingId}-description`;
|
|
504
|
-
|
|
1253
|
+
bodyId = `${this.headingId}-body`;
|
|
1254
|
+
scrollable = signal(false, /* @ts-ignore */
|
|
1255
|
+
...(ngDevMode ? [{ debugName: "scrollable" }] : /* istanbul ignore next */ []));
|
|
1256
|
+
describedBy = computed(() => {
|
|
1257
|
+
if (this.description()) {
|
|
1258
|
+
return this.descriptionId;
|
|
1259
|
+
}
|
|
1260
|
+
return this.layout() === 'confirm' ? this.bodyId : null;
|
|
1261
|
+
}, /* @ts-ignore */
|
|
1262
|
+
...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
|
|
1263
|
+
widthValue = computed(() => {
|
|
1264
|
+
const width = this.width();
|
|
1265
|
+
return Object.hasOwn(WIDTH_VALUES, width) ? WIDTH_VALUES[width] : width;
|
|
1266
|
+
}, /* @ts-ignore */
|
|
1267
|
+
...(ngDevMode ? [{ debugName: "widthValue" }] : /* istanbul ignore next */ []));
|
|
1268
|
+
spec = computed(() => LAYOUTS[this.layout()], /* @ts-ignore */
|
|
1269
|
+
...(ngDevMode ? [{ debugName: "spec" }] : /* istanbul ignore next */ []));
|
|
1270
|
+
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 */
|
|
1271
|
+
...(ngDevMode ? [{ debugName: "headerClasses" }] : /* istanbul ignore next */ []));
|
|
1272
|
+
titleClasses = computed(() => this.spec().title, /* @ts-ignore */
|
|
1273
|
+
...(ngDevMode ? [{ debugName: "titleClasses" }] : /* istanbul ignore next */ []));
|
|
1274
|
+
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 */
|
|
1275
|
+
...(ngDevMode ? [{ debugName: "crossClasses" }] : /* istanbul ignore next */ []));
|
|
1276
|
+
iconClasses = computed(() => this.spec().icon, /* @ts-ignore */
|
|
1277
|
+
...(ngDevMode ? [{ debugName: "iconClasses" }] : /* istanbul ignore next */ []));
|
|
1278
|
+
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 */
|
|
1279
|
+
...(ngDevMode ? [{ debugName: "footerClasses" }] : /* istanbul ignore next */ []));
|
|
1280
|
+
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
1281
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
506
1282
|
#host = inject(ElementRef);
|
|
507
1283
|
constructor() {
|
|
508
|
-
|
|
1284
|
+
const destroyRef = inject(DestroyRef);
|
|
1285
|
+
afterNextRender(() => {
|
|
1286
|
+
if (typeof ResizeObserver === 'undefined') {
|
|
1287
|
+
return;
|
|
1288
|
+
}
|
|
1289
|
+
const body = this.#host.nativeElement.querySelector('[data-dialog-body]');
|
|
1290
|
+
const observer = new ResizeObserver(() => this.scrollable.set(body.scrollHeight > body.clientHeight));
|
|
1291
|
+
observer.observe(body);
|
|
1292
|
+
observer.observe(body.firstElementChild);
|
|
1293
|
+
destroyRef.onDestroy(() => observer.disconnect());
|
|
1294
|
+
});
|
|
1295
|
+
afterRenderEffect(() => {
|
|
509
1296
|
// viewChild.required can't target a #private field (NG1053); safe because the template has exactly one <dialog>.
|
|
510
1297
|
const dialog = this.#host.nativeElement.querySelector('dialog');
|
|
511
1298
|
if (this.open() && !dialog.open) {
|
|
@@ -516,6 +1303,23 @@ class UiDialog {
|
|
|
516
1303
|
}
|
|
517
1304
|
});
|
|
518
1305
|
}
|
|
1306
|
+
#pressedOnBackdrop = false;
|
|
1307
|
+
onPointerDown(event) {
|
|
1308
|
+
this.#pressedOnBackdrop = event.target === this.#dialog && this.#outside(event);
|
|
1309
|
+
}
|
|
1310
|
+
onClick(event) {
|
|
1311
|
+
if (this.#pressedOnBackdrop && event.target === this.#dialog && this.#outside(event)) {
|
|
1312
|
+
this.#dialog.close();
|
|
1313
|
+
}
|
|
1314
|
+
this.#pressedOnBackdrop = false;
|
|
1315
|
+
}
|
|
1316
|
+
get #dialog() {
|
|
1317
|
+
return this.#host.nativeElement.querySelector('dialog');
|
|
1318
|
+
}
|
|
1319
|
+
#outside(event) {
|
|
1320
|
+
const rect = this.#dialog.getBoundingClientRect();
|
|
1321
|
+
return (event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom);
|
|
1322
|
+
}
|
|
519
1323
|
onNativeClose() {
|
|
520
1324
|
// The owner already knows about a close it asked for; only a close it did not ask for is news.
|
|
521
1325
|
if (this.open()) {
|
|
@@ -523,87 +1327,159 @@ class UiDialog {
|
|
|
523
1327
|
}
|
|
524
1328
|
}
|
|
525
1329
|
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: `
|
|
1330
|
+
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
1331
|
<dialog
|
|
528
|
-
|
|
1332
|
+
#dlg
|
|
1333
|
+
[attr.aria-describedby]="describedBy()"
|
|
529
1334
|
[attr.aria-labelledby]="headingId"
|
|
1335
|
+
[attr.role]="layout() === 'confirm' ? 'alertdialog' : 'dialog'"
|
|
530
1336
|
[class]="classes()"
|
|
1337
|
+
[style.--dialog-width]="widthValue()"
|
|
531
1338
|
(close)="onNativeClose()"
|
|
532
1339
|
>
|
|
533
|
-
<div aria-hidden="true" class="flex h-
|
|
534
|
-
<span class="rounded-pill h-
|
|
1340
|
+
<div aria-hidden="true" class="flex h-5 justify-center lg:hidden" data-dialog-handle [class]="spec().handle">
|
|
1341
|
+
<span class="rounded-pill h-[5px] w-9 bg-(--border)"></span>
|
|
535
1342
|
</div>
|
|
536
1343
|
|
|
537
|
-
<div
|
|
538
|
-
<
|
|
1344
|
+
<div data-dialog-header [class]="headerClasses()">
|
|
1345
|
+
<div class="flex min-w-0 flex-1 flex-col" [class]="titleClasses()">
|
|
1346
|
+
<h2 class="text-title font-semibold" [id]="headingId">{{ heading() }}</h2>
|
|
1347
|
+
|
|
1348
|
+
@if (description()) {
|
|
1349
|
+
<p
|
|
1350
|
+
class="text-label text-(--muted-foreground)"
|
|
1351
|
+
[class.truncate]="truncateDescription()"
|
|
1352
|
+
[id]="descriptionId"
|
|
1353
|
+
>
|
|
1354
|
+
{{ description() }}
|
|
1355
|
+
</p>
|
|
1356
|
+
}
|
|
1357
|
+
</div>
|
|
539
1358
|
|
|
540
|
-
@if (
|
|
541
|
-
<
|
|
1359
|
+
@if (closeLabel()) {
|
|
1360
|
+
<button type="button" [attr.aria-label]="closeLabel()" [class]="crossClasses()" (click)="dlg.close()">
|
|
1361
|
+
<svg
|
|
1362
|
+
aria-hidden="true"
|
|
1363
|
+
class="block size-[22px] fill-none stroke-current stroke-[1.75]"
|
|
1364
|
+
stroke-linecap="round"
|
|
1365
|
+
stroke-linejoin="round"
|
|
1366
|
+
viewBox="0 0 24 24"
|
|
1367
|
+
[class]="iconClasses()"
|
|
1368
|
+
>
|
|
1369
|
+
<path d="M18 6 6 18" />
|
|
1370
|
+
<path d="m6 6 12 12" />
|
|
1371
|
+
</svg>
|
|
1372
|
+
</button>
|
|
542
1373
|
}
|
|
543
1374
|
</div>
|
|
544
1375
|
|
|
545
|
-
<div
|
|
546
|
-
|
|
547
|
-
|
|
1376
|
+
<div
|
|
1377
|
+
class="min-h-0 flex-1 overflow-y-auto px-4 outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring) lg:px-6"
|
|
1378
|
+
data-dialog-body
|
|
1379
|
+
[attr.aria-labelledby]="scrollable() ? headingId : null"
|
|
1380
|
+
[attr.role]="scrollable() ? 'region' : null"
|
|
1381
|
+
[attr.tabindex]="scrollable() ? 0 : null"
|
|
1382
|
+
[id]="bodyId"
|
|
1383
|
+
>
|
|
1384
|
+
<!-- empty:hidden keeps a body-less dialog from carrying the body's vertical padding. -->
|
|
1385
|
+
<div class="flex flex-col gap-4 empty:hidden" [class]="spec().body">
|
|
548
1386
|
<ng-content />
|
|
549
1387
|
</div>
|
|
550
1388
|
</div>
|
|
551
1389
|
|
|
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
|
-
>
|
|
1390
|
+
<div data-dialog-footer [class]="footerClasses()">
|
|
556
1391
|
<ng-content select="[dialogActions]" />
|
|
557
1392
|
</div>
|
|
558
1393
|
</dialog>
|
|
559
|
-
`, isInline: true, styles: ["dialog{transition:opacity var(--duration-base) var(--ease
|
|
1394
|
+
`, 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
1395
|
}
|
|
561
1396
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiDialog, decorators: [{
|
|
562
1397
|
type: Component,
|
|
563
|
-
args: [{ selector: 'ui-dialog', template: `
|
|
1398
|
+
args: [{ selector: 'ui-dialog', host: { '(pointerdown)': 'onPointerDown($event)', '(click)': 'onClick($event)' }, template: `
|
|
564
1399
|
<dialog
|
|
565
|
-
|
|
1400
|
+
#dlg
|
|
1401
|
+
[attr.aria-describedby]="describedBy()"
|
|
566
1402
|
[attr.aria-labelledby]="headingId"
|
|
1403
|
+
[attr.role]="layout() === 'confirm' ? 'alertdialog' : 'dialog'"
|
|
567
1404
|
[class]="classes()"
|
|
1405
|
+
[style.--dialog-width]="widthValue()"
|
|
568
1406
|
(close)="onNativeClose()"
|
|
569
1407
|
>
|
|
570
|
-
<div aria-hidden="true" class="flex h-
|
|
571
|
-
<span class="rounded-pill h-
|
|
1408
|
+
<div aria-hidden="true" class="flex h-5 justify-center lg:hidden" data-dialog-handle [class]="spec().handle">
|
|
1409
|
+
<span class="rounded-pill h-[5px] w-9 bg-(--border)"></span>
|
|
572
1410
|
</div>
|
|
573
1411
|
|
|
574
|
-
<div
|
|
575
|
-
<
|
|
1412
|
+
<div data-dialog-header [class]="headerClasses()">
|
|
1413
|
+
<div class="flex min-w-0 flex-1 flex-col" [class]="titleClasses()">
|
|
1414
|
+
<h2 class="text-title font-semibold" [id]="headingId">{{ heading() }}</h2>
|
|
1415
|
+
|
|
1416
|
+
@if (description()) {
|
|
1417
|
+
<p
|
|
1418
|
+
class="text-label text-(--muted-foreground)"
|
|
1419
|
+
[class.truncate]="truncateDescription()"
|
|
1420
|
+
[id]="descriptionId"
|
|
1421
|
+
>
|
|
1422
|
+
{{ description() }}
|
|
1423
|
+
</p>
|
|
1424
|
+
}
|
|
1425
|
+
</div>
|
|
576
1426
|
|
|
577
|
-
@if (
|
|
578
|
-
<
|
|
1427
|
+
@if (closeLabel()) {
|
|
1428
|
+
<button type="button" [attr.aria-label]="closeLabel()" [class]="crossClasses()" (click)="dlg.close()">
|
|
1429
|
+
<svg
|
|
1430
|
+
aria-hidden="true"
|
|
1431
|
+
class="block size-[22px] fill-none stroke-current stroke-[1.75]"
|
|
1432
|
+
stroke-linecap="round"
|
|
1433
|
+
stroke-linejoin="round"
|
|
1434
|
+
viewBox="0 0 24 24"
|
|
1435
|
+
[class]="iconClasses()"
|
|
1436
|
+
>
|
|
1437
|
+
<path d="M18 6 6 18" />
|
|
1438
|
+
<path d="m6 6 12 12" />
|
|
1439
|
+
</svg>
|
|
1440
|
+
</button>
|
|
579
1441
|
}
|
|
580
1442
|
</div>
|
|
581
1443
|
|
|
582
|
-
<div
|
|
583
|
-
|
|
584
|
-
|
|
1444
|
+
<div
|
|
1445
|
+
class="min-h-0 flex-1 overflow-y-auto px-4 outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring) lg:px-6"
|
|
1446
|
+
data-dialog-body
|
|
1447
|
+
[attr.aria-labelledby]="scrollable() ? headingId : null"
|
|
1448
|
+
[attr.role]="scrollable() ? 'region' : null"
|
|
1449
|
+
[attr.tabindex]="scrollable() ? 0 : null"
|
|
1450
|
+
[id]="bodyId"
|
|
1451
|
+
>
|
|
1452
|
+
<!-- empty:hidden keeps a body-less dialog from carrying the body's vertical padding. -->
|
|
1453
|
+
<div class="flex flex-col gap-4 empty:hidden" [class]="spec().body">
|
|
585
1454
|
<ng-content />
|
|
586
1455
|
</div>
|
|
587
1456
|
</div>
|
|
588
1457
|
|
|
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
|
-
>
|
|
1458
|
+
<div data-dialog-footer [class]="footerClasses()">
|
|
593
1459
|
<ng-content select="[dialogActions]" />
|
|
594
1460
|
</div>
|
|
595
1461
|
</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);
|
|
1462
|
+
`, 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"] }]
|
|
1463
|
+
}], 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"] }] } });
|
|
1464
|
+
|
|
1465
|
+
const RADIUS = 78;
|
|
1466
|
+
const RING_WIDTH = 30;
|
|
1467
|
+
const ACTIVE_RING_WIDTH = 38;
|
|
1468
|
+
const CIRCUMFERENCE = 2 * Math.PI * RADIUS;
|
|
1469
|
+
const GAP = 2;
|
|
605
1470
|
function positionSlices(slices) {
|
|
606
|
-
|
|
1471
|
+
let travelled = 0;
|
|
1472
|
+
return slices.map((slice) => {
|
|
1473
|
+
const length = slice.share * CIRCUMFERENCE;
|
|
1474
|
+
const drawn = Math.max(0, length - GAP);
|
|
1475
|
+
const positioned = {
|
|
1476
|
+
...slice,
|
|
1477
|
+
dash: `${drawn.toFixed(2)} ${(CIRCUMFERENCE - drawn).toFixed(2)}`,
|
|
1478
|
+
offset: (-travelled).toFixed(2),
|
|
1479
|
+
};
|
|
1480
|
+
travelled += length;
|
|
1481
|
+
return positioned;
|
|
1482
|
+
});
|
|
607
1483
|
}
|
|
608
1484
|
|
|
609
1485
|
const MAX_RAMP = 6;
|
|
@@ -635,16 +1511,7 @@ function rankSlices(slices, othersLabel) {
|
|
|
635
1511
|
|
|
636
1512
|
const identityValue$1 = (value) => `${value}`;
|
|
637
1513
|
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
|
-
};
|
|
1514
|
+
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) active:bg-(--soft) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring)';
|
|
648
1515
|
const RAMP_DOT_CLASSES = {
|
|
649
1516
|
1: 'bg-(--ramp-1)',
|
|
650
1517
|
2: 'bg-(--ramp-2)',
|
|
@@ -671,6 +1538,8 @@ class UiDonut {
|
|
|
671
1538
|
...(ngDevMode ? [{ debugName: "valueFormat" }] : /* istanbul ignore next */ []));
|
|
672
1539
|
shareFormat = input(identityShare, /* @ts-ignore */
|
|
673
1540
|
...(ngDevMode ? [{ debugName: "shareFormat" }] : /* istanbul ignore next */ []));
|
|
1541
|
+
legendHref = input(/* @ts-ignore */
|
|
1542
|
+
...(ngDevMode ? [undefined, { debugName: "legendHref" }] : /* istanbul ignore next */ []));
|
|
674
1543
|
sliceSelect = output();
|
|
675
1544
|
activeId = signal(null, /* @ts-ignore */
|
|
676
1545
|
...(ngDevMode ? [{ debugName: "activeId" }] : /* istanbul ignore next */ []));
|
|
@@ -691,22 +1560,23 @@ class UiDonut {
|
|
|
691
1560
|
return detail ? `${this.label()} : ${detail}` : this.label();
|
|
692
1561
|
}, /* @ts-ignore */
|
|
693
1562
|
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
694
|
-
|
|
695
|
-
|
|
1563
|
+
radius = RADIUS;
|
|
1564
|
+
ringWidth = RING_WIDTH;
|
|
1565
|
+
strokeColor(slice) {
|
|
1566
|
+
return `var(--ramp-${slice.ramp})`;
|
|
1567
|
+
}
|
|
1568
|
+
strokeWidth(slice) {
|
|
1569
|
+
return this.isActive(slice) ? ACTIVE_RING_WIDTH : RING_WIDTH;
|
|
696
1570
|
}
|
|
697
1571
|
dotClasses(slice) {
|
|
698
1572
|
return `size-3 flex-none rounded-pill shadow-[inset_0_0_0_1px_var(--border)] ${RAMP_DOT_CLASSES[slice.ramp]}`;
|
|
699
1573
|
}
|
|
700
1574
|
rowClasses(slice) {
|
|
701
|
-
return `${ROW_CLASSES}${this.isActive(slice) ? ' bg-(--soft)' : ''}`;
|
|
1575
|
+
return `${ROW_CLASSES$1}${this.isActive(slice) ? ' bg-(--soft)' : ''}`;
|
|
702
1576
|
}
|
|
703
1577
|
subLabel(slice) {
|
|
704
1578
|
return slice.members.length > 0 ? slice.members.join(', ') : (slice.sublabel ?? '');
|
|
705
1579
|
}
|
|
706
|
-
arcTransform(slice) {
|
|
707
|
-
const scale = this.isActive(slice) ? ACTIVE_SCALE : 1;
|
|
708
|
-
return `translate(100px, 100px) scale(${scale})`;
|
|
709
|
-
}
|
|
710
1580
|
isActive(slice) {
|
|
711
1581
|
return this.active()?.id === slice.id;
|
|
712
1582
|
}
|
|
@@ -718,64 +1588,111 @@ class UiDonut {
|
|
|
718
1588
|
this.activeId.set(null);
|
|
719
1589
|
}
|
|
720
1590
|
}
|
|
1591
|
+
hrefFor(id) {
|
|
1592
|
+
return this.legendHref()?.(id) ?? null;
|
|
1593
|
+
}
|
|
1594
|
+
follow(event, slice) {
|
|
1595
|
+
if (event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
|
|
1596
|
+
return;
|
|
1597
|
+
}
|
|
1598
|
+
event.preventDefault();
|
|
1599
|
+
this.select(slice);
|
|
1600
|
+
}
|
|
721
1601
|
select(slice) {
|
|
722
1602
|
this.activeId.set(slice.id);
|
|
723
1603
|
this.sliceSelect.emit(slice.id);
|
|
724
1604
|
}
|
|
725
1605
|
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-
|
|
1606
|
+
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 }, legendHref: { classPropertyName: "legendHref", publicName: "legendHref", 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
1607
|
<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()">
|
|
1608
|
+
<svg class="block h-full w-full -rotate-90" role="img" viewBox="0 0 200 200" [attr.aria-label]="ariaLabel()">
|
|
1609
|
+
<circle
|
|
1610
|
+
class="stroke-(--muted)"
|
|
1611
|
+
cx="100"
|
|
1612
|
+
cy="100"
|
|
1613
|
+
fill="none"
|
|
1614
|
+
[attr.r]="radius"
|
|
1615
|
+
[attr.stroke-width]="ringWidth"
|
|
1616
|
+
/>
|
|
729
1617
|
@for (slice of positioned(); track slice.id) {
|
|
730
|
-
<
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
1618
|
+
<circle
|
|
1619
|
+
class="cursor-pointer transition-[stroke-width] duration-(--duration-fast) ease-out"
|
|
1620
|
+
cx="100"
|
|
1621
|
+
cy="100"
|
|
1622
|
+
data-slice
|
|
1623
|
+
fill="none"
|
|
1624
|
+
[attr.r]="radius"
|
|
1625
|
+
[attr.stroke-dasharray]="slice.dash"
|
|
1626
|
+
[attr.stroke-dashoffset]="slice.offset"
|
|
1627
|
+
[style.stroke]="strokeColor(slice)"
|
|
1628
|
+
[style.stroke-width.px]="strokeWidth(slice)"
|
|
1629
|
+
(click)="select(slice)"
|
|
1630
|
+
(pointerenter)="highlight(slice.id)"
|
|
1631
|
+
(pointerleave)="clearHighlight(slice.id)"
|
|
1632
|
+
/>
|
|
740
1633
|
}
|
|
741
1634
|
</svg>
|
|
742
1635
|
|
|
743
1636
|
@if (active(); as slice) {
|
|
744
1637
|
<div
|
|
745
|
-
class="pointer-events-none absolute inset-0 flex flex-col items-center justify-center px-
|
|
1638
|
+
class="pointer-events-none absolute inset-0 flex flex-col items-center justify-center px-12 text-center"
|
|
746
1639
|
data-testid="donut-centre"
|
|
747
1640
|
>
|
|
748
|
-
<span class="text-
|
|
749
|
-
|
|
750
|
-
|
|
1641
|
+
<span class="text-label max-w-full truncate font-medium whitespace-nowrap text-(--muted-foreground)">{{
|
|
1642
|
+
slice.label
|
|
1643
|
+
}}</span>
|
|
1644
|
+
<span class="text-heading font-semibold tracking-(--tracking-display)">{{ shareFormat()(slice.share) }}</span>
|
|
1645
|
+
<span class="text-caption tracking-normal text-(--muted-foreground) [font-variant-numeric:var(--numeric)]">{{
|
|
1646
|
+
valueFormat()(slice.value)
|
|
1647
|
+
}}</span>
|
|
751
1648
|
</div>
|
|
752
1649
|
}
|
|
753
1650
|
</div>
|
|
754
1651
|
|
|
755
|
-
<div class="flex min-w-0 flex-1 flex-col">
|
|
1652
|
+
<div class="flex w-full min-w-0 flex-1 flex-col sm:w-auto" data-testid="donut-legend">
|
|
756
1653
|
@for (slice of ranked(); track slice.id) {
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
1654
|
+
@if (hrefFor(slice.id); as href) {
|
|
1655
|
+
<a
|
|
1656
|
+
[attr.href]="href"
|
|
1657
|
+
[class]="rowClasses(slice)"
|
|
1658
|
+
(blur)="clearHighlight(slice.id)"
|
|
1659
|
+
(click)="follow($event, slice)"
|
|
1660
|
+
(focus)="highlight(slice.id)"
|
|
1661
|
+
(pointerenter)="highlight(slice.id)"
|
|
1662
|
+
(pointerleave)="clearHighlight(slice.id)"
|
|
1663
|
+
>
|
|
1664
|
+
<ng-container *ngTemplateOutlet="rowContent; context: { $implicit: slice }" />
|
|
1665
|
+
</a>
|
|
1666
|
+
} @else {
|
|
1667
|
+
<button
|
|
1668
|
+
type="button"
|
|
1669
|
+
[class]="rowClasses(slice)"
|
|
1670
|
+
(blur)="clearHighlight(slice.id)"
|
|
1671
|
+
(click)="select(slice)"
|
|
1672
|
+
(focus)="highlight(slice.id)"
|
|
1673
|
+
(pointerenter)="highlight(slice.id)"
|
|
1674
|
+
(pointerleave)="clearHighlight(slice.id)"
|
|
1675
|
+
>
|
|
1676
|
+
<ng-container *ngTemplateOutlet="rowContent; context: { $implicit: slice }" />
|
|
1677
|
+
</button>
|
|
1678
|
+
}
|
|
776
1679
|
}
|
|
777
1680
|
</div>
|
|
778
|
-
|
|
1681
|
+
|
|
1682
|
+
<ng-template #rowContent let-slice>
|
|
1683
|
+
<span [class]="dotClasses(slice)"></span>
|
|
1684
|
+
<span class="flex min-w-0 flex-1 flex-col">
|
|
1685
|
+
<span class="text-body truncate font-medium">{{ slice.label }}</span>
|
|
1686
|
+
<span class="text-caption truncate tracking-(--tracking-caption) text-(--subtle-foreground)">{{
|
|
1687
|
+
subLabel(slice)
|
|
1688
|
+
}}</span>
|
|
1689
|
+
</span>
|
|
1690
|
+
<span class="flex flex-none flex-col items-end whitespace-nowrap">
|
|
1691
|
+
<span class="text-body font-medium">{{ shareFormat()(slice.share) }}</span>
|
|
1692
|
+
<span class="text-caption tracking-normal text-(--muted-foreground)">{{ valueFormat()(slice.value) }}</span>
|
|
1693
|
+
</span>
|
|
1694
|
+
</ng-template>
|
|
1695
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
779
1696
|
}
|
|
780
1697
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiDonut, decorators: [{
|
|
781
1698
|
type: Component,
|
|
@@ -783,67 +1700,301 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
783
1700
|
selector: 'ui-donut',
|
|
784
1701
|
template: `
|
|
785
1702
|
<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()">
|
|
1703
|
+
<svg class="block h-full w-full -rotate-90" role="img" viewBox="0 0 200 200" [attr.aria-label]="ariaLabel()">
|
|
1704
|
+
<circle
|
|
1705
|
+
class="stroke-(--muted)"
|
|
1706
|
+
cx="100"
|
|
1707
|
+
cy="100"
|
|
1708
|
+
fill="none"
|
|
1709
|
+
[attr.r]="radius"
|
|
1710
|
+
[attr.stroke-width]="ringWidth"
|
|
1711
|
+
/>
|
|
787
1712
|
@for (slice of positioned(); track slice.id) {
|
|
788
|
-
<
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
1713
|
+
<circle
|
|
1714
|
+
class="cursor-pointer transition-[stroke-width] duration-(--duration-fast) ease-out"
|
|
1715
|
+
cx="100"
|
|
1716
|
+
cy="100"
|
|
1717
|
+
data-slice
|
|
1718
|
+
fill="none"
|
|
1719
|
+
[attr.r]="radius"
|
|
1720
|
+
[attr.stroke-dasharray]="slice.dash"
|
|
1721
|
+
[attr.stroke-dashoffset]="slice.offset"
|
|
1722
|
+
[style.stroke]="strokeColor(slice)"
|
|
1723
|
+
[style.stroke-width.px]="strokeWidth(slice)"
|
|
1724
|
+
(click)="select(slice)"
|
|
1725
|
+
(pointerenter)="highlight(slice.id)"
|
|
1726
|
+
(pointerleave)="clearHighlight(slice.id)"
|
|
1727
|
+
/>
|
|
798
1728
|
}
|
|
799
1729
|
</svg>
|
|
800
1730
|
|
|
801
1731
|
@if (active(); as slice) {
|
|
802
1732
|
<div
|
|
803
|
-
class="pointer-events-none absolute inset-0 flex flex-col items-center justify-center px-
|
|
1733
|
+
class="pointer-events-none absolute inset-0 flex flex-col items-center justify-center px-12 text-center"
|
|
804
1734
|
data-testid="donut-centre"
|
|
805
1735
|
>
|
|
806
|
-
<span class="text-
|
|
807
|
-
|
|
808
|
-
|
|
1736
|
+
<span class="text-label max-w-full truncate font-medium whitespace-nowrap text-(--muted-foreground)">{{
|
|
1737
|
+
slice.label
|
|
1738
|
+
}}</span>
|
|
1739
|
+
<span class="text-heading font-semibold tracking-(--tracking-display)">{{ shareFormat()(slice.share) }}</span>
|
|
1740
|
+
<span class="text-caption tracking-normal text-(--muted-foreground) [font-variant-numeric:var(--numeric)]">{{
|
|
1741
|
+
valueFormat()(slice.value)
|
|
1742
|
+
}}</span>
|
|
809
1743
|
</div>
|
|
810
1744
|
}
|
|
811
1745
|
</div>
|
|
812
1746
|
|
|
813
|
-
<div class="flex min-w-0 flex-1 flex-col">
|
|
1747
|
+
<div class="flex w-full min-w-0 flex-1 flex-col sm:w-auto" data-testid="donut-legend">
|
|
814
1748
|
@for (slice of ranked(); track slice.id) {
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
1749
|
+
@if (hrefFor(slice.id); as href) {
|
|
1750
|
+
<a
|
|
1751
|
+
[attr.href]="href"
|
|
1752
|
+
[class]="rowClasses(slice)"
|
|
1753
|
+
(blur)="clearHighlight(slice.id)"
|
|
1754
|
+
(click)="follow($event, slice)"
|
|
1755
|
+
(focus)="highlight(slice.id)"
|
|
1756
|
+
(pointerenter)="highlight(slice.id)"
|
|
1757
|
+
(pointerleave)="clearHighlight(slice.id)"
|
|
1758
|
+
>
|
|
1759
|
+
<ng-container *ngTemplateOutlet="rowContent; context: { $implicit: slice }" />
|
|
1760
|
+
</a>
|
|
1761
|
+
} @else {
|
|
1762
|
+
<button
|
|
1763
|
+
type="button"
|
|
1764
|
+
[class]="rowClasses(slice)"
|
|
1765
|
+
(blur)="clearHighlight(slice.id)"
|
|
1766
|
+
(click)="select(slice)"
|
|
1767
|
+
(focus)="highlight(slice.id)"
|
|
1768
|
+
(pointerenter)="highlight(slice.id)"
|
|
1769
|
+
(pointerleave)="clearHighlight(slice.id)"
|
|
1770
|
+
>
|
|
1771
|
+
<ng-container *ngTemplateOutlet="rowContent; context: { $implicit: slice }" />
|
|
1772
|
+
</button>
|
|
1773
|
+
}
|
|
834
1774
|
}
|
|
835
1775
|
</div>
|
|
1776
|
+
|
|
1777
|
+
<ng-template #rowContent let-slice>
|
|
1778
|
+
<span [class]="dotClasses(slice)"></span>
|
|
1779
|
+
<span class="flex min-w-0 flex-1 flex-col">
|
|
1780
|
+
<span class="text-body truncate font-medium">{{ slice.label }}</span>
|
|
1781
|
+
<span class="text-caption truncate tracking-(--tracking-caption) text-(--subtle-foreground)">{{
|
|
1782
|
+
subLabel(slice)
|
|
1783
|
+
}}</span>
|
|
1784
|
+
</span>
|
|
1785
|
+
<span class="flex flex-none flex-col items-end whitespace-nowrap">
|
|
1786
|
+
<span class="text-body font-medium">{{ shareFormat()(slice.share) }}</span>
|
|
1787
|
+
<span class="text-caption tracking-normal text-(--muted-foreground)">{{ valueFormat()(slice.value) }}</span>
|
|
1788
|
+
</span>
|
|
1789
|
+
</ng-template>
|
|
836
1790
|
`,
|
|
1791
|
+
imports: [NgTemplateOutlet],
|
|
837
1792
|
host: {
|
|
838
|
-
class: 'flex flex-col items-center gap-
|
|
1793
|
+
class: 'flex flex-col items-center gap-3 sm:flex-row sm:items-center sm:gap-8',
|
|
839
1794
|
},
|
|
840
1795
|
}]
|
|
841
|
-
}], 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"] }] } });
|
|
1796
|
+
}], 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 }] }], legendHref: [{ type: i0.Input, args: [{ isSignal: true, alias: "legendHref", required: false }] }], sliceSelect: [{ type: i0.Output, args: ["sliceSelect"] }] } });
|
|
842
1797
|
|
|
843
|
-
|
|
1798
|
+
/**
|
|
1799
|
+
* Link to another site: the label followed by an external-link icon. A 44px target on touch,
|
|
1800
|
+
* an underline on hover with a mouse.
|
|
1801
|
+
*
|
|
1802
|
+
* @example
|
|
1803
|
+
* <a ui-external-link href="https://example.com" target="_blank" rel="noopener">Page on example.com</a>
|
|
1804
|
+
*/
|
|
1805
|
+
class UiExternalLink {
|
|
1806
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiExternalLink, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1807
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.7", type: UiExternalLink, isStandalone: true, selector: "a[ui-external-link]", host: { classAttribute: "inline-flex min-h-11 items-center gap-1.5 rounded-[4px] text-label leading-[17px] font-medium lg:min-h-0 hover:underline underline-offset-3 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring) [&>svg]:flex-none" }, ngImport: i0, template: `
|
|
1808
|
+
<ng-content />
|
|
1809
|
+
<svg
|
|
1810
|
+
aria-hidden="true"
|
|
1811
|
+
fill="none"
|
|
1812
|
+
height="14"
|
|
1813
|
+
stroke="currentColor"
|
|
1814
|
+
stroke-linecap="round"
|
|
1815
|
+
stroke-linejoin="round"
|
|
1816
|
+
stroke-width="1.75"
|
|
1817
|
+
viewBox="0 0 24 24"
|
|
1818
|
+
width="14"
|
|
1819
|
+
>
|
|
1820
|
+
<path d="M15 3h6v6" />
|
|
1821
|
+
<path d="M10 14 21 3" />
|
|
1822
|
+
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
|
|
1823
|
+
</svg>
|
|
1824
|
+
`, isInline: true });
|
|
1825
|
+
}
|
|
1826
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiExternalLink, decorators: [{
|
|
1827
|
+
type: Component,
|
|
1828
|
+
args: [{
|
|
1829
|
+
selector: 'a[ui-external-link]',
|
|
1830
|
+
template: `
|
|
1831
|
+
<ng-content />
|
|
1832
|
+
<svg
|
|
1833
|
+
aria-hidden="true"
|
|
1834
|
+
fill="none"
|
|
1835
|
+
height="14"
|
|
1836
|
+
stroke="currentColor"
|
|
1837
|
+
stroke-linecap="round"
|
|
1838
|
+
stroke-linejoin="round"
|
|
1839
|
+
stroke-width="1.75"
|
|
1840
|
+
viewBox="0 0 24 24"
|
|
1841
|
+
width="14"
|
|
1842
|
+
>
|
|
1843
|
+
<path d="M15 3h6v6" />
|
|
1844
|
+
<path d="M10 14 21 3" />
|
|
1845
|
+
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
|
|
1846
|
+
</svg>
|
|
1847
|
+
`,
|
|
1848
|
+
host: {
|
|
1849
|
+
class: 'inline-flex min-h-11 items-center gap-1.5 rounded-[4px] text-label leading-[17px] font-medium lg:min-h-0 hover:underline underline-offset-3 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring) [&>svg]:flex-none',
|
|
1850
|
+
},
|
|
1851
|
+
}]
|
|
1852
|
+
}] });
|
|
1853
|
+
|
|
1854
|
+
/** Available fact row sizes. `FactSize` is derived from this tuple. */
|
|
1855
|
+
const FACT_SIZES = ['md', 'sm', 'auto'];
|
|
1856
|
+
/** Colour of the line under a fact value. `stale` flags an out-of-date figure. */
|
|
1857
|
+
const FACT_SUB_TONES = ['subtle', 'stale'];
|
|
1858
|
+
const SIZE_CLASSES$2 = {
|
|
1859
|
+
md: { row: 'py-3 [&:not(:first-child)]:shadow-[inset_0_1px_0_var(--hairline)]', value: 'text-body' },
|
|
1860
|
+
sm: { row: 'py-2.5', value: 'text-label' },
|
|
1861
|
+
auto: {
|
|
1862
|
+
row: 'py-3 lg:py-2.5 max-lg:[&:not(:first-child)]:shadow-[inset_0_1px_0_var(--hairline)]',
|
|
1863
|
+
value: 'text-body lg:text-label',
|
|
1864
|
+
},
|
|
1865
|
+
};
|
|
1866
|
+
const SUB_TONE_CLASSES$1 = {
|
|
1867
|
+
subtle: 'text-(--subtle-foreground)',
|
|
1868
|
+
stale: 'text-(--stale)',
|
|
1869
|
+
};
|
|
1870
|
+
/**
|
|
1871
|
+
* The list that holds `div[ui-fact]` rows, as a native description list.
|
|
1872
|
+
*
|
|
1873
|
+
* @example
|
|
1874
|
+
* <dl uiFacts>
|
|
1875
|
+
* <div ui-fact label="Quantity">500</div>
|
|
1876
|
+
* <div ui-fact label="Price" sub="24/09 · Yahoo">28,64 €</div>
|
|
1877
|
+
* </dl>
|
|
1878
|
+
*/
|
|
1879
|
+
class UiFacts {
|
|
1880
|
+
ruled = input(false, { ...(ngDevMode ? { debugName: "ruled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1881
|
+
classes = computed(() => `m-0 flex flex-col${this.ruled() ? ' shadow-[inset_0_1px_0_var(--hairline)]' : ''}`, /* @ts-ignore */
|
|
1882
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
1883
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFacts, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1884
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiFacts, isStandalone: true, selector: "dl[uiFacts]", inputs: { ruled: { classPropertyName: "ruled", publicName: "ruled", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0 });
|
|
1885
|
+
}
|
|
1886
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFacts, decorators: [{
|
|
1887
|
+
type: Directive,
|
|
1888
|
+
args: [{
|
|
1889
|
+
selector: 'dl[uiFacts]',
|
|
1890
|
+
host: { '[class]': 'classes()' },
|
|
1891
|
+
}]
|
|
1892
|
+
}], propDecorators: { ruled: [{ type: i0.Input, args: [{ isSignal: true, alias: "ruled", required: false }] }] } });
|
|
1893
|
+
/**
|
|
1894
|
+
* One fact of a `dl[uiFacts]`: a label on the left, its value on the right, an optional sub-line
|
|
1895
|
+
* under the value, and a hairline above every row but the first at the `md` size (the `sm` desktop list is separated by space only). The projected content is the value.
|
|
1896
|
+
*
|
|
1897
|
+
* @example
|
|
1898
|
+
* <div ui-fact label="Price" sub="24/09 · Yahoo" subTone="stale">28,64 €</div>
|
|
1899
|
+
*/
|
|
1900
|
+
class UiFact {
|
|
1901
|
+
label = input.required(/* @ts-ignore */
|
|
1902
|
+
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
1903
|
+
sub = input(/* @ts-ignore */
|
|
1904
|
+
...(ngDevMode ? [undefined, { debugName: "sub" }] : /* istanbul ignore next */ []));
|
|
1905
|
+
subTone = input('subtle', /* @ts-ignore */
|
|
1906
|
+
...(ngDevMode ? [{ debugName: "subTone" }] : /* istanbul ignore next */ []));
|
|
1907
|
+
size = input('md', /* @ts-ignore */
|
|
1908
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
1909
|
+
classes = computed(() => `flex items-baseline justify-between gap-4 ${SIZE_CLASSES$2[this.size()].row}`, /* @ts-ignore */
|
|
1910
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
1911
|
+
valueClasses = computed(() => `${SIZE_CLASSES$2[this.size()].value} tabular-nums`, /* @ts-ignore */
|
|
1912
|
+
...(ngDevMode ? [{ debugName: "valueClasses" }] : /* istanbul ignore next */ []));
|
|
1913
|
+
subClasses = computed(() => `text-caption ${SUB_TONE_CLASSES$1[this.subTone()]}`, /* @ts-ignore */
|
|
1914
|
+
...(ngDevMode ? [{ debugName: "subClasses" }] : /* istanbul ignore next */ []));
|
|
1915
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFact, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1916
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiFact, isStandalone: true, selector: "div[ui-fact]", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, sub: { classPropertyName: "sub", publicName: "sub", isSignal: true, isRequired: false, transformFunction: null }, subTone: { classPropertyName: "subTone", publicName: "subTone", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: `
|
|
1917
|
+
<dt class="text-label text-(--muted-foreground)">{{ label() }}</dt>
|
|
1918
|
+
<dd class="m-0 flex flex-col items-end text-right">
|
|
1919
|
+
<span [class]="valueClasses()"><ng-content /></span>
|
|
1920
|
+
@if (sub()) {
|
|
1921
|
+
<span [class]="subClasses()">{{ sub() }}</span>
|
|
1922
|
+
}
|
|
1923
|
+
</dd>
|
|
1924
|
+
`, isInline: true });
|
|
1925
|
+
}
|
|
1926
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFact, decorators: [{
|
|
1927
|
+
type: Component,
|
|
1928
|
+
args: [{
|
|
1929
|
+
selector: 'div[ui-fact]',
|
|
1930
|
+
template: `
|
|
1931
|
+
<dt class="text-label text-(--muted-foreground)">{{ label() }}</dt>
|
|
1932
|
+
<dd class="m-0 flex flex-col items-end text-right">
|
|
1933
|
+
<span [class]="valueClasses()"><ng-content /></span>
|
|
1934
|
+
@if (sub()) {
|
|
1935
|
+
<span [class]="subClasses()">{{ sub() }}</span>
|
|
1936
|
+
}
|
|
1937
|
+
</dd>
|
|
1938
|
+
`,
|
|
1939
|
+
host: { '[class]': 'classes()' },
|
|
1940
|
+
}]
|
|
1941
|
+
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], sub: [{ type: i0.Input, args: [{ isSignal: true, alias: "sub", required: false }] }], subTone: [{ type: i0.Input, args: [{ isSignal: true, alias: "subTone", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
1942
|
+
|
|
1943
|
+
const nextId$2 = (() => {
|
|
844
1944
|
let count = 0;
|
|
845
1945
|
return () => `ui-field-${++count}`;
|
|
846
1946
|
})();
|
|
1947
|
+
/**
|
|
1948
|
+
* Marks an element, typically an 18px svg icon, as the leading content of a `ui-field`: it sits
|
|
1949
|
+
* inside the control's left edge and the control's text is inset to clear it. Decorative, so hidden
|
|
1950
|
+
* from assistive technologies.
|
|
1951
|
+
*
|
|
1952
|
+
* @example
|
|
1953
|
+
* <ui-field label="Search" labelHidden>
|
|
1954
|
+
* <svg uiFieldLeading width="18" height="18" viewBox="0 0 24 24">...</svg>
|
|
1955
|
+
* <input uiInput type="search" />
|
|
1956
|
+
* </ui-field>
|
|
1957
|
+
*/
|
|
1958
|
+
class UiFieldLeading {
|
|
1959
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFieldLeading, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1960
|
+
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 });
|
|
1961
|
+
}
|
|
1962
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFieldLeading, decorators: [{
|
|
1963
|
+
type: Directive,
|
|
1964
|
+
args: [{
|
|
1965
|
+
selector: '[uiFieldLeading]',
|
|
1966
|
+
host: {
|
|
1967
|
+
class: 'pointer-events-none absolute left-3 flex text-(--muted-foreground)',
|
|
1968
|
+
'aria-hidden': 'true',
|
|
1969
|
+
},
|
|
1970
|
+
}]
|
|
1971
|
+
}] });
|
|
1972
|
+
/**
|
|
1973
|
+
* Marks an element, typically an icon button, as the trailing action of a `ui-field`: it sits on the
|
|
1974
|
+
* control's right edge, square to the control's height, and the control's text is padded to clear it.
|
|
1975
|
+
*
|
|
1976
|
+
* @example
|
|
1977
|
+
* <ui-field label="Password">
|
|
1978
|
+
* <input uiInput type="password" size="xl" />
|
|
1979
|
+
* <button uiFieldTrailing type="button" aria-label="Show the password" [attr.aria-pressed]="shown()">...</button>
|
|
1980
|
+
* </ui-field>
|
|
1981
|
+
*
|
|
1982
|
+
* A toggle such as this one should carry `aria-pressed`. The slot shares the right edge with `unit`:
|
|
1983
|
+
* set one or the other, not both.
|
|
1984
|
+
*/
|
|
1985
|
+
class UiFieldTrailing {
|
|
1986
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFieldTrailing, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1987
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.7", type: UiFieldTrailing, isStandalone: true, selector: "[uiFieldTrailing]", host: { classAttribute: "absolute right-0 grid h-full aspect-square place-items-center rounded-control cursor-pointer text-(--muted-foreground) hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-4 focus-visible:outline-(--ring)" }, ngImport: i0 });
|
|
1988
|
+
}
|
|
1989
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFieldTrailing, decorators: [{
|
|
1990
|
+
type: Directive,
|
|
1991
|
+
args: [{
|
|
1992
|
+
selector: '[uiFieldTrailing]',
|
|
1993
|
+
host: {
|
|
1994
|
+
class: 'absolute right-0 grid h-full aspect-square place-items-center rounded-control cursor-pointer text-(--muted-foreground) hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-4 focus-visible:outline-(--ring)',
|
|
1995
|
+
},
|
|
1996
|
+
}]
|
|
1997
|
+
}] });
|
|
847
1998
|
/**
|
|
848
1999
|
* Label, control, hint and error as one unit. The control stays a plain native element:
|
|
849
2000
|
* the field finds it in its own projected content and wires the ARIA attributes onto it.
|
|
@@ -876,13 +2027,22 @@ class UiField {
|
|
|
876
2027
|
...(ngDevMode ? [undefined, { debugName: "error" }] : /* istanbul ignore next */ []));
|
|
877
2028
|
unit = input(/* @ts-ignore */
|
|
878
2029
|
...(ngDevMode ? [undefined, { debugName: "unit" }] : /* istanbul ignore next */ []));
|
|
879
|
-
|
|
2030
|
+
optional = input(/* @ts-ignore */
|
|
2031
|
+
...(ngDevMode ? [undefined, { debugName: "optional" }] : /* istanbul ignore next */ []));
|
|
2032
|
+
invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2033
|
+
#id = nextId$2();
|
|
880
2034
|
hintId = `${this.#id}-hint`;
|
|
881
2035
|
errorId = `${this.#id}-error`;
|
|
882
2036
|
#host = inject(ElementRef);
|
|
883
2037
|
control = contentChild(UI_CONTROL, /* @ts-ignore */
|
|
884
2038
|
...(ngDevMode ? [{ debugName: "control" }] : /* istanbul ignore next */ []));
|
|
885
|
-
|
|
2039
|
+
leading = contentChild(UiFieldLeading, /* @ts-ignore */
|
|
2040
|
+
...(ngDevMode ? [{ debugName: "leading" }] : /* istanbul ignore next */ []));
|
|
2041
|
+
trailing = contentChild(UiFieldTrailing, /* @ts-ignore */
|
|
2042
|
+
...(ngDevMode ? [{ debugName: "trailing" }] : /* istanbul ignore next */ []));
|
|
2043
|
+
rowClasses = computed(() => `relative flex items-center${this.leading() ? ' [&>input]:pl-[38px]' : ''}${this.trailing() ? ' [&>input]:pr-12 lg:[&>input]:pr-11' : ''}`, /* @ts-ignore */
|
|
2044
|
+
...(ngDevMode ? [{ debugName: "rowClasses" }] : /* istanbul ignore next */ []));
|
|
2045
|
+
labelClasses = computed(() => this.labelHidden() ? 'sr-only' : 'text-label leading-[17px] font-medium text-(--muted-foreground)', /* @ts-ignore */
|
|
886
2046
|
...(ngDevMode ? [{ debugName: "labelClasses" }] : /* istanbul ignore next */ []));
|
|
887
2047
|
/**
|
|
888
2048
|
* The caller's own `error` wins: it is the only way to report something the control does not
|
|
@@ -901,6 +2061,7 @@ class UiField {
|
|
|
901
2061
|
}, /* @ts-ignore */
|
|
902
2062
|
...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
|
|
903
2063
|
constructor() {
|
|
2064
|
+
let markedByField = false;
|
|
904
2065
|
afterRenderEffect(() => {
|
|
905
2066
|
// querySelector, not viewChild.required, so the "no control found" guard below stays reachable and testable.
|
|
906
2067
|
const control = this.#host.nativeElement.querySelector('input, select, textarea');
|
|
@@ -916,23 +2077,31 @@ class UiField {
|
|
|
916
2077
|
else {
|
|
917
2078
|
control.removeAttribute('aria-describedby');
|
|
918
2079
|
}
|
|
919
|
-
if (this.message()) {
|
|
2080
|
+
if (this.message() || this.invalid()) {
|
|
920
2081
|
control.setAttribute('aria-invalid', 'true');
|
|
2082
|
+
markedByField = true;
|
|
921
2083
|
}
|
|
922
|
-
else {
|
|
2084
|
+
else if (markedByField) {
|
|
923
2085
|
control.removeAttribute('aria-invalid');
|
|
2086
|
+
markedByField = false;
|
|
924
2087
|
}
|
|
925
2088
|
});
|
|
926
2089
|
}
|
|
927
2090
|
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: `
|
|
2091
|
+
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 }, optional: { classPropertyName: "optional", publicName: "optional", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", 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 }, { propertyName: "trailing", first: true, predicate: UiFieldTrailing, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
929
2092
|
<div class="group flex flex-col gap-1.5">
|
|
930
2093
|
<!-- 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
|
-
<label [class]="labelClasses()"
|
|
2094
|
+
<label [class]="labelClasses()"
|
|
2095
|
+
>{{ label() }}
|
|
2096
|
+
@if (optional()) {
|
|
2097
|
+
{{ ' ' }}<span class="font-normal text-(--subtle-foreground)">{{ optional() }}</span>
|
|
2098
|
+
}
|
|
2099
|
+
</label>
|
|
932
2100
|
|
|
933
|
-
<div class="
|
|
2101
|
+
<div [class]="rowClasses()">
|
|
2102
|
+
<ng-content select="[uiFieldLeading]" />
|
|
934
2103
|
<ng-content />
|
|
935
|
-
|
|
2104
|
+
<ng-content select="[uiFieldTrailing]" />
|
|
936
2105
|
@if (unit()) {
|
|
937
2106
|
<span class="text-label pointer-events-none absolute right-3 text-(--subtle-foreground)">{{ unit() }}</span>
|
|
938
2107
|
}
|
|
@@ -955,11 +2124,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
955
2124
|
template: `
|
|
956
2125
|
<div class="group flex flex-col gap-1.5">
|
|
957
2126
|
<!-- 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
|
-
<label [class]="labelClasses()"
|
|
2127
|
+
<label [class]="labelClasses()"
|
|
2128
|
+
>{{ label() }}
|
|
2129
|
+
@if (optional()) {
|
|
2130
|
+
{{ ' ' }}<span class="font-normal text-(--subtle-foreground)">{{ optional() }}</span>
|
|
2131
|
+
}
|
|
2132
|
+
</label>
|
|
959
2133
|
|
|
960
|
-
<div class="
|
|
2134
|
+
<div [class]="rowClasses()">
|
|
2135
|
+
<ng-content select="[uiFieldLeading]" />
|
|
961
2136
|
<ng-content />
|
|
962
|
-
|
|
2137
|
+
<ng-content select="[uiFieldTrailing]" />
|
|
963
2138
|
@if (unit()) {
|
|
964
2139
|
<span class="text-label pointer-events-none absolute right-3 text-(--subtle-foreground)">{{ unit() }}</span>
|
|
965
2140
|
}
|
|
@@ -975,77 +2150,87 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
975
2150
|
</div>
|
|
976
2151
|
`,
|
|
977
2152
|
}]
|
|
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 }] }] } });
|
|
2153
|
+
}], 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 }] }], optional: [{ type: i0.Input, args: [{ isSignal: true, alias: "optional", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], control: [{ type: i0.ContentChild, args: [i0.forwardRef(() => UI_CONTROL), { isSignal: true }] }], leading: [{ type: i0.ContentChild, args: [i0.forwardRef(() => UiFieldLeading), { isSignal: true }] }], trailing: [{ type: i0.ContentChild, args: [i0.forwardRef(() => UiFieldTrailing), { isSignal: true }] }] } });
|
|
979
2154
|
|
|
980
|
-
|
|
981
|
-
const
|
|
982
|
-
const
|
|
983
|
-
const
|
|
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 }] }] } });
|
|
2155
|
+
const CHIP_CLASSES = 'flex-none flex h-11 items-center rounded-pill border-0 bg-transparent p-0 font-[inherit] cursor-pointer transition-transform duration-(--duration-press) ease-out active:scale-(--press-scale) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring) pointer-fine:h-8 pointer-fine:focus-visible:outline-offset-2';
|
|
2156
|
+
const PILL_CLASSES = 'flex h-[34px] items-center gap-1.5 rounded-pill px-3.5 text-label font-medium whitespace-nowrap pointer-fine:h-8 pointer-fine:px-3 pointer-fine:group-hover/chip:shadow-[inset_0_0_0_1px_var(--muted-foreground)]';
|
|
2157
|
+
const SELECTED_PILL_CLASSES = 'bg-(--primary) text-(--primary-foreground)';
|
|
2158
|
+
const UNSELECTED_PILL_CLASSES = 'bg-(--card) text-(--foreground) shadow-[inset_0_0_0_1px_var(--border)]';
|
|
1020
2159
|
/**
|
|
1021
|
-
*
|
|
1022
|
-
*
|
|
1023
|
-
*
|
|
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.
|
|
2160
|
+
* A row of single-choice filter pills, each with an optional count, that narrows a list in place:
|
|
2161
|
+
* an asset class, a status. On touch it scrolls on one line, bleeding to the screen edges; with a
|
|
2162
|
+
* fine pointer it wraps.
|
|
1027
2163
|
*
|
|
1028
2164
|
* @example
|
|
1029
|
-
* <
|
|
2165
|
+
* <ui-filter-chips ariaLabel="Filter by class" [options]="classes()" [(value)]="selectedClass" />
|
|
1030
2166
|
*/
|
|
1031
|
-
class
|
|
1032
|
-
|
|
1033
|
-
...(ngDevMode ? [{ debugName: "
|
|
1034
|
-
|
|
1035
|
-
...(ngDevMode ? [{ debugName: "
|
|
1036
|
-
|
|
1037
|
-
|
|
2167
|
+
class UiFilterChips {
|
|
2168
|
+
options = input.required(/* @ts-ignore */
|
|
2169
|
+
...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
|
|
2170
|
+
value = model.required(/* @ts-ignore */
|
|
2171
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
2172
|
+
ariaLabel = input.required(/* @ts-ignore */
|
|
2173
|
+
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
2174
|
+
chipClasses = CHIP_CLASSES;
|
|
2175
|
+
pillClasses(optionValue) {
|
|
2176
|
+
return `${PILL_CLASSES} ${optionValue === this.value() ? SELECTED_PILL_CLASSES : UNSELECTED_PILL_CLASSES}`;
|
|
2177
|
+
}
|
|
2178
|
+
countClasses(optionValue) {
|
|
2179
|
+
return optionValue === this.value() ? 'text-(--primary-foreground)' : 'text-(--subtle-foreground)';
|
|
2180
|
+
}
|
|
2181
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFilterChips, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2182
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiFilterChips, isStandalone: true, selector: "ui-filter-chips", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { value: "valueChange" }, host: { attributes: { "role": "group" }, properties: { "attr.aria-label": "ariaLabel()" }, classAttribute: "flex gap-2 overflow-x-auto [scrollbar-width:none] -mt-1 -mx-(--gutter) px-(--gutter) pointer-fine:m-0 pointer-fine:flex-wrap pointer-fine:overflow-visible pointer-fine:p-0" }, ngImport: i0, template: `
|
|
2183
|
+
@for (option of options(); track option.value) {
|
|
2184
|
+
<button
|
|
2185
|
+
class="group/chip"
|
|
2186
|
+
type="button"
|
|
2187
|
+
[attr.aria-pressed]="option.value === value()"
|
|
2188
|
+
[class]="chipClasses"
|
|
2189
|
+
(click)="value.set(option.value)"
|
|
2190
|
+
>
|
|
2191
|
+
<span data-chip [class]="pillClasses(option.value)"
|
|
2192
|
+
>{{ option.label }}
|
|
2193
|
+
@if (option.count !== undefined && option.count !== null) {
|
|
2194
|
+
&ngsp;<span class="[font-variant-numeric:var(--numeric)]" data-count [class]="countClasses(option.value)">{{
|
|
2195
|
+
option.count
|
|
2196
|
+
}}</span>
|
|
2197
|
+
}
|
|
2198
|
+
</span>
|
|
2199
|
+
</button>
|
|
2200
|
+
}
|
|
2201
|
+
`, isInline: true });
|
|
1038
2202
|
}
|
|
1039
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type:
|
|
1040
|
-
type:
|
|
2203
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFilterChips, decorators: [{
|
|
2204
|
+
type: Component,
|
|
1041
2205
|
args: [{
|
|
1042
|
-
selector: '
|
|
2206
|
+
selector: 'ui-filter-chips',
|
|
2207
|
+
template: `
|
|
2208
|
+
@for (option of options(); track option.value) {
|
|
2209
|
+
<button
|
|
2210
|
+
class="group/chip"
|
|
2211
|
+
type="button"
|
|
2212
|
+
[attr.aria-pressed]="option.value === value()"
|
|
2213
|
+
[class]="chipClasses"
|
|
2214
|
+
(click)="value.set(option.value)"
|
|
2215
|
+
>
|
|
2216
|
+
<span data-chip [class]="pillClasses(option.value)"
|
|
2217
|
+
>{{ option.label }}
|
|
2218
|
+
@if (option.count !== undefined && option.count !== null) {
|
|
2219
|
+
&ngsp;<span class="[font-variant-numeric:var(--numeric)]" data-count [class]="countClasses(option.value)">{{
|
|
2220
|
+
option.count
|
|
2221
|
+
}}</span>
|
|
2222
|
+
}
|
|
2223
|
+
</span>
|
|
2224
|
+
</button>
|
|
2225
|
+
}
|
|
2226
|
+
`,
|
|
1043
2227
|
host: {
|
|
1044
|
-
|
|
2228
|
+
role: 'group',
|
|
2229
|
+
class: 'flex gap-2 overflow-x-auto [scrollbar-width:none] -mt-1 -mx-(--gutter) px-(--gutter) pointer-fine:m-0 pointer-fine:flex-wrap pointer-fine:overflow-visible pointer-fine:p-0',
|
|
2230
|
+
'[attr.aria-label]': 'ariaLabel()',
|
|
1045
2231
|
},
|
|
1046
|
-
providers: [{ provide: UI_CONTROL, useExisting: forwardRef(() => UiTextarea) }],
|
|
1047
2232
|
}]
|
|
1048
|
-
}], propDecorators: {
|
|
2233
|
+
}], 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"] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: true }] }] } });
|
|
1049
2234
|
|
|
1050
2235
|
const axisTicks = (points, maxTicks = 5) => {
|
|
1051
2236
|
if (points.length <= maxTicks) {
|
|
@@ -1059,6 +2244,13 @@ const axisTicks = (points, maxTicks = 5) => {
|
|
|
1059
2244
|
}
|
|
1060
2245
|
return [...indexes].sort((a, b) => a - b).map((index) => points[index]);
|
|
1061
2246
|
};
|
|
2247
|
+
const isCoreTick = (index, count) => {
|
|
2248
|
+
if (count <= 3) {
|
|
2249
|
+
return true;
|
|
2250
|
+
}
|
|
2251
|
+
const middle = Math.floor((count - 1) / 2);
|
|
2252
|
+
return index === 0 || index === count - 1 || index === middle;
|
|
2253
|
+
};
|
|
1062
2254
|
|
|
1063
2255
|
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
|
|
1064
2256
|
const nearestPointIndex = (points, x) => {
|
|
@@ -1090,6 +2282,36 @@ const navigateIndex = (key, current, last) => {
|
|
|
1090
2282
|
}
|
|
1091
2283
|
};
|
|
1092
2284
|
|
|
2285
|
+
const START_LABEL_HEIGHT = 16;
|
|
2286
|
+
const AXIS_ROW = 17;
|
|
2287
|
+
const TOOLTIP_SIZES = ['compact', 'large'];
|
|
2288
|
+
const TOOLTIP_CLASSES = {
|
|
2289
|
+
compact: { box: '-top-3 px-2.5', value: 'text-label', delta: 'text-caption' },
|
|
2290
|
+
large: { box: 'top-0 px-3', value: 'text-body', delta: 'text-label' },
|
|
2291
|
+
};
|
|
2292
|
+
const PLOT_PADDING_RATIO = 16 / 240;
|
|
2293
|
+
const SPARKLINE_PADDING = 4;
|
|
2294
|
+
const START_LABEL_BASELINE_OFFSET = 4;
|
|
2295
|
+
const TOOLTIP_OFFSET = 14;
|
|
2296
|
+
const TOOLTIP_FLIP_RATIO = 0.55;
|
|
2297
|
+
const plotHeightFor = (height, sparkline, axisGap, wide) => sparkline ? height : Math.max(height - resolveGap(axisGap, wide) - AXIS_ROW, 1);
|
|
2298
|
+
const plotPaddingFor = (plotHeight, sparkline) => sparkline ? SPARKLINE_PADDING : plotHeight * PLOT_PADDING_RATIO;
|
|
2299
|
+
const startLabelBaseline = (boxBottom) => boxBottom - START_LABEL_BASELINE_OFFSET;
|
|
2300
|
+
const tooltipPlacement = (ratio) => {
|
|
2301
|
+
const flipped = ratio > TOOLTIP_FLIP_RATIO;
|
|
2302
|
+
return `left: calc(${ratio * 100}% ${flipped ? '-' : '+'} ${TOOLTIP_OFFSET}px); transform: ${flipped ? 'translateX(-100%)' : 'none'}`;
|
|
2303
|
+
};
|
|
2304
|
+
const deltaTone = (delta) => delta > 0 ? 'text-(--positive)' : delta < 0 ? 'text-(--negative)' : 'text-(--muted-foreground)';
|
|
2305
|
+
const DEFAULT_WIDTH = 640;
|
|
2306
|
+
const DEFAULT_HEIGHT = 240;
|
|
2307
|
+
const identityValue = (value) => `${value}`;
|
|
2308
|
+
const identityDelta = (delta) => `${delta > 0 ? '+' : ''}${delta}`;
|
|
2309
|
+
const identityTime = (time) => new Date(time).toISOString();
|
|
2310
|
+
const parseAxisTicks = (value) => value === 'auto' ? 'auto' : Number(value);
|
|
2311
|
+
const resolveGap = (gap, wide) => (gap === 'auto' ? (wide ? 16 : 12) : gap);
|
|
2312
|
+
const resolveTooltip = (size, wide) => size === 'auto' ? (wide ? 'large' : 'compact') : size;
|
|
2313
|
+
const tooltipClassesFor = (size, wide) => TOOLTIP_CLASSES[resolveTooltip(size, wide)];
|
|
2314
|
+
|
|
1093
2315
|
const CURVE = curveMonotoneX;
|
|
1094
2316
|
const buildGeometry = (points, width, height, padding = {}) => {
|
|
1095
2317
|
if (points.length === 0) {
|
|
@@ -1125,8 +2347,8 @@ const buildGeometry = (points, width, height, padding = {}) => {
|
|
|
1125
2347
|
};
|
|
1126
2348
|
};
|
|
1127
2349
|
|
|
1128
|
-
const LINE_GAP =
|
|
1129
|
-
const COLLISION_MARGIN =
|
|
2350
|
+
const LINE_GAP = 6;
|
|
2351
|
+
const COLLISION_MARGIN = 6;
|
|
1130
2352
|
const EDGE_TOLERANCE = 3;
|
|
1131
2353
|
const candidateSlots = (startY, box, label) => {
|
|
1132
2354
|
const aboveTop = startY - LINE_GAP - label.height;
|
|
@@ -1239,13 +2461,19 @@ const interpolateLine = (from, to, progress) => {
|
|
|
1239
2461
|
return buildPolyline(samples, fromYs.map((fromY, index) => fromY + (toYs[index] - fromY) * progress));
|
|
1240
2462
|
};
|
|
1241
2463
|
|
|
1242
|
-
const
|
|
1243
|
-
const
|
|
1244
|
-
const
|
|
1245
|
-
const
|
|
1246
|
-
|
|
1247
|
-
const
|
|
1248
|
-
|
|
2464
|
+
const WIDE_QUERY = '(min-width: 64rem)';
|
|
2465
|
+
const wideViewport = () => {
|
|
2466
|
+
const query = typeof matchMedia === 'function' ? matchMedia(WIDE_QUERY) : null;
|
|
2467
|
+
const wide = signal(query?.matches ?? false, /* @ts-ignore */
|
|
2468
|
+
...(ngDevMode ? [{ debugName: "wide" }] : /* istanbul ignore next */ []));
|
|
2469
|
+
const onChange = (event) => wide.set(event.matches);
|
|
2470
|
+
if (query) {
|
|
2471
|
+
query.onchange = onChange;
|
|
2472
|
+
inject(DestroyRef).onDestroy(() => (query.onchange = null));
|
|
2473
|
+
}
|
|
2474
|
+
return wide;
|
|
2475
|
+
};
|
|
2476
|
+
|
|
1249
2477
|
/**
|
|
1250
2478
|
* Value over time: a monotone curve with a dashed line at the starting value and a tooltip.
|
|
1251
2479
|
*
|
|
@@ -1259,6 +2487,8 @@ class UiLineChart {
|
|
|
1259
2487
|
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
1260
2488
|
valueFormat = input(identityValue, /* @ts-ignore */
|
|
1261
2489
|
...(ngDevMode ? [{ debugName: "valueFormat" }] : /* istanbul ignore next */ []));
|
|
2490
|
+
tooltipFormat = input(/* @ts-ignore */
|
|
2491
|
+
...(ngDevMode ? [undefined, { debugName: "tooltipFormat" }] : /* istanbul ignore next */ []));
|
|
1262
2492
|
deltaFormat = input(identityDelta, /* @ts-ignore */
|
|
1263
2493
|
...(ngDevMode ? [{ debugName: "deltaFormat" }] : /* istanbul ignore next */ []));
|
|
1264
2494
|
timeFormat = input(identityTime, /* @ts-ignore */
|
|
@@ -1271,10 +2501,19 @@ class UiLineChart {
|
|
|
1271
2501
|
...(ngDevMode ? [{ debugName: "timeColumnLabel" }] : /* istanbul ignore next */ []));
|
|
1272
2502
|
valueColumnLabel = input('Value', /* @ts-ignore */
|
|
1273
2503
|
...(ngDevMode ? [{ debugName: "valueColumnLabel" }] : /* istanbul ignore next */ []));
|
|
2504
|
+
sparkline = input(false, { ...(ngDevMode ? { debugName: "sparkline" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2505
|
+
tooltip = input('compact', /* @ts-ignore */
|
|
2506
|
+
...(ngDevMode ? [{ debugName: "tooltip" }] : /* istanbul ignore next */ []));
|
|
2507
|
+
tooltipDelta = input(true, { ...(ngDevMode ? { debugName: "tooltipDelta" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2508
|
+
axisGap = input(12, /* @ts-ignore */
|
|
2509
|
+
...(ngDevMode ? [{ debugName: "axisGap" }] : /* istanbul ignore next */ []));
|
|
2510
|
+
axisTicks = input('auto', { ...(ngDevMode ? { debugName: "axisTicks" } : /* istanbul ignore next */ {}), transform: parseAxisTicks });
|
|
1274
2511
|
#destroyRef = inject(DestroyRef);
|
|
2512
|
+
#wide = wideViewport();
|
|
1275
2513
|
#frame = null;
|
|
1276
2514
|
#hasRenderedOnce = false;
|
|
1277
2515
|
#previousGeometry = null;
|
|
2516
|
+
isCoreTick = isCoreTick;
|
|
1278
2517
|
svgRef = viewChild.required('svgRef', /* @ts-ignore */
|
|
1279
2518
|
...(ngDevMode ? [{ debugName: "svgRef" }] : /* istanbul ignore next */ []));
|
|
1280
2519
|
activeIndex = signal(null, /* @ts-ignore */
|
|
@@ -1287,7 +2526,16 @@ class UiLineChart {
|
|
|
1287
2526
|
...(ngDevMode ? [{ debugName: "effectiveWidth" }] : /* istanbul ignore next */ []));
|
|
1288
2527
|
effectiveHeight = computed(() => this.measuredSize()?.height ?? DEFAULT_HEIGHT, /* @ts-ignore */
|
|
1289
2528
|
...(ngDevMode ? [{ debugName: "effectiveHeight" }] : /* istanbul ignore next */ []));
|
|
1290
|
-
|
|
2529
|
+
plotHeight = computed(() => plotHeightFor(this.effectiveHeight(), this.sparkline(), this.axisGap(), this.#wide()), /* @ts-ignore */
|
|
2530
|
+
...(ngDevMode ? [{ debugName: "plotHeight" }] : /* istanbul ignore next */ []));
|
|
2531
|
+
tooltipStyle = (point) => tooltipPlacement(point.x / this.effectiveWidth());
|
|
2532
|
+
tooltipClasses = computed(() => tooltipClassesFor(this.tooltip(), this.#wide()), /* @ts-ignore */
|
|
2533
|
+
...(ngDevMode ? [{ debugName: "tooltipClasses" }] : /* istanbul ignore next */ []));
|
|
2534
|
+
geometry = computed(() => {
|
|
2535
|
+
const plotHeight = this.plotHeight();
|
|
2536
|
+
const padding = plotPaddingFor(plotHeight, this.sparkline());
|
|
2537
|
+
return buildGeometry(this.points(), this.effectiveWidth(), plotHeight, { x: 0, top: padding, bottom: padding });
|
|
2538
|
+
}, /* @ts-ignore */
|
|
1291
2539
|
...(ngDevMode ? [{ debugName: "geometry" }] : /* istanbul ignore next */ []));
|
|
1292
2540
|
displayLine = computed(() => this.animatedLine() ?? this.geometry().line, /* @ts-ignore */
|
|
1293
2541
|
...(ngDevMode ? [{ debugName: "displayLine" }] : /* istanbul ignore next */ []));
|
|
@@ -1307,8 +2555,8 @@ class UiLineChart {
|
|
|
1307
2555
|
}
|
|
1308
2556
|
const label = `${text} ${this.valueFormat()(geometry.points[0].v)}`;
|
|
1309
2557
|
const size = { width: label.length * 0.56 * 12 + 8, height: START_LABEL_HEIGHT };
|
|
1310
|
-
const placement = placeStartLabel(geometry.points, geometry.start.y, { width: this.effectiveWidth(), height: this.
|
|
1311
|
-
return { label, placement };
|
|
2558
|
+
const placement = placeStartLabel(geometry.points, geometry.start.y, { width: this.effectiveWidth(), height: this.plotHeight() }, size);
|
|
2559
|
+
return { label, placement: { ...placement, y: startLabelBaseline(placement.y) } };
|
|
1312
2560
|
}, /* @ts-ignore */
|
|
1313
2561
|
...(ngDevMode ? [{ debugName: "startLabelInfo" }] : /* istanbul ignore next */ []));
|
|
1314
2562
|
#renderRef = afterNextRender(() => this.#observeSize());
|
|
@@ -1353,10 +2601,8 @@ class UiLineChart {
|
|
|
1353
2601
|
this.#destroyRef.onDestroy(() => observer.disconnect());
|
|
1354
2602
|
}
|
|
1355
2603
|
#cancelAnimation() {
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
this.#frame = null;
|
|
1359
|
-
}
|
|
2604
|
+
cancelAnimationFrame(this.#frame ?? 0);
|
|
2605
|
+
this.#frame = null;
|
|
1360
2606
|
}
|
|
1361
2607
|
#animate(from, to) {
|
|
1362
2608
|
if (from.points.length < 2 || to.points.length < 2) {
|
|
@@ -1366,37 +2612,20 @@ class UiLineChart {
|
|
|
1366
2612
|
const startTime = performance.now();
|
|
1367
2613
|
const step = (now) => {
|
|
1368
2614
|
const t = Math.min(1, (now - startTime) / TRANSITION_DURATION);
|
|
1369
|
-
this.animatedLine.set(interpolateLine(from, to, easeOutQuint(t)));
|
|
1370
|
-
|
|
1371
|
-
this.#frame = requestAnimationFrame(step);
|
|
1372
|
-
}
|
|
1373
|
-
else {
|
|
1374
|
-
this.#frame = null;
|
|
1375
|
-
this.animatedLine.set(null);
|
|
1376
|
-
}
|
|
2615
|
+
this.animatedLine.set(t < 1 ? interpolateLine(from, to, easeOutQuint(t)) : null);
|
|
2616
|
+
this.#frame = t < 1 ? requestAnimationFrame(step) : null;
|
|
1377
2617
|
};
|
|
1378
2618
|
this.#frame = requestAnimationFrame(step);
|
|
1379
2619
|
}
|
|
1380
|
-
coreTick(index, count) {
|
|
1381
|
-
if (count <= 3) {
|
|
1382
|
-
return true;
|
|
1383
|
-
}
|
|
1384
|
-
const middle = Math.floor((count - 1) / 2);
|
|
1385
|
-
return index === 0 || index === count - 1 || index === middle;
|
|
1386
|
-
}
|
|
1387
2620
|
deltaFor(point) {
|
|
1388
2621
|
return point.v - this.points()[0].v;
|
|
1389
2622
|
}
|
|
1390
2623
|
deltaClasses(point) {
|
|
1391
|
-
|
|
1392
|
-
return delta > 0 ? 'text-(--positive)' : delta < 0 ? 'text-(--negative)' : 'text-(--muted-foreground)';
|
|
1393
|
-
}
|
|
1394
|
-
tooltipStyle(point) {
|
|
1395
|
-
return `left: ${(point.x / this.effectiveWidth()) * 100}%; top: ${(point.y / this.effectiveHeight()) * 100}%`;
|
|
2624
|
+
return `${this.tooltipClasses().delta} ${deltaTone(this.deltaFor(point))}`;
|
|
1396
2625
|
}
|
|
1397
2626
|
onPointerMove(event) {
|
|
1398
2627
|
const geometry = this.geometry();
|
|
1399
|
-
if (!geometry || geometry.points.length === 0) {
|
|
2628
|
+
if (this.sparkline() || !geometry || geometry.points.length === 0) {
|
|
1400
2629
|
return;
|
|
1401
2630
|
}
|
|
1402
2631
|
const rect = this.svgRef().nativeElement.getBoundingClientRect();
|
|
@@ -1409,7 +2638,7 @@ class UiLineChart {
|
|
|
1409
2638
|
}
|
|
1410
2639
|
onKeydown(event) {
|
|
1411
2640
|
const geometry = this.geometry();
|
|
1412
|
-
if (!geometry || geometry.points.length === 0) {
|
|
2641
|
+
if (this.sparkline() || !geometry || geometry.points.length === 0) {
|
|
1413
2642
|
return;
|
|
1414
2643
|
}
|
|
1415
2644
|
const navigation = navigateIndex(event.key, this.activeIndex(), geometry.points.length - 1);
|
|
@@ -1422,15 +2651,15 @@ class UiLineChart {
|
|
|
1422
2651
|
this.activeIndex.set(navigation.index);
|
|
1423
2652
|
}
|
|
1424
2653
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiLineChart, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1425
|
-
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: `
|
|
2654
|
+
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 }, tooltipFormat: { classPropertyName: "tooltipFormat", publicName: "tooltipFormat", 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: `
|
|
1426
2655
|
<div class="relative h-full">
|
|
1427
2656
|
<svg
|
|
1428
2657
|
#svgRef
|
|
1429
|
-
class="block h-full w-full touch-pan-y"
|
|
2658
|
+
class="block h-full w-full touch-pan-y overflow-visible"
|
|
1430
2659
|
role="img"
|
|
1431
|
-
tabindex="0"
|
|
1432
2660
|
[attr.aria-label]="label()"
|
|
1433
2661
|
[attr.height]="effectiveHeight()"
|
|
2662
|
+
[attr.tabindex]="sparkline() ? null : 0"
|
|
1434
2663
|
[attr.viewBox]="'0 0 ' + effectiveWidth() + ' ' + effectiveHeight()"
|
|
1435
2664
|
[attr.width]="effectiveWidth()"
|
|
1436
2665
|
(keydown)="onKeydown($event)"
|
|
@@ -1444,119 +2673,124 @@ class UiLineChart {
|
|
|
1444
2673
|
fill="none"
|
|
1445
2674
|
stroke-linecap="round"
|
|
1446
2675
|
stroke-linejoin="round"
|
|
1447
|
-
stroke-width="2"
|
|
1448
2676
|
[attr.d]="displayLine()"
|
|
2677
|
+
[attr.stroke-width]="sparkline() ? 1.5 : 2"
|
|
1449
2678
|
/>
|
|
1450
2679
|
|
|
1451
|
-
|
|
1452
|
-
class="stroke-(--border)"
|
|
1453
|
-
data-chart-start-line
|
|
1454
|
-
stroke-dasharray="4 4"
|
|
1455
|
-
stroke-width="1"
|
|
1456
|
-
x1="0"
|
|
1457
|
-
[attr.x2]="effectiveWidth()"
|
|
1458
|
-
[attr.y1]="geometry.start.y"
|
|
1459
|
-
[attr.y2]="geometry.start.y"
|
|
1460
|
-
/>
|
|
1461
|
-
|
|
1462
|
-
@if (startLabelInfo(); as info) {
|
|
1463
|
-
<text
|
|
1464
|
-
class="text-caption fill-(--subtle-foreground)"
|
|
1465
|
-
data-chart-start-label
|
|
1466
|
-
[attr.text-anchor]="info.placement.anchor"
|
|
1467
|
-
[attr.x]="info.placement.x"
|
|
1468
|
-
[attr.y]="info.placement.y"
|
|
1469
|
-
>
|
|
1470
|
-
{{ info.label }}
|
|
1471
|
-
</text>
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
<circle
|
|
1475
|
-
class="fill-(--foreground) stroke-(--card)"
|
|
1476
|
-
data-chart-end
|
|
1477
|
-
r="4"
|
|
1478
|
-
stroke-width="2"
|
|
1479
|
-
[attr.cx]="geometry.end.x"
|
|
1480
|
-
[attr.cy]="geometry.end.y"
|
|
1481
|
-
/>
|
|
1482
|
-
|
|
1483
|
-
@for (
|
|
1484
|
-
tick of ticks();
|
|
1485
|
-
track tick.t;
|
|
1486
|
-
let index = $index;
|
|
1487
|
-
let count = $count;
|
|
1488
|
-
let first = $first;
|
|
1489
|
-
let last = $last
|
|
1490
|
-
) {
|
|
1491
|
-
<text
|
|
1492
|
-
class="text-caption fill-(--subtle-foreground)"
|
|
1493
|
-
data-chart-axis-tick
|
|
1494
|
-
[attr.text-anchor]="first ? 'start' : last ? 'end' : 'middle'"
|
|
1495
|
-
[attr.x]="tick.x"
|
|
1496
|
-
[attr.y]="effectiveHeight() - 4"
|
|
1497
|
-
[class.max-sm:hidden]="!coreTick(index, count)"
|
|
1498
|
-
>
|
|
1499
|
-
{{ axisFormat()(tick.t) }}
|
|
1500
|
-
</text>
|
|
1501
|
-
}
|
|
1502
|
-
|
|
1503
|
-
@if (active(); as point) {
|
|
2680
|
+
@if (!sparkline()) {
|
|
1504
2681
|
<line
|
|
1505
2682
|
class="stroke-(--border)"
|
|
1506
|
-
data-chart-
|
|
2683
|
+
data-chart-start-line
|
|
2684
|
+
stroke-dasharray="3 4"
|
|
1507
2685
|
stroke-width="1"
|
|
1508
|
-
|
|
1509
|
-
[attr.
|
|
1510
|
-
[attr.
|
|
1511
|
-
[attr.y2]="
|
|
2686
|
+
x1="0"
|
|
2687
|
+
[attr.x2]="effectiveWidth()"
|
|
2688
|
+
[attr.y1]="geometry.start.y"
|
|
2689
|
+
[attr.y2]="geometry.start.y"
|
|
1512
2690
|
/>
|
|
2691
|
+
|
|
2692
|
+
@if (startLabelInfo(); as info) {
|
|
2693
|
+
<text
|
|
2694
|
+
class="text-caption fill-(--subtle-foreground) tabular-nums"
|
|
2695
|
+
data-chart-start-label
|
|
2696
|
+
[attr.text-anchor]="info.placement.anchor"
|
|
2697
|
+
[attr.x]="info.placement.x"
|
|
2698
|
+
[attr.y]="info.placement.y"
|
|
2699
|
+
>
|
|
2700
|
+
{{ info.label }}
|
|
2701
|
+
</text>
|
|
2702
|
+
}
|
|
2703
|
+
|
|
1513
2704
|
<circle
|
|
1514
|
-
class="fill-(--foreground) stroke-(--card)"
|
|
1515
|
-
data-chart-
|
|
2705
|
+
class="fill-(--foreground) stroke-(--card) [paint-order:stroke]"
|
|
2706
|
+
data-chart-end
|
|
1516
2707
|
r="4"
|
|
1517
|
-
stroke-width="
|
|
1518
|
-
[attr.cx]="
|
|
1519
|
-
[attr.cy]="
|
|
2708
|
+
stroke-width="6"
|
|
2709
|
+
[attr.cx]="geometry.end.x"
|
|
2710
|
+
[attr.cy]="geometry.end.y"
|
|
1520
2711
|
/>
|
|
2712
|
+
|
|
2713
|
+
@for (
|
|
2714
|
+
tick of ticks();
|
|
2715
|
+
track tick.t;
|
|
2716
|
+
let index = $index;
|
|
2717
|
+
let count = $count;
|
|
2718
|
+
let first = $first;
|
|
2719
|
+
let last = $last
|
|
2720
|
+
) {
|
|
2721
|
+
<text
|
|
2722
|
+
class="text-caption fill-(--subtle-foreground) tabular-nums"
|
|
2723
|
+
data-chart-axis-tick
|
|
2724
|
+
[attr.text-anchor]="first ? 'start' : last ? 'end' : 'middle'"
|
|
2725
|
+
[attr.x]="tick.x"
|
|
2726
|
+
[attr.y]="effectiveHeight() - 4"
|
|
2727
|
+
[class.hidden]="axisTicks() === 3 && !isCoreTick(index, count)"
|
|
2728
|
+
[class.max-sm:hidden]="axisTicks() === 'auto' && !isCoreTick(index, count)"
|
|
2729
|
+
>
|
|
2730
|
+
{{ axisFormat()(tick.t) }}
|
|
2731
|
+
</text>
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2734
|
+
@if (active(); as point) {
|
|
2735
|
+
<line
|
|
2736
|
+
class="stroke-(--border)"
|
|
2737
|
+
data-chart-crosshair
|
|
2738
|
+
stroke-width="1"
|
|
2739
|
+
y1="0"
|
|
2740
|
+
[attr.x1]="point.x"
|
|
2741
|
+
[attr.x2]="point.x"
|
|
2742
|
+
[attr.y2]="plotHeight()"
|
|
2743
|
+
/>
|
|
2744
|
+
<circle
|
|
2745
|
+
class="fill-(--foreground) stroke-(--card) [paint-order:stroke]"
|
|
2746
|
+
data-chart-active
|
|
2747
|
+
r="5"
|
|
2748
|
+
stroke-width="6"
|
|
2749
|
+
[attr.cx]="point.x"
|
|
2750
|
+
[attr.cy]="point.y"
|
|
2751
|
+
/>
|
|
2752
|
+
}
|
|
1521
2753
|
}
|
|
1522
2754
|
}
|
|
1523
2755
|
</svg>
|
|
1524
2756
|
|
|
1525
2757
|
@if (active(); as point) {
|
|
1526
2758
|
<div
|
|
1527
|
-
class="rounded-container
|
|
2759
|
+
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)]"
|
|
1528
2760
|
data-testid="chart-tooltip"
|
|
1529
2761
|
role="status"
|
|
2762
|
+
[class]="tooltipClasses().box"
|
|
1530
2763
|
[style]="tooltipStyle(point)"
|
|
1531
2764
|
>
|
|
1532
|
-
<p class="font-medium text-(--foreground)"
|
|
1533
|
-
|
|
1534
|
-
|
|
2765
|
+
<p class="font-medium text-(--foreground)" [class]="tooltipClasses().value">
|
|
2766
|
+
{{ tooltipFormat()?.(point) ?? valueFormat()(point.v) }}
|
|
2767
|
+
</p>
|
|
2768
|
+
@if (tooltipDelta()) {
|
|
2769
|
+
<p data-chart-delta [class]="deltaClasses(point)">{{ deltaFormat()(deltaFor(point)) }}</p>
|
|
2770
|
+
}
|
|
2771
|
+
<p class="text-caption text-(--subtle-foreground)" data-chart-date>{{ timeFormat()(point.t) }}</p>
|
|
1535
2772
|
</div>
|
|
1536
2773
|
}
|
|
1537
|
-
|
|
1538
2774
|
@if (points().length > 0) {
|
|
1539
|
-
<
|
|
1540
|
-
<
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
}}
|
|
1544
|
-
</caption>
|
|
1545
|
-
<thead>
|
|
1546
|
-
<tr>
|
|
1547
|
-
<th scope="col">{{ timeColumnLabel() }}</th>
|
|
1548
|
-
<th scope="col">{{ valueColumnLabel() }}</th>
|
|
1549
|
-
</tr>
|
|
1550
|
-
</thead>
|
|
1551
|
-
<tbody>
|
|
1552
|
-
@for (point of points(); track point.t) {
|
|
2775
|
+
<div class="sr-only">
|
|
2776
|
+
<table>
|
|
2777
|
+
<caption [textContent]="label()"></caption>
|
|
2778
|
+
<thead>
|
|
1553
2779
|
<tr>
|
|
1554
|
-
<
|
|
1555
|
-
<
|
|
2780
|
+
<th scope="col">{{ timeColumnLabel() }}</th>
|
|
2781
|
+
<th scope="col">{{ valueColumnLabel() }}</th>
|
|
1556
2782
|
</tr>
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
2783
|
+
</thead>
|
|
2784
|
+
<tbody>
|
|
2785
|
+
@for (point of points(); track point.t) {
|
|
2786
|
+
<tr>
|
|
2787
|
+
<td>{{ timeFormat()(point.t) }}</td>
|
|
2788
|
+
<td>{{ valueFormat()(point.v) }}</td>
|
|
2789
|
+
</tr>
|
|
2790
|
+
}
|
|
2791
|
+
</tbody>
|
|
2792
|
+
</table>
|
|
2793
|
+
</div>
|
|
1560
2794
|
}
|
|
1561
2795
|
</div>
|
|
1562
2796
|
`, isInline: true });
|
|
@@ -1569,11 +2803,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1569
2803
|
<div class="relative h-full">
|
|
1570
2804
|
<svg
|
|
1571
2805
|
#svgRef
|
|
1572
|
-
class="block h-full w-full touch-pan-y"
|
|
2806
|
+
class="block h-full w-full touch-pan-y overflow-visible"
|
|
1573
2807
|
role="img"
|
|
1574
|
-
tabindex="0"
|
|
1575
2808
|
[attr.aria-label]="label()"
|
|
1576
2809
|
[attr.height]="effectiveHeight()"
|
|
2810
|
+
[attr.tabindex]="sparkline() ? null : 0"
|
|
1577
2811
|
[attr.viewBox]="'0 0 ' + effectiveWidth() + ' ' + effectiveHeight()"
|
|
1578
2812
|
[attr.width]="effectiveWidth()"
|
|
1579
2813
|
(keydown)="onKeydown($event)"
|
|
@@ -1587,119 +2821,124 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1587
2821
|
fill="none"
|
|
1588
2822
|
stroke-linecap="round"
|
|
1589
2823
|
stroke-linejoin="round"
|
|
1590
|
-
stroke-width="2"
|
|
1591
2824
|
[attr.d]="displayLine()"
|
|
2825
|
+
[attr.stroke-width]="sparkline() ? 1.5 : 2"
|
|
1592
2826
|
/>
|
|
1593
2827
|
|
|
1594
|
-
|
|
1595
|
-
class="stroke-(--border)"
|
|
1596
|
-
data-chart-start-line
|
|
1597
|
-
stroke-dasharray="4 4"
|
|
1598
|
-
stroke-width="1"
|
|
1599
|
-
x1="0"
|
|
1600
|
-
[attr.x2]="effectiveWidth()"
|
|
1601
|
-
[attr.y1]="geometry.start.y"
|
|
1602
|
-
[attr.y2]="geometry.start.y"
|
|
1603
|
-
/>
|
|
1604
|
-
|
|
1605
|
-
@if (startLabelInfo(); as info) {
|
|
1606
|
-
<text
|
|
1607
|
-
class="text-caption fill-(--subtle-foreground)"
|
|
1608
|
-
data-chart-start-label
|
|
1609
|
-
[attr.text-anchor]="info.placement.anchor"
|
|
1610
|
-
[attr.x]="info.placement.x"
|
|
1611
|
-
[attr.y]="info.placement.y"
|
|
1612
|
-
>
|
|
1613
|
-
{{ info.label }}
|
|
1614
|
-
</text>
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
|
-
<circle
|
|
1618
|
-
class="fill-(--foreground) stroke-(--card)"
|
|
1619
|
-
data-chart-end
|
|
1620
|
-
r="4"
|
|
1621
|
-
stroke-width="2"
|
|
1622
|
-
[attr.cx]="geometry.end.x"
|
|
1623
|
-
[attr.cy]="geometry.end.y"
|
|
1624
|
-
/>
|
|
1625
|
-
|
|
1626
|
-
@for (
|
|
1627
|
-
tick of ticks();
|
|
1628
|
-
track tick.t;
|
|
1629
|
-
let index = $index;
|
|
1630
|
-
let count = $count;
|
|
1631
|
-
let first = $first;
|
|
1632
|
-
let last = $last
|
|
1633
|
-
) {
|
|
1634
|
-
<text
|
|
1635
|
-
class="text-caption fill-(--subtle-foreground)"
|
|
1636
|
-
data-chart-axis-tick
|
|
1637
|
-
[attr.text-anchor]="first ? 'start' : last ? 'end' : 'middle'"
|
|
1638
|
-
[attr.x]="tick.x"
|
|
1639
|
-
[attr.y]="effectiveHeight() - 4"
|
|
1640
|
-
[class.max-sm:hidden]="!coreTick(index, count)"
|
|
1641
|
-
>
|
|
1642
|
-
{{ axisFormat()(tick.t) }}
|
|
1643
|
-
</text>
|
|
1644
|
-
}
|
|
1645
|
-
|
|
1646
|
-
@if (active(); as point) {
|
|
2828
|
+
@if (!sparkline()) {
|
|
1647
2829
|
<line
|
|
1648
2830
|
class="stroke-(--border)"
|
|
1649
|
-
data-chart-
|
|
2831
|
+
data-chart-start-line
|
|
2832
|
+
stroke-dasharray="3 4"
|
|
1650
2833
|
stroke-width="1"
|
|
1651
|
-
|
|
1652
|
-
[attr.
|
|
1653
|
-
[attr.
|
|
1654
|
-
[attr.y2]="
|
|
2834
|
+
x1="0"
|
|
2835
|
+
[attr.x2]="effectiveWidth()"
|
|
2836
|
+
[attr.y1]="geometry.start.y"
|
|
2837
|
+
[attr.y2]="geometry.start.y"
|
|
1655
2838
|
/>
|
|
2839
|
+
|
|
2840
|
+
@if (startLabelInfo(); as info) {
|
|
2841
|
+
<text
|
|
2842
|
+
class="text-caption fill-(--subtle-foreground) tabular-nums"
|
|
2843
|
+
data-chart-start-label
|
|
2844
|
+
[attr.text-anchor]="info.placement.anchor"
|
|
2845
|
+
[attr.x]="info.placement.x"
|
|
2846
|
+
[attr.y]="info.placement.y"
|
|
2847
|
+
>
|
|
2848
|
+
{{ info.label }}
|
|
2849
|
+
</text>
|
|
2850
|
+
}
|
|
2851
|
+
|
|
1656
2852
|
<circle
|
|
1657
|
-
class="fill-(--foreground) stroke-(--card)"
|
|
1658
|
-
data-chart-
|
|
2853
|
+
class="fill-(--foreground) stroke-(--card) [paint-order:stroke]"
|
|
2854
|
+
data-chart-end
|
|
1659
2855
|
r="4"
|
|
1660
|
-
stroke-width="
|
|
1661
|
-
[attr.cx]="
|
|
1662
|
-
[attr.cy]="
|
|
2856
|
+
stroke-width="6"
|
|
2857
|
+
[attr.cx]="geometry.end.x"
|
|
2858
|
+
[attr.cy]="geometry.end.y"
|
|
1663
2859
|
/>
|
|
2860
|
+
|
|
2861
|
+
@for (
|
|
2862
|
+
tick of ticks();
|
|
2863
|
+
track tick.t;
|
|
2864
|
+
let index = $index;
|
|
2865
|
+
let count = $count;
|
|
2866
|
+
let first = $first;
|
|
2867
|
+
let last = $last
|
|
2868
|
+
) {
|
|
2869
|
+
<text
|
|
2870
|
+
class="text-caption fill-(--subtle-foreground) tabular-nums"
|
|
2871
|
+
data-chart-axis-tick
|
|
2872
|
+
[attr.text-anchor]="first ? 'start' : last ? 'end' : 'middle'"
|
|
2873
|
+
[attr.x]="tick.x"
|
|
2874
|
+
[attr.y]="effectiveHeight() - 4"
|
|
2875
|
+
[class.hidden]="axisTicks() === 3 && !isCoreTick(index, count)"
|
|
2876
|
+
[class.max-sm:hidden]="axisTicks() === 'auto' && !isCoreTick(index, count)"
|
|
2877
|
+
>
|
|
2878
|
+
{{ axisFormat()(tick.t) }}
|
|
2879
|
+
</text>
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2882
|
+
@if (active(); as point) {
|
|
2883
|
+
<line
|
|
2884
|
+
class="stroke-(--border)"
|
|
2885
|
+
data-chart-crosshair
|
|
2886
|
+
stroke-width="1"
|
|
2887
|
+
y1="0"
|
|
2888
|
+
[attr.x1]="point.x"
|
|
2889
|
+
[attr.x2]="point.x"
|
|
2890
|
+
[attr.y2]="plotHeight()"
|
|
2891
|
+
/>
|
|
2892
|
+
<circle
|
|
2893
|
+
class="fill-(--foreground) stroke-(--card) [paint-order:stroke]"
|
|
2894
|
+
data-chart-active
|
|
2895
|
+
r="5"
|
|
2896
|
+
stroke-width="6"
|
|
2897
|
+
[attr.cx]="point.x"
|
|
2898
|
+
[attr.cy]="point.y"
|
|
2899
|
+
/>
|
|
2900
|
+
}
|
|
1664
2901
|
}
|
|
1665
2902
|
}
|
|
1666
2903
|
</svg>
|
|
1667
2904
|
|
|
1668
2905
|
@if (active(); as point) {
|
|
1669
2906
|
<div
|
|
1670
|
-
class="rounded-container
|
|
2907
|
+
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)]"
|
|
1671
2908
|
data-testid="chart-tooltip"
|
|
1672
2909
|
role="status"
|
|
2910
|
+
[class]="tooltipClasses().box"
|
|
1673
2911
|
[style]="tooltipStyle(point)"
|
|
1674
2912
|
>
|
|
1675
|
-
<p class="font-medium text-(--foreground)"
|
|
1676
|
-
|
|
1677
|
-
|
|
2913
|
+
<p class="font-medium text-(--foreground)" [class]="tooltipClasses().value">
|
|
2914
|
+
{{ tooltipFormat()?.(point) ?? valueFormat()(point.v) }}
|
|
2915
|
+
</p>
|
|
2916
|
+
@if (tooltipDelta()) {
|
|
2917
|
+
<p data-chart-delta [class]="deltaClasses(point)">{{ deltaFormat()(deltaFor(point)) }}</p>
|
|
2918
|
+
}
|
|
2919
|
+
<p class="text-caption text-(--subtle-foreground)" data-chart-date>{{ timeFormat()(point.t) }}</p>
|
|
1678
2920
|
</div>
|
|
1679
2921
|
}
|
|
1680
|
-
|
|
1681
2922
|
@if (points().length > 0) {
|
|
1682
|
-
<
|
|
1683
|
-
<
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
}}
|
|
1687
|
-
</caption>
|
|
1688
|
-
<thead>
|
|
1689
|
-
<tr>
|
|
1690
|
-
<th scope="col">{{ timeColumnLabel() }}</th>
|
|
1691
|
-
<th scope="col">{{ valueColumnLabel() }}</th>
|
|
1692
|
-
</tr>
|
|
1693
|
-
</thead>
|
|
1694
|
-
<tbody>
|
|
1695
|
-
@for (point of points(); track point.t) {
|
|
2923
|
+
<div class="sr-only">
|
|
2924
|
+
<table>
|
|
2925
|
+
<caption [textContent]="label()"></caption>
|
|
2926
|
+
<thead>
|
|
1696
2927
|
<tr>
|
|
1697
|
-
<
|
|
1698
|
-
<
|
|
2928
|
+
<th scope="col">{{ timeColumnLabel() }}</th>
|
|
2929
|
+
<th scope="col">{{ valueColumnLabel() }}</th>
|
|
1699
2930
|
</tr>
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
2931
|
+
</thead>
|
|
2932
|
+
<tbody>
|
|
2933
|
+
@for (point of points(); track point.t) {
|
|
2934
|
+
<tr>
|
|
2935
|
+
<td>{{ timeFormat()(point.t) }}</td>
|
|
2936
|
+
<td>{{ valueFormat()(point.v) }}</td>
|
|
2937
|
+
</tr>
|
|
2938
|
+
}
|
|
2939
|
+
</tbody>
|
|
2940
|
+
</table>
|
|
2941
|
+
</div>
|
|
1703
2942
|
}
|
|
1704
2943
|
</div>
|
|
1705
2944
|
`,
|
|
@@ -1707,11 +2946,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1707
2946
|
class: 'block h-full',
|
|
1708
2947
|
},
|
|
1709
2948
|
}]
|
|
1710
|
-
}], 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 }] }] } });
|
|
2949
|
+
}], 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 }] }], tooltipFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipFormat", 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 }] }] } });
|
|
1711
2950
|
|
|
1712
|
-
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';
|
|
1713
|
-
const
|
|
1714
|
-
const
|
|
2951
|
+
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';
|
|
2952
|
+
const SHEET_CLASSES = 'max-lg:fixed max-lg:inset-x-4 max-lg:top-auto max-lg:w-auto max-lg:bottom-[calc(76px+env(safe-area-inset-bottom))] max-lg:min-w-0 max-lg:p-1.5 max-lg:bg-(--card) max-lg:shadow-[0_12px_32px_rgb(0_0_0/0.2),inset_0_0_0_1px_var(--border)] max-lg:backdrop:bg-[rgb(0_0_0/0.36)] max-lg:transition-[opacity,translate,overlay,display] max-lg:scale-100 max-lg:translate-y-4 max-lg:open:translate-y-0 max-lg:starting:open:scale-100 max-lg:starting:open:translate-y-4';
|
|
2953
|
+
const SHEET_ITEM_CLASSES = 'flex w-full items-center gap-3 lg:pointer-fine:gap-2.5 min-h-12 lg:min-h-11 lg:pointer-fine:min-h-9 px-3 lg:pointer-fine:px-2.5 rounded-[calc(var(--radius-container)-6px)] lg:rounded-[calc(var(--radius-container)-4px)] text-body lg:pointer-fine:text-label hover:bg-(--glow) focus-visible:bg-(--glow) active:bg-(--soft) outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring) [:where(&>svg)]:size-5 [:where(&>svg)]:flex-none lg:[:where(&>svg)]:size-[18px] lg:pointer-fine:[:where(&>svg)]:size-4';
|
|
2954
|
+
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) active:bg-(--soft) outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring) [:where(&>svg)]:size-[18px] [:where(&>svg)]:flex-none pointer-fine:[:where(&>svg)]:size-4';
|
|
2955
|
+
const nextId$1 = (() => {
|
|
1715
2956
|
let count = 0;
|
|
1716
2957
|
return () => `ui-menu-${++count}`;
|
|
1717
2958
|
})();
|
|
@@ -1725,7 +2966,7 @@ class UiMenuItem {
|
|
|
1725
2966
|
destructive = input(false, { ...(ngDevMode ? { debugName: "destructive" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1726
2967
|
#host = inject(ElementRef).nativeElement;
|
|
1727
2968
|
#menu = inject(UiMenu);
|
|
1728
|
-
classes = computed(() => `${ITEM_CLASSES}${this.destructive() ? ' text-(--negative)' : ''}`, /* @ts-ignore */
|
|
2969
|
+
classes = computed(() => `${this.#menu.sheet() ? SHEET_ITEM_CLASSES : ITEM_CLASSES}${this.destructive() ? ' text-(--negative)' : ''}`, /* @ts-ignore */
|
|
1729
2970
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
1730
2971
|
focus() {
|
|
1731
2972
|
this.#host.focus();
|
|
@@ -1752,7 +2993,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1752
2993
|
}]
|
|
1753
2994
|
}], propDecorators: { destructive: [{ type: i0.Input, args: [{ isSignal: true, alias: "destructive", required: false }] }] } });
|
|
1754
2995
|
/**
|
|
1755
|
-
* Secondary actions menu, opened from its trigger through the native Popover API.
|
|
2996
|
+
* Secondary actions menu, opened from its trigger through the native Popover API. With `sheet`, below
|
|
2997
|
+
* 64rem it opens as a bottom action sheet above the tab bar instead of beside its trigger, and
|
|
2998
|
+
* `heading` names what the actions apply to. `width` fixes the outer popover width in pixels (the sheet
|
|
2999
|
+
* always spans the screen below 64rem); without it the menu fits its content.
|
|
1756
3000
|
*
|
|
1757
3001
|
* @example
|
|
1758
3002
|
* <button ui-button size="icon" aria-label="More" [uiMenuTrigger]="menu">...</button>
|
|
@@ -1764,10 +3008,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1764
3008
|
class UiMenu {
|
|
1765
3009
|
label = input.required(/* @ts-ignore */
|
|
1766
3010
|
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
1767
|
-
|
|
3011
|
+
sheet = input(false, { ...(ngDevMode ? { debugName: "sheet" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3012
|
+
heading = input(/* @ts-ignore */
|
|
3013
|
+
...(ngDevMode ? [undefined, { debugName: "heading" }] : /* istanbul ignore next */ []));
|
|
3014
|
+
width = input(undefined, { ...(ngDevMode ? { debugName: "width" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|
|
3015
|
+
menuId = nextId$1();
|
|
1768
3016
|
isOpen = signal(false, /* @ts-ignore */
|
|
1769
3017
|
...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
|
|
1770
|
-
|
|
3018
|
+
hasWidth = computed(() => Number.isFinite(this.width()), /* @ts-ignore */
|
|
3019
|
+
...(ngDevMode ? [{ debugName: "hasWidth" }] : /* istanbul ignore next */ []));
|
|
3020
|
+
widthVar = computed(() => (this.hasWidth() ? `${this.width()}px` : null), /* @ts-ignore */
|
|
3021
|
+
...(ngDevMode ? [{ debugName: "widthVar" }] : /* istanbul ignore next */ []));
|
|
3022
|
+
classes = computed(() => {
|
|
3023
|
+
const width = !this.hasWidth() ? '' : this.sheet() ? ' lg:w-(--ui-menu-width)' : ' w-(--ui-menu-width)';
|
|
3024
|
+
return `${MENU_CLASSES}${this.sheet() ? ` ${SHEET_CLASSES}` : ''}${width}`;
|
|
3025
|
+
}, /* @ts-ignore */
|
|
3026
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
1771
3027
|
items = contentChildren(UiMenuItem, /* @ts-ignore */
|
|
1772
3028
|
...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
1773
3029
|
#host = inject(ElementRef).nativeElement;
|
|
@@ -1778,7 +3034,14 @@ class UiMenu {
|
|
|
1778
3034
|
if (typeof this.#host.showPopover === 'function') {
|
|
1779
3035
|
this.#host.showPopover();
|
|
1780
3036
|
}
|
|
1781
|
-
this.#
|
|
3037
|
+
if (this.#isSheet()) {
|
|
3038
|
+
this.#host.style.position = '';
|
|
3039
|
+
this.#host.style.top = '';
|
|
3040
|
+
this.#host.style.left = '';
|
|
3041
|
+
}
|
|
3042
|
+
else {
|
|
3043
|
+
this.#position(trigger);
|
|
3044
|
+
}
|
|
1782
3045
|
this.items()[0]?.focus();
|
|
1783
3046
|
}
|
|
1784
3047
|
close() {
|
|
@@ -1828,6 +3091,9 @@ class UiMenu {
|
|
|
1828
3091
|
event.preventDefault();
|
|
1829
3092
|
items[nextIndex]?.focus();
|
|
1830
3093
|
}
|
|
3094
|
+
#isSheet() {
|
|
3095
|
+
return this.sheet() && typeof window.matchMedia === 'function' && !window.matchMedia('(min-width: 64rem)').matches;
|
|
3096
|
+
}
|
|
1831
3097
|
#position(trigger) {
|
|
1832
3098
|
const margin = 8;
|
|
1833
3099
|
const triggerRect = trigger.getBoundingClientRect();
|
|
@@ -1841,24 +3107,39 @@ class UiMenu {
|
|
|
1841
3107
|
this.#host.style.transformOrigin = fitsBelow ? 'top right' : 'bottom right';
|
|
1842
3108
|
}
|
|
1843
3109
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1844
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.
|
|
3110
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiMenu, isStandalone: true, selector: "ui-menu", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, sheet: { classPropertyName: "sheet", publicName: "sheet", isSignal: true, isRequired: false, transformFunction: null }, heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "menu", "popover": "auto" }, listeners: { "toggle": "onToggle($event)", "keydown": "onKeydown($event)" }, properties: { "id": "menuId", "style.--ui-menu-width": "widthVar()", "class": "classes()", "attr.aria-label": "label()" } }, queries: [{ propertyName: "items", predicate: UiMenuItem, isSignal: true }], ngImport: i0, template: `
|
|
3111
|
+
@if (sheet() && heading()) {
|
|
3112
|
+
<div aria-hidden="true" class="text-label px-3 pt-2 pb-1.5 leading-[17px] text-(--muted-foreground) lg:hidden">
|
|
3113
|
+
{{ heading() }}
|
|
3114
|
+
</div>
|
|
3115
|
+
}
|
|
3116
|
+
<ng-content />
|
|
3117
|
+
`, isInline: true });
|
|
1845
3118
|
}
|
|
1846
3119
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiMenu, decorators: [{
|
|
1847
3120
|
type: Component,
|
|
1848
3121
|
args: [{
|
|
1849
3122
|
selector: 'ui-menu',
|
|
1850
|
-
template:
|
|
3123
|
+
template: `
|
|
3124
|
+
@if (sheet() && heading()) {
|
|
3125
|
+
<div aria-hidden="true" class="text-label px-3 pt-2 pb-1.5 leading-[17px] text-(--muted-foreground) lg:hidden">
|
|
3126
|
+
{{ heading() }}
|
|
3127
|
+
</div>
|
|
3128
|
+
}
|
|
3129
|
+
<ng-content />
|
|
3130
|
+
`,
|
|
1851
3131
|
host: {
|
|
1852
3132
|
role: 'menu',
|
|
1853
3133
|
popover: 'auto',
|
|
1854
3134
|
'[id]': 'menuId',
|
|
1855
|
-
'[
|
|
3135
|
+
'[style.--ui-menu-width]': 'widthVar()',
|
|
3136
|
+
'[class]': 'classes()',
|
|
1856
3137
|
'[attr.aria-label]': 'label()',
|
|
1857
3138
|
'(toggle)': 'onToggle($event)',
|
|
1858
3139
|
'(keydown)': 'onKeydown($event)',
|
|
1859
3140
|
},
|
|
1860
3141
|
}]
|
|
1861
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], items: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => UiMenuItem), { isSignal: true }] }] } });
|
|
3142
|
+
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], sheet: [{ type: i0.Input, args: [{ isSignal: true, alias: "sheet", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], items: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => UiMenuItem), { isSignal: true }] }] } });
|
|
1862
3143
|
/**
|
|
1863
3144
|
* Opens a `ui-menu` from a trigger element and wires `aria-haspopup`, `aria-expanded` and
|
|
1864
3145
|
* `aria-controls` on it.
|
|
@@ -1895,6 +3176,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1895
3176
|
}]
|
|
1896
3177
|
}], propDecorators: { uiMenuTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiMenuTrigger", required: true }] }] } });
|
|
1897
3178
|
|
|
3179
|
+
/** Track thicknesses. `MeterSize` is derived from this tuple. */
|
|
3180
|
+
const METER_SIZES = ['md', 'sm'];
|
|
3181
|
+
const TRACK_CLASSES = {
|
|
3182
|
+
md: 'h-1.5',
|
|
3183
|
+
sm: 'h-1',
|
|
3184
|
+
};
|
|
1898
3185
|
/** Ramp step used to paint the fill. `MeterTone` is derived from this tuple. */
|
|
1899
3186
|
const METER_TONES = [1, 2, 3, 4, 5, 6];
|
|
1900
3187
|
const TONE_CLASSES = {
|
|
@@ -1921,20 +3208,25 @@ class UiMeter {
|
|
|
1921
3208
|
...(ngDevMode ? [{ debugName: "valueText" }] : /* istanbul ignore next */ []));
|
|
1922
3209
|
tone = input(1, /* @ts-ignore */
|
|
1923
3210
|
...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
|
|
3211
|
+
size = input('md', /* @ts-ignore */
|
|
3212
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
3213
|
+
trackClasses = computed(() => TRACK_CLASSES[this.size()], /* @ts-ignore */
|
|
3214
|
+
...(ngDevMode ? [{ debugName: "trackClasses" }] : /* istanbul ignore next */ []));
|
|
1924
3215
|
percent = computed(() => Math.min(100, Math.max(0, this.value() * 100)), /* @ts-ignore */
|
|
1925
3216
|
...(ngDevMode ? [{ debugName: "percent" }] : /* istanbul ignore next */ []));
|
|
1926
|
-
fillClasses = computed(() => `h-full rounded-
|
|
3217
|
+
fillClasses = computed(() => `h-full rounded-pill ${TONE_CLASSES[this.tone()]}`, /* @ts-ignore */
|
|
1927
3218
|
...(ngDevMode ? [{ debugName: "fillClasses" }] : /* istanbul ignore next */ []));
|
|
1928
3219
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiMeter, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1929
|
-
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: `
|
|
3220
|
+
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 }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
1930
3221
|
<div
|
|
1931
|
-
class="rounded-
|
|
3222
|
+
class="rounded-pill w-full overflow-hidden bg-(--muted)"
|
|
1932
3223
|
role="meter"
|
|
1933
3224
|
[attr.aria-label]="label()"
|
|
1934
3225
|
[attr.aria-valuemax]="1"
|
|
1935
3226
|
[attr.aria-valuemin]="0"
|
|
1936
3227
|
[attr.aria-valuenow]="value()"
|
|
1937
3228
|
[attr.aria-valuetext]="valueText()"
|
|
3229
|
+
[class]="trackClasses()"
|
|
1938
3230
|
>
|
|
1939
3231
|
<div data-testid="meter-fill" [class]="fillClasses()" [style.width.%]="percent()"></div>
|
|
1940
3232
|
</div>
|
|
@@ -1946,22 +3238,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1946
3238
|
selector: 'ui-meter',
|
|
1947
3239
|
template: `
|
|
1948
3240
|
<div
|
|
1949
|
-
class="rounded-
|
|
3241
|
+
class="rounded-pill w-full overflow-hidden bg-(--muted)"
|
|
1950
3242
|
role="meter"
|
|
1951
3243
|
[attr.aria-label]="label()"
|
|
1952
3244
|
[attr.aria-valuemax]="1"
|
|
1953
3245
|
[attr.aria-valuemin]="0"
|
|
1954
3246
|
[attr.aria-valuenow]="value()"
|
|
1955
3247
|
[attr.aria-valuetext]="valueText()"
|
|
3248
|
+
[class]="trackClasses()"
|
|
1956
3249
|
>
|
|
1957
3250
|
<div data-testid="meter-fill" [class]="fillClasses()" [style.width.%]="percent()"></div>
|
|
1958
3251
|
</div>
|
|
1959
3252
|
`,
|
|
1960
3253
|
}]
|
|
1961
|
-
}], 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 }] }] } });
|
|
3254
|
+
}], 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 }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
1962
3255
|
|
|
1963
|
-
const BASE_CLASSES$1 = 'flex items-center gap-3 h-10 px-3 rounded-control text-label font-medium
|
|
3256
|
+
const BASE_CLASSES$1 = 'flex items-center gap-3 h-10 px-3 rounded-control text-label leading-normal 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)';
|
|
1964
3257
|
const ACTIVE_CLASSES = 'bg-(--soft) text-(--foreground)';
|
|
3258
|
+
const IDLE_CLASSES = 'text-(--muted-foreground) active:bg-(--soft)';
|
|
1965
3259
|
/**
|
|
1966
3260
|
* One destination of the sidebar navigation (Portfolio, Holdings, Allocation, Accounts).
|
|
1967
3261
|
*
|
|
@@ -1973,7 +3267,7 @@ const ACTIVE_CLASSES = 'bg-(--soft) text-(--foreground)';
|
|
|
1973
3267
|
*/
|
|
1974
3268
|
class UiNavItem {
|
|
1975
3269
|
active = input(false, { ...(ngDevMode ? { debugName: "active" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1976
|
-
classes = computed(() => `${BASE_CLASSES$1}${this.active() ?
|
|
3270
|
+
classes = computed(() => `${BASE_CLASSES$1} ${this.active() ? ACTIVE_CLASSES : IDLE_CLASSES}`, /* @ts-ignore */
|
|
1977
3271
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
1978
3272
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiNavItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1979
3273
|
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 });
|
|
@@ -1990,7 +3284,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1990
3284
|
}]
|
|
1991
3285
|
}], propDecorators: { active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }] } });
|
|
1992
3286
|
|
|
1993
|
-
const
|
|
3287
|
+
const ROW_SIZES = ['md', 'lg', 'xl', 'card', 'dense'];
|
|
3288
|
+
const ROW_PADDINGS = ['md', 'sm', 'none'];
|
|
3289
|
+
const ROW_GAPS = ['default', 'sm'];
|
|
3290
|
+
const SIZE_CLASSES$1 = {
|
|
3291
|
+
md: 'min-h-14',
|
|
3292
|
+
lg: 'min-h-15',
|
|
3293
|
+
xl: 'min-h-18 pointer-fine:min-h-17',
|
|
3294
|
+
card: 'min-h-17',
|
|
3295
|
+
dense: 'min-h-14 lg:min-h-12',
|
|
3296
|
+
};
|
|
3297
|
+
const SIZE_GAPS = { md: 'gap-2.5', lg: 'gap-2.5', xl: 'gap-3', card: 'gap-2', dense: 'gap-3' };
|
|
3298
|
+
const PADDING_CLASSES = { md: 'px-2.5', sm: 'px-2', none: 'px-0' };
|
|
3299
|
+
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)';
|
|
1994
3300
|
const SELECTED_CLASSES$1 = 'bg-(--soft)';
|
|
1995
3301
|
/**
|
|
1996
3302
|
* Clickable row of a list: a holding, an envelope, an account.
|
|
@@ -2002,10 +3308,16 @@ const SELECTED_CLASSES$1 = 'bg-(--soft)';
|
|
|
2002
3308
|
*/
|
|
2003
3309
|
class UiRow {
|
|
2004
3310
|
selected = input(false, { ...(ngDevMode ? { debugName: "selected" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2005
|
-
|
|
3311
|
+
size = input('md', /* @ts-ignore */
|
|
3312
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
3313
|
+
padding = input('md', /* @ts-ignore */
|
|
3314
|
+
...(ngDevMode ? [{ debugName: "padding" }] : /* istanbul ignore next */ []));
|
|
3315
|
+
gap = input('default', /* @ts-ignore */
|
|
3316
|
+
...(ngDevMode ? [{ debugName: "gap" }] : /* istanbul ignore next */ []));
|
|
3317
|
+
classes = computed(() => `${BASE_CLASSES} ${SIZE_CLASSES$1[this.size()]} ${this.gap() === 'sm' ? 'gap-2' : SIZE_GAPS[this.size()]} ${PADDING_CLASSES[this.padding()]}${this.selected() ? ` ${SELECTED_CLASSES$1}` : ''}`, /* @ts-ignore */
|
|
2006
3318
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
2007
3319
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRow, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2008
|
-
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 });
|
|
3320
|
+
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 }, gap: { classPropertyName: "gap", publicName: "gap", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.aria-current": "selected() ? 'true' : null" } }, ngImport: i0, template: '<ng-content />', isInline: true });
|
|
2009
3321
|
}
|
|
2010
3322
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRow, decorators: [{
|
|
2011
3323
|
type: Component,
|
|
@@ -2017,9 +3329,68 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2017
3329
|
'[attr.aria-current]': "selected() ? 'true' : null",
|
|
2018
3330
|
},
|
|
2019
3331
|
}]
|
|
2020
|
-
}], propDecorators: { selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }] } });
|
|
3332
|
+
}], 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 }] }], gap: [{ type: i0.Input, args: [{ isSignal: true, alias: "gap", required: false }] }] } });
|
|
3333
|
+
/**
|
|
3334
|
+
* Lays out a `ui-row` with a trailing action beside it, such as a "more" icon button: the row takes
|
|
3335
|
+
* the room the action leaves and the action keeps its own size.
|
|
3336
|
+
*
|
|
3337
|
+
* @example
|
|
3338
|
+
* <div uiRowItem>
|
|
3339
|
+
* <a ui-row size="xl" padding="sm" routerLink="/accounts/1">...</a>
|
|
3340
|
+
* <button ui-button variant="quiet" size="icon-sm" aria-label="Account actions">...</button>
|
|
3341
|
+
* </div>
|
|
3342
|
+
*/
|
|
3343
|
+
class UiRowItem {
|
|
3344
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRowItem, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3345
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.7", type: UiRowItem, isStandalone: true, selector: "[uiRowItem]", host: { classAttribute: "flex items-center gap-1 [&>[ui-row]]:w-auto [&>[ui-row]]:min-w-0 [&>[ui-row]]:flex-1 [&>:not([ui-row])]:flex-none" }, ngImport: i0 });
|
|
3346
|
+
}
|
|
3347
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRowItem, decorators: [{
|
|
3348
|
+
type: Directive,
|
|
3349
|
+
args: [{
|
|
3350
|
+
selector: '[uiRowItem]',
|
|
3351
|
+
host: {
|
|
3352
|
+
class: 'flex items-center gap-1 [&>[ui-row]]:w-auto [&>[ui-row]]:min-w-0 [&>[ui-row]]:flex-1 [&>:not([ui-row])]:flex-none',
|
|
3353
|
+
},
|
|
3354
|
+
}]
|
|
3355
|
+
}] });
|
|
3356
|
+
/**
|
|
3357
|
+
* Non-interactive row of a list, separated from the next by a hairline: a passkey with its delete
|
|
3358
|
+
* button, a device, a setting. It is a 72px row (68px from 64rem) with a 12px gap; put it on an
|
|
3359
|
+
* `li` or a `div`. Use `ui-row` instead when the whole row is a link or an action.
|
|
3360
|
+
*
|
|
3361
|
+
* @example
|
|
3362
|
+
* <ul>
|
|
3363
|
+
* <li uiListRow>
|
|
3364
|
+
* <span class="flex-1">MacBook Air</span>
|
|
3365
|
+
* <button ui-button variant="quiet-destructive" size="icon-sm" aria-label="Delete MacBook Air">...</button>
|
|
3366
|
+
* </li>
|
|
3367
|
+
* </ul>
|
|
3368
|
+
*/
|
|
3369
|
+
class UiListRow {
|
|
3370
|
+
ruled = input(true, { ...(ngDevMode ? { debugName: "ruled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3371
|
+
classes = computed(() => `flex min-h-18 items-center gap-3 py-1.5 lg:min-h-17${this.ruled() ? ' shadow-[inset_0_-1px_0_var(--hairline)]' : ''}`, /* @ts-ignore */
|
|
3372
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
3373
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiListRow, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3374
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiListRow, isStandalone: true, selector: "[uiListRow]", inputs: { ruled: { classPropertyName: "ruled", publicName: "ruled", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0 });
|
|
3375
|
+
}
|
|
3376
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiListRow, decorators: [{
|
|
3377
|
+
type: Directive,
|
|
3378
|
+
args: [{
|
|
3379
|
+
selector: '[uiListRow]',
|
|
3380
|
+
host: { '[class]': 'classes()' },
|
|
3381
|
+
}]
|
|
3382
|
+
}], propDecorators: { ruled: [{ type: i0.Input, args: [{ isSignal: true, alias: "ruled", required: false }] }] } });
|
|
2021
3383
|
|
|
2022
|
-
const
|
|
3384
|
+
const nextId = (() => {
|
|
3385
|
+
let count = 0;
|
|
3386
|
+
return () => `ui-segmented-${++count}`;
|
|
3387
|
+
})();
|
|
3388
|
+
const OPTION_CLASSES = "relative z-10 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)";
|
|
3389
|
+
const SEGMENTED_SIZES = ['md', 'sm'];
|
|
3390
|
+
const SIZE_CLASSES = {
|
|
3391
|
+
md: 'h-10 pointer-fine:h-8',
|
|
3392
|
+
sm: 'h-10 pointer-fine:h-[30px]',
|
|
3393
|
+
};
|
|
2023
3394
|
const SELECTED_CLASSES = 'text-(--foreground)';
|
|
2024
3395
|
const UNSELECTED_CLASSES = 'text-(--muted-foreground) hover:text-(--foreground)';
|
|
2025
3396
|
/**
|
|
@@ -2034,8 +3405,12 @@ class UiSegmented {
|
|
|
2034
3405
|
...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
|
|
2035
3406
|
label = input.required(/* @ts-ignore */
|
|
2036
3407
|
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
3408
|
+
showLabel = input(false, { ...(ngDevMode ? { debugName: "showLabel" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3409
|
+
labelId = nextId();
|
|
2037
3410
|
value = model.required(/* @ts-ignore */
|
|
2038
3411
|
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
3412
|
+
size = input('md', /* @ts-ignore */
|
|
3413
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
2039
3414
|
radios = viewChildren('radio', /* @ts-ignore */
|
|
2040
3415
|
...(ngDevMode ? [{ debugName: "radios" }] : /* istanbul ignore next */ []));
|
|
2041
3416
|
thumbIndex = computed(() => {
|
|
@@ -2044,7 +3419,7 @@ class UiSegmented {
|
|
|
2044
3419
|
}, /* @ts-ignore */
|
|
2045
3420
|
...(ngDevMode ? [{ debugName: "thumbIndex" }] : /* istanbul ignore next */ []));
|
|
2046
3421
|
optionClasses(optionValue) {
|
|
2047
|
-
return `${OPTION_CLASSES} ${optionValue === this.value() ? SELECTED_CLASSES : UNSELECTED_CLASSES}`;
|
|
3422
|
+
return `${OPTION_CLASSES} ${SIZE_CLASSES[this.size()]} ${optionValue === this.value() ? SELECTED_CLASSES : UNSELECTED_CLASSES}`;
|
|
2048
3423
|
}
|
|
2049
3424
|
tabIndexFor(optionValue) {
|
|
2050
3425
|
const opts = this.options();
|
|
@@ -2068,37 +3443,45 @@ class UiSegmented {
|
|
|
2068
3443
|
this.radios()[nextIndex]?.nativeElement.focus();
|
|
2069
3444
|
}
|
|
2070
3445
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiSegmented, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2071
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiSegmented, isStandalone: true, selector: "ui-segmented", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { value: "valueChange" }, viewQueries: [{ propertyName: "radios", predicate: ["radio"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
2072
|
-
<div
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
>
|
|
2078
|
-
@if (thumbIndex(); as index) {
|
|
2079
|
-
<span
|
|
2080
|
-
aria-hidden="true"
|
|
2081
|
-
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"
|
|
2082
|
-
data-thumb
|
|
2083
|
-
[style.transform]="'translateX(' + (index - 1) * 100 + '%)'"
|
|
2084
|
-
[style.width]="'calc(100% / ' + options().length + ')'"
|
|
2085
|
-
></span>
|
|
3446
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiSegmented, isStandalone: true, selector: "ui-segmented", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, showLabel: { classPropertyName: "showLabel", publicName: "showLabel", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, viewQueries: [{ propertyName: "radios", predicate: ["radio"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
3447
|
+
<div [class]="showLabel() ? 'flex flex-col gap-1.5' : ''">
|
|
3448
|
+
@if (showLabel()) {
|
|
3449
|
+
<span class="text-label leading-[17px] font-medium text-(--muted-foreground)" [id]="labelId">{{
|
|
3450
|
+
label()
|
|
3451
|
+
}}</span>
|
|
2086
3452
|
}
|
|
3453
|
+
<div
|
|
3454
|
+
class="rounded-control relative grid bg-(--muted) p-0.5"
|
|
3455
|
+
role="radiogroup"
|
|
3456
|
+
[attr.aria-label]="showLabel() ? null : label()"
|
|
3457
|
+
[attr.aria-labelledby]="showLabel() ? labelId : null"
|
|
3458
|
+
[style.grid-template-columns]="'repeat(' + options().length + ', 1fr)'"
|
|
3459
|
+
>
|
|
3460
|
+
@if (thumbIndex(); as index) {
|
|
3461
|
+
<span
|
|
3462
|
+
aria-hidden="true"
|
|
3463
|
+
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"
|
|
3464
|
+
data-thumb
|
|
3465
|
+
[style.transform]="'translateX(' + (index - 1) * 100 + '%)'"
|
|
3466
|
+
[style.width]="'calc((100% - 4px) / ' + options().length + ')'"
|
|
3467
|
+
></span>
|
|
3468
|
+
}
|
|
2087
3469
|
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
3470
|
+
@for (option of options(); track option.value) {
|
|
3471
|
+
<button
|
|
3472
|
+
#radio
|
|
3473
|
+
role="radio"
|
|
3474
|
+
type="button"
|
|
3475
|
+
[attr.aria-checked]="option.value === value()"
|
|
3476
|
+
[attr.tabindex]="tabIndexFor(option.value)"
|
|
3477
|
+
[class]="optionClasses(option.value)"
|
|
3478
|
+
(click)="select(option.value)"
|
|
3479
|
+
(keydown)="onKeydown($event)"
|
|
3480
|
+
>
|
|
3481
|
+
{{ option.label }}
|
|
3482
|
+
</button>
|
|
3483
|
+
}
|
|
3484
|
+
</div>
|
|
2102
3485
|
</div>
|
|
2103
3486
|
`, isInline: true });
|
|
2104
3487
|
}
|
|
@@ -2107,48 +3490,55 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2107
3490
|
args: [{
|
|
2108
3491
|
selector: 'ui-segmented',
|
|
2109
3492
|
template: `
|
|
2110
|
-
<div
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
>
|
|
2116
|
-
@if (thumbIndex(); as index) {
|
|
2117
|
-
<span
|
|
2118
|
-
aria-hidden="true"
|
|
2119
|
-
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"
|
|
2120
|
-
data-thumb
|
|
2121
|
-
[style.transform]="'translateX(' + (index - 1) * 100 + '%)'"
|
|
2122
|
-
[style.width]="'calc(100% / ' + options().length + ')'"
|
|
2123
|
-
></span>
|
|
3493
|
+
<div [class]="showLabel() ? 'flex flex-col gap-1.5' : ''">
|
|
3494
|
+
@if (showLabel()) {
|
|
3495
|
+
<span class="text-label leading-[17px] font-medium text-(--muted-foreground)" [id]="labelId">{{
|
|
3496
|
+
label()
|
|
3497
|
+
}}</span>
|
|
2124
3498
|
}
|
|
3499
|
+
<div
|
|
3500
|
+
class="rounded-control relative grid bg-(--muted) p-0.5"
|
|
3501
|
+
role="radiogroup"
|
|
3502
|
+
[attr.aria-label]="showLabel() ? null : label()"
|
|
3503
|
+
[attr.aria-labelledby]="showLabel() ? labelId : null"
|
|
3504
|
+
[style.grid-template-columns]="'repeat(' + options().length + ', 1fr)'"
|
|
3505
|
+
>
|
|
3506
|
+
@if (thumbIndex(); as index) {
|
|
3507
|
+
<span
|
|
3508
|
+
aria-hidden="true"
|
|
3509
|
+
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"
|
|
3510
|
+
data-thumb
|
|
3511
|
+
[style.transform]="'translateX(' + (index - 1) * 100 + '%)'"
|
|
3512
|
+
[style.width]="'calc((100% - 4px) / ' + options().length + ')'"
|
|
3513
|
+
></span>
|
|
3514
|
+
}
|
|
2125
3515
|
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
3516
|
+
@for (option of options(); track option.value) {
|
|
3517
|
+
<button
|
|
3518
|
+
#radio
|
|
3519
|
+
role="radio"
|
|
3520
|
+
type="button"
|
|
3521
|
+
[attr.aria-checked]="option.value === value()"
|
|
3522
|
+
[attr.tabindex]="tabIndexFor(option.value)"
|
|
3523
|
+
[class]="optionClasses(option.value)"
|
|
3524
|
+
(click)="select(option.value)"
|
|
3525
|
+
(keydown)="onKeydown($event)"
|
|
3526
|
+
>
|
|
3527
|
+
{{ option.label }}
|
|
3528
|
+
</button>
|
|
3529
|
+
}
|
|
3530
|
+
</div>
|
|
2140
3531
|
</div>
|
|
2141
3532
|
`,
|
|
2142
3533
|
}]
|
|
2143
|
-
}], 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 }] }] } });
|
|
3534
|
+
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], showLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLabel", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }, { type: i0.Output, args: ["valueChange"] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], radios: [{ type: i0.ViewChildren, args: ['radio', { isSignal: true }] }] } });
|
|
2144
3535
|
|
|
2145
|
-
const SELECT_CLASSES = 'cursor-pointer pr-
|
|
3536
|
+
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]';
|
|
2146
3537
|
// Spelled out prefix included: Tailwind scans for literal strings, so a prefix applied in code
|
|
2147
|
-
// emits nothing.
|
|
3538
|
+
// emits nothing.
|
|
2148
3539
|
const PICKER_CLASSES = [
|
|
2149
3540
|
'pointer-fine:supports-[appearance:base-select]:[appearance:base-select]',
|
|
2150
3541
|
'pointer-fine:supports-[appearance:base-select]:items-center',
|
|
2151
|
-
'pointer-fine:supports-[appearance:base-select]:pr-3',
|
|
2152
3542
|
'pointer-fine:supports-[appearance:base-select]:[&_option]:cursor-pointer',
|
|
2153
3543
|
'pointer-fine:supports-[appearance:base-select]:[&_option]:rounded-control',
|
|
2154
3544
|
'pointer-fine:supports-[appearance:base-select]:[&_option]:px-2.5',
|
|
@@ -2156,8 +3546,7 @@ const PICKER_CLASSES = [
|
|
|
2156
3546
|
'pointer-fine:supports-[appearance:base-select]:[&_option:hover]:bg-(--soft)',
|
|
2157
3547
|
'pointer-fine:supports-[appearance:base-select]:[&_option:focus]:bg-(--soft)',
|
|
2158
3548
|
'pointer-fine:supports-[appearance:base-select]:[&_option:checked]:font-medium',
|
|
2159
|
-
'[&::picker-icon]:
|
|
2160
|
-
'[&::picker-icon]:text-(--muted-foreground)',
|
|
3549
|
+
'[&::picker-icon]:hidden',
|
|
2161
3550
|
'[&::picker(select)]:[appearance:base-select]',
|
|
2162
3551
|
'[&::picker(select)]:my-1.5',
|
|
2163
3552
|
'[&::picker(select)]:rounded-control',
|
|
@@ -2186,7 +3575,7 @@ class UiSelect {
|
|
|
2186
3575
|
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
2187
3576
|
touched = input(false, /* @ts-ignore */
|
|
2188
3577
|
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
2189
|
-
classes = computed(() => `${CONTROL_BASE_CLASSES} ${SELECT_CLASSES} ${PICKER_CLASSES} ${CONTROL_SIZE_CLASSES[this.size()]}`, /* @ts-ignore */
|
|
3578
|
+
classes = computed(() => `${CONTROL_BASE_CLASSES} bg-(--background) ${SELECT_CLASSES} ${PICKER_CLASSES} ${CONTROL_SIZE_CLASSES[this.size()]}`, /* @ts-ignore */
|
|
2190
3579
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
2191
3580
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiSelect, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2192
3581
|
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 });
|
|
@@ -2203,7 +3592,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2203
3592
|
}], 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 }] }] } });
|
|
2204
3593
|
|
|
2205
3594
|
/** Available skeleton shapes. `SkeletonShape` is derived from this tuple. */
|
|
2206
|
-
const SKELETON_SHAPES = ['text', 'figure', 'row', 'chart', 'ring'];
|
|
3595
|
+
const SKELETON_SHAPES = ['text', 'figure', 'row', 'chart', 'ring', 'dot'];
|
|
2207
3596
|
const LAST_LINE_WIDTH = '62%';
|
|
2208
3597
|
const PULSE_ANIMATION = 'cairn-pulse var(--pulse-duration) var(--ease-out) infinite alternate';
|
|
2209
3598
|
const BAR_CLASSES = 'block rounded-control bg-(--muted)';
|
|
@@ -2222,6 +3611,8 @@ class UiSkeleton {
|
|
|
2222
3611
|
...(ngDevMode ? [{ debugName: "lines" }] : /* istanbul ignore next */ []));
|
|
2223
3612
|
height = input(12, /* @ts-ignore */
|
|
2224
3613
|
...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
|
|
3614
|
+
size = input(232, /* @ts-ignore */
|
|
3615
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
2225
3616
|
animation = PULSE_ANIMATION;
|
|
2226
3617
|
bars = computed(() => {
|
|
2227
3618
|
const count = Math.max(1, this.lines());
|
|
@@ -2229,28 +3620,36 @@ class UiSkeleton {
|
|
|
2229
3620
|
}, /* @ts-ignore */
|
|
2230
3621
|
...(ngDevMode ? [{ debugName: "bars" }] : /* istanbul ignore next */ []));
|
|
2231
3622
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiSkeleton, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2232
|
-
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-
|
|
3623
|
+
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 ('dot') {\n <span class=\"rounded-pill size-3 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"] });
|
|
2233
3624
|
}
|
|
2234
3625
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiSkeleton, decorators: [{
|
|
2235
3626
|
type: Component,
|
|
2236
3627
|
args: [{ selector: 'ui-skeleton', template: `
|
|
2237
3628
|
@switch (shape()) {
|
|
2238
3629
|
@case ('figure') {
|
|
2239
|
-
<span class="${BAR_CLASSES} h-
|
|
3630
|
+
<span class="${BAR_CLASSES} h-10 w-65" [style.animation]="animation"></span>
|
|
2240
3631
|
}
|
|
2241
3632
|
@case ('row') {
|
|
2242
|
-
<span class="flex h-14
|
|
2243
|
-
<span class="
|
|
2244
|
-
|
|
3633
|
+
<span class="flex h-14 items-center justify-between gap-4">
|
|
3634
|
+
<span class="flex min-w-0 flex-1 flex-col gap-1.5">
|
|
3635
|
+
<span class="${BAR_CLASSES} h-4 w-3/5" [style.animation]="animation"></span>
|
|
3636
|
+
<span class="${BAR_CLASSES} h-3 w-20" [style.animation]="animation"></span>
|
|
3637
|
+
</span>
|
|
3638
|
+
<span class="${BAR_CLASSES} h-4 w-[90px] flex-none" [style.animation]="animation"></span>
|
|
2245
3639
|
</span>
|
|
2246
3640
|
}
|
|
2247
3641
|
@case ('chart') {
|
|
2248
|
-
<span class="rounded-
|
|
3642
|
+
<span class="rounded-control min-h-50 w-full flex-1 bg-(--muted)" [style.animation]="animation"></span>
|
|
3643
|
+
}
|
|
3644
|
+
@case ('dot') {
|
|
3645
|
+
<span class="rounded-pill size-3 bg-(--muted)" [style.animation]="animation"></span>
|
|
2249
3646
|
}
|
|
2250
3647
|
@case ('ring') {
|
|
2251
3648
|
<span
|
|
2252
|
-
class="rounded-pill
|
|
3649
|
+
class="rounded-pill shadow-[inset_0_0_0_30px_var(--muted)]"
|
|
2253
3650
|
[style.animation]="animation"
|
|
3651
|
+
[style.height.px]="size()"
|
|
3652
|
+
[style.width.px]="size()"
|
|
2254
3653
|
></span>
|
|
2255
3654
|
}
|
|
2256
3655
|
@default {
|
|
@@ -2268,15 +3667,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2268
3667
|
'aria-hidden': 'true',
|
|
2269
3668
|
class: 'flex flex-col gap-2',
|
|
2270
3669
|
}, styles: ["@keyframes cairn-pulse{0%{opacity:1}to{opacity:.45}}\n"] }]
|
|
2271
|
-
}], 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 }] }] } });
|
|
3670
|
+
}], 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 }] }] } });
|
|
2272
3671
|
|
|
2273
3672
|
/** Available stat sizes. `StatSize` is derived from this tuple. */
|
|
2274
3673
|
const STAT_SIZES = ['hero', 'tile'];
|
|
2275
3674
|
const VALUE_CLASSES = {
|
|
2276
|
-
hero: 'text-display font-semibold text-(--foreground)',
|
|
2277
|
-
tile: 'text-title font-semibold text-(--foreground)',
|
|
3675
|
+
hero: 'text-display font-semibold tracking-(--tracking-display) text-(--foreground)',
|
|
3676
|
+
tile: 'text-title font-semibold tabular-nums text-(--foreground)',
|
|
3677
|
+
};
|
|
3678
|
+
const LABEL_CLASSES = {
|
|
3679
|
+
hero: 'text-label font-medium text-(--muted-foreground)',
|
|
3680
|
+
tile: 'text-label font-normal text-(--muted-foreground)',
|
|
3681
|
+
};
|
|
3682
|
+
const STACK_CLASSES = {
|
|
3683
|
+
hero: 'flex flex-col gap-1',
|
|
3684
|
+
tile: 'flex flex-col gap-0.5',
|
|
2278
3685
|
};
|
|
2279
|
-
const LABEL_CLASSES = 'text-label font-medium text-(--subtle-foreground)';
|
|
2280
3686
|
/**
|
|
2281
3687
|
* Label, figure and a named period of change, at two sizes: a `hero` for a screen's single
|
|
2282
3688
|
* headline number, or a smaller `tile` repeated in a grid. The figure itself, its delta and its
|
|
@@ -2297,21 +3703,24 @@ class UiStat {
|
|
|
2297
3703
|
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
2298
3704
|
size = input('tile', /* @ts-ignore */
|
|
2299
3705
|
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
2300
|
-
labelClasses = LABEL_CLASSES
|
|
3706
|
+
labelClasses = computed(() => LABEL_CLASSES[this.size()], /* @ts-ignore */
|
|
3707
|
+
...(ngDevMode ? [{ debugName: "labelClasses" }] : /* istanbul ignore next */ []));
|
|
3708
|
+
stackClasses = computed(() => STACK_CLASSES[this.size()], /* @ts-ignore */
|
|
3709
|
+
...(ngDevMode ? [{ debugName: "stackClasses" }] : /* istanbul ignore next */ []));
|
|
2301
3710
|
valueClasses = computed(() => VALUE_CLASSES[this.size()], /* @ts-ignore */
|
|
2302
3711
|
...(ngDevMode ? [{ debugName: "valueClasses" }] : /* istanbul ignore next */ []));
|
|
2303
3712
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiStat, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2304
3713
|
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: `
|
|
2305
3714
|
<div class="flex items-start justify-between gap-4">
|
|
2306
|
-
<div class="
|
|
2307
|
-
<dl>
|
|
2308
|
-
<dt [class]="labelClasses">{{ label() }}</dt>
|
|
3715
|
+
<div [class]="stackClasses()">
|
|
3716
|
+
<dl [class]="stackClasses()">
|
|
3717
|
+
<dt [class]="labelClasses()">{{ label() }}</dt>
|
|
2309
3718
|
<dd [class]="valueClasses()">
|
|
2310
3719
|
<ng-content select="[uiStatValue]" />
|
|
2311
3720
|
</dd>
|
|
2312
3721
|
</dl>
|
|
2313
3722
|
|
|
2314
|
-
<div class="text-label flex flex-wrap items-center gap-x-
|
|
3723
|
+
<div class="text-label flex flex-wrap items-center gap-x-1.5 gap-y-1 text-(--muted-foreground)">
|
|
2315
3724
|
<ng-content select="[uiStatDelta]" />
|
|
2316
3725
|
<ng-content select="[uiStatCaption]" />
|
|
2317
3726
|
</div>
|
|
@@ -2327,15 +3736,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2327
3736
|
selector: 'ui-stat',
|
|
2328
3737
|
template: `
|
|
2329
3738
|
<div class="flex items-start justify-between gap-4">
|
|
2330
|
-
<div class="
|
|
2331
|
-
<dl>
|
|
2332
|
-
<dt [class]="labelClasses">{{ label() }}</dt>
|
|
3739
|
+
<div [class]="stackClasses()">
|
|
3740
|
+
<dl [class]="stackClasses()">
|
|
3741
|
+
<dt [class]="labelClasses()">{{ label() }}</dt>
|
|
2333
3742
|
<dd [class]="valueClasses()">
|
|
2334
3743
|
<ng-content select="[uiStatValue]" />
|
|
2335
3744
|
</dd>
|
|
2336
3745
|
</dl>
|
|
2337
3746
|
|
|
2338
|
-
<div class="text-label flex flex-wrap items-center gap-x-
|
|
3747
|
+
<div class="text-label flex flex-wrap items-center gap-x-1.5 gap-y-1 text-(--muted-foreground)">
|
|
2339
3748
|
<ng-content select="[uiStatDelta]" />
|
|
2340
3749
|
<ng-content select="[uiStatCaption]" />
|
|
2341
3750
|
</div>
|
|
@@ -2347,9 +3756,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2347
3756
|
}]
|
|
2348
3757
|
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
2349
3758
|
|
|
2350
|
-
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]";
|
|
3759
|
+
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";
|
|
2351
3760
|
/**
|
|
2352
3761
|
* Native checkbox styled as an iOS-style switch, exposed to assistive technology as `role="switch"`.
|
|
3762
|
+
* 51 by 31 on touch, 40 by 24 with a mouse.
|
|
2353
3763
|
*
|
|
2354
3764
|
* @example
|
|
2355
3765
|
* <input type="checkbox" uiSwitch [checked]="hidden()" (change)="toggle()" aria-label="Hide amounts" />
|
|
@@ -2370,44 +3780,154 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2370
3780
|
}]
|
|
2371
3781
|
}] });
|
|
2372
3782
|
|
|
3783
|
+
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)';
|
|
3784
|
+
const INACTIVE_TAB_CLASSES = 'font-medium text-(--muted-foreground)';
|
|
3785
|
+
const ACTIVE_TAB_CLASSES = 'font-semibold text-(--foreground)';
|
|
3786
|
+
/**
|
|
3787
|
+
* Bottom navigation bar for iPhone: 52px of tabs plus the home indicator's safe area.
|
|
3788
|
+
*
|
|
3789
|
+
* @example
|
|
3790
|
+
* <nav ui-tab-bar>
|
|
3791
|
+
* <a ui-tab [active]="url === '/'" routerLink="/"><lucide-icon tabIcon name="house" />Portfolio</a>
|
|
3792
|
+
* </nav>
|
|
3793
|
+
*/
|
|
3794
|
+
class UiTabBar {
|
|
3795
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTabBar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3796
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.7", type: UiTabBar, isStandalone: true, selector: "nav[ui-tab-bar]", host: { classAttribute: "grid grid-flow-col auto-cols-fr items-stretch bg-(--background)/90 backdrop-blur [@media(prefers-reduced-transparency:reduce)]:bg-(--background) shadow-[inset_0_1px_0_var(--hairline)] pb-[env(safe-area-inset-bottom)]" }, ngImport: i0, template: '<ng-content />', isInline: true });
|
|
3797
|
+
}
|
|
3798
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTabBar, decorators: [{
|
|
3799
|
+
type: Component,
|
|
3800
|
+
args: [{
|
|
3801
|
+
selector: 'nav[ui-tab-bar]',
|
|
3802
|
+
template: '<ng-content />',
|
|
3803
|
+
host: {
|
|
3804
|
+
class: 'grid grid-flow-col auto-cols-fr items-stretch bg-(--background)/90 backdrop-blur [@media(prefers-reduced-transparency:reduce)]:bg-(--background) shadow-[inset_0_1px_0_var(--hairline)] pb-[env(safe-area-inset-bottom)]',
|
|
3805
|
+
},
|
|
3806
|
+
}]
|
|
3807
|
+
}] });
|
|
3808
|
+
/**
|
|
3809
|
+
* One destination of `ui-tab-bar`.
|
|
3810
|
+
*
|
|
3811
|
+
* @example
|
|
3812
|
+
* <a ui-tab active routerLink="/"><lucide-icon tabIcon name="house" />Portfolio</a>
|
|
3813
|
+
*/
|
|
3814
|
+
class UiTab {
|
|
3815
|
+
active = input(false, { ...(ngDevMode ? { debugName: "active" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3816
|
+
classes = computed(() => `${TAB_CLASSES} ${this.active() ? ACTIVE_TAB_CLASSES : INACTIVE_TAB_CLASSES}`, /* @ts-ignore */
|
|
3817
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
3818
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTab, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3819
|
+
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: `
|
|
3820
|
+
<span class="size-6" data-tab-icon><ng-content select="[tabIcon]" /></span>
|
|
3821
|
+
<span class="text-caption leading-none" data-tab-label><ng-content /></span>
|
|
3822
|
+
`, isInline: true });
|
|
3823
|
+
}
|
|
3824
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTab, decorators: [{
|
|
3825
|
+
type: Component,
|
|
3826
|
+
args: [{
|
|
3827
|
+
selector: 'a[ui-tab]',
|
|
3828
|
+
template: `
|
|
3829
|
+
<span class="size-6" data-tab-icon><ng-content select="[tabIcon]" /></span>
|
|
3830
|
+
<span class="text-caption leading-none" data-tab-label><ng-content /></span>
|
|
3831
|
+
`,
|
|
3832
|
+
host: {
|
|
3833
|
+
'[class]': 'classes()',
|
|
3834
|
+
'[attr.aria-current]': "active() ? 'page' : null",
|
|
3835
|
+
},
|
|
3836
|
+
}]
|
|
3837
|
+
}], propDecorators: { active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }] } });
|
|
3838
|
+
|
|
2373
3839
|
/** Breakpoints a secondary column can be held back until. */
|
|
2374
3840
|
const CELL_BREAKPOINTS = ['md', 'lg'];
|
|
3841
|
+
/** Body row heights. */
|
|
3842
|
+
const TABLE_ROWS = ['48', '52', '60'];
|
|
3843
|
+
const ROW_CLASSES = {
|
|
3844
|
+
'48': '[--table-row:3rem]',
|
|
3845
|
+
'52': '[--table-row:3.25rem]',
|
|
3846
|
+
'60': '[--table-row:3.75rem]',
|
|
3847
|
+
};
|
|
2375
3848
|
const FROM_CLASSES = {
|
|
2376
3849
|
md: 'hidden md:table-cell',
|
|
2377
3850
|
lg: 'hidden lg:table-cell',
|
|
2378
3851
|
};
|
|
2379
|
-
const TH_CLASSES = 'h-
|
|
2380
|
-
const TD_CLASSES = 'h-
|
|
2381
|
-
const NUMERIC_CLASSES = 'text-right tabular-nums';
|
|
3852
|
+
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)';
|
|
3853
|
+
const TD_CLASSES = 'h-(--table-row) px-2 align-middle text-body';
|
|
3854
|
+
const NUMERIC_CLASSES = 'text-right tabular-nums whitespace-nowrap';
|
|
2382
3855
|
const TEXTUAL_CLASSES = 'text-left';
|
|
2383
|
-
|
|
3856
|
+
const PRIMARY_CLASSES = 'w-full max-w-0';
|
|
3857
|
+
/**
|
|
3858
|
+
* Styled native table. The rows and cells stay plain <tr> and <td>. `row` sets the height of every
|
|
3859
|
+
* body row, `rule` draws or drops the hairline under the header, `spaced` leaves 4px between the
|
|
3860
|
+
* header and the first row.
|
|
3861
|
+
*
|
|
3862
|
+
* @example
|
|
3863
|
+
* <table uiTable row="60" [rule]="false">
|
|
3864
|
+
*/
|
|
2384
3865
|
class UiTable {
|
|
3866
|
+
row = input('48', /* @ts-ignore */
|
|
3867
|
+
...(ngDevMode ? [{ debugName: "row" }] : /* istanbul ignore next */ []));
|
|
3868
|
+
rule = input(true, { ...(ngDevMode ? { debugName: "rule" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3869
|
+
spaced = input(false, { ...(ngDevMode ? { debugName: "spaced" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3870
|
+
classes = computed(() => [
|
|
3871
|
+
'w-full border-separate border-spacing-0',
|
|
3872
|
+
ROW_CLASSES[this.row()],
|
|
3873
|
+
this.rule() ? '[--table-rule:inset_0_-1px_0_var(--hairline)]' : '[--table-rule:none]',
|
|
3874
|
+
this.spaced() ? '[--table-head-gap:0.25rem]' : '[--table-head-gap:0px]',
|
|
3875
|
+
].join(' '), /* @ts-ignore */
|
|
3876
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
2385
3877
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTable, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2386
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "
|
|
3878
|
+
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 });
|
|
2387
3879
|
}
|
|
2388
3880
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTable, decorators: [{
|
|
2389
3881
|
type: Directive,
|
|
2390
3882
|
args: [{
|
|
2391
3883
|
selector: 'table[uiTable]',
|
|
2392
3884
|
host: {
|
|
2393
|
-
class: '
|
|
3885
|
+
'[class]': 'classes()',
|
|
2394
3886
|
},
|
|
2395
3887
|
}]
|
|
3888
|
+
}], 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 }] }] } });
|
|
3889
|
+
/** Body of one group of rows: leaves a 4px tail after its last row. */
|
|
3890
|
+
class UiGroup {
|
|
3891
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3892
|
+
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 });
|
|
3893
|
+
}
|
|
3894
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiGroup, decorators: [{
|
|
3895
|
+
type: Directive,
|
|
3896
|
+
args: [{
|
|
3897
|
+
selector: 'tbody[uiGroup]',
|
|
3898
|
+
host: { class: 'after:table-row after:h-1 after:content-[""]' },
|
|
3899
|
+
}]
|
|
2396
3900
|
}] });
|
|
2397
3901
|
/**
|
|
2398
|
-
* Body or group row.
|
|
2399
|
-
*
|
|
3902
|
+
* Body or group row. An ordinary row glows on hover and takes the soft fill when `selected`; an
|
|
3903
|
+
* `interactive` row (one that opens something) also presses to the soft fill. A row with no action keeps a
|
|
3904
|
+
* plain name: `<td uiTd primary class="truncate font-medium">`.
|
|
3905
|
+
* `group` marks the row that holds a group band: it carries no hover state.
|
|
2400
3906
|
*
|
|
2401
3907
|
* @example
|
|
2402
|
-
* <tr uiTr>...
|
|
2403
|
-
* <tr uiTr group>...
|
|
3908
|
+
* <tr uiTr [selected]="open">...
|
|
3909
|
+
* <tr uiTr group><td ui-group-cell name="Brokerage">...
|
|
2404
3910
|
*/
|
|
2405
3911
|
class UiTr {
|
|
2406
3912
|
group = input(false, { ...(ngDevMode ? { debugName: "group" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2407
|
-
|
|
3913
|
+
selected = input(false, { ...(ngDevMode ? { debugName: "selected" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3914
|
+
interactive = input(false, { ...(ngDevMode ? { debugName: "interactive" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3915
|
+
classes = computed(() => {
|
|
3916
|
+
if (this.group()) {
|
|
3917
|
+
return '';
|
|
3918
|
+
}
|
|
3919
|
+
return [
|
|
3920
|
+
'relative [&>td:first-child]:rounded-l-control [&>td:last-child]:rounded-r-control',
|
|
3921
|
+
this.selected() ? '[&>td]:bg-(--soft)' : '',
|
|
3922
|
+
'hover:[&>td]:bg-(--glow)',
|
|
3923
|
+
this.interactive() ? 'active:[&>td]:bg-(--soft)' : '',
|
|
3924
|
+
]
|
|
3925
|
+
.filter(Boolean)
|
|
3926
|
+
.join(' ');
|
|
3927
|
+
}, /* @ts-ignore */
|
|
2408
3928
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
2409
3929
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTr, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2410
|
-
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 });
|
|
3930
|
+
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 });
|
|
2411
3931
|
}
|
|
2412
3932
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTr, decorators: [{
|
|
2413
3933
|
type: Directive,
|
|
@@ -2415,25 +3935,42 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2415
3935
|
selector: 'tr[uiTr]',
|
|
2416
3936
|
host: {
|
|
2417
3937
|
'[class]': 'classes()',
|
|
3938
|
+
'[attr.aria-selected]': 'selected() ? "true" : null',
|
|
2418
3939
|
},
|
|
2419
3940
|
}]
|
|
2420
|
-
}], propDecorators: { group: [{ type: i0.Input, args: [{ isSignal: true, alias: "group", required: false }] }] } });
|
|
2421
|
-
const cellClasses = (base, numeric,
|
|
3941
|
+
}], 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 }] }] } });
|
|
3942
|
+
const cellClasses = (base, numeric, primary, from, secondary) => {
|
|
3943
|
+
const breakpoint = from ?? (secondary ? 'lg' : null);
|
|
3944
|
+
return [
|
|
3945
|
+
base,
|
|
3946
|
+
numeric ? NUMERIC_CLASSES : TEXTUAL_CLASSES,
|
|
3947
|
+
primary ? PRIMARY_CLASSES : '',
|
|
3948
|
+
breakpoint ? FROM_CLASSES[breakpoint] : '',
|
|
3949
|
+
]
|
|
3950
|
+
.filter(Boolean)
|
|
3951
|
+
.join(' ');
|
|
3952
|
+
};
|
|
2422
3953
|
/**
|
|
2423
|
-
* Column header. `numeric` right-aligns and lines the digits up; `
|
|
2424
|
-
*
|
|
3954
|
+
* Column header, centred in its 36px. `numeric` right-aligns and lines the digits up; `secondary`
|
|
3955
|
+
* (or `from`) holds a column back until the viewport is wide enough for it; `primary` makes it
|
|
3956
|
+
* the column that absorbs the free width and truncates; `tall` is a 40px header; `width` fixes the column width and keeps it from shrinking.
|
|
2425
3957
|
*
|
|
2426
3958
|
* @example
|
|
2427
|
-
* <th uiTh numeric
|
|
3959
|
+
* <th uiTh numeric secondary width="108px">Quantity</th>
|
|
2428
3960
|
*/
|
|
2429
3961
|
class UiTh {
|
|
3962
|
+
width = input(null, /* @ts-ignore */
|
|
3963
|
+
...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
|
|
2430
3964
|
numeric = input(false, { ...(ngDevMode ? { debugName: "numeric" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3965
|
+
primary = input(false, { ...(ngDevMode ? { debugName: "primary" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3966
|
+
secondary = input(false, { ...(ngDevMode ? { debugName: "secondary" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3967
|
+
tall = input(false, { ...(ngDevMode ? { debugName: "tall" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2431
3968
|
from = input(null, /* @ts-ignore */
|
|
2432
3969
|
...(ngDevMode ? [{ debugName: "from" }] : /* istanbul ignore next */ []));
|
|
2433
|
-
classes = computed(() => cellClasses(TH_CLASSES
|
|
3970
|
+
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 */
|
|
2434
3971
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
2435
3972
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTh, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2436
|
-
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 });
|
|
3973
|
+
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 });
|
|
2437
3974
|
}
|
|
2438
3975
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTh, decorators: [{
|
|
2439
3976
|
type: Directive,
|
|
@@ -2441,18 +3978,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2441
3978
|
selector: 'th[uiTh]',
|
|
2442
3979
|
host: {
|
|
2443
3980
|
'[class]': 'classes()',
|
|
3981
|
+
'[style.width]': 'width()',
|
|
3982
|
+
'[style.min-width]': 'width()',
|
|
2444
3983
|
},
|
|
2445
3984
|
}]
|
|
2446
|
-
}], propDecorators: { numeric: [{ type: i0.Input, args: [{ isSignal: true, alias: "numeric", required: false }] }], from: [{ type: i0.Input, args: [{ isSignal: true, alias: "from", required: false }] }] } });
|
|
2447
|
-
/** Body cell. Same
|
|
3985
|
+
}], 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 }] }] } });
|
|
3986
|
+
/** Body cell. Same inputs as `UiTh` (bar `tall` and `width`), and they must be set on both to match. */
|
|
2448
3987
|
class UiTd {
|
|
2449
3988
|
numeric = input(false, { ...(ngDevMode ? { debugName: "numeric" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3989
|
+
primary = input(false, { ...(ngDevMode ? { debugName: "primary" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3990
|
+
secondary = input(false, { ...(ngDevMode ? { debugName: "secondary" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2450
3991
|
from = input(null, /* @ts-ignore */
|
|
2451
3992
|
...(ngDevMode ? [{ debugName: "from" }] : /* istanbul ignore next */ []));
|
|
2452
|
-
classes = computed(() => cellClasses(TD_CLASSES, this.numeric(), this.from()), /* @ts-ignore */
|
|
3993
|
+
classes = computed(() => cellClasses(TD_CLASSES, this.numeric(), this.primary(), this.from(), this.secondary()), /* @ts-ignore */
|
|
2453
3994
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
2454
3995
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTd, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2455
|
-
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 });
|
|
3996
|
+
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 });
|
|
2456
3997
|
}
|
|
2457
3998
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTd, decorators: [{
|
|
2458
3999
|
type: Directive,
|
|
@@ -2462,62 +4003,144 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2462
4003
|
'[class]': 'classes()',
|
|
2463
4004
|
},
|
|
2464
4005
|
}]
|
|
2465
|
-
}], propDecorators: { numeric: [{ type: i0.Input, args: [{ isSignal: true, alias: "numeric", required: false }] }], from: [{ type: i0.Input, args: [{ isSignal: true, alias: "from", required: false }] }] } });
|
|
2466
|
-
|
|
2467
|
-
const
|
|
2468
|
-
const ACTIVE_TAB_CLASSES = 'font-semibold text-(--foreground)';
|
|
4006
|
+
}], 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 }] }] } });
|
|
4007
|
+
/** Group band sizes. */
|
|
4008
|
+
const GROUP_SIZES = ['md', 'lg'];
|
|
2469
4009
|
/**
|
|
2470
|
-
*
|
|
4010
|
+
* The band that opens a group of rows: name in 600 (a heading), meta beside it, the projected
|
|
4011
|
+
* total pinned to the right. Spans the whole row through `colspan`.
|
|
2471
4012
|
*
|
|
2472
4013
|
* @example
|
|
2473
|
-
* <
|
|
2474
|
-
* <a ui-tab [active]="url === '/'" routerLink="/"><lucide-icon tabIcon name="house" />Portfolio</a>
|
|
2475
|
-
* </nav>
|
|
4014
|
+
* <tr uiTr group><td ui-group-cell colspan="4" name="Brokerage" meta="Savings plan">...total...</td></tr>
|
|
2476
4015
|
*/
|
|
2477
|
-
class
|
|
2478
|
-
|
|
2479
|
-
|
|
4016
|
+
class UiGroupCell {
|
|
4017
|
+
name = input.required(/* @ts-ignore */
|
|
4018
|
+
...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
|
|
4019
|
+
meta = input(/* @ts-ignore */
|
|
4020
|
+
...(ngDevMode ? [undefined, { debugName: "meta" }] : /* istanbul ignore next */ []));
|
|
4021
|
+
size = input('md', /* @ts-ignore */
|
|
4022
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
4023
|
+
hostClasses = computed(() => `px-0 ${this.size() === 'lg' ? 'pt-3' : 'pt-2.5'} pb-1 align-middle text-body`, /* @ts-ignore */
|
|
4024
|
+
...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
|
|
4025
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiGroupCell, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4026
|
+
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: `
|
|
4027
|
+
<div
|
|
4028
|
+
class="rounded-control flex items-center justify-between gap-4 bg-(--muted) px-2"
|
|
4029
|
+
[class]="size() === 'lg' ? 'min-h-12' : 'min-h-11'"
|
|
4030
|
+
>
|
|
4031
|
+
<div class="flex min-w-0 items-baseline gap-3">
|
|
4032
|
+
<h2 class="text-body m-0 font-semibold whitespace-nowrap outline-none" data-group-heading tabindex="-1">
|
|
4033
|
+
{{ name() }}
|
|
4034
|
+
</h2>
|
|
4035
|
+
@if (meta()) {
|
|
4036
|
+
<span class="text-label truncate text-(--muted-foreground)">{{ meta() }}</span>
|
|
4037
|
+
}
|
|
4038
|
+
</div>
|
|
4039
|
+
<span class="font-semibold whitespace-nowrap tabular-nums"><ng-content /></span>
|
|
4040
|
+
</div>
|
|
4041
|
+
`, isInline: true });
|
|
2480
4042
|
}
|
|
2481
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type:
|
|
4043
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiGroupCell, decorators: [{
|
|
2482
4044
|
type: Component,
|
|
2483
4045
|
args: [{
|
|
2484
|
-
selector: '
|
|
2485
|
-
template: '<ng-content />',
|
|
4046
|
+
selector: 'td[ui-group-cell]',
|
|
2486
4047
|
host: {
|
|
2487
|
-
|
|
4048
|
+
'[class]': 'hostClasses()',
|
|
4049
|
+
},
|
|
4050
|
+
template: `
|
|
4051
|
+
<div
|
|
4052
|
+
class="rounded-control flex items-center justify-between gap-4 bg-(--muted) px-2"
|
|
4053
|
+
[class]="size() === 'lg' ? 'min-h-12' : 'min-h-11'"
|
|
4054
|
+
>
|
|
4055
|
+
<div class="flex min-w-0 items-baseline gap-3">
|
|
4056
|
+
<h2 class="text-body m-0 font-semibold whitespace-nowrap outline-none" data-group-heading tabindex="-1">
|
|
4057
|
+
{{ name() }}
|
|
4058
|
+
</h2>
|
|
4059
|
+
@if (meta()) {
|
|
4060
|
+
<span class="text-label truncate text-(--muted-foreground)">{{ meta() }}</span>
|
|
4061
|
+
}
|
|
4062
|
+
</div>
|
|
4063
|
+
<span class="font-semibold whitespace-nowrap tabular-nums"><ng-content /></span>
|
|
4064
|
+
</div>
|
|
4065
|
+
`,
|
|
4066
|
+
}]
|
|
4067
|
+
}], 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 }] }] } });
|
|
4068
|
+
/**
|
|
4069
|
+
* Makes a link or button the way into its row. By default an invisible layer stretches over the
|
|
4070
|
+
* whole row, so the row is one target for the pointer, the keyboard and a screen reader, and its
|
|
4071
|
+
* focus ring wraps the row. With `[stretch]="false"` only the name is the
|
|
4072
|
+
* target: it underlines on hover and takes its own ring. `current` marks the open line.
|
|
4073
|
+
*
|
|
4074
|
+
* @example
|
|
4075
|
+
* <td uiTd primary><a uiRowLink href="/lines/42">Ferrari</a></td>
|
|
4076
|
+
* <td uiTd primary><a uiRowLink [stretch]="false" href="/accounts/3">Brokerage</a></td>
|
|
4077
|
+
*/
|
|
4078
|
+
class UiRowLink {
|
|
4079
|
+
stretch = input(true, { ...(ngDevMode ? { debugName: "stretch" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
4080
|
+
current = input(false, { ...(ngDevMode ? { debugName: "current" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
4081
|
+
classes = computed(() => this.stretch()
|
|
4082
|
+
? '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)'
|
|
4083
|
+
: '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 */
|
|
4084
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
4085
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRowLink, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
4086
|
+
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 });
|
|
4087
|
+
}
|
|
4088
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRowLink, decorators: [{
|
|
4089
|
+
type: Directive,
|
|
4090
|
+
args: [{
|
|
4091
|
+
selector: 'a[uiRowLink], button[uiRowLink]',
|
|
4092
|
+
host: {
|
|
4093
|
+
'[class]': 'classes()',
|
|
4094
|
+
'[attr.aria-current]': 'current() ? "true" : null',
|
|
2488
4095
|
},
|
|
2489
4096
|
}]
|
|
4097
|
+
}], propDecorators: { stretch: [{ type: i0.Input, args: [{ isSignal: true, alias: "stretch", required: false }] }], current: [{ type: i0.Input, args: [{ isSignal: true, alias: "current", required: false }] }] } });
|
|
4098
|
+
/** A control in another cell of a stretched-link row: lifts it above the layer that covers the row. */
|
|
4099
|
+
class UiRowAction {
|
|
4100
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRowAction, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
4101
|
+
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 });
|
|
4102
|
+
}
|
|
4103
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRowAction, decorators: [{
|
|
4104
|
+
type: Directive,
|
|
4105
|
+
args: [{
|
|
4106
|
+
selector: '[uiRowAction]',
|
|
4107
|
+
host: { class: 'relative z-1' },
|
|
4108
|
+
}]
|
|
2490
4109
|
}] });
|
|
4110
|
+
/** Tones of a subtitle: subtle (default), `--stale` at 500, or the color of the cell. */
|
|
4111
|
+
const SUB_TONES = ['subtle', 'stale', 'inherit'];
|
|
4112
|
+
const SUB_TONE_CLASSES = {
|
|
4113
|
+
subtle: 'font-normal text-(--subtle-foreground)',
|
|
4114
|
+
stale: 'font-medium text-(--stale)',
|
|
4115
|
+
inherit: 'font-normal',
|
|
4116
|
+
};
|
|
2491
4117
|
/**
|
|
2492
|
-
*
|
|
4118
|
+
* A second line under a cell's main text. `narrow` shows it only under 1024px, where it carries
|
|
4119
|
+
* the quantity, average cost and quote that were held back. Its amounts go through `ui-amount`
|
|
4120
|
+
* so they mask.
|
|
2493
4121
|
*
|
|
2494
4122
|
* @example
|
|
2495
|
-
* <
|
|
4123
|
+
* <span uiCellSub narrow>10 × 421.26 € · cost 388.10 €</span>
|
|
4124
|
+
* <span uiCellSub tone="stale">Quote of 24/09</span>
|
|
2496
4125
|
*/
|
|
2497
|
-
class
|
|
2498
|
-
|
|
2499
|
-
|
|
4126
|
+
class UiCellSub {
|
|
4127
|
+
narrow = input(false, { ...(ngDevMode ? { debugName: "narrow" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
4128
|
+
tone = input('subtle', /* @ts-ignore */
|
|
4129
|
+
...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
|
|
4130
|
+
classes = computed(() => `${this.narrow() ? 'lg:hidden ' : ''}block truncate text-caption tabular-nums ${SUB_TONE_CLASSES[this.tone()]}`, /* @ts-ignore */
|
|
2500
4131
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
2501
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type:
|
|
2502
|
-
static
|
|
2503
|
-
<span class="size-6" data-tab-icon><ng-content select="[tabIcon]" /></span>
|
|
2504
|
-
<span class="text-caption" data-tab-label><ng-content /></span>
|
|
2505
|
-
`, isInline: true });
|
|
4132
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiCellSub, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
4133
|
+
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 });
|
|
2506
4134
|
}
|
|
2507
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type:
|
|
2508
|
-
type:
|
|
4135
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiCellSub, decorators: [{
|
|
4136
|
+
type: Directive,
|
|
2509
4137
|
args: [{
|
|
2510
|
-
selector: '
|
|
2511
|
-
template: `
|
|
2512
|
-
<span class="size-6" data-tab-icon><ng-content select="[tabIcon]" /></span>
|
|
2513
|
-
<span class="text-caption" data-tab-label><ng-content /></span>
|
|
2514
|
-
`,
|
|
4138
|
+
selector: '[uiCellSub]',
|
|
2515
4139
|
host: {
|
|
2516
4140
|
'[class]': 'classes()',
|
|
2517
|
-
'[attr.aria-current]': "active() ? 'page' : null",
|
|
2518
4141
|
},
|
|
2519
4142
|
}]
|
|
2520
|
-
}], propDecorators: {
|
|
4143
|
+
}], propDecorators: { narrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "narrow", required: false }] }], tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }] } });
|
|
2521
4144
|
|
|
2522
4145
|
/*
|
|
2523
4146
|
* Public API surface of the ui library.
|
|
@@ -2527,5 +4150,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2527
4150
|
* Generated bundle index. Do not edit.
|
|
2528
4151
|
*/
|
|
2529
4152
|
|
|
2530
|
-
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 };
|
|
4153
|
+
export { ALERT_VARIANTS, AMOUNT_MASKINGS, AMOUNT_NUMERICS, ASYNC_ALIGNS, ASYNC_STATES, ASYNC_VARIANTS, AVATAR_SIZES, BACK_LINK_SIZES, BADGE_SIZES, BADGE_VARIANTS, BUTTON_SIZES, BUTTON_VARIANTS, CARD_PADDINGS, CARD_SURFACES, CARD_VARIANTS, CELL_BREAKPOINTS, CONTROL_SIZES, CONTROL_SURFACES, DELTA_EMPHASES, DELTA_SIZES, DELTA_WEIGHTS, DIALOG_LAYOUTS, DIALOG_WIDTHS, FACT_SIZES, FACT_SUB_TONES, GROUP_SIZES, METER_SIZES, METER_TONES, ROW_GAPS, ROW_PADDINGS, ROW_SIZES, SEGMENTED_SIZES, SKELETON_SHAPES, STAT_SIZES, SUB_TONES, TABLE_ROWS, UI_AMOUNT_MASKED, UiActionBar, UiAlert, UiAmount, UiAsync, UiAvatar, UiAvatarLink, UiBackLink, UiBadge, UiButton, UiCard, UiCellSub, UiChoiceChips, UiDelta, UiDialog, UiDonut, UiExternalLink, UiFact, UiFacts, UiField, UiFieldLeading, UiFieldTrailing, UiFilterChips, UiGroup, UiGroupCell, UiInput, UiLineChart, UiListRow, UiMenu, UiMenuItem, UiMenuTrigger, UiMeter, UiNavItem, UiRow, UiRowAction, UiRowItem, UiRowLink, UiSegmented, UiSelect, UiSkeleton, UiStat, UiSwitch, UiTab, UiTabBar, UiTable, UiTd, UiTextarea, UiTh, UiTr, formatAmount };
|
|
2531
4154
|
//# sourceMappingURL=joanroucoux-cairn-ui.mjs.map
|