@joanroucoux/cairn-ui 0.6.5 → 0.7.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/CHANGELOG.md +63 -0
- package/fesm2022/joanroucoux-cairn-ui.mjs +1105 -173
- package/fesm2022/joanroucoux-cairn-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/styles/motion.css +83 -0
- package/styles/theme.css +6 -0
- package/styles/tokens.css +5 -0
- package/types/joanroucoux-cairn-ui.d.ts +190 -13
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
|
|
1
2
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Component, input, computed, InjectionToken, signal,
|
|
3
|
-
import { NgTemplateOutlet } from '@angular/common';
|
|
3
|
+
import { inject, ElementRef, DestroyRef, afterNextRender, Component, input, booleanAttribute, computed, InjectionToken, signal, LOCALE_ID, effect, untracked, output, Directive, forwardRef, model, viewChildren, afterRenderEffect, contentChild, viewChild, numberAttribute, contentChildren, Injectable } from '@angular/core';
|
|
4
4
|
import { scaleLinear } from 'd3-scale';
|
|
5
5
|
import { curveMonotoneX, line } from 'd3-shape';
|
|
6
6
|
|
|
7
|
+
const HEIGHT_PROPERTY = '--action-bar-height';
|
|
7
8
|
/**
|
|
8
9
|
* Bar of actions fixed above the tab bar on iPhone: the primary actions of a detail screen, within
|
|
9
10
|
* thumb reach. It sits 52px plus the safe area above the bottom edge, so it clears `ui-tab-bar`, and
|
|
10
11
|
* it is hidden from `64rem`, where the same actions live in the page itself. Its children share the
|
|
11
|
-
* width equally.
|
|
12
|
+
* width equally. While it is on the page it publishes its height as `--action-bar-height` on the
|
|
13
|
+
* root element, which `ui-toaster` adds to its offset so a confirmation never covers the actions.
|
|
12
14
|
*
|
|
13
15
|
* @example
|
|
14
16
|
* <ui-action-bar>
|
|
@@ -17,6 +19,21 @@ import { curveMonotoneX, line } from 'd3-shape';
|
|
|
17
19
|
* </ui-action-bar>
|
|
18
20
|
*/
|
|
19
21
|
class UiActionBar {
|
|
22
|
+
constructor() {
|
|
23
|
+
const host = inject(ElementRef).nativeElement;
|
|
24
|
+
const root = inject(DOCUMENT).documentElement;
|
|
25
|
+
const destroyRef = inject(DestroyRef);
|
|
26
|
+
const publish = () => root.style.setProperty(HEIGHT_PROPERTY, `${host.offsetHeight}px`);
|
|
27
|
+
afterNextRender(() => {
|
|
28
|
+
publish();
|
|
29
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
30
|
+
const observer = new ResizeObserver(publish);
|
|
31
|
+
observer.observe(host);
|
|
32
|
+
destroyRef.onDestroy(() => observer.disconnect());
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
destroyRef.onDestroy(() => root.style.removeProperty(HEIGHT_PROPERTY));
|
|
36
|
+
}
|
|
20
37
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiActionBar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
21
38
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.7", type: UiActionBar, isStandalone: true, selector: "ui-action-bar", host: { classAttribute: "fixed inset-x-0 bottom-[calc(52px+env(safe-area-inset-bottom))] z-40 grid grid-flow-col auto-cols-fr gap-2 bg-(--background) px-(--gutter) py-3 shadow-[0_-1px_0_var(--hairline)] lg:hidden" }, ngImport: i0, template: '<ng-content />', isInline: true });
|
|
22
39
|
}
|
|
@@ -29,16 +46,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
29
46
|
class: 'fixed inset-x-0 bottom-[calc(52px+env(safe-area-inset-bottom))] z-40 grid grid-flow-col auto-cols-fr gap-2 bg-(--background) px-(--gutter) py-3 shadow-[0_-1px_0_var(--hairline)] lg:hidden',
|
|
30
47
|
},
|
|
31
48
|
}]
|
|
32
|
-
}] });
|
|
49
|
+
}], ctorParameters: () => [] });
|
|
33
50
|
|
|
34
51
|
const ALERT_VARIANTS = ['error', 'warning'];
|
|
35
|
-
const BASE_CLASSES$
|
|
52
|
+
const BASE_CLASSES$9 = 'flex items-start gap-2.5 text-left text-label';
|
|
36
53
|
const VARIANT_CLASSES$3 = {
|
|
37
54
|
error: 'rounded-control bg-(--card) px-3.5 py-3 shadow-[inset_0_0_0_1px_var(--border)]',
|
|
38
55
|
warning: 'text-(--foreground)',
|
|
39
56
|
};
|
|
40
57
|
/**
|
|
41
58
|
* Inline message explaining a failure or a consequence: an icon, an optional heading and a text.
|
|
59
|
+
* It fades in when it appears; set `[fadeIn]="false"` on an alert that is part of the page as it
|
|
60
|
+
* opens (an error state after a load), which shows without motion.
|
|
42
61
|
*
|
|
43
62
|
* @example
|
|
44
63
|
* <ui-alert heading="Sign-in failed">Try again.</ui-alert>
|
|
@@ -48,10 +67,11 @@ class UiAlert {
|
|
|
48
67
|
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
49
68
|
heading = input(/* @ts-ignore */
|
|
50
69
|
...(ngDevMode ? [undefined, { debugName: "heading" }] : /* istanbul ignore next */ []));
|
|
51
|
-
|
|
70
|
+
fadeIn = input(true, { ...(ngDevMode ? { debugName: "fadeIn" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
71
|
+
classes = computed(() => `${BASE_CLASSES$9} ${VARIANT_CLASSES$3[this.variant()]}${this.fadeIn() ? ' ui-enter-fade' : ''}`, /* @ts-ignore */
|
|
52
72
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
53
73
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAlert, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
54
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiAlert, isStandalone: true, selector: "ui-alert", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.role": "variant() === 'warning' ? 'status' : 'alert'" } }, ngImport: i0, template: `
|
|
74
|
+
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 }, fadeIn: { classPropertyName: "fadeIn", publicName: "fadeIn", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "animate.leave": "ui-leave-fade" }, properties: { "class": "classes()", "attr.role": "variant() === 'warning' ? 'status' : 'alert'" } }, ngImport: i0, template: `
|
|
55
75
|
@if (variant() === 'warning') {
|
|
56
76
|
<svg
|
|
57
77
|
aria-hidden="true"
|
|
@@ -141,11 +161,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
141
161
|
</div>
|
|
142
162
|
`,
|
|
143
163
|
host: {
|
|
164
|
+
'animate.leave': 'ui-leave-fade',
|
|
144
165
|
'[class]': 'classes()',
|
|
145
166
|
'[attr.role]': "variant() === 'warning' ? 'status' : 'alert'",
|
|
146
167
|
},
|
|
147
168
|
}]
|
|
148
|
-
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }] } });
|
|
169
|
+
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], fadeIn: [{ type: i0.Input, args: [{ isSignal: true, alias: "fadeIn", required: false }] }] } });
|
|
149
170
|
|
|
150
171
|
const MINUS = '−';
|
|
151
172
|
const EM_DASH = '—';
|
|
@@ -252,13 +273,66 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
252
273
|
}]
|
|
253
274
|
}], 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 }] }] } });
|
|
254
275
|
|
|
276
|
+
const SKELETON_DELAY_MS = 150;
|
|
277
|
+
const SKELETON_MIN_MS = 400;
|
|
278
|
+
/**
|
|
279
|
+
* Turns the live state of a call into the state to draw: `loading` only appears once the call has
|
|
280
|
+
* lasted 150 ms and, once shown, stays at least 400 ms, so a fast call never flashes a skeleton and a
|
|
281
|
+
* slow one never blinks. Until then the previous state stays on screen (a reload keeps its content);
|
|
282
|
+
* `null` means nothing to draw yet, for a first load still under 150 ms. Call it in an injection context.
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* protected readonly shown = delayedState(this.state);
|
|
286
|
+
*/
|
|
287
|
+
function delayedState(source) {
|
|
288
|
+
const displayed = signal(null, /* @ts-ignore */
|
|
289
|
+
...(ngDevMode ? [{ debugName: "displayed" }] : /* istanbul ignore next */ []));
|
|
290
|
+
let timer;
|
|
291
|
+
let shownAt = 0;
|
|
292
|
+
const clear = () => {
|
|
293
|
+
clearTimeout(timer);
|
|
294
|
+
timer = undefined;
|
|
295
|
+
};
|
|
296
|
+
inject(DestroyRef).onDestroy(clear);
|
|
297
|
+
effect(() => {
|
|
298
|
+
const state = source();
|
|
299
|
+
untracked(() => {
|
|
300
|
+
if (state === 'loading') {
|
|
301
|
+
if (displayed() === 'loading') {
|
|
302
|
+
clear();
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
timer = setTimeout(() => {
|
|
306
|
+
timer = undefined;
|
|
307
|
+
shownAt = Date.now();
|
|
308
|
+
displayed.set('loading');
|
|
309
|
+
}, SKELETON_DELAY_MS);
|
|
310
|
+
}
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
clear();
|
|
314
|
+
const remaining = shownAt + SKELETON_MIN_MS - Date.now();
|
|
315
|
+
if (displayed() === 'loading' && remaining > 0) {
|
|
316
|
+
timer = setTimeout(() => {
|
|
317
|
+
timer = undefined;
|
|
318
|
+
displayed.set(untracked(source));
|
|
319
|
+
}, remaining);
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
displayed.set(state);
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
return displayed.asReadonly();
|
|
327
|
+
}
|
|
328
|
+
|
|
255
329
|
/** Available async block states. `AsyncState` is derived from this tuple. */
|
|
256
330
|
const ASYNC_STATES = ['loading', 'error', 'empty', 'ready'];
|
|
257
331
|
/** Looks of the error block. `AsyncVariant` is derived from this tuple. */
|
|
258
332
|
const ASYNC_VARIANTS = ['elevated', 'plain', 'emphasis', 'inline'];
|
|
259
333
|
/** Alignments of the error block; `auto` is centred from 64rem. `AsyncAlign` is derived from this tuple. */
|
|
260
334
|
const ASYNC_ALIGNS = ['start', 'center', 'auto'];
|
|
261
|
-
const RETRY_BASE_CLASSES = 'relative inline-flex items-center justify-center rounded-control font-medium whitespace-nowrap cursor-pointer select-none touch-manipulation transition-[
|
|
335
|
+
const RETRY_BASE_CLASSES = 'relative inline-flex items-center justify-center rounded-control font-medium whitespace-nowrap cursor-pointer select-none touch-manipulation transition-[scale,background-color,opacity] [transition-duration:var(--duration-press),var(--duration-fast),var(--duration-fast)] ease-out active:scale-(--press-scale) focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring) text-label';
|
|
262
336
|
const RETRY_OUTLINE_CLASSES = 'bg-(--card) text-(--foreground) shadow-[inset_0_0_0_1px_var(--border)] hover:bg-(--glow)';
|
|
263
337
|
const RETRY_PRIMARY_CLASSES = 'bg-(--primary) text-(--primary-foreground) hover:bg-(--primary-to)';
|
|
264
338
|
const RETRY_BLOCK_CLASSES = 'min-h-(--row-min) gap-2 pl-3 pr-4';
|
|
@@ -334,7 +408,8 @@ class UiAsync {
|
|
|
334
408
|
card = input(false, { ...(ngDevMode ? { debugName: "card" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
335
409
|
fill = input(false, { ...(ngDevMode ? { debugName: "fill" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
336
410
|
retry = output();
|
|
337
|
-
|
|
411
|
+
shown = delayedState(this.state);
|
|
412
|
+
filling = computed(() => this.fill() && this.shown() === 'error', /* @ts-ignore */
|
|
338
413
|
...(ngDevMode ? [{ debugName: "filling" }] : /* istanbul ignore next */ []));
|
|
339
414
|
iconSize = computed(() => (this.variant() === 'inline' ? 16 : 18), /* @ts-ignore */
|
|
340
415
|
...(ngDevMode ? [{ debugName: "iconSize" }] : /* istanbul ignore next */ []));
|
|
@@ -353,9 +428,9 @@ class UiAsync {
|
|
|
353
428
|
return `flex flex-col ${surface} ${spec.gap} ${ALIGN_CLASSES[this.align()]} ${spec.padding[this.align()]}${fill}`;
|
|
354
429
|
}, /* @ts-ignore */
|
|
355
430
|
...(ngDevMode ? [{ debugName: "boxClasses" }] : /* istanbul ignore next */ []));
|
|
356
|
-
titleClasses = computed(() => this.#spec()
|
|
431
|
+
titleClasses = computed(() => this.#spec().title, /* @ts-ignore */
|
|
357
432
|
...(ngDevMode ? [{ debugName: "titleClasses" }] : /* istanbul ignore next */ []));
|
|
358
|
-
messageClasses = computed(() => this.#spec()
|
|
433
|
+
messageClasses = computed(() => this.#spec().message[this.align()], /* @ts-ignore */
|
|
359
434
|
...(ngDevMode ? [{ debugName: "messageClasses" }] : /* istanbul ignore next */ []));
|
|
360
435
|
retryButtonClasses = computed(() => {
|
|
361
436
|
const spec = this.#spec();
|
|
@@ -367,7 +442,8 @@ class UiAsync {
|
|
|
367
442
|
...(ngDevMode ? [{ debugName: "retryButtonClasses" }] : /* istanbul ignore next */ []));
|
|
368
443
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAsync, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
369
444
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiAsync, isStandalone: true, selector: "ui-async", inputs: { state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: true, transformFunction: null }, errorTitle: { classPropertyName: "errorTitle", publicName: "errorTitle", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, retryLabel: { classPropertyName: "retryLabel", publicName: "retryLabel", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, card: { classPropertyName: "card", publicName: "card", isSignal: true, isRequired: false, transformFunction: null }, fill: { classPropertyName: "fill", publicName: "fill", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { retry: "retry" }, host: { properties: { "attr.aria-busy": "state() === 'loading' || null", "class.flex": "filling()", "class.flex-col": "filling()" } }, ngImport: i0, template: `
|
|
370
|
-
@switch (
|
|
445
|
+
@switch (shown()) {
|
|
446
|
+
@case (null) {}
|
|
371
447
|
@case ('loading') {
|
|
372
448
|
<ng-content select="[asyncLoading]" />
|
|
373
449
|
}
|
|
@@ -415,7 +491,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
415
491
|
args: [{
|
|
416
492
|
selector: 'ui-async',
|
|
417
493
|
template: `
|
|
418
|
-
@switch (
|
|
494
|
+
@switch (shown()) {
|
|
495
|
+
@case (null) {}
|
|
419
496
|
@case ('loading') {
|
|
420
497
|
<ng-content select="[asyncLoading]" />
|
|
421
498
|
}
|
|
@@ -467,7 +544,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
467
544
|
|
|
468
545
|
/** Available avatar sizes. `AvatarSize` is derived from this tuple. */
|
|
469
546
|
const AVATAR_SIZES = ['sm', 'md', 'lg', 'auto'];
|
|
470
|
-
const BASE_CLASSES$
|
|
547
|
+
const BASE_CLASSES$8 = 'inline-flex items-center justify-center rounded-pill bg-(--muted) font-medium tabular-nums';
|
|
471
548
|
const SIZE_CLASSES$7 = {
|
|
472
549
|
sm: 'size-8 text-caption',
|
|
473
550
|
md: 'size-[34px] text-label',
|
|
@@ -487,7 +564,7 @@ class UiAvatar {
|
|
|
487
564
|
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
488
565
|
size = input('md', /* @ts-ignore */
|
|
489
566
|
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
490
|
-
classes = computed(() => `${BASE_CLASSES$
|
|
567
|
+
classes = computed(() => `${BASE_CLASSES$8} ${SIZE_CLASSES$7[this.size()]}`, /* @ts-ignore */
|
|
491
568
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
492
569
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAvatar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
493
570
|
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 });
|
|
@@ -514,21 +591,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
514
591
|
*/
|
|
515
592
|
class UiAvatarLink {
|
|
516
593
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAvatarLink, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
517
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.7", type: UiAvatarLink, isStandalone: true, selector: "a[uiAvatarLink], button[uiAvatarLink]", host: { classAttribute: "rounded-pill grid size-11 lg:size-10 place-items-center cursor-pointer select-none touch-manipulation transition-[
|
|
594
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.7", type: UiAvatarLink, isStandalone: true, selector: "a[uiAvatarLink], button[uiAvatarLink]", host: { classAttribute: "rounded-pill grid size-11 lg:size-10 place-items-center cursor-pointer select-none touch-manipulation transition-[scale,background-color] [transition-duration:var(--duration-press),var(--duration-fast)] ease-out hover:bg-(--glow) aria-[current=page]:bg-(--soft) active:scale-(--press-scale) focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring)" }, ngImport: i0 });
|
|
518
595
|
}
|
|
519
596
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiAvatarLink, decorators: [{
|
|
520
597
|
type: Directive,
|
|
521
598
|
args: [{
|
|
522
599
|
selector: 'a[uiAvatarLink], button[uiAvatarLink]',
|
|
523
600
|
host: {
|
|
524
|
-
class: 'rounded-pill grid size-11 lg:size-10 place-items-center cursor-pointer select-none touch-manipulation transition-[
|
|
601
|
+
class: 'rounded-pill grid size-11 lg:size-10 place-items-center cursor-pointer select-none touch-manipulation transition-[scale,background-color] [transition-duration:var(--duration-press),var(--duration-fast)] ease-out hover:bg-(--glow) aria-[current=page]:bg-(--soft) active:scale-(--press-scale) focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring)',
|
|
525
602
|
},
|
|
526
603
|
}]
|
|
527
604
|
}] });
|
|
528
605
|
|
|
529
606
|
/** Available back link sizes. `BackLinkSize` is derived from this tuple. */
|
|
530
607
|
const BACK_LINK_SIZES = ['md', 'sm', 'header'];
|
|
531
|
-
const BASE_CLASSES$
|
|
608
|
+
const BASE_CLASSES$7 = 'inline-flex items-center gap-0.5 rounded-control text-body font-medium whitespace-nowrap cursor-pointer select-none touch-manipulation transition-[scale,background-color,color] [transition-duration:var(--duration-press),var(--duration-fast),var(--duration-fast)] ease-out active:scale-(--press-scale) focus-visible:outline-2 focus-visible:outline-(--ring)';
|
|
532
609
|
const SIZE_CLASSES$6 = {
|
|
533
610
|
md: 'h-11 pr-3 pl-1 text-(--foreground) focus-visible:outline-offset-2',
|
|
534
611
|
sm: 'h-9 pr-2 pl-0.5 text-(--muted-foreground) hover:bg-(--glow) hover:text-(--foreground) focus-visible:outline-offset-2',
|
|
@@ -546,7 +623,7 @@ class UiBackLink {
|
|
|
546
623
|
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
547
624
|
chevron = computed(() => CHEVRON[this.size()], /* @ts-ignore */
|
|
548
625
|
...(ngDevMode ? [{ debugName: "chevron" }] : /* istanbul ignore next */ []));
|
|
549
|
-
classes = computed(() => `${BASE_CLASSES$
|
|
626
|
+
classes = computed(() => `${BASE_CLASSES$7} ${SIZE_CLASSES$6[this.size()]}`, /* @ts-ignore */
|
|
550
627
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
551
628
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiBackLink, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
552
629
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: UiBackLink, isStandalone: true, selector: "a[ui-back-link]", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: `
|
|
@@ -595,7 +672,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
595
672
|
/** Available badge variants. `BadgeVariant` is derived from this tuple. */
|
|
596
673
|
const BADGE_VARIANTS = ['neutral', 'outline'];
|
|
597
674
|
const BADGE_SIZES = ['md', 'sm'];
|
|
598
|
-
const BASE_CLASSES$
|
|
675
|
+
const BASE_CLASSES$6 = 'inline-flex items-center rounded-pill text-caption font-medium';
|
|
599
676
|
const SIZE_CLASSES$5 = {
|
|
600
677
|
md: 'h-6 px-2.5',
|
|
601
678
|
sm: 'h-[22px] px-2',
|
|
@@ -615,7 +692,7 @@ class UiBadge {
|
|
|
615
692
|
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
616
693
|
size = input('md', /* @ts-ignore */
|
|
617
694
|
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
618
|
-
classes = computed(() => `${BASE_CLASSES$
|
|
695
|
+
classes = computed(() => `${BASE_CLASSES$6} ${SIZE_CLASSES$5[this.size()]} ${VARIANT_CLASSES$2[this.variant()]}`, /* @ts-ignore */
|
|
619
696
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
620
697
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiBadge, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
621
698
|
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 });
|
|
@@ -658,7 +735,7 @@ const BUTTON_SIZES = [
|
|
|
658
735
|
'icon',
|
|
659
736
|
'icon-sm',
|
|
660
737
|
];
|
|
661
|
-
const BASE_CLASSES$
|
|
738
|
+
const BASE_CLASSES$5 = 'relative inline-flex items-center justify-center rounded-control font-medium whitespace-nowrap cursor-pointer select-none touch-manipulation transition-[scale,background-color,opacity] [transition-duration:var(--duration-press),var(--duration-fast),var(--duration-fast)] ease-out active:scale-(--press-scale) focus-visible:outline-2 focus-visible:outline-(--ring) disabled:pointer-events-none disabled:opacity-40 aria-disabled:not-aria-busy:opacity-40';
|
|
662
739
|
const RING_OUTSIDE = 'focus-visible:outline-offset-2';
|
|
663
740
|
const RING_INSIDE = 'focus-visible:-outline-offset-2';
|
|
664
741
|
const OUTLINE = 'bg-(--card) shadow-[inset_0_0_0_1px_var(--border)] hover:bg-(--glow) active:bg-(--soft)';
|
|
@@ -678,10 +755,10 @@ const SIZE_CLASSES$4 = {
|
|
|
678
755
|
slim: 'h-11 lg:h-8 gap-1.5 px-2.5 text-label',
|
|
679
756
|
xs: 'h-8 gap-1.5 px-2.5 text-label',
|
|
680
757
|
sm: 'h-9 gap-2 px-3 text-label',
|
|
681
|
-
md: 'min-h-(--row-min) gap-2 px-4 text-label has-[>svg:first-child]:pl-3',
|
|
758
|
+
md: 'min-h-(--row-min) gap-2 px-4 text-label has-[>span>svg:first-child]:pl-3',
|
|
682
759
|
lg: 'h-11 gap-2 px-[18px] text-label',
|
|
683
760
|
xl: 'h-[50px] gap-2 px-6 text-body',
|
|
684
|
-
xxl: 'h-[52px] lg:h-11 gap-2.5 px-6 lg:px-5 text-body lg:has-[>svg:first-child]:pl-4',
|
|
761
|
+
xxl: 'h-[52px] lg:h-11 gap-2.5 px-6 lg:px-5 text-body lg:has-[>span>svg:first-child]:pl-4',
|
|
685
762
|
tall: 'h-12 lg:h-10 gap-2 px-4 text-body',
|
|
686
763
|
block: 'h-[50px] lg:h-11 gap-2 px-4 text-body',
|
|
687
764
|
icon: 'size-(--row-min) gap-2 p-0',
|
|
@@ -703,7 +780,7 @@ class UiButton {
|
|
|
703
780
|
busy = input(false, { ...(ngDevMode ? { debugName: "busy" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
704
781
|
inactive = computed(() => this.loading() || this.busy(), /* @ts-ignore */
|
|
705
782
|
...(ngDevMode ? [{ debugName: "inactive" }] : /* istanbul ignore next */ []));
|
|
706
|
-
classes = computed(() => `${BASE_CLASSES$
|
|
783
|
+
classes = computed(() => `${BASE_CLASSES$5} ${VARIANT_CLASSES$1[this.variant()]} ${SIZE_CLASSES$4[this.size()]}${this.inactive() ? ' pointer-events-none opacity-70' : ''}`, /* @ts-ignore */
|
|
707
784
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
708
785
|
constructor() {
|
|
709
786
|
const host = inject(ElementRef).nativeElement;
|
|
@@ -721,10 +798,10 @@ class UiButton {
|
|
|
721
798
|
@if (loading()) {
|
|
722
799
|
<span
|
|
723
800
|
aria-hidden="true"
|
|
724
|
-
class="rounded-pill size-4 border-2 border-current border-r-transparent
|
|
801
|
+
class="rounded-pill animate-cairn-spin absolute inset-0 m-auto size-4 border-2 border-current border-r-transparent"
|
|
725
802
|
></span>
|
|
726
803
|
}
|
|
727
|
-
<ng-content
|
|
804
|
+
<span class="contents" [class.text-transparent]="loading()"><ng-content /></span>
|
|
728
805
|
`, isInline: true });
|
|
729
806
|
}
|
|
730
807
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiButton, decorators: [{
|
|
@@ -735,10 +812,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
735
812
|
@if (loading()) {
|
|
736
813
|
<span
|
|
737
814
|
aria-hidden="true"
|
|
738
|
-
class="rounded-pill size-4 border-2 border-current border-r-transparent
|
|
815
|
+
class="rounded-pill animate-cairn-spin absolute inset-0 m-auto size-4 border-2 border-current border-r-transparent"
|
|
739
816
|
></span>
|
|
740
817
|
}
|
|
741
|
-
<ng-content
|
|
818
|
+
<span class="contents" [class.text-transparent]="loading()"><ng-content /></span>
|
|
742
819
|
`,
|
|
743
820
|
host: {
|
|
744
821
|
'[class]': 'classes()',
|
|
@@ -756,7 +833,7 @@ const CARD_PADDINGS = ['none', 'xs', 'sm', 'md', 'list', 'rows', 'recap', 'panel
|
|
|
756
833
|
const CARD_SURFACES = ['always', 'lg', 'max-lg'];
|
|
757
834
|
/** Border of the card surface; `auto` follows the variant. `CardBorder` is derived from this tuple. */
|
|
758
835
|
const CARD_BORDERS = ['auto', 'none', 'border', 'hairline'];
|
|
759
|
-
const BASE_CLASSES$
|
|
836
|
+
const BASE_CLASSES$4 = 'block';
|
|
760
837
|
const VARIANT_CLASSES = {
|
|
761
838
|
default: {
|
|
762
839
|
always: 'rounded-container bg-(--card) text-(--card-foreground)',
|
|
@@ -861,7 +938,7 @@ class UiCard {
|
|
|
861
938
|
const surface = this.surface();
|
|
862
939
|
const border = this.border();
|
|
863
940
|
return [
|
|
864
|
-
BASE_CLASSES$
|
|
941
|
+
BASE_CLASSES$4,
|
|
865
942
|
VARIANT_CLASSES[variant][surface],
|
|
866
943
|
BORDER_CLASSES[border === 'auto' ? AUTO_BORDERS[variant] : border][surface],
|
|
867
944
|
PADDING_CLASSES$1[this.padding()][surface],
|
|
@@ -897,7 +974,7 @@ const UI_CONTROL = new InjectionToken('UI_CONTROL');
|
|
|
897
974
|
|
|
898
975
|
/** Available control sizes. `md` is the 44/40px touch target; `lg` and `xl` are the 48px sheet and sign-in fields. */
|
|
899
976
|
const CONTROL_SIZES = ['sm', 'md', 'lg', 'xl'];
|
|
900
|
-
const CONTROL_BASE_CLASSES = 'w-full rounded-control px-3 text-body text-(--foreground) shadow-[inset_0_0_0_1px_var(--border)]
|
|
977
|
+
const CONTROL_BASE_CLASSES = 'w-full rounded-control px-3 text-body text-(--foreground) shadow-[inset_0_0_0_1px_var(--border)] 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';
|
|
901
978
|
const CONTROL_SURFACES = ['background', 'card'];
|
|
902
979
|
const CONTROL_SURFACE_CLASSES = {
|
|
903
980
|
background: 'bg-(--background)',
|
|
@@ -962,7 +1039,7 @@ class UiTextarea {
|
|
|
962
1039
|
touched = input(false, /* @ts-ignore */
|
|
963
1040
|
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
964
1041
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTextarea, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
965
|
-
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)]
|
|
1042
|
+
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)] 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 });
|
|
966
1043
|
}
|
|
967
1044
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiTextarea, decorators: [{
|
|
968
1045
|
type: Directive,
|
|
@@ -1142,7 +1219,7 @@ const DELTA_EMPHASES = ['text', 'pill'];
|
|
|
1142
1219
|
const DELTA_SIZES = ['label', 'inherit'];
|
|
1143
1220
|
/** Font weights. `DeltaWeight` is derived from this tuple. */
|
|
1144
1221
|
const DELTA_WEIGHTS = ['medium', 'regular'];
|
|
1145
|
-
const BASE_CLASSES$
|
|
1222
|
+
const BASE_CLASSES$3 = 'inline-flex items-center gap-1 tabular-nums';
|
|
1146
1223
|
const SIZE_CLASSES$3 = {
|
|
1147
1224
|
label: 'text-label',
|
|
1148
1225
|
inherit: '',
|
|
@@ -1199,7 +1276,7 @@ class UiDelta {
|
|
|
1199
1276
|
classes = computed(() => {
|
|
1200
1277
|
const sign = this.sign();
|
|
1201
1278
|
const background = this.emphasis() === 'pill' ? `${PILL_CLASSES$1} ${PILL_BACKGROUND_CLASS}` : 'bg-transparent';
|
|
1202
|
-
return `${BASE_CLASSES$
|
|
1279
|
+
return `${BASE_CLASSES$3} ${SIZE_CLASSES$3[this.size()]} ${WEIGHT_CLASSES[this.weight()]} ${TEXT_CLASSES[sign]} ${background}`;
|
|
1203
1280
|
}, /* @ts-ignore */
|
|
1204
1281
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
1205
1282
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiDelta, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
@@ -1230,6 +1307,242 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1230
1307
|
}]
|
|
1231
1308
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], unknownLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "unknownLabel", required: true }] }], emphasis: [{ type: i0.Input, args: [{ isSignal: true, alias: "emphasis", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], weight: [{ type: i0.Input, args: [{ isSignal: true, alias: "weight", required: false }] }] } });
|
|
1232
1309
|
|
|
1310
|
+
const GRACE = 50;
|
|
1311
|
+
function afterExit(element, done) {
|
|
1312
|
+
const style = getComputedStyle(element);
|
|
1313
|
+
const wait = longest(style.transitionDuration) + longest(style.transitionDelay);
|
|
1314
|
+
if (wait === 0) {
|
|
1315
|
+
done();
|
|
1316
|
+
return () => undefined;
|
|
1317
|
+
}
|
|
1318
|
+
const onEnd = (event) => {
|
|
1319
|
+
if (event.target === element && !event.pseudoElement) {
|
|
1320
|
+
cancel();
|
|
1321
|
+
done();
|
|
1322
|
+
}
|
|
1323
|
+
};
|
|
1324
|
+
const timer = setTimeout(() => {
|
|
1325
|
+
cancel();
|
|
1326
|
+
done();
|
|
1327
|
+
}, wait + GRACE);
|
|
1328
|
+
const cancel = () => {
|
|
1329
|
+
clearTimeout(timer);
|
|
1330
|
+
element.removeEventListener('transitionend', onEnd);
|
|
1331
|
+
};
|
|
1332
|
+
element.addEventListener('transitionend', onEnd);
|
|
1333
|
+
return cancel;
|
|
1334
|
+
}
|
|
1335
|
+
function longest(list) {
|
|
1336
|
+
return Math.max(0, ...list.split(',').map(toMs));
|
|
1337
|
+
}
|
|
1338
|
+
function toMs(value) {
|
|
1339
|
+
const amount = Number.parseFloat(value);
|
|
1340
|
+
if (Number.isNaN(amount)) {
|
|
1341
|
+
return 0;
|
|
1342
|
+
}
|
|
1343
|
+
return value.trim().endsWith('ms') ? amount : amount * 1000;
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
const DIALOG_STYLES = `
|
|
1347
|
+
dialog {
|
|
1348
|
+
--dialog-ease: var(--ease-sheet);
|
|
1349
|
+
transition:
|
|
1350
|
+
transform var(--duration-base) var(--dialog-ease),
|
|
1351
|
+
overlay var(--duration-base) allow-discrete,
|
|
1352
|
+
display var(--duration-base) allow-discrete;
|
|
1353
|
+
transform: translateY(var(--drag-y, 0px));
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
dialog:not([open]) {
|
|
1357
|
+
transform: translateY(100%);
|
|
1358
|
+
transition-duration: var(--duration-exit);
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
@starting-style {
|
|
1362
|
+
dialog[open] {
|
|
1363
|
+
transform: translateY(100%);
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
dialog[data-dragging] {
|
|
1368
|
+
transition: none;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1372
|
+
dialog {
|
|
1373
|
+
transition:
|
|
1374
|
+
opacity var(--duration-base) var(--dialog-ease),
|
|
1375
|
+
overlay var(--duration-base) allow-discrete,
|
|
1376
|
+
display var(--duration-base) allow-discrete;
|
|
1377
|
+
opacity: 1;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
dialog:not([open]) {
|
|
1381
|
+
opacity: 0;
|
|
1382
|
+
transform: translateY(var(--drag-y, 0px));
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
@starting-style {
|
|
1386
|
+
dialog[open] {
|
|
1387
|
+
opacity: 0;
|
|
1388
|
+
transform: translateY(0);
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
@media (min-width: 64rem) {
|
|
1394
|
+
dialog {
|
|
1395
|
+
--dialog-ease: var(--ease-out);
|
|
1396
|
+
transition:
|
|
1397
|
+
opacity var(--duration-base) var(--dialog-ease),
|
|
1398
|
+
transform var(--duration-base) var(--dialog-ease),
|
|
1399
|
+
overlay var(--duration-base) allow-discrete,
|
|
1400
|
+
display var(--duration-base) allow-discrete;
|
|
1401
|
+
opacity: 1;
|
|
1402
|
+
transform: scale(1);
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
dialog:not([open]) {
|
|
1406
|
+
opacity: 0;
|
|
1407
|
+
transform: scale(var(--enter-scale));
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
@starting-style {
|
|
1411
|
+
dialog[open] {
|
|
1412
|
+
opacity: 0;
|
|
1413
|
+
transform: scale(var(--enter-scale));
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
dialog::backdrop {
|
|
1419
|
+
transition: opacity var(--duration-base) var(--ease-out);
|
|
1420
|
+
opacity: 1;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
dialog:not([open])::backdrop {
|
|
1424
|
+
opacity: 0;
|
|
1425
|
+
transition-duration: var(--duration-exit);
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
@starting-style {
|
|
1429
|
+
dialog[open]::backdrop {
|
|
1430
|
+
opacity: 0;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
`;
|
|
1434
|
+
|
|
1435
|
+
const DISMISS_RATIO = 0.3;
|
|
1436
|
+
const DISMISS_SPEED = 0.5;
|
|
1437
|
+
const SPEED_WINDOW = 100;
|
|
1438
|
+
const SLOP = 6;
|
|
1439
|
+
const CONTROLS = 'button, a, input, select, textarea, [role="button"]';
|
|
1440
|
+
class SheetDrag {
|
|
1441
|
+
#panel;
|
|
1442
|
+
#grips;
|
|
1443
|
+
#dismiss;
|
|
1444
|
+
#gesture = null;
|
|
1445
|
+
constructor(panel, grips, dismiss) {
|
|
1446
|
+
this.#panel = panel;
|
|
1447
|
+
this.#grips = grips;
|
|
1448
|
+
this.#dismiss = dismiss;
|
|
1449
|
+
for (const grip of grips) {
|
|
1450
|
+
grip.addEventListener('pointerdown', this.#onDown);
|
|
1451
|
+
grip.addEventListener('pointermove', this.#onMove);
|
|
1452
|
+
grip.addEventListener('pointerup', this.#onUp);
|
|
1453
|
+
grip.addEventListener('pointercancel', this.#onCancel);
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
reset() {
|
|
1457
|
+
this.#gesture = null;
|
|
1458
|
+
this.#panel.removeAttribute('data-dragging');
|
|
1459
|
+
this.#panel.style.removeProperty('--drag-y');
|
|
1460
|
+
}
|
|
1461
|
+
destroy() {
|
|
1462
|
+
for (const grip of this.#grips) {
|
|
1463
|
+
grip.removeEventListener('pointerdown', this.#onDown);
|
|
1464
|
+
grip.removeEventListener('pointermove', this.#onMove);
|
|
1465
|
+
grip.removeEventListener('pointerup', this.#onUp);
|
|
1466
|
+
grip.removeEventListener('pointercancel', this.#onCancel);
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
#onDown = (event) => {
|
|
1470
|
+
const grip = event.currentTarget;
|
|
1471
|
+
if (event.button !== 0 || !isSheet() || event.target.closest(CONTROLS)) {
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1474
|
+
grip.setPointerCapture(event.pointerId);
|
|
1475
|
+
this.#gesture = {
|
|
1476
|
+
id: event.pointerId,
|
|
1477
|
+
startX: event.clientX,
|
|
1478
|
+
startY: event.clientY,
|
|
1479
|
+
dragging: false,
|
|
1480
|
+
height: 0,
|
|
1481
|
+
offset: 0,
|
|
1482
|
+
samples: [{ y: event.clientY, at: event.timeStamp }],
|
|
1483
|
+
};
|
|
1484
|
+
};
|
|
1485
|
+
#onMove = (event) => {
|
|
1486
|
+
const gesture = this.#current(event);
|
|
1487
|
+
if (!gesture) {
|
|
1488
|
+
return;
|
|
1489
|
+
}
|
|
1490
|
+
const dx = event.clientX - gesture.startX;
|
|
1491
|
+
const dy = event.clientY - gesture.startY;
|
|
1492
|
+
if (!gesture.dragging) {
|
|
1493
|
+
if (Math.max(Math.abs(dx), Math.abs(dy)) < SLOP) {
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
if (Math.abs(dx) > Math.abs(dy)) {
|
|
1497
|
+
this.#gesture = null;
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
gesture.dragging = true;
|
|
1501
|
+
gesture.height = this.#panel.getBoundingClientRect().height;
|
|
1502
|
+
this.#panel.setAttribute('data-dragging', '');
|
|
1503
|
+
}
|
|
1504
|
+
gesture.offset = Math.max(0, dy);
|
|
1505
|
+
gesture.samples.push({ y: event.clientY, at: event.timeStamp });
|
|
1506
|
+
this.#panel.style.setProperty('--drag-y', `${gesture.offset}px`);
|
|
1507
|
+
};
|
|
1508
|
+
#onUp = (event) => {
|
|
1509
|
+
const gesture = this.#current(event);
|
|
1510
|
+
if (!gesture) {
|
|
1511
|
+
return;
|
|
1512
|
+
}
|
|
1513
|
+
this.#gesture = null;
|
|
1514
|
+
if (!gesture.dragging) {
|
|
1515
|
+
return;
|
|
1516
|
+
}
|
|
1517
|
+
this.#panel.removeAttribute('data-dragging');
|
|
1518
|
+
const release = { y: event.clientY, at: event.timeStamp };
|
|
1519
|
+
if (gesture.offset > gesture.height * DISMISS_RATIO || releaseSpeed(gesture.samples, release) > DISMISS_SPEED) {
|
|
1520
|
+
this.#dismiss();
|
|
1521
|
+
}
|
|
1522
|
+
else {
|
|
1523
|
+
this.reset();
|
|
1524
|
+
}
|
|
1525
|
+
};
|
|
1526
|
+
#onCancel = (event) => {
|
|
1527
|
+
if (this.#current(event)) {
|
|
1528
|
+
this.#gesture = null;
|
|
1529
|
+
this.#panel.removeAttribute('data-dragging');
|
|
1530
|
+
this.reset();
|
|
1531
|
+
}
|
|
1532
|
+
};
|
|
1533
|
+
#current(event) {
|
|
1534
|
+
return this.#gesture?.id === event.pointerId ? this.#gesture : null;
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
function isSheet() {
|
|
1538
|
+
return typeof matchMedia === 'function' && !matchMedia('(min-width: 64rem)').matches;
|
|
1539
|
+
}
|
|
1540
|
+
function releaseSpeed(samples, last) {
|
|
1541
|
+
const first = samples.find((sample) => sample.at >= last.at - SPEED_WINDOW) ?? last;
|
|
1542
|
+
const elapsed = last.at - first.at;
|
|
1543
|
+
return elapsed > 0 ? (last.y - first.y) / elapsed : 0;
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1233
1546
|
/** Named dialog widths; any other CSS length is accepted as is. `DialogWidth` is derived from this tuple. */
|
|
1234
1547
|
const DIALOG_WIDTHS = ['md', 'lg'];
|
|
1235
1548
|
const WIDTH_VALUES = {
|
|
@@ -1280,6 +1593,8 @@ const LAYOUTS = {
|
|
|
1280
1593
|
footer: 'max-lg:pb-[calc(8px+env(safe-area-inset-bottom))] lg:pb-6',
|
|
1281
1594
|
},
|
|
1282
1595
|
};
|
|
1596
|
+
/** What started a close, as `closed` reports it. `DialogCloseReason` is derived from this tuple. */
|
|
1597
|
+
const DIALOG_CLOSE_REASONS = ['escape', 'backdrop', 'cross', 'drag', 'programmatic'];
|
|
1283
1598
|
const nextId$3 = (() => {
|
|
1284
1599
|
let count = 0;
|
|
1285
1600
|
return () => `ui-dialog-${++count}`;
|
|
@@ -1308,6 +1623,7 @@ class UiDialog {
|
|
|
1308
1623
|
...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
|
|
1309
1624
|
open = input(false, { ...(ngDevMode ? { debugName: "open" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1310
1625
|
dismissed = output();
|
|
1626
|
+
closed = output();
|
|
1311
1627
|
headingId = nextId$3();
|
|
1312
1628
|
descriptionId = `${this.headingId}-description`;
|
|
1313
1629
|
bodyId = `${this.headingId}-body`;
|
|
@@ -1327,11 +1643,11 @@ class UiDialog {
|
|
|
1327
1643
|
...(ngDevMode ? [{ debugName: "widthValue" }] : /* istanbul ignore next */ []));
|
|
1328
1644
|
spec = computed(() => LAYOUTS[this.layout()], /* @ts-ignore */
|
|
1329
1645
|
...(ngDevMode ? [{ debugName: "spec" }] : /* istanbul ignore next */ []));
|
|
1330
|
-
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 */
|
|
1646
|
+
headerClasses = computed(() => `flex gap-2 pl-4 max-lg:touch-none lg:gap-3 lg:pl-6 ${this.spec().header} ${this.closeLabel() ? 'pr-2 lg:pr-4' : 'pr-4 lg:pr-6'}`, /* @ts-ignore */
|
|
1331
1647
|
...(ngDevMode ? [{ debugName: "headerClasses" }] : /* istanbul ignore next */ []));
|
|
1332
1648
|
titleClasses = computed(() => this.spec().title, /* @ts-ignore */
|
|
1333
1649
|
...(ngDevMode ? [{ debugName: "titleClasses" }] : /* istanbul ignore next */ []));
|
|
1334
|
-
crossClasses = computed(() => `rounded-pill lg:rounded-control grid size-11 flex-none cursor-pointer place-items-center text-(--muted-foreground) transition-[
|
|
1650
|
+
crossClasses = computed(() => `rounded-pill lg:rounded-control grid size-11 flex-none cursor-pointer place-items-center text-(--muted-foreground) transition-[scale,background-color,color] [transition-duration:var(--duration-press),var(--duration-fast),var(--duration-fast)] 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 */
|
|
1335
1651
|
...(ngDevMode ? [{ debugName: "crossClasses" }] : /* istanbul ignore next */ []));
|
|
1336
1652
|
iconClasses = computed(() => this.spec().icon, /* @ts-ignore */
|
|
1337
1653
|
...(ngDevMode ? [{ debugName: "iconClasses" }] : /* istanbul ignore next */ []));
|
|
@@ -1343,6 +1659,13 @@ class UiDialog {
|
|
|
1343
1659
|
constructor() {
|
|
1344
1660
|
const destroyRef = inject(DestroyRef);
|
|
1345
1661
|
afterNextRender(() => {
|
|
1662
|
+
const host = this.#host.nativeElement;
|
|
1663
|
+
const grips = ['[data-dialog-handle]', '[data-dialog-header]'].map((grip) => host.querySelector(grip));
|
|
1664
|
+
this.#drag = new SheetDrag(this.#dialog, grips, () => this.close('drag'));
|
|
1665
|
+
destroyRef.onDestroy(() => {
|
|
1666
|
+
this.#drag?.destroy();
|
|
1667
|
+
this.#cancelExit();
|
|
1668
|
+
});
|
|
1346
1669
|
if (typeof ResizeObserver === 'undefined') {
|
|
1347
1670
|
return;
|
|
1348
1671
|
}
|
|
@@ -1356,20 +1679,38 @@ class UiDialog {
|
|
|
1356
1679
|
// viewChild.required can't target a #private field (NG1053); safe because the template has exactly one <dialog>.
|
|
1357
1680
|
const dialog = this.#host.nativeElement.querySelector('dialog');
|
|
1358
1681
|
if (this.open() && !dialog.open) {
|
|
1682
|
+
this.#cancelExit();
|
|
1683
|
+
this.#drag?.reset();
|
|
1359
1684
|
dialog.showModal();
|
|
1360
1685
|
}
|
|
1361
1686
|
else if (!this.open() && dialog.open) {
|
|
1362
|
-
|
|
1687
|
+
this.close('programmatic');
|
|
1363
1688
|
}
|
|
1364
1689
|
});
|
|
1365
1690
|
}
|
|
1366
1691
|
#pressedOnBackdrop = false;
|
|
1692
|
+
#drag = null;
|
|
1693
|
+
#reason = null;
|
|
1694
|
+
#cancelExit = () => undefined;
|
|
1695
|
+
close(reason) {
|
|
1696
|
+
if (this.#dialog.open) {
|
|
1697
|
+
this.#reason = reason;
|
|
1698
|
+
this.#dialog.close();
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
onCancel(event) {
|
|
1702
|
+
if (event.target !== event.currentTarget) {
|
|
1703
|
+
return;
|
|
1704
|
+
}
|
|
1705
|
+
event.preventDefault();
|
|
1706
|
+
this.close('escape');
|
|
1707
|
+
}
|
|
1367
1708
|
onPointerDown(event) {
|
|
1368
1709
|
this.#pressedOnBackdrop = event.target === this.#dialog && this.#outside(event);
|
|
1369
1710
|
}
|
|
1370
1711
|
onClick(event) {
|
|
1371
1712
|
if (this.#pressedOnBackdrop && event.target === this.#dialog && this.#outside(event)) {
|
|
1372
|
-
this
|
|
1713
|
+
this.close('backdrop');
|
|
1373
1714
|
}
|
|
1374
1715
|
this.#pressedOnBackdrop = false;
|
|
1375
1716
|
}
|
|
@@ -1381,13 +1722,26 @@ class UiDialog {
|
|
|
1381
1722
|
return (event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom);
|
|
1382
1723
|
}
|
|
1383
1724
|
onNativeClose() {
|
|
1384
|
-
|
|
1385
|
-
|
|
1725
|
+
const reason = this.#reason ?? 'escape';
|
|
1726
|
+
this.#reason = null;
|
|
1727
|
+
if (this.#dialog.open) {
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1730
|
+
if (reason !== 'programmatic') {
|
|
1386
1731
|
this.dismissed.emit();
|
|
1387
1732
|
}
|
|
1733
|
+
this.#awaitExit(reason);
|
|
1734
|
+
}
|
|
1735
|
+
#awaitExit(reason) {
|
|
1736
|
+
this.#cancelExit();
|
|
1737
|
+
this.#cancelExit = afterExit(this.#dialog, () => {
|
|
1738
|
+
this.#cancelExit = () => undefined;
|
|
1739
|
+
this.#drag?.reset();
|
|
1740
|
+
this.closed.emit(reason);
|
|
1741
|
+
});
|
|
1388
1742
|
}
|
|
1389
1743
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1390
|
-
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: `
|
|
1744
|
+
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", closed: "closed" }, host: { listeners: { "pointerdown": "onPointerDown($event)", "click": "onClick($event)" } }, ngImport: i0, template: `
|
|
1391
1745
|
<dialog
|
|
1392
1746
|
#dlg
|
|
1393
1747
|
[attr.aria-describedby]="describedBy()"
|
|
@@ -1395,9 +1749,15 @@ class UiDialog {
|
|
|
1395
1749
|
[attr.role]="layout() === 'confirm' ? 'alertdialog' : 'dialog'"
|
|
1396
1750
|
[class]="classes()"
|
|
1397
1751
|
[style.--dialog-width]="widthValue()"
|
|
1752
|
+
(cancel)="onCancel($event)"
|
|
1398
1753
|
(close)="onNativeClose()"
|
|
1399
1754
|
>
|
|
1400
|
-
<div
|
|
1755
|
+
<div
|
|
1756
|
+
aria-hidden="true"
|
|
1757
|
+
class="flex h-5 touch-none justify-center lg:hidden"
|
|
1758
|
+
data-dialog-handle
|
|
1759
|
+
[class]="spec().handle"
|
|
1760
|
+
>
|
|
1401
1761
|
<span class="rounded-pill h-[5px] w-9 bg-(--border)"></span>
|
|
1402
1762
|
</div>
|
|
1403
1763
|
|
|
@@ -1417,7 +1777,7 @@ class UiDialog {
|
|
|
1417
1777
|
</div>
|
|
1418
1778
|
|
|
1419
1779
|
@if (closeLabel()) {
|
|
1420
|
-
<button type="button" [attr.aria-label]="closeLabel()" [class]="crossClasses()" (click)="
|
|
1780
|
+
<button type="button" [attr.aria-label]="closeLabel()" [class]="crossClasses()" (click)="close('cross')">
|
|
1421
1781
|
<svg
|
|
1422
1782
|
aria-hidden="true"
|
|
1423
1783
|
class="block size-[22px] fill-none stroke-current stroke-[1.75]"
|
|
@@ -1451,7 +1811,7 @@ class UiDialog {
|
|
|
1451
1811
|
<ng-content select="[dialogActions]" />
|
|
1452
1812
|
</div>
|
|
1453
1813
|
</dialog>
|
|
1454
|
-
`, isInline: true, styles: ["dialog{--dialog-ease: var(--ease-sheet);transition:
|
|
1814
|
+
`, isInline: true, styles: ["dialog{--dialog-ease: var(--ease-sheet);transition:transform var(--duration-base) var(--dialog-ease),overlay var(--duration-base) allow-discrete,display var(--duration-base) allow-discrete;transform:translateY(var(--drag-y, 0px))}dialog:not([open]){transform:translateY(100%);transition-duration:var(--duration-exit)}@starting-style{dialog[open]{transform:translateY(100%)}}dialog[data-dragging]{transition:none}@media(prefers-reduced-motion:reduce){dialog{transition:opacity var(--duration-base) var(--dialog-ease),overlay var(--duration-base) allow-discrete,display var(--duration-base) allow-discrete;opacity:1}dialog:not([open]){opacity:0;transform:translateY(var(--drag-y, 0px))}@starting-style{dialog[open]{opacity:0;transform:translateY(0)}}}@media(min-width:64rem){dialog{--dialog-ease: var(--ease-out);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:scale(1)}dialog:not([open]){opacity:0;transform:scale(var(--enter-scale))}@starting-style{dialog[open]{opacity:0;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"] });
|
|
1455
1815
|
}
|
|
1456
1816
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiDialog, decorators: [{
|
|
1457
1817
|
type: Component,
|
|
@@ -1463,9 +1823,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1463
1823
|
[attr.role]="layout() === 'confirm' ? 'alertdialog' : 'dialog'"
|
|
1464
1824
|
[class]="classes()"
|
|
1465
1825
|
[style.--dialog-width]="widthValue()"
|
|
1826
|
+
(cancel)="onCancel($event)"
|
|
1466
1827
|
(close)="onNativeClose()"
|
|
1467
1828
|
>
|
|
1468
|
-
<div
|
|
1829
|
+
<div
|
|
1830
|
+
aria-hidden="true"
|
|
1831
|
+
class="flex h-5 touch-none justify-center lg:hidden"
|
|
1832
|
+
data-dialog-handle
|
|
1833
|
+
[class]="spec().handle"
|
|
1834
|
+
>
|
|
1469
1835
|
<span class="rounded-pill h-[5px] w-9 bg-(--border)"></span>
|
|
1470
1836
|
</div>
|
|
1471
1837
|
|
|
@@ -1485,7 +1851,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1485
1851
|
</div>
|
|
1486
1852
|
|
|
1487
1853
|
@if (closeLabel()) {
|
|
1488
|
-
<button type="button" [attr.aria-label]="closeLabel()" [class]="crossClasses()" (click)="
|
|
1854
|
+
<button type="button" [attr.aria-label]="closeLabel()" [class]="crossClasses()" (click)="close('cross')">
|
|
1489
1855
|
<svg
|
|
1490
1856
|
aria-hidden="true"
|
|
1491
1857
|
class="block size-[22px] fill-none stroke-current stroke-[1.75]"
|
|
@@ -1519,12 +1885,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1519
1885
|
<ng-content select="[dialogActions]" />
|
|
1520
1886
|
</div>
|
|
1521
1887
|
</dialog>
|
|
1522
|
-
`, styles: ["dialog{--dialog-ease: var(--ease-sheet);transition:
|
|
1523
|
-
}], 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"] }] } });
|
|
1888
|
+
`, styles: ["dialog{--dialog-ease: var(--ease-sheet);transition:transform var(--duration-base) var(--dialog-ease),overlay var(--duration-base) allow-discrete,display var(--duration-base) allow-discrete;transform:translateY(var(--drag-y, 0px))}dialog:not([open]){transform:translateY(100%);transition-duration:var(--duration-exit)}@starting-style{dialog[open]{transform:translateY(100%)}}dialog[data-dragging]{transition:none}@media(prefers-reduced-motion:reduce){dialog{transition:opacity var(--duration-base) var(--dialog-ease),overlay var(--duration-base) allow-discrete,display var(--duration-base) allow-discrete;opacity:1}dialog:not([open]){opacity:0;transform:translateY(var(--drag-y, 0px))}@starting-style{dialog[open]{opacity:0;transform:translateY(0)}}}@media(min-width:64rem){dialog{--dialog-ease: var(--ease-out);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:scale(1)}dialog:not([open]){opacity:0;transform:scale(var(--enter-scale))}@starting-style{dialog[open]{opacity:0;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"] }]
|
|
1889
|
+
}], 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"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
|
|
1524
1890
|
|
|
1525
1891
|
const RADIUS = 78;
|
|
1526
1892
|
const RING_WIDTH = 30;
|
|
1527
|
-
const ACTIVE_RING_WIDTH = 38;
|
|
1528
1893
|
const CIRCUMFERENCE = 2 * Math.PI * RADIUS;
|
|
1529
1894
|
const GAP = 2;
|
|
1530
1895
|
function positionSlices(slices) {
|
|
@@ -1571,7 +1936,8 @@ function rankSlices(slices, othersLabel) {
|
|
|
1571
1936
|
|
|
1572
1937
|
const identityValue$1 = (value) => `${value}`;
|
|
1573
1938
|
const identityShare = (share) => `${Math.round(share * 100)}%`;
|
|
1574
|
-
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-
|
|
1939
|
+
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-[scale,background-color] [transition-duration:var(--duration-press),var(--duration-fast)] ease-out hover:bg-(--glow) active:bg-(--soft) active:scale-(--press-scale) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring)';
|
|
1940
|
+
const SLICE_CLASSES = 'cursor-pointer origin-center [transform-box:view-box] transition-[scale,opacity] duration-(--duration-fast) ease-out';
|
|
1575
1941
|
const RAMP_DOT_CLASSES = {
|
|
1576
1942
|
1: 'bg-(--ramp-1)',
|
|
1577
1943
|
2: 'bg-(--ramp-2)',
|
|
@@ -1625,8 +1991,12 @@ class UiDonut {
|
|
|
1625
1991
|
strokeColor(slice) {
|
|
1626
1992
|
return `var(--ramp-${slice.ramp})`;
|
|
1627
1993
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1994
|
+
sliceClasses(slice) {
|
|
1995
|
+
const id = this.activeId();
|
|
1996
|
+
if (id === null) {
|
|
1997
|
+
return SLICE_CLASSES;
|
|
1998
|
+
}
|
|
1999
|
+
return `${SLICE_CLASSES} ${id === slice.id ? 'scale-104 motion-reduce:scale-100' : 'opacity-50'}`;
|
|
1630
2000
|
}
|
|
1631
2001
|
dotClasses(slice) {
|
|
1632
2002
|
return `size-3 flex-none rounded-pill shadow-[inset_0_0_0_1px_var(--border)] ${RAMP_DOT_CLASSES[slice.ramp]}`;
|
|
@@ -1676,7 +2046,6 @@ class UiDonut {
|
|
|
1676
2046
|
/>
|
|
1677
2047
|
@for (slice of positioned(); track slice.id) {
|
|
1678
2048
|
<circle
|
|
1679
|
-
class="cursor-pointer transition-[stroke-width] duration-(--duration-fast) ease-out"
|
|
1680
2049
|
cx="100"
|
|
1681
2050
|
cy="100"
|
|
1682
2051
|
data-slice
|
|
@@ -1684,8 +2053,9 @@ class UiDonut {
|
|
|
1684
2053
|
[attr.r]="radius"
|
|
1685
2054
|
[attr.stroke-dasharray]="slice.dash"
|
|
1686
2055
|
[attr.stroke-dashoffset]="slice.offset"
|
|
2056
|
+
[attr.stroke-width]="ringWidth"
|
|
2057
|
+
[class]="sliceClasses(slice)"
|
|
1687
2058
|
[style.stroke]="strokeColor(slice)"
|
|
1688
|
-
[style.stroke-width.px]="strokeWidth(slice)"
|
|
1689
2059
|
(click)="select(slice)"
|
|
1690
2060
|
(pointerenter)="highlight(slice.id)"
|
|
1691
2061
|
(pointerleave)="clearHighlight(slice.id)"
|
|
@@ -1771,7 +2141,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1771
2141
|
/>
|
|
1772
2142
|
@for (slice of positioned(); track slice.id) {
|
|
1773
2143
|
<circle
|
|
1774
|
-
class="cursor-pointer transition-[stroke-width] duration-(--duration-fast) ease-out"
|
|
1775
2144
|
cx="100"
|
|
1776
2145
|
cy="100"
|
|
1777
2146
|
data-slice
|
|
@@ -1779,8 +2148,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1779
2148
|
[attr.r]="radius"
|
|
1780
2149
|
[attr.stroke-dasharray]="slice.dash"
|
|
1781
2150
|
[attr.stroke-dashoffset]="slice.offset"
|
|
2151
|
+
[attr.stroke-width]="ringWidth"
|
|
2152
|
+
[class]="sliceClasses(slice)"
|
|
1782
2153
|
[style.stroke]="strokeColor(slice)"
|
|
1783
|
-
[style.stroke-width.px]="strokeWidth(slice)"
|
|
1784
2154
|
(click)="select(slice)"
|
|
1785
2155
|
(pointerenter)="highlight(slice.id)"
|
|
1786
2156
|
(pointerleave)="clearHighlight(slice.id)"
|
|
@@ -1855,6 +2225,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
1855
2225
|
}]
|
|
1856
2226
|
}], propDecorators: { slices: [{ type: i0.Input, args: [{ isSignal: true, alias: "slices", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], othersLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "othersLabel", required: true }] }], valueFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueFormat", required: false }] }], shareFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "shareFormat", required: false }] }], legendHref: [{ type: i0.Input, args: [{ isSignal: true, alias: "legendHref", required: false }] }], sliceSelect: [{ type: i0.Output, args: ["sliceSelect"] }] } });
|
|
1857
2227
|
|
|
2228
|
+
/**
|
|
2229
|
+
* Centred empty state: a title, a hint and an action slot, such as a catalogue search that matches
|
|
2230
|
+
* nothing. The padding is 24px, 48px from 64rem.
|
|
2231
|
+
*
|
|
2232
|
+
* @example
|
|
2233
|
+
* <ui-empty heading="Aucun instrument ne correspond à « zzz »" hint="La recherche porte sur le nom et l'ISIN.">
|
|
2234
|
+
* <button ui-button variant="outline" size="md" type="button">Ajouter une ligne</button>
|
|
2235
|
+
* </ui-empty>
|
|
2236
|
+
*/
|
|
2237
|
+
class UiEmpty {
|
|
2238
|
+
heading = input.required(/* @ts-ignore */
|
|
2239
|
+
...(ngDevMode ? [{ debugName: "heading" }] : /* istanbul ignore next */ []));
|
|
2240
|
+
hint = input('', /* @ts-ignore */
|
|
2241
|
+
...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
|
|
2242
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiEmpty, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2243
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiEmpty, isStandalone: true, selector: "ui-empty", inputs: { heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: true, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "flex flex-col items-center gap-1.5 px-2 py-6 text-center lg:py-12" }, ngImport: i0, template: `
|
|
2244
|
+
<span class="text-body font-medium text-pretty">{{ heading() }}</span>
|
|
2245
|
+
@if (hint()) {
|
|
2246
|
+
<span class="text-label text-(--muted-foreground)">{{ hint() }}</span>
|
|
2247
|
+
}
|
|
2248
|
+
<div class="mt-2 empty:hidden"><ng-content /></div>
|
|
2249
|
+
`, isInline: true });
|
|
2250
|
+
}
|
|
2251
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiEmpty, decorators: [{
|
|
2252
|
+
type: Component,
|
|
2253
|
+
args: [{
|
|
2254
|
+
selector: 'ui-empty',
|
|
2255
|
+
template: `
|
|
2256
|
+
<span class="text-body font-medium text-pretty">{{ heading() }}</span>
|
|
2257
|
+
@if (hint()) {
|
|
2258
|
+
<span class="text-label text-(--muted-foreground)">{{ hint() }}</span>
|
|
2259
|
+
}
|
|
2260
|
+
<div class="mt-2 empty:hidden"><ng-content /></div>
|
|
2261
|
+
`,
|
|
2262
|
+
host: { class: 'flex flex-col items-center gap-1.5 px-2 py-6 text-center lg:py-12' },
|
|
2263
|
+
}]
|
|
2264
|
+
}], propDecorators: { heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: true }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }] } });
|
|
2265
|
+
|
|
1858
2266
|
/**
|
|
1859
2267
|
* Link to another site: the label followed by an external-link icon. A 44px target on touch,
|
|
1860
2268
|
* an underline on hover with a mouse.
|
|
@@ -2045,14 +2453,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2045
2453
|
*/
|
|
2046
2454
|
class UiFieldTrailing {
|
|
2047
2455
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFieldTrailing, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2048
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.7", type: UiFieldTrailing, isStandalone: true, selector: "[uiFieldTrailing]", host: { classAttribute: "absolute right-0 grid h-full aspect-square place-items-center rounded-control cursor-pointer text-(--muted-foreground) hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-4 focus-visible:outline-(--ring)" }, ngImport: i0 });
|
|
2456
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.7", type: UiFieldTrailing, isStandalone: true, selector: "[uiFieldTrailing]", host: { classAttribute: "absolute right-0 grid h-full aspect-square place-items-center rounded-control cursor-pointer text-(--muted-foreground) transition-[color] duration-(--duration-fast) ease-out hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-4 focus-visible:outline-(--ring)" }, ngImport: i0 });
|
|
2049
2457
|
}
|
|
2050
2458
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFieldTrailing, decorators: [{
|
|
2051
2459
|
type: Directive,
|
|
2052
2460
|
args: [{
|
|
2053
2461
|
selector: '[uiFieldTrailing]',
|
|
2054
2462
|
host: {
|
|
2055
|
-
class: 'absolute right-0 grid h-full aspect-square place-items-center rounded-control cursor-pointer text-(--muted-foreground) hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-4 focus-visible:outline-(--ring)',
|
|
2463
|
+
class: 'absolute right-0 grid h-full aspect-square place-items-center rounded-control cursor-pointer text-(--muted-foreground) transition-[color] duration-(--duration-fast) ease-out hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-4 focus-visible:outline-(--ring)',
|
|
2056
2464
|
},
|
|
2057
2465
|
}]
|
|
2058
2466
|
}] });
|
|
@@ -2179,7 +2587,9 @@ class UiField {
|
|
|
2179
2587
|
}
|
|
2180
2588
|
|
|
2181
2589
|
@if (message()) {
|
|
2182
|
-
<p class="text-label font-medium text-(--negative)" role="alert" [id]="errorId">
|
|
2590
|
+
<p animate.enter="ui-enter-fade" class="text-label font-medium text-(--negative)" role="alert" [id]="errorId">
|
|
2591
|
+
{{ message() }}
|
|
2592
|
+
</p>
|
|
2183
2593
|
}
|
|
2184
2594
|
</div>
|
|
2185
2595
|
`, isInline: true });
|
|
@@ -2212,7 +2622,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2212
2622
|
}
|
|
2213
2623
|
|
|
2214
2624
|
@if (message()) {
|
|
2215
|
-
<p class="text-label font-medium text-(--negative)" role="alert" [id]="errorId">
|
|
2625
|
+
<p animate.enter="ui-enter-fade" class="text-label font-medium text-(--negative)" role="alert" [id]="errorId">
|
|
2626
|
+
{{ message() }}
|
|
2627
|
+
</p>
|
|
2216
2628
|
}
|
|
2217
2629
|
</div>
|
|
2218
2630
|
`,
|
|
@@ -2299,6 +2711,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2299
2711
|
}]
|
|
2300
2712
|
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }, { type: i0.Output, args: ["valueChange"] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: true }] }] } });
|
|
2301
2713
|
|
|
2714
|
+
const QUERY = '(prefers-reduced-motion: reduce)';
|
|
2715
|
+
/**
|
|
2716
|
+
* A signal that follows the user's `prefers-reduced-motion` preference live.
|
|
2717
|
+
* Call it in an injection context; the listener is removed with that context.
|
|
2718
|
+
*
|
|
2719
|
+
* @example
|
|
2720
|
+
* protected readonly reduced = injectReducedMotion();
|
|
2721
|
+
*/
|
|
2722
|
+
function injectReducedMotion() {
|
|
2723
|
+
if (typeof matchMedia === 'undefined') {
|
|
2724
|
+
return signal(false).asReadonly();
|
|
2725
|
+
}
|
|
2726
|
+
const query = matchMedia(QUERY);
|
|
2727
|
+
const reduced = signal(query.matches, /* @ts-ignore */
|
|
2728
|
+
...(ngDevMode ? [{ debugName: "reduced" }] : /* istanbul ignore next */ []));
|
|
2729
|
+
const listener = (event) => reduced.set(event.matches);
|
|
2730
|
+
query.addEventListener('change', listener);
|
|
2731
|
+
inject(DestroyRef).onDestroy(() => query.removeEventListener('change', listener));
|
|
2732
|
+
return reduced.asReadonly();
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2302
2735
|
const axisTicks = (points, maxTicks = 5) => {
|
|
2303
2736
|
if (points.length <= maxTicks) {
|
|
2304
2737
|
return [...points];
|
|
@@ -2441,6 +2874,23 @@ const buildGeometry = (points, width, height, padding = {}) => {
|
|
|
2441
2874
|
};
|
|
2442
2875
|
};
|
|
2443
2876
|
|
|
2877
|
+
const observeSize = (element, destroyRef, measured) => {
|
|
2878
|
+
if (typeof ResizeObserver === 'undefined') {
|
|
2879
|
+
return;
|
|
2880
|
+
}
|
|
2881
|
+
const { clientWidth: width, clientHeight: height } = element;
|
|
2882
|
+
if (width > 0 && height > 0) {
|
|
2883
|
+
measured({ width, height });
|
|
2884
|
+
}
|
|
2885
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
2886
|
+
if (entry) {
|
|
2887
|
+
measured({ width: entry.contentRect.width, height: entry.contentRect.height });
|
|
2888
|
+
}
|
|
2889
|
+
});
|
|
2890
|
+
observer.observe(element);
|
|
2891
|
+
destroyRef.onDestroy(() => observer.disconnect());
|
|
2892
|
+
};
|
|
2893
|
+
|
|
2444
2894
|
const LINE_GAP = 6;
|
|
2445
2895
|
const COLLISION_MARGIN = 6;
|
|
2446
2896
|
const EDGE_TOLERANCE = 3;
|
|
@@ -2489,7 +2939,15 @@ const placeStartLabel = (points, startY, box, label) => {
|
|
|
2489
2939
|
const TRANSITION_SAMPLES = 120;
|
|
2490
2940
|
const TRANSITION_DURATION = 260;
|
|
2491
2941
|
const easeOutQuint = (t) => 1 - (1 - t) ** 5;
|
|
2492
|
-
const
|
|
2942
|
+
const durationFrom = (value) => {
|
|
2943
|
+
const match = /^\s*([\d.]+)(ms|s)\s*$/.exec(value);
|
|
2944
|
+
const duration = match ? Number(match[1]) * (match[2] === 's' ? 1000 : 1) : Number.NaN;
|
|
2945
|
+
return Number.isFinite(duration) ? duration : TRANSITION_DURATION;
|
|
2946
|
+
};
|
|
2947
|
+
const sameSeries = (a, b) => a === b ||
|
|
2948
|
+
(b !== null &&
|
|
2949
|
+
a.length === b.length &&
|
|
2950
|
+
a.every((point, index) => point.t === b[index].t && point.v === b[index].v));
|
|
2493
2951
|
const monotoneTangents = (xs, ys) => {
|
|
2494
2952
|
const n = xs.length;
|
|
2495
2953
|
const slopes = [];
|
|
@@ -2545,15 +3003,85 @@ const sampleMonotone = (points, sampleXs) => {
|
|
|
2545
3003
|
return (2 * f3 - 3 * f2 + 1) * y0 + (f3 - 2 * f2 + f) * m0 * dx + (-2 * f3 + 3 * f2) * y1 + (f3 - f2) * m1 * dx;
|
|
2546
3004
|
});
|
|
2547
3005
|
};
|
|
2548
|
-
const
|
|
2549
|
-
const
|
|
2550
|
-
const left = to
|
|
2551
|
-
const right = to.
|
|
2552
|
-
const
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
3006
|
+
const polyline = (xs, ys) => xs.map((x, index) => `${index === 0 ? 'M' : 'L'}${x.toFixed(2)},${ys[index].toFixed(2)}`).join(' ');
|
|
3007
|
+
const shapeTransition = (from, to) => {
|
|
3008
|
+
const left = to[0].x;
|
|
3009
|
+
const right = to.at(-1).x;
|
|
3010
|
+
const xs = Array.from({ length: TRANSITION_SAMPLES }, (_, index) => left + ((right - left) * index) / (TRANSITION_SAMPLES - 1));
|
|
3011
|
+
return { xs, from: sampleMonotone(from, xs), to: sampleMonotone(to, xs) };
|
|
3012
|
+
};
|
|
3013
|
+
const shapeAt = (transition, progress) => transition.from.map((fromY, index) => fromY + (transition.to[index] - fromY) * progress);
|
|
3014
|
+
const animateShape = (from, to, duration, draw, done) => {
|
|
3015
|
+
const transition = shapeTransition(from, to);
|
|
3016
|
+
const start = performance.now();
|
|
3017
|
+
let frame = 0;
|
|
3018
|
+
const step = (now) => {
|
|
3019
|
+
const t = Math.min(1, Math.max(0, (now - start) / duration));
|
|
3020
|
+
if (t === 1) {
|
|
3021
|
+
done();
|
|
3022
|
+
return;
|
|
3023
|
+
}
|
|
3024
|
+
const ys = shapeAt(transition, easeOutQuint(t));
|
|
3025
|
+
draw(transition.xs.map((x, index) => ({ x, y: ys[index] })), polyline(transition.xs, ys));
|
|
3026
|
+
frame = requestAnimationFrame(step);
|
|
3027
|
+
};
|
|
3028
|
+
frame = requestAnimationFrame(step);
|
|
3029
|
+
return () => cancelAnimationFrame(frame);
|
|
2556
3030
|
};
|
|
3031
|
+
class ShapeMotion {
|
|
3032
|
+
#view;
|
|
3033
|
+
#points = null;
|
|
3034
|
+
#target = null;
|
|
3035
|
+
#held = null;
|
|
3036
|
+
#drawn = null;
|
|
3037
|
+
#stop = null;
|
|
3038
|
+
constructor(view) {
|
|
3039
|
+
this.#view = view;
|
|
3040
|
+
}
|
|
3041
|
+
follow(points, geometry, options) {
|
|
3042
|
+
const newSeries = !sameSeries(points, this.#points);
|
|
3043
|
+
this.#points = points;
|
|
3044
|
+
if (this.#stop && !newSeries && !options.reduced && geometry?.line === this.#target?.line) {
|
|
3045
|
+
this.#target = geometry;
|
|
3046
|
+
return;
|
|
3047
|
+
}
|
|
3048
|
+
const from = this.#drawn;
|
|
3049
|
+
const held = this.#held ?? this.#target;
|
|
3050
|
+
this.#target = geometry;
|
|
3051
|
+
this.stop();
|
|
3052
|
+
if (!newSeries || !geometry || !from || from.length < 2 || geometry.points.length < 2 || options.reduced) {
|
|
3053
|
+
this.#settle(geometry);
|
|
3054
|
+
return;
|
|
3055
|
+
}
|
|
3056
|
+
const duration = options.duration();
|
|
3057
|
+
if (duration <= 0) {
|
|
3058
|
+
this.#settle(geometry);
|
|
3059
|
+
return;
|
|
3060
|
+
}
|
|
3061
|
+
this.#hold(held);
|
|
3062
|
+
this.#stop = animateShape(from, geometry.points, duration, (shape, line) => this.#draw(shape, line, shape.at(-1)), () => this.#settle(geometry));
|
|
3063
|
+
}
|
|
3064
|
+
stop() {
|
|
3065
|
+
this.#stop?.();
|
|
3066
|
+
this.#stop = null;
|
|
3067
|
+
}
|
|
3068
|
+
#hold(geometry) {
|
|
3069
|
+
this.#held = geometry;
|
|
3070
|
+
this.#view.hold(geometry);
|
|
3071
|
+
}
|
|
3072
|
+
#settle(geometry) {
|
|
3073
|
+
this.#stop = null;
|
|
3074
|
+
this.#hold(null);
|
|
3075
|
+
this.#drawn = null;
|
|
3076
|
+
if (geometry) {
|
|
3077
|
+
this.#draw(geometry.points, geometry.line, geometry.end);
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
#draw(shape, line, end) {
|
|
3081
|
+
this.#drawn = shape;
|
|
3082
|
+
this.#view.draw(line, end);
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
2557
3085
|
|
|
2558
3086
|
const WIDE_QUERY = '(min-width: 64rem)';
|
|
2559
3087
|
const wideViewport = () => {
|
|
@@ -2608,16 +3136,30 @@ class UiLineChart {
|
|
|
2608
3136
|
...(ngDevMode ? [{ debugName: "axisGap" }] : /* istanbul ignore next */ []));
|
|
2609
3137
|
axisTicks = input('auto', { ...(ngDevMode ? { debugName: "axisTicks" } : /* istanbul ignore next */ {}), transform: parseAxisTicks });
|
|
2610
3138
|
#destroyRef = inject(DestroyRef);
|
|
3139
|
+
#host = inject(ElementRef);
|
|
2611
3140
|
#wide = wideViewport();
|
|
2612
|
-
#
|
|
2613
|
-
#
|
|
2614
|
-
|
|
3141
|
+
#reducedMotion = injectReducedMotion();
|
|
3142
|
+
#motion = new ShapeMotion({
|
|
3143
|
+
hold: (geometry) => {
|
|
3144
|
+
this.held.set(geometry);
|
|
3145
|
+
this.activeIndex.update((index) => (geometry ? null : index));
|
|
3146
|
+
},
|
|
3147
|
+
draw: (line, end) => {
|
|
3148
|
+
this.lineRef()?.nativeElement.setAttribute('d', line);
|
|
3149
|
+
this.endRef()?.nativeElement.setAttribute('cx', String(end.x));
|
|
3150
|
+
this.endRef()?.nativeElement.setAttribute('cy', String(end.y));
|
|
3151
|
+
},
|
|
3152
|
+
});
|
|
2615
3153
|
svgRef = viewChild.required('svgRef', /* @ts-ignore */
|
|
2616
3154
|
...(ngDevMode ? [{ debugName: "svgRef" }] : /* istanbul ignore next */ []));
|
|
3155
|
+
lineRef = viewChild('lineRef', /* @ts-ignore */
|
|
3156
|
+
...(ngDevMode ? [{ debugName: "lineRef" }] : /* istanbul ignore next */ []));
|
|
3157
|
+
endRef = viewChild('endRef', /* @ts-ignore */
|
|
3158
|
+
...(ngDevMode ? [{ debugName: "endRef" }] : /* istanbul ignore next */ []));
|
|
2617
3159
|
activeIndex = signal(null, /* @ts-ignore */
|
|
2618
3160
|
...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
|
|
2619
|
-
|
|
2620
|
-
...(ngDevMode ? [{ debugName: "
|
|
3161
|
+
held = signal(null, /* @ts-ignore */
|
|
3162
|
+
...(ngDevMode ? [{ debugName: "held" }] : /* istanbul ignore next */ []));
|
|
2621
3163
|
measuredSize = signal(null, /* @ts-ignore */
|
|
2622
3164
|
...(ngDevMode ? [{ debugName: "measuredSize" }] : /* istanbul ignore next */ []));
|
|
2623
3165
|
effectiveWidth = computed(() => this.measuredSize()?.width ?? DEFAULT_WIDTH, /* @ts-ignore */
|
|
@@ -2635,8 +3177,10 @@ class UiLineChart {
|
|
|
2635
3177
|
return buildGeometry(this.points(), this.effectiveWidth(), plotHeight, { x: 0, top: padding, bottom: padding });
|
|
2636
3178
|
}, /* @ts-ignore */
|
|
2637
3179
|
...(ngDevMode ? [{ debugName: "geometry" }] : /* istanbul ignore next */ []));
|
|
2638
|
-
|
|
2639
|
-
...(ngDevMode ? [{ debugName: "
|
|
3180
|
+
shown = computed(() => this.held() ?? this.geometry(), /* @ts-ignore */
|
|
3181
|
+
...(ngDevMode ? [{ debugName: "shown" }] : /* istanbul ignore next */ []));
|
|
3182
|
+
startFade = computed(() => this.held() ? 'opacity-0 duration-(--duration-exit)' : 'duration-(--duration-fast)', /* @ts-ignore */
|
|
3183
|
+
...(ngDevMode ? [{ debugName: "startFade" }] : /* istanbul ignore next */ []));
|
|
2640
3184
|
ticks = computed(() => axisTicks(this.geometry().points), /* @ts-ignore */
|
|
2641
3185
|
...(ngDevMode ? [{ debugName: "ticks" }] : /* istanbul ignore next */ []));
|
|
2642
3186
|
tickTexts = computed(() => tickLabels(this.ticks(), this.axisFormat(), this.axisTicks()), /* @ts-ignore */
|
|
@@ -2644,12 +3188,12 @@ class UiLineChart {
|
|
|
2644
3188
|
active = computed(() => {
|
|
2645
3189
|
const geometry = this.geometry();
|
|
2646
3190
|
const index = this.activeIndex();
|
|
2647
|
-
return geometry && index !== null ? geometry.points[index] : null;
|
|
3191
|
+
return geometry && index !== null && !this.held() ? geometry.points[index] : null;
|
|
2648
3192
|
}, /* @ts-ignore */
|
|
2649
3193
|
...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
|
|
2650
3194
|
startLabelInfo = computed(() => {
|
|
2651
3195
|
const text = this.startLabel();
|
|
2652
|
-
const geometry = this.
|
|
3196
|
+
const geometry = this.shown();
|
|
2653
3197
|
if (!text || !geometry) {
|
|
2654
3198
|
return null;
|
|
2655
3199
|
}
|
|
@@ -2659,63 +3203,21 @@ class UiLineChart {
|
|
|
2659
3203
|
return { label, placement: { ...placement, y: startLabelBaseline(placement.y) } };
|
|
2660
3204
|
}, /* @ts-ignore */
|
|
2661
3205
|
...(ngDevMode ? [{ debugName: "startLabelInfo" }] : /* istanbul ignore next */ []));
|
|
2662
|
-
#renderRef = afterNextRender(() =>
|
|
3206
|
+
#renderRef = afterNextRender(() => {
|
|
3207
|
+
this.#destroyRef.onDestroy(() => this.#renderRef.destroy());
|
|
3208
|
+
observeSize(this.svgRef().nativeElement, this.#destroyRef, (size) => this.measuredSize.set(size));
|
|
3209
|
+
});
|
|
2663
3210
|
constructor() {
|
|
2664
3211
|
effect(() => {
|
|
3212
|
+
const points = this.points();
|
|
2665
3213
|
const geometry = this.geometry();
|
|
2666
|
-
const
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
this.#cancelAnimation();
|
|
2672
|
-
if (!this.#hasRenderedOnce) {
|
|
2673
|
-
this.#hasRenderedOnce = true;
|
|
2674
|
-
return;
|
|
2675
|
-
}
|
|
2676
|
-
if (!previous || !geometry) {
|
|
2677
|
-
this.animatedLine.set(null);
|
|
2678
|
-
return;
|
|
2679
|
-
}
|
|
2680
|
-
if (prefersReducedMotion()) {
|
|
2681
|
-
this.animatedLine.set(null);
|
|
2682
|
-
return;
|
|
2683
|
-
}
|
|
2684
|
-
this.#animate(previous, geometry);
|
|
2685
|
-
});
|
|
2686
|
-
this.#destroyRef.onDestroy(() => this.#cancelAnimation());
|
|
2687
|
-
}
|
|
2688
|
-
#observeSize() {
|
|
2689
|
-
this.#destroyRef.onDestroy(() => this.#renderRef.destroy());
|
|
2690
|
-
if (typeof ResizeObserver === 'undefined') {
|
|
2691
|
-
return;
|
|
2692
|
-
}
|
|
2693
|
-
const element = this.svgRef().nativeElement;
|
|
2694
|
-
const observer = new ResizeObserver(([entry]) => {
|
|
2695
|
-
if (entry) {
|
|
2696
|
-
const { width, height } = entry.contentRect;
|
|
2697
|
-
this.measuredSize.set({ width, height });
|
|
2698
|
-
}
|
|
3214
|
+
const reduced = this.#reducedMotion();
|
|
3215
|
+
untracked(() => this.#motion.follow(points, geometry, {
|
|
3216
|
+
reduced,
|
|
3217
|
+
duration: () => durationFrom(getComputedStyle(this.#host.nativeElement).getPropertyValue('--duration-base')),
|
|
3218
|
+
}));
|
|
2699
3219
|
});
|
|
2700
|
-
|
|
2701
|
-
this.#destroyRef.onDestroy(() => observer.disconnect());
|
|
2702
|
-
}
|
|
2703
|
-
#cancelAnimation() {
|
|
2704
|
-
cancelAnimationFrame(this.#frame ?? 0);
|
|
2705
|
-
this.#frame = null;
|
|
2706
|
-
}
|
|
2707
|
-
#animate(from, to) {
|
|
2708
|
-
if (from.points.length < 2 || to.points.length < 2) {
|
|
2709
|
-
this.animatedLine.set(null);
|
|
2710
|
-
return;
|
|
2711
|
-
}
|
|
2712
|
-
const startTime = performance.now();
|
|
2713
|
-
const step = (now) => {
|
|
2714
|
-
const t = Math.min(1, (now - startTime) / TRANSITION_DURATION);
|
|
2715
|
-
this.animatedLine.set(t < 1 ? interpolateLine(from, to, easeOutQuint(t)) : null);
|
|
2716
|
-
this.#frame = t < 1 ? requestAnimationFrame(step) : null;
|
|
2717
|
-
};
|
|
2718
|
-
this.#frame = requestAnimationFrame(step);
|
|
3220
|
+
this.#destroyRef.onDestroy(() => this.#motion.stop());
|
|
2719
3221
|
}
|
|
2720
3222
|
deltaFor(point) {
|
|
2721
3223
|
return point.v - this.points()[0].v;
|
|
@@ -2751,7 +3253,7 @@ class UiLineChart {
|
|
|
2751
3253
|
this.activeIndex.set(navigation.index);
|
|
2752
3254
|
}
|
|
2753
3255
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiLineChart, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2754
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiLineChart, isStandalone: true, selector: "ui-line-chart", inputs: { points: { classPropertyName: "points", publicName: "points", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, valueFormat: { classPropertyName: "valueFormat", publicName: "valueFormat", isSignal: true, isRequired: false, transformFunction: null }, tooltipFormat: { classPropertyName: "tooltipFormat", publicName: "tooltipFormat", isSignal: true, isRequired: false, transformFunction: null }, deltaFormat: { classPropertyName: "deltaFormat", publicName: "deltaFormat", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, axisFormat: { classPropertyName: "axisFormat", publicName: "axisFormat", isSignal: true, isRequired: false, transformFunction: null }, startLabel: { classPropertyName: "startLabel", publicName: "startLabel", isSignal: true, isRequired: false, transformFunction: null }, timeColumnLabel: { classPropertyName: "timeColumnLabel", publicName: "timeColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, valueColumnLabel: { classPropertyName: "valueColumnLabel", publicName: "valueColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, sparkline: { classPropertyName: "sparkline", publicName: "sparkline", isSignal: true, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: true, isRequired: false, transformFunction: null }, tooltipDelta: { classPropertyName: "tooltipDelta", publicName: "tooltipDelta", isSignal: true, isRequired: false, transformFunction: null }, axisGap: { classPropertyName: "axisGap", publicName: "axisGap", isSignal: true, isRequired: false, transformFunction: null }, axisTicks: { classPropertyName: "axisTicks", publicName: "axisTicks", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "block h-full" }, viewQueries: [{ propertyName: "svgRef", first: true, predicate: ["svgRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
3256
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiLineChart, isStandalone: true, selector: "ui-line-chart", inputs: { points: { classPropertyName: "points", publicName: "points", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, valueFormat: { classPropertyName: "valueFormat", publicName: "valueFormat", isSignal: true, isRequired: false, transformFunction: null }, tooltipFormat: { classPropertyName: "tooltipFormat", publicName: "tooltipFormat", isSignal: true, isRequired: false, transformFunction: null }, deltaFormat: { classPropertyName: "deltaFormat", publicName: "deltaFormat", isSignal: true, isRequired: false, transformFunction: null }, timeFormat: { classPropertyName: "timeFormat", publicName: "timeFormat", isSignal: true, isRequired: false, transformFunction: null }, axisFormat: { classPropertyName: "axisFormat", publicName: "axisFormat", isSignal: true, isRequired: false, transformFunction: null }, startLabel: { classPropertyName: "startLabel", publicName: "startLabel", isSignal: true, isRequired: false, transformFunction: null }, timeColumnLabel: { classPropertyName: "timeColumnLabel", publicName: "timeColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, valueColumnLabel: { classPropertyName: "valueColumnLabel", publicName: "valueColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, sparkline: { classPropertyName: "sparkline", publicName: "sparkline", isSignal: true, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: true, isRequired: false, transformFunction: null }, tooltipDelta: { classPropertyName: "tooltipDelta", publicName: "tooltipDelta", isSignal: true, isRequired: false, transformFunction: null }, axisGap: { classPropertyName: "axisGap", publicName: "axisGap", isSignal: true, isRequired: false, transformFunction: null }, axisTicks: { classPropertyName: "axisTicks", publicName: "axisTicks", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "block h-full" }, viewQueries: [{ propertyName: "svgRef", first: true, predicate: ["svgRef"], descendants: true, isSignal: true }, { propertyName: "lineRef", first: true, predicate: ["lineRef"], descendants: true, isSignal: true }, { propertyName: "endRef", first: true, predicate: ["endRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
2755
3257
|
<div class="relative h-full">
|
|
2756
3258
|
<svg
|
|
2757
3259
|
#svgRef
|
|
@@ -2766,48 +3268,52 @@ class UiLineChart {
|
|
|
2766
3268
|
(pointerleave)="onPointerLeave()"
|
|
2767
3269
|
(pointermove)="onPointerMove($event)"
|
|
2768
3270
|
>
|
|
2769
|
-
@if (
|
|
3271
|
+
@if (shown(); as shape) {
|
|
2770
3272
|
<path
|
|
3273
|
+
#lineRef
|
|
2771
3274
|
class="stroke-(--foreground)"
|
|
2772
3275
|
data-chart-line
|
|
2773
3276
|
fill="none"
|
|
2774
3277
|
stroke-linecap="round"
|
|
2775
3278
|
stroke-linejoin="round"
|
|
2776
|
-
[attr.d]="
|
|
3279
|
+
[attr.d]="shape.line"
|
|
2777
3280
|
[attr.stroke-width]="sparkline() ? 1.5 : 2"
|
|
2778
3281
|
/>
|
|
2779
3282
|
|
|
2780
3283
|
@if (!sparkline()) {
|
|
2781
3284
|
<line
|
|
2782
|
-
class="stroke-(--border)"
|
|
3285
|
+
class="stroke-(--border) transition-opacity ease-(--ease-out)"
|
|
2783
3286
|
data-chart-start-line
|
|
2784
3287
|
stroke-dasharray="3 4"
|
|
2785
3288
|
stroke-width="1"
|
|
2786
3289
|
x1="0"
|
|
2787
3290
|
[attr.x2]="effectiveWidth()"
|
|
2788
|
-
[attr.y1]="
|
|
2789
|
-
[attr.y2]="
|
|
3291
|
+
[attr.y1]="shape.start.y"
|
|
3292
|
+
[attr.y2]="shape.start.y"
|
|
3293
|
+
[class]="startFade()"
|
|
2790
3294
|
/>
|
|
2791
3295
|
|
|
2792
3296
|
@if (startLabelInfo(); as info) {
|
|
2793
3297
|
<text
|
|
2794
|
-
class="text-caption fill-(--subtle-foreground) tabular-nums"
|
|
3298
|
+
class="text-caption fill-(--subtle-foreground) tabular-nums transition-opacity ease-(--ease-out)"
|
|
2795
3299
|
data-chart-start-label
|
|
2796
3300
|
[attr.text-anchor]="info.placement.anchor"
|
|
2797
3301
|
[attr.x]="info.placement.x"
|
|
2798
3302
|
[attr.y]="info.placement.y"
|
|
3303
|
+
[class]="startFade()"
|
|
2799
3304
|
>
|
|
2800
3305
|
{{ info.label }}
|
|
2801
3306
|
</text>
|
|
2802
3307
|
}
|
|
2803
3308
|
|
|
2804
3309
|
<circle
|
|
3310
|
+
#endRef
|
|
2805
3311
|
class="fill-(--foreground) stroke-(--card) [paint-order:stroke]"
|
|
2806
3312
|
data-chart-end
|
|
2807
3313
|
r="4"
|
|
2808
3314
|
stroke-width="6"
|
|
2809
|
-
[attr.cx]="
|
|
2810
|
-
[attr.cy]="
|
|
3315
|
+
[attr.cx]="shape.end.x"
|
|
3316
|
+
[attr.cy]="shape.end.y"
|
|
2811
3317
|
/>
|
|
2812
3318
|
|
|
2813
3319
|
@for (tick of ticks(); track tick.t; let index = $index; let first = $first; let last = $last) {
|
|
@@ -2908,48 +3414,52 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
2908
3414
|
(pointerleave)="onPointerLeave()"
|
|
2909
3415
|
(pointermove)="onPointerMove($event)"
|
|
2910
3416
|
>
|
|
2911
|
-
@if (
|
|
3417
|
+
@if (shown(); as shape) {
|
|
2912
3418
|
<path
|
|
3419
|
+
#lineRef
|
|
2913
3420
|
class="stroke-(--foreground)"
|
|
2914
3421
|
data-chart-line
|
|
2915
3422
|
fill="none"
|
|
2916
3423
|
stroke-linecap="round"
|
|
2917
3424
|
stroke-linejoin="round"
|
|
2918
|
-
[attr.d]="
|
|
3425
|
+
[attr.d]="shape.line"
|
|
2919
3426
|
[attr.stroke-width]="sparkline() ? 1.5 : 2"
|
|
2920
3427
|
/>
|
|
2921
3428
|
|
|
2922
3429
|
@if (!sparkline()) {
|
|
2923
3430
|
<line
|
|
2924
|
-
class="stroke-(--border)"
|
|
3431
|
+
class="stroke-(--border) transition-opacity ease-(--ease-out)"
|
|
2925
3432
|
data-chart-start-line
|
|
2926
3433
|
stroke-dasharray="3 4"
|
|
2927
3434
|
stroke-width="1"
|
|
2928
3435
|
x1="0"
|
|
2929
3436
|
[attr.x2]="effectiveWidth()"
|
|
2930
|
-
[attr.y1]="
|
|
2931
|
-
[attr.y2]="
|
|
3437
|
+
[attr.y1]="shape.start.y"
|
|
3438
|
+
[attr.y2]="shape.start.y"
|
|
3439
|
+
[class]="startFade()"
|
|
2932
3440
|
/>
|
|
2933
3441
|
|
|
2934
3442
|
@if (startLabelInfo(); as info) {
|
|
2935
3443
|
<text
|
|
2936
|
-
class="text-caption fill-(--subtle-foreground) tabular-nums"
|
|
3444
|
+
class="text-caption fill-(--subtle-foreground) tabular-nums transition-opacity ease-(--ease-out)"
|
|
2937
3445
|
data-chart-start-label
|
|
2938
3446
|
[attr.text-anchor]="info.placement.anchor"
|
|
2939
3447
|
[attr.x]="info.placement.x"
|
|
2940
3448
|
[attr.y]="info.placement.y"
|
|
3449
|
+
[class]="startFade()"
|
|
2941
3450
|
>
|
|
2942
3451
|
{{ info.label }}
|
|
2943
3452
|
</text>
|
|
2944
3453
|
}
|
|
2945
3454
|
|
|
2946
3455
|
<circle
|
|
3456
|
+
#endRef
|
|
2947
3457
|
class="fill-(--foreground) stroke-(--card) [paint-order:stroke]"
|
|
2948
3458
|
data-chart-end
|
|
2949
3459
|
r="4"
|
|
2950
3460
|
stroke-width="6"
|
|
2951
|
-
[attr.cx]="
|
|
2952
|
-
[attr.cy]="
|
|
3461
|
+
[attr.cx]="shape.end.x"
|
|
3462
|
+
[attr.cy]="shape.end.y"
|
|
2953
3463
|
/>
|
|
2954
3464
|
|
|
2955
3465
|
@for (tick of ticks(); track tick.t; let index = $index; let first = $first; let last = $last) {
|
|
@@ -3034,12 +3544,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
3034
3544
|
class: 'block h-full',
|
|
3035
3545
|
},
|
|
3036
3546
|
}]
|
|
3037
|
-
}], ctorParameters: () => [], propDecorators: { points: [{ type: i0.Input, args: [{ isSignal: true, alias: "points", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], valueFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueFormat", required: false }] }], tooltipFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipFormat", required: false }] }], deltaFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "deltaFormat", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], axisFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "axisFormat", required: false }] }], startLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "startLabel", required: false }] }], timeColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeColumnLabel", required: false }] }], valueColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueColumnLabel", required: false }] }], sparkline: [{ type: i0.Input, args: [{ isSignal: true, alias: "sparkline", required: false }] }], tooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltip", required: false }] }], tooltipDelta: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipDelta", required: false }] }], axisGap: [{ type: i0.Input, args: [{ isSignal: true, alias: "axisGap", required: false }] }], axisTicks: [{ type: i0.Input, args: [{ isSignal: true, alias: "axisTicks", required: false }] }], svgRef: [{ type: i0.ViewChild, args: ['svgRef', { isSignal: true }] }] } });
|
|
3547
|
+
}], ctorParameters: () => [], propDecorators: { points: [{ type: i0.Input, args: [{ isSignal: true, alias: "points", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], valueFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueFormat", required: false }] }], tooltipFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipFormat", required: false }] }], deltaFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "deltaFormat", required: false }] }], timeFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeFormat", required: false }] }], axisFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "axisFormat", required: false }] }], startLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "startLabel", required: false }] }], timeColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "timeColumnLabel", required: false }] }], valueColumnLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueColumnLabel", required: false }] }], sparkline: [{ type: i0.Input, args: [{ isSignal: true, alias: "sparkline", required: false }] }], tooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltip", required: false }] }], tooltipDelta: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipDelta", required: false }] }], axisGap: [{ type: i0.Input, args: [{ isSignal: true, alias: "axisGap", required: false }] }], axisTicks: [{ type: i0.Input, args: [{ isSignal: true, alias: "axisTicks", required: false }] }], svgRef: [{ type: i0.ViewChild, args: ['svgRef', { isSignal: true }] }], lineRef: [{ type: i0.ViewChild, args: ['lineRef', { isSignal: true }] }], endRef: [{ type: i0.ViewChild, args: ['endRef', { isSignal: true }] }] } });
|
|
3038
3548
|
|
|
3039
|
-
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,
|
|
3040
|
-
const SHEET_CLASSES = 'max-lg:fixed max-lg:inset-x-4 max-lg:top-auto max-lg:w-auto max-lg:bottom-[calc(76px+env(safe-area-inset-bottom))] max-lg:min-w-0 max-lg:p-1.5 max-lg:bg-(--card) max-lg:shadow-[0_12px_32px_rgb(0_0_0/0.2),inset_0_0_0_1px_var(--border)] max-lg:backdrop:bg-[rgb(0_0_0/0.36)] max-lg:transition-[opacity,translate,overlay,display] max-lg:scale-100 max-lg:translate-y-4 max-lg:open:translate-y-0 max-lg:starting:open:scale-100 max-lg:starting:open:translate-y-4';
|
|
3041
|
-
const SHEET_ITEM_CLASSES = 'flex w-full items-center gap-3 lg:pointer-fine:gap-2.5 min-h-12 lg:min-h-11 lg:pointer-fine:min-h-9 px-3 lg:pointer-fine:px-2.5 rounded-[calc(var(--radius-container)-6px)] lg:rounded-[calc(var(--radius-container)-4px)] text-body lg:pointer-fine:text-label hover:bg-(--glow) focus-visible:bg-(--glow) active:bg-(--soft) outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring) [:where(&>svg)]:size-5 [:where(&>svg)]:flex-none lg:[:where(&>svg)]:size-[18px] lg:pointer-fine:[:where(&>svg)]:size-4';
|
|
3042
|
-
const ITEM_CLASSES = 'flex w-full items-center gap-3 pointer-fine:gap-2.5 min-h-11 pointer-fine:min-h-9 px-3 pointer-fine:px-2.5 rounded-[calc(var(--radius-container)-4px)] text-body pointer-fine:text-label hover:bg-(--glow) focus-visible:bg-(--glow) active:bg-(--soft) outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring) [:where(&>svg)]:size-[18px] [:where(&>svg)]:flex-none pointer-fine:[:where(&>svg)]:size-4';
|
|
3549
|
+
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,scale,overlay,display] transition-discrete duration-(--duration-fast) not-open:duration-[120ms] ease-out starting:open:opacity-0 starting:open:scale-(--enter-scale) opacity-0 scale-(--enter-scale) open:opacity-100 open:scale-100';
|
|
3550
|
+
const SHEET_CLASSES = 'max-lg:fixed max-lg:inset-x-4 max-lg:top-auto max-lg:w-auto max-lg:bottom-[calc(76px+env(safe-area-inset-bottom))] max-lg:min-w-0 max-lg:p-1.5 max-lg:bg-(--card) max-lg:shadow-[0_12px_32px_rgb(0_0_0/0.2),inset_0_0_0_1px_var(--border)] max-lg:backdrop:bg-[rgb(0_0_0/0.36)] max-lg:transition-[opacity,translate,overlay,display] max-lg:scale-100 max-lg:translate-y-4 max-lg:open:translate-y-0 max-lg:starting:open:scale-100 max-lg:starting:open:translate-y-4 max-lg:motion-reduce:translate-y-0 max-lg:motion-reduce:starting:open:translate-y-0';
|
|
3551
|
+
const SHEET_ITEM_CLASSES = 'flex w-full items-center gap-3 lg:pointer-fine:gap-2.5 min-h-12 lg:min-h-11 lg:pointer-fine:min-h-9 px-3 lg:pointer-fine:px-2.5 rounded-[calc(var(--radius-container)-6px)] lg:rounded-[calc(var(--radius-container)-4px)] text-body lg:pointer-fine:text-label hover:bg-(--glow) focus-visible:bg-(--glow) active:bg-(--soft) transition-[background-color] duration-(--duration-fast) ease-out outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring) [:where(&>svg)]:size-5 [:where(&>svg)]:flex-none lg:[:where(&>svg)]:size-[18px] lg:pointer-fine:[:where(&>svg)]:size-4';
|
|
3552
|
+
const ITEM_CLASSES = 'flex w-full items-center gap-3 pointer-fine:gap-2.5 min-h-11 pointer-fine:min-h-9 px-3 pointer-fine:px-2.5 rounded-[calc(var(--radius-container)-4px)] text-body pointer-fine:text-label hover:bg-(--glow) focus-visible:bg-(--glow) active:bg-(--soft) transition-[background-color] duration-(--duration-fast) ease-out outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring) [:where(&>svg)]:size-[18px] [:where(&>svg)]:flex-none pointer-fine:[:where(&>svg)]:size-4';
|
|
3043
3553
|
const nextId$1 = (() => {
|
|
3044
3554
|
let count = 0;
|
|
3045
3555
|
return () => `ui-menu-${++count}`;
|
|
@@ -3341,7 +3851,221 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
3341
3851
|
}]
|
|
3342
3852
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], valueText: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueText", required: true }] }], tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
3343
3853
|
|
|
3344
|
-
|
|
3854
|
+
function readDuration$1(element, name, fallback) {
|
|
3855
|
+
const raw = getComputedStyle(element).getPropertyValue(name).trim();
|
|
3856
|
+
const value = parseFloat(raw);
|
|
3857
|
+
if (Number.isNaN(value)) {
|
|
3858
|
+
return fallback;
|
|
3859
|
+
}
|
|
3860
|
+
return raw.endsWith('ms') ? value : value * 1000;
|
|
3861
|
+
}
|
|
3862
|
+
function readEasing(element, name, fallback) {
|
|
3863
|
+
return getComputedStyle(element).getPropertyValue(name).trim() || fallback;
|
|
3864
|
+
}
|
|
3865
|
+
|
|
3866
|
+
/**
|
|
3867
|
+
* Slides the remaining children of a list into place when one is removed or inserted (FLIP): it
|
|
3868
|
+
* measures every child before and after the change, then animates the shift in `translateY` over
|
|
3869
|
+
* `--duration-base` `--ease-out`. Pair it with `animate.leave="ui-leave-fade"` on the item so it fades
|
|
3870
|
+
* out first. Nothing moves under `prefers-reduced-motion`: the list closes up at once.
|
|
3871
|
+
*
|
|
3872
|
+
* @example
|
|
3873
|
+
* <ul uiFlipList>
|
|
3874
|
+
* @for (key of keys(); track key.id) {
|
|
3875
|
+
* <li uiListRow animate.leave="ui-leave-fade">...</li>
|
|
3876
|
+
* }
|
|
3877
|
+
* </ul>
|
|
3878
|
+
*/
|
|
3879
|
+
class UiFlipList {
|
|
3880
|
+
host = inject(ElementRef).nativeElement;
|
|
3881
|
+
reduced = injectReducedMotion();
|
|
3882
|
+
mutations = new MutationObserver(() => this.onChange());
|
|
3883
|
+
resizes = new ResizeObserver(() => this.measure());
|
|
3884
|
+
running = new Map();
|
|
3885
|
+
watched = new Set();
|
|
3886
|
+
tops = new Map();
|
|
3887
|
+
constructor() {
|
|
3888
|
+
afterNextRender(() => {
|
|
3889
|
+
this.measure();
|
|
3890
|
+
this.mutations.observe(this.host, { childList: true });
|
|
3891
|
+
this.resizes.observe(this.host);
|
|
3892
|
+
});
|
|
3893
|
+
inject(DestroyRef).onDestroy(() => {
|
|
3894
|
+
this.mutations.disconnect();
|
|
3895
|
+
this.resizes.disconnect();
|
|
3896
|
+
});
|
|
3897
|
+
}
|
|
3898
|
+
measure() {
|
|
3899
|
+
const children = Array.from(this.host.children).filter((child) => child instanceof HTMLElement);
|
|
3900
|
+
this.tops = new Map(children.map((child) => [child, child.offsetTop]));
|
|
3901
|
+
for (const child of children) {
|
|
3902
|
+
if (!this.watched.has(child)) {
|
|
3903
|
+
this.watched.add(child);
|
|
3904
|
+
this.resizes.observe(child);
|
|
3905
|
+
}
|
|
3906
|
+
}
|
|
3907
|
+
for (const child of this.watched) {
|
|
3908
|
+
if (!this.tops.has(child)) {
|
|
3909
|
+
this.watched.delete(child);
|
|
3910
|
+
this.running.delete(child);
|
|
3911
|
+
this.resizes.unobserve(child);
|
|
3912
|
+
}
|
|
3913
|
+
}
|
|
3914
|
+
}
|
|
3915
|
+
interruptedOffset(child) {
|
|
3916
|
+
const running = this.running.get(child);
|
|
3917
|
+
if (!running) {
|
|
3918
|
+
return 0;
|
|
3919
|
+
}
|
|
3920
|
+
const shown = child.getBoundingClientRect().top;
|
|
3921
|
+
running.cancel();
|
|
3922
|
+
this.running.delete(child);
|
|
3923
|
+
return shown - child.getBoundingClientRect().top;
|
|
3924
|
+
}
|
|
3925
|
+
onChange() {
|
|
3926
|
+
const before = this.tops;
|
|
3927
|
+
this.measure();
|
|
3928
|
+
if (this.reduced()) {
|
|
3929
|
+
return;
|
|
3930
|
+
}
|
|
3931
|
+
const duration = readDuration$1(this.host, '--duration-base', 260);
|
|
3932
|
+
const easing = readEasing(this.host, '--ease-out', 'ease-out');
|
|
3933
|
+
for (const [child, top] of this.tops) {
|
|
3934
|
+
const previous = before.get(child);
|
|
3935
|
+
if (previous === undefined || previous === top) {
|
|
3936
|
+
continue;
|
|
3937
|
+
}
|
|
3938
|
+
const from = previous - top + this.interruptedOffset(child);
|
|
3939
|
+
this.running.set(child, child.animate([{ transform: `translateY(${from}px)` }, { transform: 'translateY(0)' }], { duration, easing }));
|
|
3940
|
+
}
|
|
3941
|
+
}
|
|
3942
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFlipList, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3943
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.7", type: UiFlipList, isStandalone: true, selector: "[uiFlipList]", ngImport: i0 });
|
|
3944
|
+
}
|
|
3945
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiFlipList, decorators: [{
|
|
3946
|
+
type: Directive,
|
|
3947
|
+
args: [{
|
|
3948
|
+
selector: '[uiFlipList]',
|
|
3949
|
+
}]
|
|
3950
|
+
}], ctorParameters: () => [] });
|
|
3951
|
+
|
|
3952
|
+
const HOLD_MS = 200;
|
|
3953
|
+
const SCROLL_SETTLE_MS = 200;
|
|
3954
|
+
const SCROLL_START_MS = 300;
|
|
3955
|
+
function paintedElements(host) {
|
|
3956
|
+
if (host.tagName === 'TR') {
|
|
3957
|
+
return Array.from(host.children).filter((cell) => cell instanceof HTMLElement);
|
|
3958
|
+
}
|
|
3959
|
+
if (host.hasAttribute('ui-group-cell') && host.firstElementChild instanceof HTMLElement) {
|
|
3960
|
+
return [host.firstElementChild];
|
|
3961
|
+
}
|
|
3962
|
+
return [host];
|
|
3963
|
+
}
|
|
3964
|
+
/**
|
|
3965
|
+
* Draws the eye to an element that just changed: scrolls it into view when it is off screen, holds the
|
|
3966
|
+
* `--soft` fill for 200 ms, then fades back to the element's own background over `--duration-highlight`.
|
|
3967
|
+
* Each new non-null token plays once, so pass a fresh value per event (an object or a counter), not a
|
|
3968
|
+
* boolean. A non-null token already present at first render plays on arrival. On a `tr` it paints the
|
|
3969
|
+
* cells, on a `td[ui-group-cell]` the band, anywhere else the host. Under `prefers-reduced-motion` the
|
|
3970
|
+
* scroll is instant and the fade lasts 600 ms.
|
|
3971
|
+
*
|
|
3972
|
+
* Give the element `scroll-margin-top` and `scroll-margin-bottom` equal to what is pinned above and
|
|
3973
|
+
* below it (header, tab bar, action bar): a row under them counts as off screen and is scrolled out.
|
|
3974
|
+
* For an arrival on a page opened at the element, scroll to it at once first (`scrollIntoView` in
|
|
3975
|
+
* `afterNextRender`) and set the token afterwards: a token present at first render scrolls smoothly
|
|
3976
|
+
* from where the page is.
|
|
3977
|
+
*
|
|
3978
|
+
* @example
|
|
3979
|
+
* <a ui-row [uiHighlight]="changed() === holding.id ? token() : null" routerLink="/holdings/1">...</a>
|
|
3980
|
+
*/
|
|
3981
|
+
class UiHighlight {
|
|
3982
|
+
uiHighlight = input(null, /* @ts-ignore */
|
|
3983
|
+
...(ngDevMode ? [{ debugName: "uiHighlight" }] : /* istanbul ignore next */ []));
|
|
3984
|
+
host = inject(ElementRef).nativeElement;
|
|
3985
|
+
reduced = injectReducedMotion();
|
|
3986
|
+
cancel = null;
|
|
3987
|
+
constructor() {
|
|
3988
|
+
effect(() => {
|
|
3989
|
+
const token = this.uiHighlight();
|
|
3990
|
+
if (token === null || token === undefined) {
|
|
3991
|
+
return;
|
|
3992
|
+
}
|
|
3993
|
+
untracked(() => this.play());
|
|
3994
|
+
});
|
|
3995
|
+
inject(DestroyRef).onDestroy(() => this.cancel?.());
|
|
3996
|
+
}
|
|
3997
|
+
play() {
|
|
3998
|
+
this.cancel?.();
|
|
3999
|
+
if (this.isVisible()) {
|
|
4000
|
+
this.cancel = this.flash();
|
|
4001
|
+
return;
|
|
4002
|
+
}
|
|
4003
|
+
const reduced = this.reduced();
|
|
4004
|
+
this.host.scrollIntoView({ behavior: reduced ? 'auto' : 'smooth', block: 'center' });
|
|
4005
|
+
if (reduced) {
|
|
4006
|
+
this.cancel = this.flash();
|
|
4007
|
+
return;
|
|
4008
|
+
}
|
|
4009
|
+
let stopFlash = null;
|
|
4010
|
+
let timer;
|
|
4011
|
+
const moves = (event) => event.target === document || (event.target instanceof Node && event.target.contains(this.host));
|
|
4012
|
+
const start = () => {
|
|
4013
|
+
stopListening();
|
|
4014
|
+
stopFlash = this.flash();
|
|
4015
|
+
};
|
|
4016
|
+
const onScrollEnd = (event) => {
|
|
4017
|
+
if (moves(event)) {
|
|
4018
|
+
start();
|
|
4019
|
+
}
|
|
4020
|
+
};
|
|
4021
|
+
const onScroll = (event) => {
|
|
4022
|
+
if (moves(event)) {
|
|
4023
|
+
clearTimeout(timer);
|
|
4024
|
+
timer = setTimeout(start, SCROLL_SETTLE_MS);
|
|
4025
|
+
}
|
|
4026
|
+
};
|
|
4027
|
+
const stopListening = () => {
|
|
4028
|
+
clearTimeout(timer);
|
|
4029
|
+
window.removeEventListener('scrollend', onScrollEnd, true);
|
|
4030
|
+
window.removeEventListener('scroll', onScroll, true);
|
|
4031
|
+
};
|
|
4032
|
+
timer = setTimeout(start, SCROLL_START_MS);
|
|
4033
|
+
window.addEventListener('scrollend', onScrollEnd, true);
|
|
4034
|
+
window.addEventListener('scroll', onScroll, true);
|
|
4035
|
+
this.cancel = () => {
|
|
4036
|
+
stopListening();
|
|
4037
|
+
stopFlash?.();
|
|
4038
|
+
};
|
|
4039
|
+
}
|
|
4040
|
+
isVisible() {
|
|
4041
|
+
const rect = this.host.getBoundingClientRect();
|
|
4042
|
+
const style = getComputedStyle(this.host);
|
|
4043
|
+
const top = parseFloat(style.scrollMarginTop) || 0;
|
|
4044
|
+
const bottom = parseFloat(style.scrollMarginBottom) || 0;
|
|
4045
|
+
return rect.top >= top && rect.bottom <= window.innerHeight - bottom;
|
|
4046
|
+
}
|
|
4047
|
+
flash() {
|
|
4048
|
+
const fade = readDuration$1(this.host, '--duration-highlight', 1200);
|
|
4049
|
+
const easing = readEasing(this.host, '--ease-out', 'ease-out');
|
|
4050
|
+
const total = HOLD_MS + fade;
|
|
4051
|
+
const animations = paintedElements(this.host).map((element) => element.animate([
|
|
4052
|
+
{ backgroundColor: 'var(--soft)', offset: 0 },
|
|
4053
|
+
{ backgroundColor: 'var(--soft)', offset: HOLD_MS / total, easing },
|
|
4054
|
+
{ offset: 1 },
|
|
4055
|
+
], { duration: total }));
|
|
4056
|
+
return () => animations.forEach((animation) => animation.cancel());
|
|
4057
|
+
}
|
|
4058
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiHighlight, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
4059
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiHighlight, isStandalone: true, selector: "[uiHighlight]", inputs: { uiHighlight: { classPropertyName: "uiHighlight", publicName: "uiHighlight", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
4060
|
+
}
|
|
4061
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiHighlight, decorators: [{
|
|
4062
|
+
type: Directive,
|
|
4063
|
+
args: [{
|
|
4064
|
+
selector: '[uiHighlight]',
|
|
4065
|
+
}]
|
|
4066
|
+
}], ctorParameters: () => [], propDecorators: { uiHighlight: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiHighlight", required: false }] }] } });
|
|
4067
|
+
|
|
4068
|
+
const BASE_CLASSES$2 = 'flex items-center gap-3 h-10 px-3 rounded-control text-label leading-normal font-medium transition-[scale,background-color,color] [transition-duration:var(--duration-press),var(--duration-fast),var(--duration-fast)] ease-out active:scale-(--press-scale) hover:bg-(--glow) hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring)';
|
|
3345
4069
|
const ACTIVE_CLASSES = 'bg-(--soft) text-(--foreground)';
|
|
3346
4070
|
const IDLE_CLASSES = 'text-(--muted-foreground) active:bg-(--soft)';
|
|
3347
4071
|
/**
|
|
@@ -3355,7 +4079,7 @@ const IDLE_CLASSES = 'text-(--muted-foreground) active:bg-(--soft)';
|
|
|
3355
4079
|
*/
|
|
3356
4080
|
class UiNavItem {
|
|
3357
4081
|
active = input(false, { ...(ngDevMode ? { debugName: "active" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3358
|
-
classes = computed(() => `${BASE_CLASSES$
|
|
4082
|
+
classes = computed(() => `${BASE_CLASSES$2} ${this.active() ? ACTIVE_CLASSES : IDLE_CLASSES}`, /* @ts-ignore */
|
|
3359
4083
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
3360
4084
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiNavItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3361
4085
|
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 });
|
|
@@ -3384,10 +4108,12 @@ const SIZE_CLASSES$1 = {
|
|
|
3384
4108
|
};
|
|
3385
4109
|
const SIZE_GAPS = { md: 'gap-2.5', lg: 'gap-2.5', xl: 'gap-3', card: 'gap-2', dense: 'gap-3' };
|
|
3386
4110
|
const PADDING_CLASSES = { md: 'px-2.5', sm: 'px-2', none: 'px-0' };
|
|
3387
|
-
const BASE_CLASSES = 'flex w-full items-center py-1.5 rounded-control text-left select-none touch-manipulation
|
|
4111
|
+
const BASE_CLASSES$1 = 'flex w-full items-center py-1.5 rounded-control text-left select-none touch-manipulation focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring)';
|
|
4112
|
+
const INTERACTIVE_CLASSES = 'transition-[scale,background-color] [transition-duration:var(--duration-press),var(--duration-fast)] ease-out hover:bg-(--glow) active:bg-(--soft) active:scale-(--press-scale)';
|
|
4113
|
+
const UNAVAILABLE_CLASSES = 'opacity-50 cursor-not-allowed';
|
|
3388
4114
|
const SELECTED_CLASSES$1 = 'bg-(--soft)';
|
|
3389
4115
|
/**
|
|
3390
|
-
* Clickable row of a list: a holding, an
|
|
4116
|
+
* Clickable row of a list: a holding, an account, a search result.
|
|
3391
4117
|
*
|
|
3392
4118
|
* @example
|
|
3393
4119
|
* <a ui-row [selected]="holding.id === openId()" [routerLink]="['/holdings', holding.id]">
|
|
@@ -3396,28 +4122,59 @@ const SELECTED_CLASSES$1 = 'bg-(--soft)';
|
|
|
3396
4122
|
*/
|
|
3397
4123
|
class UiRow {
|
|
3398
4124
|
selected = input(false, { ...(ngDevMode ? { debugName: "selected" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
4125
|
+
busy = input(false, { ...(ngDevMode ? { debugName: "busy" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
4126
|
+
unavailable = input(false, { ...(ngDevMode ? { debugName: "unavailable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
3399
4127
|
size = input('md', /* @ts-ignore */
|
|
3400
4128
|
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
3401
4129
|
padding = input('md', /* @ts-ignore */
|
|
3402
4130
|
...(ngDevMode ? [{ debugName: "padding" }] : /* istanbul ignore next */ []));
|
|
3403
4131
|
gap = input('default', /* @ts-ignore */
|
|
3404
4132
|
...(ngDevMode ? [{ debugName: "gap" }] : /* istanbul ignore next */ []));
|
|
3405
|
-
classes = computed(() => `${BASE_CLASSES} ${SIZE_CLASSES$1[this.size()]} ${this.gap() === 'sm' ? 'gap-2' : SIZE_GAPS[this.size()]} ${PADDING_CLASSES[this.padding()]}${this.selected() ? ` ${SELECTED_CLASSES$1}` : ''}`, /* @ts-ignore */
|
|
4133
|
+
classes = computed(() => `${BASE_CLASSES$1} ${SIZE_CLASSES$1[this.size()]} ${this.gap() === 'sm' ? 'gap-2' : SIZE_GAPS[this.size()]} ${PADDING_CLASSES[this.padding()]}${this.unavailable() ? ` ${UNAVAILABLE_CLASSES}` : ` ${INTERACTIVE_CLASSES}`}${this.selected() ? ` ${SELECTED_CLASSES$1}` : ''}${this.busy() ? ' pointer-events-none' : ''}`, /* @ts-ignore */
|
|
3406
4134
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
4135
|
+
constructor() {
|
|
4136
|
+
const host = inject(ElementRef).nativeElement;
|
|
4137
|
+
const guard = (event) => {
|
|
4138
|
+
if (this.busy() || this.unavailable()) {
|
|
4139
|
+
event.preventDefault();
|
|
4140
|
+
event.stopImmediatePropagation();
|
|
4141
|
+
}
|
|
4142
|
+
};
|
|
4143
|
+
host.addEventListener('click', guard, { capture: true });
|
|
4144
|
+
inject(DestroyRef).onDestroy(() => host.removeEventListener('click', guard, { capture: true }));
|
|
4145
|
+
}
|
|
3407
4146
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRow, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3408
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.
|
|
4147
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.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 }, busy: { classPropertyName: "busy", publicName: "busy", isSignal: true, isRequired: false, transformFunction: null }, unavailable: { classPropertyName: "unavailable", publicName: "unavailable", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, padding: { classPropertyName: "padding", publicName: "padding", isSignal: true, isRequired: false, transformFunction: null }, gap: { classPropertyName: "gap", publicName: "gap", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.aria-busy": "busy() || null", "attr.aria-disabled": "busy() || unavailable() ? 'true' : null", "attr.aria-current": "selected() ? 'true' : null" } }, ngImport: i0, template: `
|
|
4148
|
+
<ng-content />
|
|
4149
|
+
@if (busy()) {
|
|
4150
|
+
<span
|
|
4151
|
+
aria-hidden="true"
|
|
4152
|
+
class="rounded-pill animate-cairn-spin size-4 flex-none border-2 border-current border-r-transparent"
|
|
4153
|
+
></span>
|
|
4154
|
+
}
|
|
4155
|
+
`, isInline: true });
|
|
3409
4156
|
}
|
|
3410
4157
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiRow, decorators: [{
|
|
3411
4158
|
type: Component,
|
|
3412
4159
|
args: [{
|
|
3413
4160
|
selector: 'a[ui-row], button[ui-row]',
|
|
3414
|
-
template:
|
|
4161
|
+
template: `
|
|
4162
|
+
<ng-content />
|
|
4163
|
+
@if (busy()) {
|
|
4164
|
+
<span
|
|
4165
|
+
aria-hidden="true"
|
|
4166
|
+
class="rounded-pill animate-cairn-spin size-4 flex-none border-2 border-current border-r-transparent"
|
|
4167
|
+
></span>
|
|
4168
|
+
}
|
|
4169
|
+
`,
|
|
3415
4170
|
host: {
|
|
3416
4171
|
'[class]': 'classes()',
|
|
4172
|
+
'[attr.aria-busy]': 'busy() || null',
|
|
4173
|
+
'[attr.aria-disabled]': "busy() || unavailable() ? 'true' : null",
|
|
3417
4174
|
'[attr.aria-current]': "selected() ? 'true' : null",
|
|
3418
4175
|
},
|
|
3419
4176
|
}]
|
|
3420
|
-
}], propDecorators: { selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], padding: [{ type: i0.Input, args: [{ isSignal: true, alias: "padding", required: false }] }], gap: [{ type: i0.Input, args: [{ isSignal: true, alias: "gap", required: false }] }] } });
|
|
4177
|
+
}], ctorParameters: () => [], propDecorators: { selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], busy: [{ type: i0.Input, args: [{ isSignal: true, alias: "busy", required: false }] }], unavailable: [{ type: i0.Input, args: [{ isSignal: true, alias: "unavailable", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], padding: [{ type: i0.Input, args: [{ isSignal: true, alias: "padding", required: false }] }], gap: [{ type: i0.Input, args: [{ isSignal: true, alias: "gap", required: false }] }] } });
|
|
3421
4178
|
/**
|
|
3422
4179
|
* Lays out a `ui-row` with a trailing action beside it, such as a "more" icon button: the row takes
|
|
3423
4180
|
* the room the action leaves and the action keeps its own size.
|
|
@@ -3496,7 +4253,7 @@ const nextId = (() => {
|
|
|
3496
4253
|
let count = 0;
|
|
3497
4254
|
return () => `ui-segmented-${++count}`;
|
|
3498
4255
|
})();
|
|
3499
|
-
const OPTION_CLASSES = "relative z-10 flex-1 cursor-pointer px-3 text-label font-medium transition-
|
|
4256
|
+
const OPTION_CLASSES = "relative z-10 flex-1 cursor-pointer px-3 text-label font-medium transition-[scale,color] duration-(--duration-press) ease-out 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)";
|
|
3500
4257
|
const SEGMENTED_SIZES = ['md', 'sm'];
|
|
3501
4258
|
const SIZE_CLASSES = {
|
|
3502
4259
|
md: 'h-10 pointer-fine:h-8',
|
|
@@ -3731,11 +4488,13 @@ class UiSkeleton {
|
|
|
3731
4488
|
}, /* @ts-ignore */
|
|
3732
4489
|
...(ngDevMode ? [{ debugName: "bars" }] : /* istanbul ignore next */ []));
|
|
3733
4490
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiSkeleton, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3734
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiSkeleton, isStandalone: true, selector: "ui-skeleton", inputs: { shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null }, lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-hidden": "true" }, classAttribute: "flex flex-col gap-2" }, ngImport: i0, template: "\n @switch (shape()) {\n @case ('figure') {\n <span class=\"block rounded-control bg-(--muted) h-10 w-65\" [style.animation]=\"animation\"></span>\n }\n @case ('row') {\n <span class=\"flex h-14 items-center justify-between gap-4\">\n <span class=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <span class=\"block rounded-control bg-(--muted) h-4 w-3/5\" [style.animation]=\"animation\"></span>\n <span class=\"block rounded-control bg-(--muted) h-3 w-20\" [style.animation]=\"animation\"></span>\n </span>\n <span class=\"block rounded-control bg-(--muted) h-4 w-[90px] flex-none\" [style.animation]=\"animation\"></span>\n </span>\n }\n @case ('chart') {\n <span class=\"rounded-control min-h-50 w-full flex-1 bg-(--muted)\" [style.animation]=\"animation\"></span>\n }\n @case ('dot') {\n <span class=\"rounded-pill size-3 bg-(--muted)\" [style.animation]=\"animation\"></span>\n }\n @case ('ring') {\n <span\n class=\"rounded-pill shadow-[inset_0_0_0_30px_var(--muted)]\"\n [style.animation]=\"animation\"\n [style.height.px]=\"size()\"\n [style.width.px]=\"size()\"\n ></span>\n }\n @default {\n @for (line of bars(); track $index) {\n <span\n class=\"block rounded-control bg-(--muted)\"\n [style.animation]=\"animation\"\n [style.height.px]=\"height()\"\n [style.width]=\"line\"\n ></span>\n }\n }\n }\n ", isInline: true
|
|
4491
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiSkeleton, isStandalone: true, selector: "ui-skeleton", inputs: { shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null }, lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-hidden": "true" }, classAttribute: "flex flex-col gap-2" }, ngImport: i0, template: "\n @switch (shape()) {\n @case ('figure') {\n <span class=\"block rounded-control bg-(--muted) h-10 w-65\" [style.animation]=\"animation\"></span>\n }\n @case ('row') {\n <span class=\"flex h-14 items-center justify-between gap-4\">\n <span class=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n <span class=\"block rounded-control bg-(--muted) h-4 w-3/5\" [style.animation]=\"animation\"></span>\n <span class=\"block rounded-control bg-(--muted) h-3 w-20\" [style.animation]=\"animation\"></span>\n </span>\n <span class=\"block rounded-control bg-(--muted) h-4 w-[90px] flex-none\" [style.animation]=\"animation\"></span>\n </span>\n }\n @case ('chart') {\n <span class=\"rounded-control min-h-50 w-full flex-1 bg-(--muted)\" [style.animation]=\"animation\"></span>\n }\n @case ('dot') {\n <span class=\"rounded-pill size-3 bg-(--muted)\" [style.animation]=\"animation\"></span>\n }\n @case ('ring') {\n <span\n class=\"rounded-pill shadow-[inset_0_0_0_30px_var(--muted)]\"\n [style.animation]=\"animation\"\n [style.height.px]=\"size()\"\n [style.width.px]=\"size()\"\n ></span>\n }\n @default {\n @for (line of bars(); track $index) {\n <span\n class=\"block rounded-control bg-(--muted)\"\n [style.animation]=\"animation\"\n [style.height.px]=\"height()\"\n [style.width]=\"line\"\n ></span>\n }\n }\n }\n ", isInline: true });
|
|
3735
4492
|
}
|
|
3736
4493
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiSkeleton, decorators: [{
|
|
3737
4494
|
type: Component,
|
|
3738
|
-
args: [{
|
|
4495
|
+
args: [{
|
|
4496
|
+
selector: 'ui-skeleton',
|
|
4497
|
+
template: `
|
|
3739
4498
|
@switch (shape()) {
|
|
3740
4499
|
@case ('figure') {
|
|
3741
4500
|
<span class="${BAR_CLASSES} h-10 w-65" [style.animation]="animation"></span>
|
|
@@ -3774,12 +4533,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
3774
4533
|
}
|
|
3775
4534
|
}
|
|
3776
4535
|
}
|
|
3777
|
-
`,
|
|
4536
|
+
`,
|
|
4537
|
+
host: {
|
|
3778
4538
|
'aria-hidden': 'true',
|
|
3779
4539
|
class: 'flex flex-col gap-2',
|
|
3780
|
-
},
|
|
4540
|
+
},
|
|
4541
|
+
}]
|
|
3781
4542
|
}], 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 }] }] } });
|
|
3782
4543
|
|
|
4544
|
+
const BASE_CLASSES = 'inline-flex items-center gap-0.5 rounded-[4px] text-caption font-medium text-(--stale) hover:underline underline-offset-3 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--ring)';
|
|
4545
|
+
const CHEVRON_CLASSES = "after:size-4 after:flex-none after:bg-current after:content-[''] after:mask-center after:mask-no-repeat after:mask-[url(data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2024%2024%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.75%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27%3E%3Cpath%20d%3D%27m9%2018%206-6-6-6%27%2F%3E%3C%2Fsvg%3E)]";
|
|
4546
|
+
/**
|
|
4547
|
+
* Link in the stale tone, for a caption about data that is late or left out of a total, such as
|
|
4548
|
+
* "1 ligne sans cours, non comptée". Caption size, weight 500, underlined on hover, with an optional
|
|
4549
|
+
* trailing chevron.
|
|
4550
|
+
*
|
|
4551
|
+
* @example
|
|
4552
|
+
* <a uiStaleLink chevron routerLink="/holdings">1 cours en retard</a>
|
|
4553
|
+
*/
|
|
4554
|
+
class UiStaleLink {
|
|
4555
|
+
chevron = input(false, { ...(ngDevMode ? { debugName: "chevron" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
4556
|
+
classes = computed(() => (this.chevron() ? `${BASE_CLASSES} ${CHEVRON_CLASSES}` : BASE_CLASSES), /* @ts-ignore */
|
|
4557
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
4558
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiStaleLink, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
4559
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.7", type: UiStaleLink, isStandalone: true, selector: "a[uiStaleLink]", inputs: { chevron: { classPropertyName: "chevron", publicName: "chevron", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0 });
|
|
4560
|
+
}
|
|
4561
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiStaleLink, decorators: [{
|
|
4562
|
+
type: Directive,
|
|
4563
|
+
args: [{
|
|
4564
|
+
selector: 'a[uiStaleLink]',
|
|
4565
|
+
host: { '[class]': 'classes()' },
|
|
4566
|
+
}]
|
|
4567
|
+
}], propDecorators: { chevron: [{ type: i0.Input, args: [{ isSignal: true, alias: "chevron", required: false }] }] } });
|
|
4568
|
+
|
|
3783
4569
|
/** Available stat sizes. `StatSize` is derived from this tuple. */
|
|
3784
4570
|
const STAT_SIZES = ['hero', 'tile'];
|
|
3785
4571
|
const VALUE_CLASSES = {
|
|
@@ -3867,7 +4653,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
3867
4653
|
}]
|
|
3868
4654
|
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|
|
3869
4655
|
|
|
3870
|
-
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-
|
|
4656
|
+
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-[background-color] 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";
|
|
3871
4657
|
/**
|
|
3872
4658
|
* Native checkbox styled as an iOS-style switch, exposed to assistive technology as `role="switch"`.
|
|
3873
4659
|
* 51 by 31 on touch, 40 by 24 with a mouse.
|
|
@@ -3891,7 +4677,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
3891
4677
|
}]
|
|
3892
4678
|
}] });
|
|
3893
4679
|
|
|
3894
|
-
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)';
|
|
4680
|
+
const TAB_CLASSES = 'flex h-[52px] flex-col items-center justify-center gap-[3px] touch-manipulation select-none transition-transform duration-(--duration-press) ease-out active:scale-(--press-scale) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--ring)';
|
|
3895
4681
|
const INACTIVE_TAB_CLASSES = 'font-medium text-(--muted-foreground)';
|
|
3896
4682
|
const ACTIVE_TAB_CLASSES = 'font-semibold text-(--foreground)';
|
|
3897
4683
|
/**
|
|
@@ -3947,6 +4733,150 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
3947
4733
|
}]
|
|
3948
4734
|
}], propDecorators: { active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }] } });
|
|
3949
4735
|
|
|
4736
|
+
/**
|
|
4737
|
+
* One-slot confirmation message queue read by `ui-toaster`.
|
|
4738
|
+
*
|
|
4739
|
+
* @example
|
|
4740
|
+
* inject(UiToasts).show('Achat enregistré');
|
|
4741
|
+
*/
|
|
4742
|
+
class UiToasts {
|
|
4743
|
+
current = signal(null, /* @ts-ignore */
|
|
4744
|
+
...(ngDevMode ? [{ debugName: "current" }] : /* istanbul ignore next */ []));
|
|
4745
|
+
sequence = 0;
|
|
4746
|
+
toast = this.current.asReadonly();
|
|
4747
|
+
show(message) {
|
|
4748
|
+
this.current.set({ id: ++this.sequence, text: message });
|
|
4749
|
+
}
|
|
4750
|
+
dismiss() {
|
|
4751
|
+
this.current.set(null);
|
|
4752
|
+
}
|
|
4753
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiToasts, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
4754
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiToasts, providedIn: 'root' });
|
|
4755
|
+
}
|
|
4756
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiToasts, decorators: [{
|
|
4757
|
+
type: Injectable,
|
|
4758
|
+
args: [{ providedIn: 'root' }]
|
|
4759
|
+
}] });
|
|
4760
|
+
|
|
4761
|
+
const DEFAULT_DURATION = 5000;
|
|
4762
|
+
const TOAST_CLASSES = 'pointer-events-auto max-w-[min(28rem,calc(100vw-2rem))] rounded-container bg-(--elevated) px-4 py-3 text-label text-(--foreground) shadow-[0_8px_24px_rgb(0_0_0/0.16),inset_0_0_0_1px_var(--border)] transition-[opacity,translate] duration-(--duration-base) ease-out starting:opacity-0 starting:translate-y-2 motion-reduce:starting:translate-y-0';
|
|
4763
|
+
const readDuration = (host) => {
|
|
4764
|
+
const raw = getComputedStyle(host).getPropertyValue('--toast-duration').trim();
|
|
4765
|
+
const value = parseFloat(raw);
|
|
4766
|
+
if (Number.isNaN(value)) {
|
|
4767
|
+
return DEFAULT_DURATION;
|
|
4768
|
+
}
|
|
4769
|
+
return raw.endsWith('ms') ? value : value * 1000;
|
|
4770
|
+
};
|
|
4771
|
+
/**
|
|
4772
|
+
* Confirmation message shown by `UiToasts.show`: one at a time, no action, gone after `--toast-duration`.
|
|
4773
|
+
* Place it once in the app shell.
|
|
4774
|
+
*
|
|
4775
|
+
* @example
|
|
4776
|
+
* <ui-toaster />
|
|
4777
|
+
*/
|
|
4778
|
+
class UiToaster {
|
|
4779
|
+
toasts = inject(UiToasts);
|
|
4780
|
+
toastClasses = TOAST_CLASSES;
|
|
4781
|
+
host = inject(ElementRef).nativeElement;
|
|
4782
|
+
hovered = signal(false, /* @ts-ignore */
|
|
4783
|
+
...(ngDevMode ? [{ debugName: "hovered" }] : /* istanbul ignore next */ []));
|
|
4784
|
+
focused = signal(false, /* @ts-ignore */
|
|
4785
|
+
...(ngDevMode ? [{ debugName: "focused" }] : /* istanbul ignore next */ []));
|
|
4786
|
+
lastId = 0;
|
|
4787
|
+
remaining = DEFAULT_DURATION;
|
|
4788
|
+
startedAt = 0;
|
|
4789
|
+
timer;
|
|
4790
|
+
constructor() {
|
|
4791
|
+
effect(() => {
|
|
4792
|
+
const toast = this.toasts.toast();
|
|
4793
|
+
const paused = this.hovered() || this.focused();
|
|
4794
|
+
untracked(() => {
|
|
4795
|
+
if (!toast) {
|
|
4796
|
+
this.stop();
|
|
4797
|
+
this.hovered.set(false);
|
|
4798
|
+
this.focused.set(false);
|
|
4799
|
+
return;
|
|
4800
|
+
}
|
|
4801
|
+
this.host.querySelectorAll('.ui-leave-fade').forEach((leaving) => leaving.remove());
|
|
4802
|
+
if (paused) {
|
|
4803
|
+
this.pause();
|
|
4804
|
+
}
|
|
4805
|
+
else {
|
|
4806
|
+
this.resume(toast.id);
|
|
4807
|
+
}
|
|
4808
|
+
});
|
|
4809
|
+
});
|
|
4810
|
+
inject(DestroyRef).onDestroy(() => this.stop());
|
|
4811
|
+
}
|
|
4812
|
+
setHovered(value) {
|
|
4813
|
+
this.hovered.set(value);
|
|
4814
|
+
}
|
|
4815
|
+
setFocused(value) {
|
|
4816
|
+
this.focused.set(value);
|
|
4817
|
+
}
|
|
4818
|
+
resume(id) {
|
|
4819
|
+
if (id !== this.lastId) {
|
|
4820
|
+
this.lastId = id;
|
|
4821
|
+
this.remaining = readDuration(this.host);
|
|
4822
|
+
}
|
|
4823
|
+
clearTimeout(this.timer);
|
|
4824
|
+
this.startedAt = Date.now();
|
|
4825
|
+
this.timer = setTimeout(() => this.toasts.dismiss(), this.remaining);
|
|
4826
|
+
}
|
|
4827
|
+
pause() {
|
|
4828
|
+
if (this.timer !== undefined) {
|
|
4829
|
+
this.remaining -= Date.now() - this.startedAt;
|
|
4830
|
+
clearTimeout(this.timer);
|
|
4831
|
+
this.timer = undefined;
|
|
4832
|
+
}
|
|
4833
|
+
}
|
|
4834
|
+
stop() {
|
|
4835
|
+
clearTimeout(this.timer);
|
|
4836
|
+
this.timer = undefined;
|
|
4837
|
+
this.lastId = 0;
|
|
4838
|
+
}
|
|
4839
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiToaster, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4840
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: UiToaster, isStandalone: true, selector: "ui-toaster", host: { attributes: { "role": "status" }, classAttribute: "pointer-events-none fixed inset-x-0 z-50 flex justify-center bottom-[calc(52px+env(safe-area-inset-bottom)+var(--action-bar-height,0px)+8px)] lg:inset-x-auto lg:right-6 lg:bottom-6" }, ngImport: i0, template: `
|
|
4841
|
+
@if (toasts.toast(); as toast) {
|
|
4842
|
+
<div
|
|
4843
|
+
animate.leave="ui-leave-fade"
|
|
4844
|
+
[class]="toastClasses"
|
|
4845
|
+
(focusin)="setFocused(true)"
|
|
4846
|
+
(focusout)="setFocused(false)"
|
|
4847
|
+
(mouseenter)="setHovered(true)"
|
|
4848
|
+
(mouseleave)="setHovered(false)"
|
|
4849
|
+
>
|
|
4850
|
+
{{ toast.text }}
|
|
4851
|
+
</div>
|
|
4852
|
+
}
|
|
4853
|
+
`, isInline: true });
|
|
4854
|
+
}
|
|
4855
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: UiToaster, decorators: [{
|
|
4856
|
+
type: Component,
|
|
4857
|
+
args: [{
|
|
4858
|
+
selector: 'ui-toaster',
|
|
4859
|
+
template: `
|
|
4860
|
+
@if (toasts.toast(); as toast) {
|
|
4861
|
+
<div
|
|
4862
|
+
animate.leave="ui-leave-fade"
|
|
4863
|
+
[class]="toastClasses"
|
|
4864
|
+
(focusin)="setFocused(true)"
|
|
4865
|
+
(focusout)="setFocused(false)"
|
|
4866
|
+
(mouseenter)="setHovered(true)"
|
|
4867
|
+
(mouseleave)="setHovered(false)"
|
|
4868
|
+
>
|
|
4869
|
+
{{ toast.text }}
|
|
4870
|
+
</div>
|
|
4871
|
+
}
|
|
4872
|
+
`,
|
|
4873
|
+
host: {
|
|
4874
|
+
role: 'status',
|
|
4875
|
+
class: 'pointer-events-none fixed inset-x-0 z-50 flex justify-center bottom-[calc(52px+env(safe-area-inset-bottom)+var(--action-bar-height,0px)+8px)] lg:inset-x-auto lg:right-6 lg:bottom-6',
|
|
4876
|
+
},
|
|
4877
|
+
}]
|
|
4878
|
+
}], ctorParameters: () => [] });
|
|
4879
|
+
|
|
3950
4880
|
/** Breakpoints a secondary column can be held back until. */
|
|
3951
4881
|
const CELL_BREAKPOINTS = ['md', 'lg'];
|
|
3952
4882
|
/** Body row heights. */
|
|
@@ -4030,8 +4960,10 @@ class UiTr {
|
|
|
4030
4960
|
return [
|
|
4031
4961
|
'relative [&>td:first-child]:rounded-l-control [&>td:last-child]:rounded-r-control',
|
|
4032
4962
|
this.selected() ? '[&>td]:bg-(--soft)' : '',
|
|
4033
|
-
'hover:[&>td]:bg-(--glow)',
|
|
4034
|
-
this.interactive()
|
|
4963
|
+
'hover:[&>td]:bg-(--glow) [&>td]:transition-colors [&>td]:duration-(--duration-fast) [&>td]:ease-out',
|
|
4964
|
+
this.interactive()
|
|
4965
|
+
? 'active:[&>td]:bg-(--soft) transition-transform duration-(--duration-press) ease-out active:scale-(--press-scale)'
|
|
4966
|
+
: '',
|
|
4035
4967
|
]
|
|
4036
4968
|
.filter(Boolean)
|
|
4037
4969
|
.join(' ');
|
|
@@ -4261,5 +5193,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
4261
5193
|
* Generated bundle index. Do not edit.
|
|
4262
5194
|
*/
|
|
4263
5195
|
|
|
4264
|
-
export { ALERT_VARIANTS, AMOUNT_MASKINGS, AMOUNT_NUMERICS, ASYNC_ALIGNS, ASYNC_STATES, ASYNC_VARIANTS, AVATAR_SIZES, BACK_LINK_SIZES, BADGE_SIZES, BADGE_VARIANTS, BUTTON_SIZES, BUTTON_VARIANTS, CARD_PADDINGS, CARD_SURFACES, CARD_VARIANTS, CELL_BREAKPOINTS, CONTROL_SIZES, CONTROL_SURFACES, DELTA_EMPHASES, DELTA_SIZES, DELTA_WEIGHTS, DIALOG_LAYOUTS, DIALOG_WIDTHS, FACT_SIZES, FACT_SUB_TONES, GROUP_SIZES, METER_SIZES, METER_TONES, ROW_GAPS, ROW_PADDINGS, ROW_SIZES, SEGMENTED_SIZES, SKELETON_SHAPES, STAT_SIZES, SUB_TONES, TABLE_ROWS, UI_AMOUNT_MASKED, UiActionBar, UiAlert, UiAmount, UiAsync, UiAvatar, UiAvatarLink, UiBackLink, UiBadge, UiButton, UiCard, UiCellSub, UiChoiceChips, UiDelta, UiDialog, UiDonut, UiExternalLink, UiFact, UiFacts, UiField, UiFieldLeading, UiFieldTrailing, UiFilterChips, UiGroup, UiGroupCell, UiInput, UiLineChart, UiListRow, UiMenu, UiMenuItem, UiMenuTrigger, UiMeter, UiNavItem, UiRow, UiRowAction, UiRowItem, UiRowLink, UiRowTile, UiSegmented, UiSelect, UiSkeleton, UiStat, UiSwitch, UiTab, UiTabBar, UiTable, UiTd, UiTextarea, UiTh, UiTr, formatAmount };
|
|
5196
|
+
export { ALERT_VARIANTS, AMOUNT_MASKINGS, AMOUNT_NUMERICS, ASYNC_ALIGNS, ASYNC_STATES, ASYNC_VARIANTS, AVATAR_SIZES, BACK_LINK_SIZES, BADGE_SIZES, BADGE_VARIANTS, BUTTON_SIZES, BUTTON_VARIANTS, CARD_PADDINGS, CARD_SURFACES, CARD_VARIANTS, CELL_BREAKPOINTS, CONTROL_SIZES, CONTROL_SURFACES, DELTA_EMPHASES, DELTA_SIZES, DELTA_WEIGHTS, DIALOG_CLOSE_REASONS, DIALOG_LAYOUTS, DIALOG_WIDTHS, FACT_SIZES, FACT_SUB_TONES, GROUP_SIZES, METER_SIZES, METER_TONES, ROW_GAPS, ROW_PADDINGS, ROW_SIZES, SEGMENTED_SIZES, SKELETON_SHAPES, STAT_SIZES, SUB_TONES, TABLE_ROWS, UI_AMOUNT_MASKED, UiActionBar, UiAlert, UiAmount, UiAsync, UiAvatar, UiAvatarLink, UiBackLink, UiBadge, UiButton, UiCard, UiCellSub, UiChoiceChips, UiDelta, UiDialog, UiDonut, UiEmpty, UiExternalLink, UiFact, UiFacts, UiField, UiFieldLeading, UiFieldTrailing, UiFilterChips, UiFlipList, UiGroup, UiGroupCell, UiHighlight, UiInput, UiLineChart, UiListRow, UiMenu, UiMenuItem, UiMenuTrigger, UiMeter, UiNavItem, UiRow, UiRowAction, UiRowItem, UiRowLink, UiRowTile, UiSegmented, UiSelect, UiSkeleton, UiStaleLink, UiStat, UiSwitch, UiTab, UiTabBar, UiTable, UiTd, UiTextarea, UiTh, UiToaster, UiToasts, UiTr, delayedState, formatAmount, injectReducedMotion };
|
|
4265
5197
|
//# sourceMappingURL=joanroucoux-cairn-ui.mjs.map
|