@blotch/dolan 22.2.3 → 22.2.4
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/dist/commands/add.js +9 -1
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/add.test.js +36 -3
- package/dist/commands/add.test.js.map +1 -1
- package/dist/commands/doctor.js +187 -7
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/doctor.test.js +280 -7
- package/dist/commands/doctor.test.js.map +1 -1
- package/dist/commands/init.d.ts +2 -2
- package/dist/commands/init.js +38 -18
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/init.test.js +107 -1
- package/dist/commands/init.test.js.map +1 -1
- package/dist/commands/theme.js +1 -1
- package/dist/commands/theme.js.map +1 -1
- package/dist/commands/update.d.ts +5 -0
- package/dist/commands/update.js +126 -45
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/update.test.js +314 -2
- package/dist/commands/update.test.js.map +1 -1
- package/dist/lockfile.d.ts +7 -0
- package/dist/lockfile.js +36 -0
- package/dist/lockfile.js.map +1 -1
- package/dist/lockfile.test.d.ts +1 -0
- package/dist/lockfile.test.js +25 -0
- package/dist/lockfile.test.js.map +1 -0
- package/dist/registry.d.ts +6 -0
- package/dist/registry.js +48 -2
- package/dist/registry.js.map +1 -1
- package/dist/registry.test.js +45 -3
- package/dist/registry.test.js.map +1 -1
- package/dist/test-utils.d.ts +5 -0
- package/dist/test-utils.js +6 -1
- package/dist/test-utils.js.map +1 -1
- package/dist/testing/fire-lynx-event.d.ts +14 -0
- package/dist/testing/fire-lynx-event.js +19 -0
- package/dist/testing/fire-lynx-event.js.map +1 -0
- package/dist/testing/fire-lynx-event.test.d.ts +1 -0
- package/dist/testing/fire-lynx-event.test.js +44 -0
- package/dist/testing/fire-lynx-event.test.js.map +1 -0
- package/dist/testing/lynx-main-thread.d.ts +22 -0
- package/dist/testing/lynx-main-thread.js +11 -0
- package/dist/testing/lynx-main-thread.js.map +1 -0
- package/dist/testing/lynx-main-thread.test.d.ts +1 -0
- package/dist/testing/lynx-main-thread.test.js +24 -0
- package/dist/testing/lynx-main-thread.test.js.map +1 -0
- package/dist/testing/set-input-signal.d.ts +5 -4
- package/dist/testing/set-input-signal.js +5 -4
- package/dist/testing/set-input-signal.js.map +1 -1
- package/dist/ui/components/accordion/accordion.test.ts +158 -144
- package/dist/ui/components/accordion/accordion.ts +19 -14
- package/dist/ui/components/action-sheet/action-sheet.test.ts +272 -187
- package/dist/ui/components/action-sheet/action-sheet.ts +40 -34
- package/dist/ui/components/alert/alert.test.ts +67 -19
- package/dist/ui/components/alert/alert.ts +14 -16
- package/dist/ui/components/alert-dialog/alert-dialog.test.ts +206 -139
- package/dist/ui/components/alert-dialog/alert-dialog.ts +32 -26
- package/dist/ui/components/area-chart/area-chart.test.ts +81 -1
- package/dist/ui/components/avatar/avatar.test.ts +89 -45
- package/dist/ui/components/badge/badge.test.ts +57 -23
- package/dist/ui/components/badge/badge.ts +12 -14
- package/dist/ui/components/bar-chart/bar-chart.test.ts +82 -1
- package/dist/ui/components/bottom-sheet/bottom-sheet.test.ts +373 -297
- package/dist/ui/components/bottom-sheet/bottom-sheet.ts +34 -33
- package/dist/ui/components/button/button.test.ts +611 -2
- package/dist/ui/components/button/button.ts +431 -62
- package/dist/ui/components/button/index.ts +2 -0
- package/dist/ui/components/button-group/button-group.test.ts +484 -2
- package/dist/ui/components/button-group/button-group.ts +380 -68
- package/dist/ui/components/button-group/index.ts +3 -0
- package/dist/ui/components/candlestick-chart/candlestick-chart.test.ts +82 -1
- package/dist/ui/components/card/card.test.ts +82 -62
- package/dist/ui/components/chart/chart-presets.test.ts +197 -1
- package/dist/ui/components/chart/chart-presets.ts +8 -1
- package/dist/ui/components/chart/chart-theme.ts +12 -0
- package/dist/ui/components/chart/chart.test.ts +1017 -0
- package/dist/ui/components/chart/chart.ts +56 -43
- package/dist/ui/components/checkbox/checkbox.test.ts +124 -42
- package/dist/ui/components/checkbox/checkbox.ts +23 -23
- package/dist/ui/components/collapsible/collapsible.test.ts +158 -81
- package/dist/ui/components/collapsible/collapsible.ts +19 -14
- package/dist/ui/components/context-menu/context-menu.test.ts +224 -0
- package/dist/ui/components/context-menu/context-menu.ts +110 -0
- package/dist/ui/components/context-menu/index.ts +1 -0
- package/dist/ui/components/dialog/dialog.test.ts +210 -152
- package/dist/ui/components/dialog/dialog.ts +29 -23
- package/dist/ui/components/dock/dock-scroll.test.ts +130 -0
- package/dist/ui/components/dock/dock-scroll.ts +133 -0
- package/dist/ui/components/dock/dock.test.ts +749 -0
- package/dist/ui/components/dock/dock.ts +960 -0
- package/dist/ui/components/dock/index.ts +2 -0
- package/dist/ui/components/empty-state/empty-state.test.ts +28 -39
- package/dist/ui/components/glass/concentric-radius.test.ts +13 -0
- package/dist/ui/components/glass/concentric-radius.ts +17 -0
- package/dist/ui/components/glass/glass-design.test.ts +78 -0
- package/dist/ui/components/glass/glass-design.ts +119 -0
- package/dist/ui/components/glass/glass.test.ts +338 -0
- package/dist/ui/components/glass/glass.ts +360 -0
- package/dist/ui/components/glass/index.ts +18 -0
- package/dist/ui/components/icon/icon-theme.test.ts +36 -0
- package/dist/ui/components/icon/icon-theme.ts +36 -13
- package/dist/ui/components/icon/icon.test.ts +52 -41
- package/dist/ui/components/input/input.test.ts +178 -101
- package/dist/ui/components/input/input.ts +15 -12
- package/dist/ui/components/label/label.test.ts +11 -24
- package/dist/ui/components/line-chart/line-chart.test.ts +76 -1
- package/dist/ui/components/list/list.test.ts +80 -49
- package/dist/ui/components/menu/index.ts +25 -0
- package/dist/ui/components/menu/menu-placement.test.ts +153 -0
- package/dist/ui/components/menu/menu-placement.ts +159 -0
- package/dist/ui/components/menu/menu-popup.test.ts +632 -0
- package/dist/ui/components/menu/menu-popup.ts +544 -0
- package/dist/ui/components/menu/menu.test.ts +429 -0
- package/dist/ui/components/menu/menu.ts +415 -0
- package/dist/ui/components/nav-drawer/nav-drawer.test.ts +425 -260
- package/dist/ui/components/nav-drawer/nav-drawer.ts +72 -56
- package/dist/ui/components/pagination/pagination.test.ts +136 -86
- package/dist/ui/components/progress/progress.test.ts +102 -46
- package/dist/ui/components/progress/progress.ts +52 -54
- package/dist/ui/components/radio-group/radio-group.test.ts +128 -83
- package/dist/ui/components/radio-group/radio-group.ts +24 -24
- package/dist/ui/components/scatter-chart/scatter-chart.test.ts +74 -1
- package/dist/ui/components/scroll-area/scroll-area.test.ts +72 -36
- package/dist/ui/components/select/select.test.ts +138 -78
- package/dist/ui/components/select/select.ts +17 -11
- package/dist/ui/components/separator/separator.test.ts +18 -17
- package/dist/ui/components/sheet/sheet.test.ts +64 -11
- package/dist/ui/components/sheet/sheet.ts +9 -1
- package/dist/ui/components/skeleton/skeleton.test.ts +24 -7
- package/dist/ui/components/skeleton/skeleton.ts +10 -16
- package/dist/ui/components/spinner/spinner.test.ts +64 -46
- package/dist/ui/components/spinner/spinner.ts +16 -19
- package/dist/ui/components/switch/switch.test.ts +116 -46
- package/dist/ui/components/switch/switch.ts +8 -13
- package/dist/ui/components/tab-bar/index.ts +1 -0
- package/dist/ui/components/tab-bar/tab-bar.test.ts +280 -0
- package/dist/ui/components/tab-bar/tab-bar.ts +230 -0
- package/dist/ui/components/tabs/tabs.test.ts +215 -157
- package/dist/ui/components/tabs/tabs.ts +110 -118
- package/dist/ui/components/textarea/textarea.test.ts +206 -100
- package/dist/ui/components/textarea/textarea.ts +14 -12
- package/dist/ui/components/toast/toast.test.ts +434 -350
- package/dist/ui/components/toast/toast.ts +42 -51
- package/dist/ui/components/toggle/toggle.test.ts +247 -140
- package/dist/ui/theme/chart-colors.test.ts +8 -3
- package/dist/ui/theme/dark.css +38 -2
- package/dist/ui/theme/default.css +55 -7
- package/dist/ui/theme/icon-colors.test.ts +8 -3
- package/dist/ui/theme/rgb-channels.test.ts +84 -0
- package/dist/ui/theme/tailwind-build.test.ts +114 -0
- package/dist/ui/theme/tailwind-css.test.ts +83 -0
- package/dist/ui/theme/tailwind-plugin.test.ts +42 -2
- package/dist/ui/theme/tailwind-plugin.ts +93 -29
- package/dist/ui/theme/tailwind.css +113 -0
- package/dist/ui/utils/animate.test.ts +13 -1
- package/dist/utils/analyze.d.ts +14 -0
- package/dist/utils/analyze.js +15 -0
- package/dist/utils/analyze.js.map +1 -1
- package/dist/utils/analyze.test.js +14 -1
- package/dist/utils/analyze.test.js.map +1 -1
- package/dist/utils/installed.d.ts +12 -0
- package/dist/utils/installed.js +16 -0
- package/dist/utils/installed.js.map +1 -1
- package/dist/utils/installed.test.js +17 -1
- package/dist/utils/installed.test.js.map +1 -1
- package/dist/utils/resolve-paths.d.ts +4 -4
- package/dist/utils/resolve-paths.js +5 -7
- package/dist/utils/resolve-paths.js.map +1 -1
- package/dist/utils/resolve-paths.test.js +9 -5
- package/dist/utils/resolve-paths.test.js.map +1 -1
- package/dist/utils/tailwind.d.ts +25 -0
- package/dist/utils/tailwind.js +51 -0
- package/dist/utils/tailwind.js.map +1 -0
- package/dist/utils/tailwind.test.d.ts +1 -0
- package/dist/utils/tailwind.test.js +71 -0
- package/dist/utils/tailwind.test.js.map +1 -0
- package/package.json +9 -1
- package/dist/ui/components/area-chart/area-chart-render.test.ts +0 -63
- package/dist/ui/components/bar-chart/bar-chart-render.test.ts +0 -58
- package/dist/ui/components/button/button-render.test.ts +0 -132
- package/dist/ui/components/button-group/button-group-render.test.ts +0 -146
- package/dist/ui/components/candlestick-chart/candlestick-chart-render.test.ts +0 -59
- package/dist/ui/components/chart/chart-render.test.ts +0 -730
- package/dist/ui/components/line-chart/line-chart-render.test.ts +0 -83
- package/dist/ui/components/scatter-chart/scatter-chart-render.test.ts +0 -64
|
@@ -131,6 +131,13 @@ export class UiChartTooltip {
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/**
|
|
135
|
+
* `UiChartTooltip`, for `contentChild()`. A call rather than the class itself:
|
|
136
|
+
* for a class, Angular's test build keeps an arrow function that nothing calls,
|
|
137
|
+
* which an app's coverage report would show as uncovered.
|
|
138
|
+
*/
|
|
139
|
+
const tooltipDirectiveType = () => UiChartTooltip;
|
|
140
|
+
|
|
134
141
|
/** Default height, like the browser's 150px replaced-element default, but roomier. */
|
|
135
142
|
const DEFAULT_HEIGHT = 200;
|
|
136
143
|
/** A touch that moves less than this is a tap, not a drag. */
|
|
@@ -352,7 +359,7 @@ export class UiChart {
|
|
|
352
359
|
/** The point a tap landed on, or `null` for a tap on empty space. */
|
|
353
360
|
readonly pointSelect = output<ChartPoint | null>();
|
|
354
361
|
|
|
355
|
-
protected readonly tooltipTemplate = contentChild(
|
|
362
|
+
protected readonly tooltipTemplate = contentChild(tooltipDirectiveType());
|
|
356
363
|
|
|
357
364
|
readonly #theme = inject(UI_CHART_THEME);
|
|
358
365
|
readonly #appearance = inject(LynxTheme);
|
|
@@ -405,6 +412,15 @@ export class UiChart {
|
|
|
405
412
|
});
|
|
406
413
|
});
|
|
407
414
|
|
|
415
|
+
/**
|
|
416
|
+
* The scene, for what the template draws inside `@if (scene())`: those
|
|
417
|
+
* bindings, and the values below derived for them, are only read while there
|
|
418
|
+
* is one, so they need no fallback for a chart without a size.
|
|
419
|
+
*/
|
|
420
|
+
#drawnScene(): ChartScene<any, any, any> {
|
|
421
|
+
return this.scene()!;
|
|
422
|
+
}
|
|
423
|
+
|
|
408
424
|
readonly #focusModel = computed(() => {
|
|
409
425
|
const scene = this.scene();
|
|
410
426
|
return scene ? createChartFocusModel(scene, this.definition()) : null;
|
|
@@ -424,24 +440,23 @@ export class UiChart {
|
|
|
424
440
|
});
|
|
425
441
|
|
|
426
442
|
/** The scene with mark states (e.g. dim the unfocused bars) resolved. */
|
|
427
|
-
readonly #presented = computed(
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
443
|
+
readonly #presented = computed(
|
|
444
|
+
() =>
|
|
445
|
+
resolveMarkStateScene(
|
|
446
|
+
this.#drawnScene(),
|
|
447
|
+
this.#focusState(),
|
|
448
|
+
this.#pointer(),
|
|
449
|
+
).scene,
|
|
450
|
+
);
|
|
433
451
|
|
|
434
|
-
readonly #focusPresentation = computed(() =>
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
)
|
|
443
|
-
: { under: [], over: [] };
|
|
444
|
-
});
|
|
452
|
+
readonly #focusPresentation = computed(() =>
|
|
453
|
+
resolveFocusPresentation(
|
|
454
|
+
this.#presented(),
|
|
455
|
+
this.#focusState(),
|
|
456
|
+
this.#pointer(),
|
|
457
|
+
null,
|
|
458
|
+
),
|
|
459
|
+
);
|
|
445
460
|
|
|
446
461
|
readonly #colors = computed(() => {
|
|
447
462
|
const option = this.colorScheme() ?? this.#theme.colorScheme ?? 'light';
|
|
@@ -457,12 +472,12 @@ export class UiChart {
|
|
|
457
472
|
});
|
|
458
473
|
|
|
459
474
|
readonly #svgOptions = computed(() => {
|
|
460
|
-
const scene = this
|
|
475
|
+
const scene = this.#drawnScene();
|
|
461
476
|
const colors = this.#colors();
|
|
462
477
|
return {
|
|
463
|
-
width: scene
|
|
464
|
-
height: scene
|
|
465
|
-
gradients: scene
|
|
478
|
+
width: scene.width,
|
|
479
|
+
height: scene.height,
|
|
480
|
+
gradients: scene.gradients,
|
|
466
481
|
idPrefix: this.#idPrefix,
|
|
467
482
|
resolvePaint: (paint: string) => resolveChartPaint(paint, colors),
|
|
468
483
|
};
|
|
@@ -475,8 +490,7 @@ export class UiChart {
|
|
|
475
490
|
);
|
|
476
491
|
protected readonly marksSvg = computed(
|
|
477
492
|
() =>
|
|
478
|
-
renderChartSvg(this.#presented()
|
|
479
|
-
EMPTY_SVG,
|
|
493
|
+
renderChartSvg(this.#presented().nodes, this.#svgOptions()) || EMPTY_SVG,
|
|
480
494
|
);
|
|
481
495
|
protected readonly overSvg = computed(
|
|
482
496
|
() =>
|
|
@@ -485,18 +499,14 @@ export class UiChart {
|
|
|
485
499
|
);
|
|
486
500
|
|
|
487
501
|
protected readonly layerStyle = computed(() => {
|
|
488
|
-
const scene = this
|
|
489
|
-
return `position: absolute; left: 0px; top: 0px; width: ${scene
|
|
502
|
+
const scene = this.#drawnScene();
|
|
503
|
+
return `position: absolute; left: 0px; top: 0px; width: ${scene.width}px; height: ${scene.height}px;`;
|
|
490
504
|
});
|
|
491
505
|
|
|
492
506
|
readonly #labels = computed<readonly ChartLabel[]>(() => {
|
|
493
507
|
const presentation = this.#focusPresentation();
|
|
494
508
|
return collectChartLabels(
|
|
495
|
-
[
|
|
496
|
-
...presentation.under,
|
|
497
|
-
...(this.#presented()?.nodes ?? []),
|
|
498
|
-
...presentation.over,
|
|
499
|
-
],
|
|
509
|
+
[...presentation.under, ...this.#presented().nodes, ...presentation.over],
|
|
500
510
|
{
|
|
501
511
|
defaultColor: this.#theme.chart.foreground ?? 'var(--foreground)',
|
|
502
512
|
focus: this.#focusState(),
|
|
@@ -600,18 +610,21 @@ export class UiChart {
|
|
|
600
610
|
protected readonly zoomButtonClass =
|
|
601
611
|
'flex h-7 w-7 items-center justify-center rounded-md border border-border bg-card';
|
|
602
612
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
613
|
+
/**
|
|
614
|
+
* Keeps the focus on the same datum when a new scene (data, size or zoom
|
|
615
|
+
* changed) brings new point objects, as TanStack's hosts do. A field rather
|
|
616
|
+
* than a constructor: Angular's test build keeps a function for a
|
|
617
|
+
* constructor that nothing calls, which an app's coverage report would show
|
|
618
|
+
* as uncovered.
|
|
619
|
+
*/
|
|
620
|
+
protected readonly restoringFocus = effect(() => {
|
|
621
|
+
const model = this.#focusModel();
|
|
622
|
+
const previous = untracked(this.#focused);
|
|
623
|
+
if (!model || previous.length === 0) return;
|
|
624
|
+
const restored = model.restore(previous[0]!);
|
|
625
|
+
this.#focused.set(restored ? model.group(restored) : EMPTY_POINTS);
|
|
626
|
+
if (!restored) this.#pinned.set(false);
|
|
627
|
+
});
|
|
615
628
|
|
|
616
629
|
/**
|
|
617
630
|
* ---------------------------------------------------------------------------
|
|
@@ -1,59 +1,141 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { Component, signal } from '@angular/core';
|
|
2
|
+
import {
|
|
3
|
+
fireEvent,
|
|
4
|
+
render,
|
|
5
|
+
waitForUpdate,
|
|
6
|
+
} from '@blotch/angular-lynx-testing-library';
|
|
7
|
+
import {
|
|
8
|
+
type MockInstance,
|
|
9
|
+
afterEach,
|
|
10
|
+
beforeEach,
|
|
11
|
+
describe,
|
|
12
|
+
expect,
|
|
13
|
+
it,
|
|
14
|
+
vi,
|
|
15
|
+
} from 'vitest';
|
|
16
|
+
import {
|
|
17
|
+
type LynxMainThread,
|
|
18
|
+
lynxMainThread,
|
|
19
|
+
} from '../../../test-utils/lynx-main-thread';
|
|
4
20
|
import { UiCheckbox } from './checkbox';
|
|
5
21
|
|
|
22
|
+
@Component({
|
|
23
|
+
imports: [UiCheckbox],
|
|
24
|
+
template: `
|
|
25
|
+
<ui-checkbox
|
|
26
|
+
[(checked)]="checked"
|
|
27
|
+
[disabled]="disabled()"
|
|
28
|
+
class="mr-2"
|
|
29
|
+
(changed)="changes.push($event)"
|
|
30
|
+
/>
|
|
31
|
+
`,
|
|
32
|
+
})
|
|
33
|
+
class CheckboxHost {
|
|
34
|
+
readonly checked = signal(false);
|
|
35
|
+
readonly disabled = signal(false);
|
|
36
|
+
readonly changes: boolean[] = [];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const renderCheckbox = async () => {
|
|
40
|
+
const result = await render(CheckboxHost);
|
|
41
|
+
return {
|
|
42
|
+
...result,
|
|
43
|
+
host: result.componentRef.instance as CheckboxHost,
|
|
44
|
+
/** The 44pt tap target around the box. */
|
|
45
|
+
target: () => result.container.querySelector('.h-11')!,
|
|
46
|
+
box: () => result.container.querySelector('.rounded-sm')!,
|
|
47
|
+
checkmark: () => result.getByText('✓'),
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** `__ElementAnimate`'s first argument for starting an animation. */
|
|
52
|
+
const START = 0;
|
|
53
|
+
/** `__ElementAnimate`'s first argument for canceling one. */
|
|
54
|
+
const CANCEL = 3;
|
|
55
|
+
|
|
6
56
|
describe('UiCheckbox', () => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
57
|
+
// Watched per test: the testing library resets the main thread after each.
|
|
58
|
+
let animate: MockInstance<LynxMainThread['__ElementAnimate']>;
|
|
59
|
+
beforeEach(() => {
|
|
60
|
+
animate = vi.spyOn(lynxMainThread(), '__ElementAnimate');
|
|
10
61
|
});
|
|
62
|
+
afterEach(() => animate.mockRestore());
|
|
11
63
|
|
|
12
|
-
it('
|
|
13
|
-
const {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
inst.toggle();
|
|
19
|
-
expect(inst.checked()).toBe(true);
|
|
20
|
-
inst.toggle();
|
|
21
|
-
expect(inst.checked()).toBe(false);
|
|
22
|
-
expect(changes).toEqual([true, false]);
|
|
64
|
+
it('renders an empty box with the given class', async () => {
|
|
65
|
+
const { box, checkmark } = await renderCheckbox();
|
|
66
|
+
expect(box().classList).toContain('bg-transparent');
|
|
67
|
+
expect(box().classList).toContain('mr-2');
|
|
68
|
+
expect(checkmark().getAttribute('style')).toContain('opacity: 0');
|
|
23
69
|
});
|
|
24
70
|
|
|
25
|
-
it('
|
|
26
|
-
const {
|
|
27
|
-
const inst = componentRef.instance as UiCheckbox;
|
|
28
|
-
setInputSignal(inst.disabled, true);
|
|
29
|
-
const changed = vi.fn();
|
|
30
|
-
inst.changed.subscribe(changed);
|
|
71
|
+
it('checks and unchecks on tap, emitting `changed`', async () => {
|
|
72
|
+
const { host, target, box, checkmark } = await renderCheckbox();
|
|
31
73
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
expect(
|
|
74
|
+
fireEvent.tap(target());
|
|
75
|
+
await waitForUpdate();
|
|
76
|
+
expect(host.checked()).toBe(true);
|
|
77
|
+
expect(box().classList).toContain('bg-primary');
|
|
78
|
+
expect(checkmark().getAttribute('style')).toContain('opacity: 1');
|
|
79
|
+
|
|
80
|
+
fireEvent.tap(target());
|
|
81
|
+
await waitForUpdate();
|
|
82
|
+
expect(host.checked()).toBe(false);
|
|
83
|
+
expect(host.changes).toEqual([true, false]);
|
|
35
84
|
});
|
|
36
85
|
|
|
37
|
-
it('
|
|
38
|
-
const {
|
|
39
|
-
|
|
40
|
-
|
|
86
|
+
it("doesn't animate on mount, then pops the checkmark in and out", async () => {
|
|
87
|
+
const { target, checkmark } = await renderCheckbox();
|
|
88
|
+
expect(animate).not.toHaveBeenCalled();
|
|
89
|
+
|
|
90
|
+
fireEvent.tap(target());
|
|
41
91
|
await waitForUpdate();
|
|
92
|
+
expect(animate).toHaveBeenCalledWith(checkmark(), [
|
|
93
|
+
START,
|
|
94
|
+
expect.any(String),
|
|
95
|
+
[
|
|
96
|
+
{ transform: 'scale(0.6)', opacity: 0 },
|
|
97
|
+
{ transform: 'scale(1)', opacity: 1 },
|
|
98
|
+
],
|
|
99
|
+
expect.objectContaining({ fill: 'forwards' }),
|
|
100
|
+
]);
|
|
42
101
|
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
|
|
102
|
+
// Unchecking cuts the pop-in short and pops the checkmark out.
|
|
103
|
+
fireEvent.tap(target());
|
|
104
|
+
await waitForUpdate();
|
|
105
|
+
expect(animate).toHaveBeenCalledWith(checkmark(), [
|
|
106
|
+
CANCEL,
|
|
107
|
+
expect.any(String),
|
|
108
|
+
]);
|
|
109
|
+
expect(animate).toHaveBeenLastCalledWith(checkmark(), [
|
|
110
|
+
START,
|
|
111
|
+
expect.any(String),
|
|
112
|
+
[
|
|
113
|
+
{ transform: 'scale(1)', opacity: 1 },
|
|
114
|
+
{ transform: 'scale(0.8)', opacity: 0 },
|
|
115
|
+
],
|
|
116
|
+
expect.objectContaining({ fill: 'forwards' }),
|
|
117
|
+
]);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("doesn't animate two taps in one frame, which leave it as it was", async () => {
|
|
121
|
+
const { host, target } = await renderCheckbox();
|
|
122
|
+
fireEvent.tap(target());
|
|
123
|
+
fireEvent.tap(target());
|
|
124
|
+
await waitForUpdate();
|
|
125
|
+
expect(host.checked()).toBe(false);
|
|
126
|
+
expect(host.changes).toEqual([true, false]);
|
|
127
|
+
expect(animate).not.toHaveBeenCalled();
|
|
46
128
|
});
|
|
47
129
|
|
|
48
|
-
it('
|
|
49
|
-
const {
|
|
50
|
-
|
|
130
|
+
it('dims and ignores taps while disabled', async () => {
|
|
131
|
+
const { host, target, box } = await renderCheckbox();
|
|
132
|
+
host.disabled.set(true);
|
|
133
|
+
await waitForUpdate();
|
|
134
|
+
expect(box().classList).toContain('opacity-50');
|
|
135
|
+
|
|
136
|
+
fireEvent.tap(target());
|
|
51
137
|
await waitForUpdate();
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const hasDim = Array.from(boxes).some((el) =>
|
|
55
|
-
el.getAttribute('class')?.includes('opacity-50'),
|
|
56
|
-
);
|
|
57
|
-
expect(hasDim).toBe(true);
|
|
138
|
+
expect(host.checked()).toBe(false);
|
|
139
|
+
expect(host.changes).toEqual([]);
|
|
58
140
|
});
|
|
59
141
|
});
|
|
@@ -43,34 +43,34 @@ export class UiCheckbox {
|
|
|
43
43
|
|
|
44
44
|
readonly changed = output<boolean>();
|
|
45
45
|
|
|
46
|
-
readonly checkmarkRef = viewChild<ElementRef>('checkmark');
|
|
46
|
+
readonly checkmarkRef = viewChild.required<ElementRef>('checkmark');
|
|
47
47
|
#checkAnim?: AnimationHandle;
|
|
48
48
|
#previousChecked?: boolean;
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
if (isChecked === this.#previousChecked) return;
|
|
50
|
+
/**
|
|
51
|
+
* Pops the checkmark in when checked and out when unchecked. A field rather
|
|
52
|
+
* than a constructor: Angular's test build keeps a function for a
|
|
53
|
+
* constructor that nothing calls, which an app's coverage report would show
|
|
54
|
+
* as uncovered.
|
|
55
|
+
*
|
|
56
|
+
* `#previousChecked === undefined` guards the first run: we don't want to
|
|
57
|
+
* pop in the checkmark when the component mounts already checked. The
|
|
58
|
+
* equality guard skips a run that isn't a change: `checked` set and set
|
|
59
|
+
* back before the effect runs (two taps in one frame) still re-runs it.
|
|
60
|
+
*/
|
|
61
|
+
protected readonly checkmarkAnimation = effect(() => {
|
|
62
|
+
const isChecked = this.checked();
|
|
63
|
+
const el = this.checkmarkRef().nativeElement;
|
|
64
|
+
if (this.#previousChecked === undefined) {
|
|
67
65
|
this.#previousChecked = isChecked;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (isChecked === this.#previousChecked) return;
|
|
69
|
+
this.#previousChecked = isChecked;
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
});
|
|
73
|
-
}
|
|
71
|
+
this.#checkAnim?.cancel();
|
|
72
|
+
this.#checkAnim = isChecked ? popIn(el) : popOut(el);
|
|
73
|
+
});
|
|
74
74
|
|
|
75
75
|
protected readonly boxClass = computed(() =>
|
|
76
76
|
cn(
|