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