@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
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** The config files Tailwind 3 reads. Tailwind 4 needs none. */
|
|
2
|
+
export declare const TAILWIND_CONFIG_FILES: string[];
|
|
3
|
+
/**
|
|
4
|
+
* Whether the project is set up for Tailwind 4, where the theme's plugin is
|
|
5
|
+
* loaded with `@plugin` in the stylesheet rather than listed in
|
|
6
|
+
* `tailwind.config.ts`: it has no Tailwind config, and depends on Tailwind 4
|
|
7
|
+
* or on its PostCSS plugin, as `ng add @blotch/angular-lynx` and
|
|
8
|
+
* `ng new --style=tailwind` set it up.
|
|
9
|
+
*/
|
|
10
|
+
export declare const usesTailwind4: (cwd: string) => boolean;
|
|
11
|
+
/**
|
|
12
|
+
* The theme files a project takes: the colors, and what maps them to
|
|
13
|
+
* Tailwind's utilities, `tailwind.css` for Tailwind 4 (imported in the
|
|
14
|
+
* stylesheet) or `tailwind-plugin.ts` for Tailwind 3 (a config plugin).
|
|
15
|
+
*
|
|
16
|
+
* With `tests`, the plugin comes with its test, for the same reason as a
|
|
17
|
+
* component's (see getComponentFiles): it covers the plugin in the app's
|
|
18
|
+
* coverage report. `tailwind.css` has no code to cover. The theme folder's
|
|
19
|
+
* other tests stay behind: they check the theme in packages/ui with Node,
|
|
20
|
+
* against the components and Tailwind's own builds, which an app's `ng test`
|
|
21
|
+
* can't do.
|
|
22
|
+
*/
|
|
23
|
+
export declare const themeFilesFor: (cwd: string, { tests }?: {
|
|
24
|
+
tests?: boolean;
|
|
25
|
+
}) => string[];
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
/** The config files Tailwind 3 reads. Tailwind 4 needs none. */
|
|
4
|
+
export const TAILWIND_CONFIG_FILES = [
|
|
5
|
+
'tailwind.config.ts',
|
|
6
|
+
'tailwind.config.js',
|
|
7
|
+
'tailwind.config.mjs',
|
|
8
|
+
'tailwind.config.cjs',
|
|
9
|
+
];
|
|
10
|
+
/**
|
|
11
|
+
* Whether the project is set up for Tailwind 4, where the theme's plugin is
|
|
12
|
+
* loaded with `@plugin` in the stylesheet rather than listed in
|
|
13
|
+
* `tailwind.config.ts`: it has no Tailwind config, and depends on Tailwind 4
|
|
14
|
+
* or on its PostCSS plugin, as `ng add @blotch/angular-lynx` and
|
|
15
|
+
* `ng new --style=tailwind` set it up.
|
|
16
|
+
*/
|
|
17
|
+
export const usesTailwind4 = (cwd) => {
|
|
18
|
+
if (TAILWIND_CONFIG_FILES.some((file) => existsSync(join(cwd, file)))) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const { dependencies = {}, devDependencies = {} } = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf-8'));
|
|
23
|
+
const all = { ...dependencies, ...devDependencies };
|
|
24
|
+
const major = Number(/\d+/.exec(all['tailwindcss'] ?? '')?.[0]);
|
|
25
|
+
return Boolean(all['@tailwindcss/postcss']) || major >= 4;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The theme files a project takes: the colors, and what maps them to
|
|
33
|
+
* Tailwind's utilities, `tailwind.css` for Tailwind 4 (imported in the
|
|
34
|
+
* stylesheet) or `tailwind-plugin.ts` for Tailwind 3 (a config plugin).
|
|
35
|
+
*
|
|
36
|
+
* With `tests`, the plugin comes with its test, for the same reason as a
|
|
37
|
+
* component's (see getComponentFiles): it covers the plugin in the app's
|
|
38
|
+
* coverage report. `tailwind.css` has no code to cover. The theme folder's
|
|
39
|
+
* other tests stay behind: they check the theme in packages/ui with Node,
|
|
40
|
+
* against the components and Tailwind's own builds, which an app's `ng test`
|
|
41
|
+
* can't do.
|
|
42
|
+
*/
|
|
43
|
+
export const themeFilesFor = (cwd, { tests = false } = {}) => usesTailwind4(cwd)
|
|
44
|
+
? ['default.css', 'dark.css', 'tailwind.css']
|
|
45
|
+
: [
|
|
46
|
+
'default.css',
|
|
47
|
+
'dark.css',
|
|
48
|
+
'tailwind-plugin.ts',
|
|
49
|
+
...(tests ? ['tailwind-plugin.test.ts'] : []),
|
|
50
|
+
];
|
|
51
|
+
//# sourceMappingURL=tailwind.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tailwind.js","sourceRoot":"","sources":["../../src/utils/tailwind.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,gEAAgE;AAChE,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,oBAAoB;IACpB,oBAAoB;IACpB,qBAAqB;IACrB,qBAAqB;CACtB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAW,EAAW,EAAE;IACpD,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACH,MAAM,EAAE,YAAY,GAAG,EAAE,EAAE,eAAe,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,CAC5D,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAIjD,CAAC;QACF,MAAM,GAAG,GAAG,EAAE,GAAG,YAAY,EAAE,GAAG,eAAe,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,OAAO,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,GAAW,EACX,EAAE,KAAK,GAAG,KAAK,KAA0B,EAAE,EACjC,EAAE,CACZ,aAAa,CAAC,GAAG,CAAC;IAChB,CAAC,CAAC,CAAC,aAAa,EAAE,UAAU,EAAE,cAAc,CAAC;IAC7C,CAAC,CAAC;QACE,aAAa;QACb,UAAU;QACV,oBAAoB;QACpB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, expect, it, afterEach } from 'vitest';
|
|
2
|
+
import { existsSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { createFixture } from '../test-utils';
|
|
5
|
+
import { getUiSourceDir } from './resolve-paths';
|
|
6
|
+
import { themeFilesFor, usesTailwind4 } from './tailwind';
|
|
7
|
+
let fixture;
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
fixture?.cleanup();
|
|
10
|
+
});
|
|
11
|
+
/**
|
|
12
|
+
* A project with these dev dependencies, and these other files.
|
|
13
|
+
*/
|
|
14
|
+
const project = (devDependencies, files = {}) => {
|
|
15
|
+
fixture = createFixture({});
|
|
16
|
+
if (devDependencies) {
|
|
17
|
+
writeFileSync(join(fixture.dir, 'package.json'), JSON.stringify({ devDependencies }));
|
|
18
|
+
}
|
|
19
|
+
for (const [file, content] of Object.entries(files)) {
|
|
20
|
+
writeFileSync(join(fixture.dir, file), content);
|
|
21
|
+
}
|
|
22
|
+
return fixture.dir;
|
|
23
|
+
};
|
|
24
|
+
describe('usesTailwind4', () => {
|
|
25
|
+
it('is true for a project on Tailwind 4 without a Tailwind config', () => {
|
|
26
|
+
expect(usesTailwind4(project({ tailwindcss: '^4.3.3' }))).toBe(true);
|
|
27
|
+
expect(usesTailwind4(project({ '@tailwindcss/postcss': '^4.3.3' }))).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
it('is false for Tailwind 3, a Tailwind config, or no Tailwind', () => {
|
|
30
|
+
expect(usesTailwind4(project({ tailwindcss: '^3.4.19' }))).toBe(false);
|
|
31
|
+
expect(usesTailwind4(project({ tailwindcss: '^4.0.0' }, { 'tailwind.config.js': '' }))).toBe(false);
|
|
32
|
+
expect(usesTailwind4(project({}))).toBe(false);
|
|
33
|
+
expect(usesTailwind4(project(undefined))).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe('themeFilesFor', () => {
|
|
37
|
+
it('takes tailwind.css on Tailwind 4, and the config plugin on Tailwind 3', () => {
|
|
38
|
+
expect(themeFilesFor(project({ tailwindcss: '^4.3.3' }))).toEqual([
|
|
39
|
+
'default.css',
|
|
40
|
+
'dark.css',
|
|
41
|
+
'tailwind.css',
|
|
42
|
+
]);
|
|
43
|
+
expect(themeFilesFor(project({ tailwindcss: '^3.4.19' }))).toEqual([
|
|
44
|
+
'default.css',
|
|
45
|
+
'dark.css',
|
|
46
|
+
'tailwind-plugin.ts',
|
|
47
|
+
]);
|
|
48
|
+
});
|
|
49
|
+
it("adds the Tailwind plugin's test with the components' tests", () => {
|
|
50
|
+
// It covers the plugin in the app's coverage report. Tailwind 4's
|
|
51
|
+
// tailwind.css has no code to cover.
|
|
52
|
+
expect(themeFilesFor(project({ tailwindcss: '^3.4.19' }), { tests: true })).toEqual([
|
|
53
|
+
'default.css',
|
|
54
|
+
'dark.css',
|
|
55
|
+
'tailwind-plugin.ts',
|
|
56
|
+
'tailwind-plugin.test.ts',
|
|
57
|
+
]);
|
|
58
|
+
expect(themeFilesFor(project({ tailwindcss: '^4.3.3' }), { tests: true })).toEqual(['default.css', 'dark.css', 'tailwind.css']);
|
|
59
|
+
});
|
|
60
|
+
it('lists only files the theme folder has', () => {
|
|
61
|
+
for (const version of ['^3.4.19', '^4.3.3']) {
|
|
62
|
+
const files = themeFilesFor(project({ tailwindcss: version }), {
|
|
63
|
+
tests: true,
|
|
64
|
+
});
|
|
65
|
+
for (const file of files) {
|
|
66
|
+
expect(existsSync(join(getUiSourceDir(), 'theme', file)), file).toBe(true);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
//# sourceMappingURL=tailwind.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tailwind.test.js","sourceRoot":"","sources":["../../src/utils/tailwind.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blotch/dolan",
|
|
3
|
-
"version": "22.2.
|
|
3
|
+
"version": "22.2.4",
|
|
4
4
|
"description": "CLI for adding @blotch/ui components to your project",
|
|
5
5
|
"homepage": "https://github.com/Blotch-Smart-Frames/AngularLynx#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -31,6 +31,14 @@
|
|
|
31
31
|
"./testing/set-input-signal": {
|
|
32
32
|
"types": "./dist/testing/set-input-signal.d.ts",
|
|
33
33
|
"default": "./dist/testing/set-input-signal.js"
|
|
34
|
+
},
|
|
35
|
+
"./testing/fire-lynx-event": {
|
|
36
|
+
"types": "./dist/testing/fire-lynx-event.d.ts",
|
|
37
|
+
"default": "./dist/testing/fire-lynx-event.js"
|
|
38
|
+
},
|
|
39
|
+
"./testing/lynx-main-thread": {
|
|
40
|
+
"types": "./dist/testing/lynx-main-thread.d.ts",
|
|
41
|
+
"default": "./dist/testing/lynx-main-thread.js"
|
|
34
42
|
}
|
|
35
43
|
},
|
|
36
44
|
"scripts": {
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { render } from '@blotch/angular-lynx-testing-library';
|
|
2
|
-
import { createChartRuntime } from '@tanstack/charts/runtime';
|
|
3
|
-
import type {
|
|
4
|
-
ChartDefinition,
|
|
5
|
-
ChartPoint,
|
|
6
|
-
SceneNode,
|
|
7
|
-
} from '@tanstack/charts/types';
|
|
8
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
9
|
-
import { setInputSignal } from '../../../test-utils/set-input-signal';
|
|
10
|
-
import { UiAreaChart } from './area-chart';
|
|
11
|
-
|
|
12
|
-
const data = [
|
|
13
|
-
{ x: 0, y: 4 },
|
|
14
|
-
{ x: 1, y: -2 },
|
|
15
|
-
{ x: 2, y: 6 },
|
|
16
|
-
];
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Every drawn shape in a definition's scene, labels excluded.
|
|
20
|
-
*/
|
|
21
|
-
const shapes = (definition: ChartDefinition<any, any, any>) => {
|
|
22
|
-
const scene = createChartRuntime().render(definition, {
|
|
23
|
-
width: 300,
|
|
24
|
-
height: 200,
|
|
25
|
-
});
|
|
26
|
-
const found: SceneNode[] = [];
|
|
27
|
-
const walk = (nodes: readonly SceneNode[]) => {
|
|
28
|
-
for (const node of nodes) {
|
|
29
|
-
if (node.kind === 'group') {
|
|
30
|
-
if (!node.focus) walk(node.children);
|
|
31
|
-
} else if (node.kind !== 'label') found.push(node);
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
walk(scene.nodes);
|
|
35
|
-
return { scene, found };
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
describe('UiAreaChart', () => {
|
|
39
|
-
type Internals = {
|
|
40
|
-
definition: () => ChartDefinition<any, any, any>;
|
|
41
|
-
onSelect(point: ChartPoint | null): void;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
it('builds its definition from its inputs', async () => {
|
|
45
|
-
const { componentRef } = await render(UiAreaChart);
|
|
46
|
-
const chart = componentRef.instance as UiAreaChart;
|
|
47
|
-
setInputSignal(chart.data, data);
|
|
48
|
-
setInputSignal(chart.baseline, -20);
|
|
49
|
-
const { scene } = shapes((chart as unknown as Internals).definition());
|
|
50
|
-
expect(scene.scales['y']!.domain[0]).toBeLessThanOrEqual(-20);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('emits the tapped datum', async () => {
|
|
54
|
-
const { componentRef } = await render(UiAreaChart);
|
|
55
|
-
const chart = componentRef.instance as UiAreaChart;
|
|
56
|
-
const tapped = vi.fn();
|
|
57
|
-
chart.pointTap.subscribe(tapped);
|
|
58
|
-
const internals = chart as unknown as Internals;
|
|
59
|
-
internals.onSelect({ datum: data[0] } as ChartPoint);
|
|
60
|
-
internals.onSelect(null);
|
|
61
|
-
expect(tapped.mock.calls).toEqual([[data[0]]]);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { render } from '@blotch/angular-lynx-testing-library';
|
|
2
|
-
import { createChartRuntime } from '@tanstack/charts/runtime';
|
|
3
|
-
import type {
|
|
4
|
-
ChartDefinition,
|
|
5
|
-
ChartPoint,
|
|
6
|
-
SceneNode,
|
|
7
|
-
SceneRect,
|
|
8
|
-
} from '@tanstack/charts/types';
|
|
9
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
10
|
-
import { setInputSignal } from '../../../test-utils/set-input-signal';
|
|
11
|
-
import { UiBarChart } from './bar-chart';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Every bar in a definition's scene.
|
|
15
|
-
*/
|
|
16
|
-
const bars = (definition: ChartDefinition<any, any, any>) => {
|
|
17
|
-
const scene = createChartRuntime().render(definition, {
|
|
18
|
-
width: 300,
|
|
19
|
-
height: 200,
|
|
20
|
-
});
|
|
21
|
-
const found: SceneRect[] = [];
|
|
22
|
-
const walk = (nodes: readonly SceneNode[]) => {
|
|
23
|
-
for (const node of nodes) {
|
|
24
|
-
if (node.kind === 'group') {
|
|
25
|
-
if (!node.focus) walk(node.children);
|
|
26
|
-
} else if (node.kind === 'rect') found.push(node);
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
walk(scene.nodes);
|
|
30
|
-
return { scene, found };
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
describe('UiBarChart', () => {
|
|
34
|
-
type Internals = {
|
|
35
|
-
definition: () => ChartDefinition<any, any, any>;
|
|
36
|
-
onSelect(point: ChartPoint | null): void;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
it('builds its definition from its inputs', async () => {
|
|
40
|
-
const { componentRef } = await render(UiBarChart);
|
|
41
|
-
const chart = componentRef.instance as UiBarChart;
|
|
42
|
-
setInputSignal(chart.data, [{ x: 'a', y: 1 }]);
|
|
43
|
-
setInputSignal(chart.color, 'red');
|
|
44
|
-
const { found } = bars((chart as unknown as Internals).definition());
|
|
45
|
-
expect(found[0]!.style?.fill).toBe('red');
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('emits the tapped datum', async () => {
|
|
49
|
-
const { componentRef } = await render(UiBarChart);
|
|
50
|
-
const chart = componentRef.instance as UiBarChart;
|
|
51
|
-
const tapped = vi.fn();
|
|
52
|
-
chart.barTap.subscribe(tapped);
|
|
53
|
-
const internals = chart as unknown as Internals;
|
|
54
|
-
internals.onSelect({ datum: { x: 'a', y: 1 } } as ChartPoint);
|
|
55
|
-
internals.onSelect(null);
|
|
56
|
-
expect(tapped.mock.calls).toEqual([[{ x: 'a', y: 1 }]]);
|
|
57
|
-
});
|
|
58
|
-
});
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { Component } from '@angular/core';
|
|
2
|
-
import { render, waitForUpdate } from '@blotch/angular-lynx-testing-library';
|
|
3
|
-
import { LYNX_ELEMENTS } from '@blotch/angular-lynx';
|
|
4
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
-
import { setInputSignal } from '../../../test-utils/set-input-signal';
|
|
6
|
-
import { UiButton } from './button';
|
|
7
|
-
|
|
8
|
-
@Component({
|
|
9
|
-
standalone: true,
|
|
10
|
-
imports: [UiButton, LYNX_ELEMENTS],
|
|
11
|
-
template: `<ui-button (pressed)="onPressed()"><text>Go</text></ui-button>`,
|
|
12
|
-
})
|
|
13
|
-
class ButtonHost {
|
|
14
|
-
count = 0;
|
|
15
|
-
onPressed = () => {
|
|
16
|
-
this.count++;
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
describe('UiButton (render)', () => {
|
|
21
|
-
it('renders and mounts without throwing', async () => {
|
|
22
|
-
const { container } = await render(ButtonHost);
|
|
23
|
-
expect(container).toBeTruthy();
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('emits `pressed` from onTap() when not disabled/loading', async () => {
|
|
27
|
-
const { componentRef } = await render(UiButton);
|
|
28
|
-
const inst = componentRef.instance as unknown as {
|
|
29
|
-
onTap: () => void;
|
|
30
|
-
pressed: { subscribe: (cb: () => void) => void };
|
|
31
|
-
};
|
|
32
|
-
const emitted = vi.fn();
|
|
33
|
-
inst.pressed.subscribe(emitted);
|
|
34
|
-
inst.onTap();
|
|
35
|
-
expect(emitted).toHaveBeenCalledTimes(1);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('onTap() is a no-op when disabled', async () => {
|
|
39
|
-
const { componentRef } = await render(UiButton);
|
|
40
|
-
const inst = componentRef.instance as unknown as UiButton & {
|
|
41
|
-
onTap: () => void;
|
|
42
|
-
};
|
|
43
|
-
setInputSignal(inst.disabled, true);
|
|
44
|
-
const emitted = vi.fn();
|
|
45
|
-
inst.pressed.subscribe(emitted);
|
|
46
|
-
inst.onTap();
|
|
47
|
-
expect(emitted).not.toHaveBeenCalled();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('onTap() is a no-op when loading', async () => {
|
|
51
|
-
const { componentRef } = await render(UiButton);
|
|
52
|
-
const inst = componentRef.instance as unknown as UiButton & {
|
|
53
|
-
onTap: () => void;
|
|
54
|
-
};
|
|
55
|
-
setInputSignal(inst.loading, true);
|
|
56
|
-
const emitted = vi.fn();
|
|
57
|
-
inst.pressed.subscribe(emitted);
|
|
58
|
-
inst.onTap();
|
|
59
|
-
expect(emitted).not.toHaveBeenCalled();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('shows the spinner while loading', async () => {
|
|
63
|
-
const { componentRef, container } = await render(UiButton);
|
|
64
|
-
setInputSignal((componentRef.instance as UiButton).loading, true);
|
|
65
|
-
await waitForUpdate();
|
|
66
|
-
// Spinner renders as a nested view with an svg — searching for that
|
|
67
|
-
// suffices without asserting on the internal Lynx tree.
|
|
68
|
-
expect(container.querySelector('svg')).toBeTruthy();
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('applies disabled dim opacity when disabled or loading', async () => {
|
|
72
|
-
const { componentRef, container } = await render(UiButton);
|
|
73
|
-
setInputSignal((componentRef.instance as UiButton).disabled, true);
|
|
74
|
-
await waitForUpdate();
|
|
75
|
-
const outer = container.querySelector('view');
|
|
76
|
-
expect(outer?.getAttribute('class')).toContain('opacity-50');
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('picks the right spinner size for each button size', async () => {
|
|
80
|
-
// spinnerSize returns 'xs' for size='sm' and 'sm' otherwise. Cover both.
|
|
81
|
-
const { componentRef } = await render(UiButton);
|
|
82
|
-
const inst = componentRef.instance as unknown as UiButton & {
|
|
83
|
-
spinnerSize: () => 'xs' | 'sm';
|
|
84
|
-
};
|
|
85
|
-
setInputSignal(inst.size, 'sm');
|
|
86
|
-
await waitForUpdate();
|
|
87
|
-
expect(inst.spinnerSize()).toBe('xs');
|
|
88
|
-
|
|
89
|
-
setInputSignal(inst.size, 'default');
|
|
90
|
-
await waitForUpdate();
|
|
91
|
-
expect(inst.spinnerSize()).toBe('sm');
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it("colors the spinner like each variant's label", async () => {
|
|
95
|
-
// The template binding doesn't reach the spinner's input under JIT (see
|
|
96
|
-
// setInputSignal), so check the value the button passes it.
|
|
97
|
-
const { componentRef } = await render(UiButton);
|
|
98
|
-
const inst = componentRef.instance as unknown as UiButton & {
|
|
99
|
-
spinnerColor: () => string;
|
|
100
|
-
};
|
|
101
|
-
for (const [variant, color] of [
|
|
102
|
-
['default', 'var(--primary-foreground)'],
|
|
103
|
-
['destructive', 'var(--destructive-foreground)'],
|
|
104
|
-
['outline', 'var(--foreground)'],
|
|
105
|
-
['secondary', 'var(--secondary-foreground)'],
|
|
106
|
-
['ghost', 'var(--foreground)'],
|
|
107
|
-
] as const) {
|
|
108
|
-
setInputSignal(inst.variant, variant);
|
|
109
|
-
expect(inst.spinnerColor()).toBe(color);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('press handlers run cleanly (guarded by disabled/loading state)', async () => {
|
|
114
|
-
// onPressStart/End are no-ops when the button is disabled/loading; the
|
|
115
|
-
// active-press path relies on the ref being wired up on-device — assert
|
|
116
|
-
// only that the handlers run without throwing here.
|
|
117
|
-
const { componentRef } = await render(UiButton);
|
|
118
|
-
const inst = componentRef.instance as unknown as {
|
|
119
|
-
onPressStart: () => void;
|
|
120
|
-
onPressEnd: () => void;
|
|
121
|
-
onPressCancel: () => void;
|
|
122
|
-
};
|
|
123
|
-
expect(() => inst.onPressStart()).not.toThrow();
|
|
124
|
-
expect(() => inst.onPressEnd()).not.toThrow();
|
|
125
|
-
expect(() => inst.onPressCancel()).not.toThrow();
|
|
126
|
-
|
|
127
|
-
// Disabled path (early return in onPressStart / onPressEnd)
|
|
128
|
-
setInputSignal((componentRef.instance as UiButton).disabled, true);
|
|
129
|
-
expect(() => inst.onPressStart()).not.toThrow();
|
|
130
|
-
expect(() => inst.onPressEnd()).not.toThrow();
|
|
131
|
-
});
|
|
132
|
-
});
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { Component } from '@angular/core';
|
|
2
|
-
import { render, waitForUpdate } from '@blotch/angular-lynx-testing-library';
|
|
3
|
-
import { LYNX_ELEMENTS } from '@blotch/angular-lynx';
|
|
4
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
-
import { setInputSignal } from '../../../test-utils/set-input-signal';
|
|
6
|
-
import { UiButtonGroup, UiButtonGroupItem } from './button-group';
|
|
7
|
-
|
|
8
|
-
@Component({
|
|
9
|
-
standalone: true,
|
|
10
|
-
imports: [UiButtonGroup, UiButtonGroupItem, LYNX_ELEMENTS],
|
|
11
|
-
template: `
|
|
12
|
-
<ui-button-group [orientation]="orientation">
|
|
13
|
-
<ui-button-group-item (pressed)="onPressed()"
|
|
14
|
-
><text>A</text></ui-button-group-item
|
|
15
|
-
>
|
|
16
|
-
<ui-button-group-item [disabled]="disabled" (pressed)="onPressed()"
|
|
17
|
-
><text>B</text></ui-button-group-item
|
|
18
|
-
>
|
|
19
|
-
</ui-button-group>
|
|
20
|
-
`,
|
|
21
|
-
})
|
|
22
|
-
class ButtonGroupHost {
|
|
23
|
-
orientation: 'horizontal' | 'vertical' = 'horizontal';
|
|
24
|
-
disabled = false;
|
|
25
|
-
onPressed = () => {};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
describe('UiButtonGroup (render)', () => {
|
|
29
|
-
it('renders horizontally by default', async () => {
|
|
30
|
-
const { container } = await render(ButtonGroupHost);
|
|
31
|
-
expect(container).toBeTruthy();
|
|
32
|
-
const flexRow = container.querySelector('.flex-row');
|
|
33
|
-
expect(flexRow).toBeTruthy();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('switches to vertical layout when orientation is flipped', async () => {
|
|
37
|
-
const { componentRef, container } = await render(UiButtonGroup);
|
|
38
|
-
setInputSignal(
|
|
39
|
-
(componentRef.instance as UiButtonGroup).orientation,
|
|
40
|
-
'vertical',
|
|
41
|
-
);
|
|
42
|
-
await waitForUpdate();
|
|
43
|
-
expect(container.querySelector('.flex-col')).toBeTruthy();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('applies a user class from the alias input', async () => {
|
|
47
|
-
const { componentRef, container } = await render(UiButtonGroup);
|
|
48
|
-
setInputSignal(
|
|
49
|
-
(componentRef.instance as UiButtonGroup).userClass,
|
|
50
|
-
'w-full',
|
|
51
|
-
);
|
|
52
|
-
await waitForUpdate();
|
|
53
|
-
const outer = container.querySelector('view');
|
|
54
|
-
expect(outer?.getAttribute('class')).toContain('w-full');
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
describe('UiButtonGroupItem', () => {
|
|
59
|
-
const renderItem = async (
|
|
60
|
-
variant: 'default' | 'outline' = 'default',
|
|
61
|
-
size: 'default' | 'sm' | 'lg' = 'default',
|
|
62
|
-
disabledGroup = false,
|
|
63
|
-
) => {
|
|
64
|
-
const parentResult = await render(UiButtonGroup);
|
|
65
|
-
const parent = parentResult.componentRef.instance as UiButtonGroup;
|
|
66
|
-
setInputSignal(parent.variant, variant);
|
|
67
|
-
setInputSignal(parent.size, size);
|
|
68
|
-
setInputSignal(parent.disabled, disabledGroup);
|
|
69
|
-
await waitForUpdate();
|
|
70
|
-
|
|
71
|
-
const itemResult = await render(UiButtonGroupItem, {
|
|
72
|
-
providers: [{ provide: UiButtonGroup, useValue: parent }],
|
|
73
|
-
});
|
|
74
|
-
await waitForUpdate();
|
|
75
|
-
return { parent, itemResult };
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
it('onTap emits `pressed` when neither the group nor the item is disabled', async () => {
|
|
79
|
-
const { itemResult } = await renderItem();
|
|
80
|
-
const inst = itemResult.componentRef
|
|
81
|
-
.instance as unknown as UiButtonGroupItem & {
|
|
82
|
-
onTap: () => void;
|
|
83
|
-
};
|
|
84
|
-
const emitted = vi.fn();
|
|
85
|
-
inst.pressed.subscribe(emitted);
|
|
86
|
-
inst.onTap();
|
|
87
|
-
expect(emitted).toHaveBeenCalledTimes(1);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('onTap is a no-op when the group is disabled', async () => {
|
|
91
|
-
const { itemResult } = await renderItem('default', 'default', true);
|
|
92
|
-
const inst = itemResult.componentRef
|
|
93
|
-
.instance as unknown as UiButtonGroupItem & {
|
|
94
|
-
onTap: () => void;
|
|
95
|
-
};
|
|
96
|
-
const emitted = vi.fn();
|
|
97
|
-
inst.pressed.subscribe(emitted);
|
|
98
|
-
inst.onTap();
|
|
99
|
-
expect(emitted).not.toHaveBeenCalled();
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('onTap is a no-op when the item itself is disabled', async () => {
|
|
103
|
-
const { itemResult } = await renderItem();
|
|
104
|
-
const inst = itemResult.componentRef
|
|
105
|
-
.instance as unknown as UiButtonGroupItem & {
|
|
106
|
-
onTap: () => void;
|
|
107
|
-
};
|
|
108
|
-
setInputSignal(inst.disabled, true);
|
|
109
|
-
await waitForUpdate();
|
|
110
|
-
const emitted = vi.fn();
|
|
111
|
-
inst.pressed.subscribe(emitted);
|
|
112
|
-
inst.onTap();
|
|
113
|
-
expect(emitted).not.toHaveBeenCalled();
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('press handlers run cleanly on both enabled and disabled paths', async () => {
|
|
117
|
-
const { itemResult } = await renderItem();
|
|
118
|
-
const inst = itemResult.componentRef.instance as unknown as {
|
|
119
|
-
onPressStart: () => void;
|
|
120
|
-
onPressEnd: () => void;
|
|
121
|
-
onPressCancel: () => void;
|
|
122
|
-
disabled: unknown;
|
|
123
|
-
};
|
|
124
|
-
expect(() => inst.onPressStart()).not.toThrow();
|
|
125
|
-
expect(() => inst.onPressEnd()).not.toThrow();
|
|
126
|
-
expect(() => inst.onPressCancel()).not.toThrow();
|
|
127
|
-
setInputSignal((inst as unknown as UiButtonGroupItem).disabled, true);
|
|
128
|
-
await waitForUpdate();
|
|
129
|
-
expect(() => inst.onPressStart()).not.toThrow();
|
|
130
|
-
expect(() => inst.onPressEnd()).not.toThrow();
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('renders label with `outline` group variant classes', async () => {
|
|
134
|
-
// Covers the `outline` branch of both buttonGroupItemVariants and
|
|
135
|
-
// buttonGroupTextVariants.
|
|
136
|
-
const { itemResult } = await renderItem('outline', 'lg');
|
|
137
|
-
const view = itemResult.container.querySelector('view');
|
|
138
|
-
expect(view?.getAttribute('class')).toContain('bg-background');
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it('renders with size sm variant classes', async () => {
|
|
142
|
-
const { itemResult } = await renderItem('default', 'sm');
|
|
143
|
-
const view = itemResult.container.querySelector('view');
|
|
144
|
-
expect(view?.getAttribute('class')).toContain('h-9');
|
|
145
|
-
});
|
|
146
|
-
});
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { render } from '@blotch/angular-lynx-testing-library';
|
|
2
|
-
import { createChartRuntime } from '@tanstack/charts/runtime';
|
|
3
|
-
import type {
|
|
4
|
-
ChartDefinition,
|
|
5
|
-
ChartPoint,
|
|
6
|
-
SceneNode,
|
|
7
|
-
} from '@tanstack/charts/types';
|
|
8
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
9
|
-
import { setInputSignal } from '../../../test-utils/set-input-signal';
|
|
10
|
-
import { UiCandlestickChart } from './candlestick-chart';
|
|
11
|
-
|
|
12
|
-
const data = [
|
|
13
|
-
{ x: 0, open: 100, high: 104, low: 98, close: 102 },
|
|
14
|
-
{ x: 1, open: 102, high: 103, low: 97, close: 99 },
|
|
15
|
-
];
|
|
16
|
-
|
|
17
|
-
const render2 = (definition: ChartDefinition<any, any, any>) => {
|
|
18
|
-
const scene = createChartRuntime().render(definition, {
|
|
19
|
-
width: 300,
|
|
20
|
-
height: 200,
|
|
21
|
-
});
|
|
22
|
-
const found: SceneNode[] = [];
|
|
23
|
-
const walk = (nodes: readonly SceneNode[]) => {
|
|
24
|
-
for (const node of nodes) {
|
|
25
|
-
if (node.kind === 'group') {
|
|
26
|
-
if (!node.focus) walk(node.children);
|
|
27
|
-
} else if (node.kind !== 'label') found.push(node);
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
walk(scene.nodes);
|
|
31
|
-
return { scene, found };
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
describe('UiCandlestickChart', () => {
|
|
35
|
-
type Internals = {
|
|
36
|
-
definition: () => ChartDefinition<any, any, any>;
|
|
37
|
-
onSelect(point: ChartPoint | null): void;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
it('builds its definition from its inputs', async () => {
|
|
41
|
-
const { componentRef } = await render(UiCandlestickChart);
|
|
42
|
-
const chart = componentRef.instance as UiCandlestickChart;
|
|
43
|
-
setInputSignal(chart.data, data);
|
|
44
|
-
setInputSignal(chart.upColor, 'blue');
|
|
45
|
-
const { found } = render2((chart as unknown as Internals).definition());
|
|
46
|
-
expect(found.filter((n) => n.kind === 'rect')[0]!.style?.fill).toBe('blue');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('emits the tapped datum', async () => {
|
|
50
|
-
const { componentRef } = await render(UiCandlestickChart);
|
|
51
|
-
const chart = componentRef.instance as UiCandlestickChart;
|
|
52
|
-
const tapped = vi.fn();
|
|
53
|
-
chart.candleTap.subscribe(tapped);
|
|
54
|
-
const internals = chart as unknown as Internals;
|
|
55
|
-
internals.onSelect({ datum: data[0] } as ChartPoint);
|
|
56
|
-
internals.onSelect(null);
|
|
57
|
-
expect(tapped.mock.calls).toEqual([[data[0]]]);
|
|
58
|
-
});
|
|
59
|
-
});
|