@blotch/dolan 22.2.3 → 22.2.5
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 +38 -3
- package/dist/commands/add.test.js.map +1 -1
- package/dist/commands/doctor.js +258 -21
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/doctor.test.js +425 -11
- 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 +105 -2
- 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 +7 -0
- package/dist/commands/update.js +194 -50
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/update.test.js +570 -3
- package/dist/commands/update.test.js.map +1 -1
- package/dist/lockfile.d.ts +17 -0
- package/dist/lockfile.js +56 -1
- package/dist/lockfile.js.map +1 -1
- package/dist/lockfile.test.d.ts +1 -0
- package/dist/lockfile.test.js +65 -0
- package/dist/lockfile.test.js.map +1 -0
- package/dist/registry.d.ts +6 -0
- package/dist/registry.js +119 -11
- package/dist/registry.js.map +1 -1
- package/dist/registry.test.js +61 -6
- package/dist/registry.test.js.map +1 -1
- package/dist/test-utils.d.ts +27 -0
- package/dist/test-utils.js +45 -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/boolean-inputs.test.ts +76 -0
- 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 +637 -183
- package/dist/ui/components/action-sheet/action-sheet.ts +339 -55
- package/dist/ui/components/action-sheet/index.ts +1 -0
- 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 +740 -129
- package/dist/ui/components/alert-dialog/alert-dialog.ts +672 -58
- package/dist/ui/components/alert-dialog/index.ts +5 -0
- package/dist/ui/components/area-chart/area-chart.test.ts +81 -1
- package/dist/ui/components/area-chart/area-chart.ts +3 -2
- 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 +14 -15
- package/dist/ui/components/bar-chart/bar-chart.test.ts +82 -1
- package/dist/ui/components/bottom-sheet/bottom-sheet.test.ts +1314 -273
- package/dist/ui/components/bottom-sheet/bottom-sheet.ts +1046 -119
- package/dist/ui/components/bottom-sheet/index.ts +7 -1
- package/dist/ui/components/button/button.test.ts +646 -2
- package/dist/ui/components/button/button.ts +443 -64
- package/dist/ui/components/button/index.ts +2 -0
- package/dist/ui/components/button-group/button-group.test.ts +528 -2
- package/dist/ui/components/button-group/button-group.ts +428 -70
- 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 +97 -61
- package/dist/ui/components/card/card.ts +2 -1
- package/dist/ui/components/chart/chart-presets.test.ts +197 -1
- package/dist/ui/components/chart/chart-presets.ts +14 -7
- package/dist/ui/components/chart/chart-theme.ts +12 -0
- package/dist/ui/components/chart/chart.test.ts +1031 -0
- package/dist/ui/components/chart/chart.ts +66 -46
- package/dist/ui/components/checkbox/checkbox.test.ts +124 -42
- package/dist/ui/components/checkbox/checkbox.ts +25 -24
- package/dist/ui/components/collapsible/collapsible.test.ts +158 -81
- package/dist/ui/components/collapsible/collapsible.ts +21 -15
- 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 +35 -29
- package/dist/ui/components/dock/dock-scroll.test.ts +130 -0
- package/dist/ui/components/dock/dock-scroll.ts +142 -0
- package/dist/ui/components/dock/dock-search.test.ts +594 -0
- package/dist/ui/components/dock/dock.test.ts +752 -0
- package/dist/ui/components/dock/dock.ts +1438 -0
- package/dist/ui/components/dock/index.ts +2 -0
- package/dist/ui/components/dynamic-color/dynamic-color.test.ts +144 -0
- package/dist/ui/components/dynamic-color/dynamic-color.ts +146 -0
- package/dist/ui/components/dynamic-color/index.ts +5 -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 +376 -0
- package/dist/ui/components/glass/glass.ts +430 -0
- package/dist/ui/components/glass/index.ts +19 -0
- package/dist/ui/components/icon/icon-theme.test.ts +64 -0
- package/dist/ui/components/icon/icon-theme.ts +70 -16
- 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 +17 -13
- package/dist/ui/components/label/label.test.ts +11 -24
- package/dist/ui/components/label/label.ts +8 -2
- package/dist/ui/components/line-chart/line-chart.test.ts +76 -1
- package/dist/ui/components/line-chart/line-chart.ts +3 -2
- package/dist/ui/components/list/list.test.ts +80 -49
- package/dist/ui/components/list/list.ts +5 -4
- 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 +636 -0
- package/dist/ui/components/menu/menu-popup.ts +565 -0
- package/dist/ui/components/menu/menu.test.ts +523 -0
- package/dist/ui/components/menu/menu.ts +455 -0
- package/dist/ui/components/nav-drawer/nav-drawer.test.ts +425 -260
- package/dist/ui/components/nav-drawer/nav-drawer.ts +75 -58
- package/dist/ui/components/navigation-bar/index.ts +1 -0
- package/dist/ui/components/navigation-bar/navigation-bar.test.ts +425 -0
- package/dist/ui/components/navigation-bar/navigation-bar.ts +411 -0
- package/dist/ui/components/pagination/pagination.test.ts +136 -86
- package/dist/ui/components/popover/index.ts +9 -0
- package/dist/ui/components/popover/popover-panel.test.ts +735 -0
- package/dist/ui/components/popover/popover-panel.ts +603 -0
- package/dist/ui/components/popover/popover.test.ts +286 -0
- package/dist/ui/components/popover/popover.ts +207 -0
- package/dist/ui/components/progress/progress.test.ts +102 -46
- package/dist/ui/components/progress/progress.ts +54 -55
- package/dist/ui/components/radio-group/radio-group.test.ts +128 -83
- package/dist/ui/components/radio-group/radio-group.ts +26 -25
- 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/scroll-area/scroll-area.ts +4 -3
- package/dist/ui/components/search-field/index.ts +15 -0
- package/dist/ui/components/search-field/keyboard.test.ts +147 -0
- package/dist/ui/components/search-field/keyboard.ts +123 -0
- package/dist/ui/components/search-field/search-field.test.ts +549 -0
- package/dist/ui/components/search-field/search-field.ts +628 -0
- package/dist/ui/components/segmented-control/index.ts +8 -0
- package/dist/ui/components/segmented-control/segmented-control.test.ts +861 -0
- package/dist/ui/components/segmented-control/segmented-control.ts +884 -0
- package/dist/ui/components/select/select.test.ts +138 -78
- package/dist/ui/components/select/select.ts +19 -12
- package/dist/ui/components/separator/separator.test.ts +18 -17
- package/dist/ui/components/sheet/sheet.test.ts +151 -11
- package/dist/ui/components/sheet/sheet.ts +68 -5
- package/dist/ui/components/skeleton/skeleton.test.ts +24 -7
- package/dist/ui/components/skeleton/skeleton.ts +10 -16
- package/dist/ui/components/slider/index.ts +1 -0
- package/dist/ui/components/slider/slider.test.ts +695 -0
- package/dist/ui/components/slider/slider.ts +901 -0
- package/dist/ui/components/spinner/spinner.test.ts +64 -46
- package/dist/ui/components/spinner/spinner.ts +16 -19
- package/dist/ui/components/switch/index.ts +1 -1
- package/dist/ui/components/switch/switch.test.ts +534 -48
- package/dist/ui/components/switch/switch.ts +613 -48
- 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/index.ts +7 -1
- package/dist/ui/components/tabs/tabs.test.ts +484 -150
- package/dist/ui/components/tabs/tabs.ts +344 -149
- package/dist/ui/components/textarea/textarea.test.ts +206 -100
- package/dist/ui/components/textarea/textarea.ts +16 -13
- package/dist/ui/components/toast/toast.test.ts +434 -350
- package/dist/ui/components/toast/toast.ts +42 -51
- package/dist/ui/components/toggle/index.ts +1 -0
- package/dist/ui/components/toggle/toggle.test.ts +559 -146
- package/dist/ui/components/toggle/toggle.ts +241 -26
- package/dist/ui/components/toolbar/bar-scroll.test.ts +310 -0
- package/dist/ui/components/toolbar/bar-scroll.ts +372 -0
- package/dist/ui/components/toolbar/index.ts +12 -0
- package/dist/ui/components/toolbar/toolbar.test.ts +438 -0
- package/dist/ui/components/toolbar/toolbar.ts +535 -0
- 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 +19 -0
- package/dist/utils/analyze.js +16 -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 +25 -1
- package/dist/utils/installed.js +33 -0
- package/dist/utils/installed.js.map +1 -1
- package/dist/utils/installed.test.js +55 -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 +45 -0
- package/dist/utils/tailwind.js +90 -0
- package/dist/utils/tailwind.js.map +1 -0
- package/dist/utils/tailwind.test.d.ts +1 -0
- package/dist/utils/tailwind.test.js +134 -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,90 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
/** The config files Tailwind 3 reads. Tailwind 4 needs none. */
|
|
5
|
+
export const TAILWIND_CONFIG_FILES = [
|
|
6
|
+
'tailwind.config.ts',
|
|
7
|
+
'tailwind.config.js',
|
|
8
|
+
'tailwind.config.mjs',
|
|
9
|
+
'tailwind.config.cjs',
|
|
10
|
+
];
|
|
11
|
+
/** The Tailwind config in the project's folder, if it has one. */
|
|
12
|
+
export const tailwindConfigFile = (cwd) => TAILWIND_CONFIG_FILES.find((file) => existsSync(join(cwd, file)));
|
|
13
|
+
/**
|
|
14
|
+
* The version of `tailwindcss` that `require` finds, if any. Both majors'
|
|
15
|
+
* package.json resolve: Tailwind 3 has no `exports` map, and Tailwind 4's
|
|
16
|
+
* lists `./package.json`.
|
|
17
|
+
*/
|
|
18
|
+
const tailwindVersion = (require) => {
|
|
19
|
+
try {
|
|
20
|
+
return require('tailwindcss/package.json').version;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The version of Tailwind CSS installed for the project, resolved from its
|
|
28
|
+
* folder as the build resolves it. Reading the project's package.json missed
|
|
29
|
+
* two setups that build fine: a workspace whose root installs `tailwindcss`
|
|
30
|
+
* for every package, and a Tailwind 4 app that lists only
|
|
31
|
+
* `@tailwindcss/postcss`, which depends on `tailwindcss` itself.
|
|
32
|
+
*
|
|
33
|
+
* npm hoists that dependency next to the plugin, where the app finds it.
|
|
34
|
+
* pnpm's strict layout keeps it out of the app's reach, so this looks from
|
|
35
|
+
* the plugin's own folder too. The build still finds it under pnpm: pnpm's
|
|
36
|
+
* bin scripts, `ng` among them, put the packages pnpm hoists on `NODE_PATH`,
|
|
37
|
+
* and Tailwind resolves the stylesheet's `@import 'tailwindcss'` against it.
|
|
38
|
+
* Undefined when neither finds it.
|
|
39
|
+
*/
|
|
40
|
+
export const installedTailwindVersion = (cwd) => {
|
|
41
|
+
const require = createRequire(join(cwd, 'package.json'));
|
|
42
|
+
const version = tailwindVersion(require);
|
|
43
|
+
if (version !== undefined)
|
|
44
|
+
return version;
|
|
45
|
+
try {
|
|
46
|
+
// The plugin's `exports` map doesn't list its package.json, so this
|
|
47
|
+
// starts from its entry point.
|
|
48
|
+
return tailwindVersion(createRequire(require.resolve('@tailwindcss/postcss')));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
/** A version's major, `4` for `4.3.3`. */
|
|
55
|
+
export const majorVersion = (version) => Number.parseInt(version, 10);
|
|
56
|
+
/**
|
|
57
|
+
* Whether the project is set up for Tailwind 4, where the stylesheet imports
|
|
58
|
+
* the theme's `tailwind.css` rather than `tailwind.config.ts` listing its
|
|
59
|
+
* plugin: it has no Tailwind config, and Tailwind 4 installed, as
|
|
60
|
+
* `ng add @blotch/angular-lynx` and `ng new --style=tailwind` set it up. A
|
|
61
|
+
* config means a Tailwind 3 setup, even with Tailwind 4 installed, as
|
|
62
|
+
* `doctor` warns.
|
|
63
|
+
*/
|
|
64
|
+
export const usesTailwind4 = (cwd) => {
|
|
65
|
+
if (tailwindConfigFile(cwd))
|
|
66
|
+
return false;
|
|
67
|
+
const version = installedTailwindVersion(cwd);
|
|
68
|
+
return version !== undefined && majorVersion(version) >= 4;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* The theme files a project takes: the colors, and what maps them to
|
|
72
|
+
* Tailwind's utilities, `tailwind.css` for Tailwind 4 (imported in the
|
|
73
|
+
* stylesheet) or `tailwind-plugin.ts` for Tailwind 3 (a config plugin).
|
|
74
|
+
*
|
|
75
|
+
* With `tests`, the plugin comes with its test, for the same reason as a
|
|
76
|
+
* component's (see getComponentFiles): it covers the plugin in the app's
|
|
77
|
+
* coverage report. `tailwind.css` has no code to cover. The theme folder's
|
|
78
|
+
* other tests stay behind: they check the theme in packages/ui with Node,
|
|
79
|
+
* against the components and Tailwind's own builds, which an app's `ng test`
|
|
80
|
+
* can't do.
|
|
81
|
+
*/
|
|
82
|
+
export const themeFilesFor = (cwd, { tests = false } = {}) => usesTailwind4(cwd)
|
|
83
|
+
? ['default.css', 'dark.css', 'tailwind.css']
|
|
84
|
+
: [
|
|
85
|
+
'default.css',
|
|
86
|
+
'dark.css',
|
|
87
|
+
'tailwind-plugin.ts',
|
|
88
|
+
...(tests ? ['tailwind-plugin.test.ts'] : []),
|
|
89
|
+
];
|
|
90
|
+
//# 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,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,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,kEAAkE;AAClE,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,GAAW,EAAsB,EAAE,CACpE,qBAAqB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAEpE;;;;GAIG;AACH,MAAM,eAAe,GAAG,CAAC,OAAuB,EAAsB,EAAE;IACtE,IAAI,CAAC;QACH,OAAQ,OAAO,CAAC,0BAA0B,CAAyB,CAAC,OAAO,CAAC;IAC9E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,GAAW,EAAsB,EAAE;IAC1E,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IAC1C,IAAI,CAAC;QACH,oEAAoE;QACpE,+BAA+B;QAC/B,OAAO,eAAe,CACpB,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC,CACvD,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC,CAAC;AAEF,0CAA0C;AAC1C,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAe,EAAU,EAAE,CACtD,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAE/B;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAW,EAAW,EAAE;IACpD,IAAI,kBAAkB,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,MAAM,OAAO,GAAG,wBAAwB,CAAC,GAAG,CAAC,CAAC;IAC9C,OAAO,OAAO,KAAK,SAAS,IAAI,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC7D,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,134 @@
|
|
|
1
|
+
import { describe, expect, it, afterEach } from 'vitest';
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { createFixture, installPackage } from '../test-utils';
|
|
5
|
+
import { getUiSourceDir } from './resolve-paths';
|
|
6
|
+
import { installedTailwindVersion, majorVersion, tailwindConfigFile, themeFilesFor, usesTailwind4, } from './tailwind';
|
|
7
|
+
let fixtures = [];
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
for (const fixture of fixtures)
|
|
10
|
+
fixture.cleanup();
|
|
11
|
+
fixtures = [];
|
|
12
|
+
});
|
|
13
|
+
/**
|
|
14
|
+
* A project with these packages installed, and these other files. Its
|
|
15
|
+
* package.json lists none of them: what's installed is what counts.
|
|
16
|
+
*/
|
|
17
|
+
const project = (installed = {}, files = {}) => {
|
|
18
|
+
const fixture = createFixture({});
|
|
19
|
+
fixtures.push(fixture);
|
|
20
|
+
writeFileSync(join(fixture.dir, 'package.json'), '{}');
|
|
21
|
+
for (const [name, version] of Object.entries(installed)) {
|
|
22
|
+
installPackage(fixture.dir, name, version);
|
|
23
|
+
}
|
|
24
|
+
for (const [file, content] of Object.entries(files)) {
|
|
25
|
+
writeFileSync(join(fixture.dir, file), content);
|
|
26
|
+
}
|
|
27
|
+
return fixture.dir;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* A project that lists only `@tailwindcss/postcss`, with Tailwind in the
|
|
31
|
+
* plugin's own node_modules, out of the project's reach, as pnpm installs it.
|
|
32
|
+
*/
|
|
33
|
+
const postcssOnly = () => {
|
|
34
|
+
const dir = project();
|
|
35
|
+
installPackage(installPackage(dir, '@tailwindcss/postcss', '4.3.3'), 'tailwindcss', '4.3.3');
|
|
36
|
+
return dir;
|
|
37
|
+
};
|
|
38
|
+
describe('installedTailwindVersion', () => {
|
|
39
|
+
it("reads the version of the project's own Tailwind, 3 or 4", () => {
|
|
40
|
+
expect(installedTailwindVersion(project({ tailwindcss: '4.3.3' }))).toBe('4.3.3');
|
|
41
|
+
expect(installedTailwindVersion(project({ tailwindcss: '3.4.19' }))).toBe('3.4.19');
|
|
42
|
+
});
|
|
43
|
+
it('finds the Tailwind a workspace root installs', () => {
|
|
44
|
+
// The app's package.json lists no Tailwind: the root's is every package's.
|
|
45
|
+
const root = project({ tailwindcss: '4.3.3' });
|
|
46
|
+
const app = join(root, 'apps', 'app');
|
|
47
|
+
mkdirSync(app, { recursive: true });
|
|
48
|
+
writeFileSync(join(app, 'package.json'), '{}');
|
|
49
|
+
expect(installedTailwindVersion(app)).toBe('4.3.3');
|
|
50
|
+
});
|
|
51
|
+
it('finds the Tailwind @tailwindcss/postcss depends on, hoisted next to it', () => {
|
|
52
|
+
// npm's layout: the plugin's dependency sits in the app's node_modules.
|
|
53
|
+
expect(installedTailwindVersion(project({ '@tailwindcss/postcss': '4.3.3', tailwindcss: '4.3.3' }))).toBe('4.3.3');
|
|
54
|
+
});
|
|
55
|
+
it("finds it from the plugin's own folder when the project can't", () => {
|
|
56
|
+
expect(installedTailwindVersion(postcssOnly())).toBe('4.3.3');
|
|
57
|
+
});
|
|
58
|
+
it("prefers the project's own Tailwind to the plugin's", () => {
|
|
59
|
+
// What the stylesheet's `@import 'tailwindcss'` finds first.
|
|
60
|
+
const dir = project({ tailwindcss: '4.2.0' });
|
|
61
|
+
installPackage(installPackage(dir, '@tailwindcss/postcss', '4.3.3'), 'tailwindcss', '4.3.3');
|
|
62
|
+
expect(installedTailwindVersion(dir)).toBe('4.2.0');
|
|
63
|
+
});
|
|
64
|
+
it('is undefined without Tailwind, even when the plugin is there', () => {
|
|
65
|
+
expect(installedTailwindVersion(project())).toBeUndefined();
|
|
66
|
+
expect(installedTailwindVersion(project({ '@tailwindcss/postcss': '4.3.3' }))).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe('majorVersion', () => {
|
|
70
|
+
it("reads a version's major", () => {
|
|
71
|
+
expect(majorVersion('4.3.3')).toBe(4);
|
|
72
|
+
expect(majorVersion('3.4.19')).toBe(3);
|
|
73
|
+
expect(majorVersion('4.0.0-beta.1')).toBe(4);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe('tailwindConfigFile', () => {
|
|
77
|
+
it('names the Tailwind config in the project, if any', () => {
|
|
78
|
+
expect(tailwindConfigFile(project({}, { 'tailwind.config.js': '' }))).toBe('tailwind.config.js');
|
|
79
|
+
expect(tailwindConfigFile(project())).toBeUndefined();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe('usesTailwind4', () => {
|
|
83
|
+
it('is true for a project with Tailwind 4 installed and no Tailwind config', () => {
|
|
84
|
+
expect(usesTailwind4(project({ tailwindcss: '4.3.3' }))).toBe(true);
|
|
85
|
+
expect(usesTailwind4(postcssOnly())).toBe(true);
|
|
86
|
+
});
|
|
87
|
+
it('is false for Tailwind 3, a Tailwind config, or no Tailwind', () => {
|
|
88
|
+
expect(usesTailwind4(project({ tailwindcss: '3.4.19' }))).toBe(false);
|
|
89
|
+
// A config is a Tailwind 3 setup, whatever's installed.
|
|
90
|
+
expect(usesTailwind4(project({ tailwindcss: '4.3.3' }, { 'tailwind.config.js': '' }))).toBe(false);
|
|
91
|
+
expect(usesTailwind4(project())).toBe(false);
|
|
92
|
+
});
|
|
93
|
+
it('reads the installed version, not the one package.json asks for', () => {
|
|
94
|
+
const dir = project({ tailwindcss: '3.4.19' });
|
|
95
|
+
writeFileSync(join(dir, 'package.json'), JSON.stringify({ devDependencies: { tailwindcss: '^4.3.3' } }));
|
|
96
|
+
expect(usesTailwind4(dir)).toBe(false);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
describe('themeFilesFor', () => {
|
|
100
|
+
it('takes tailwind.css on Tailwind 4, and the config plugin on Tailwind 3', () => {
|
|
101
|
+
expect(themeFilesFor(project({ tailwindcss: '4.3.3' }))).toEqual([
|
|
102
|
+
'default.css',
|
|
103
|
+
'dark.css',
|
|
104
|
+
'tailwind.css',
|
|
105
|
+
]);
|
|
106
|
+
expect(themeFilesFor(project({ tailwindcss: '3.4.19' }))).toEqual([
|
|
107
|
+
'default.css',
|
|
108
|
+
'dark.css',
|
|
109
|
+
'tailwind-plugin.ts',
|
|
110
|
+
]);
|
|
111
|
+
});
|
|
112
|
+
it("adds the Tailwind plugin's test with the components' tests", () => {
|
|
113
|
+
// It covers the plugin in the app's coverage report. Tailwind 4's
|
|
114
|
+
// tailwind.css has no code to cover.
|
|
115
|
+
expect(themeFilesFor(project({ tailwindcss: '3.4.19' }), { tests: true })).toEqual([
|
|
116
|
+
'default.css',
|
|
117
|
+
'dark.css',
|
|
118
|
+
'tailwind-plugin.ts',
|
|
119
|
+
'tailwind-plugin.test.ts',
|
|
120
|
+
]);
|
|
121
|
+
expect(themeFilesFor(project({ tailwindcss: '4.3.3' }), { tests: true })).toEqual(['default.css', 'dark.css', 'tailwind.css']);
|
|
122
|
+
});
|
|
123
|
+
it('lists only files the theme folder has', () => {
|
|
124
|
+
for (const version of ['3.4.19', '4.3.3']) {
|
|
125
|
+
const files = themeFilesFor(project({ tailwindcss: version }), {
|
|
126
|
+
tests: true,
|
|
127
|
+
});
|
|
128
|
+
for (const file of files) {
|
|
129
|
+
expect(existsSync(join(getUiSourceDir(), 'theme', file)), file).toBe(true);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
//# 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.5",
|
|
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
|
-
});
|