@blotch/dolan 22.2.2 → 22.2.3

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.
Files changed (154) hide show
  1. package/dist/commands/add.d.ts +6 -2
  2. package/dist/commands/add.js +32 -10
  3. package/dist/commands/add.js.map +1 -1
  4. package/dist/commands/add.test.js +129 -9
  5. package/dist/commands/add.test.js.map +1 -1
  6. package/dist/commands/diff.d.ts +2 -1
  7. package/dist/commands/diff.js +38 -25
  8. package/dist/commands/diff.js.map +1 -1
  9. package/dist/commands/diff.test.js +72 -11
  10. package/dist/commands/diff.test.js.map +1 -1
  11. package/dist/commands/doctor.js +41 -27
  12. package/dist/commands/doctor.js.map +1 -1
  13. package/dist/commands/doctor.test.js +93 -9
  14. package/dist/commands/doctor.test.js.map +1 -1
  15. package/dist/commands/eject.js +7 -0
  16. package/dist/commands/eject.js.map +1 -1
  17. package/dist/commands/eject.test.js +39 -0
  18. package/dist/commands/eject.test.js.map +1 -1
  19. package/dist/commands/info.js +3 -2
  20. package/dist/commands/info.js.map +1 -1
  21. package/dist/commands/init.d.ts +37 -1
  22. package/dist/commands/init.js +149 -40
  23. package/dist/commands/init.js.map +1 -1
  24. package/dist/commands/init.test.js +285 -26
  25. package/dist/commands/init.test.js.map +1 -1
  26. package/dist/commands/install-packages.d.ts +6 -0
  27. package/dist/commands/install-packages.js +20 -0
  28. package/dist/commands/install-packages.js.map +1 -0
  29. package/dist/commands/install-packages.test.d.ts +1 -0
  30. package/dist/commands/install-packages.test.js +55 -0
  31. package/dist/commands/install-packages.test.js.map +1 -0
  32. package/dist/commands/list.js +21 -14
  33. package/dist/commands/list.js.map +1 -1
  34. package/dist/commands/list.test.js +62 -5
  35. package/dist/commands/list.test.js.map +1 -1
  36. package/dist/commands/outdated.js +11 -10
  37. package/dist/commands/outdated.js.map +1 -1
  38. package/dist/commands/outdated.test.js +20 -5
  39. package/dist/commands/outdated.test.js.map +1 -1
  40. package/dist/commands/remove.d.ts +4 -0
  41. package/dist/commands/remove.js +17 -4
  42. package/dist/commands/remove.js.map +1 -1
  43. package/dist/commands/remove.test.js +53 -2
  44. package/dist/commands/remove.test.js.map +1 -1
  45. package/dist/commands/update.d.ts +6 -0
  46. package/dist/commands/update.js +59 -24
  47. package/dist/commands/update.js.map +1 -1
  48. package/dist/commands/update.test.js +273 -31
  49. package/dist/commands/update.test.js.map +1 -1
  50. package/dist/index.js +7 -0
  51. package/dist/index.js.map +1 -1
  52. package/dist/registry.d.ts +8 -0
  53. package/dist/registry.js +32 -24
  54. package/dist/registry.js.map +1 -1
  55. package/dist/registry.test.js +76 -37
  56. package/dist/registry.test.js.map +1 -1
  57. package/dist/testing/set-input-signal.d.ts +13 -0
  58. package/dist/testing/set-input-signal.js +20 -0
  59. package/dist/testing/set-input-signal.js.map +1 -0
  60. package/dist/testing/set-input-signal.test.d.ts +1 -0
  61. package/dist/testing/set-input-signal.test.js +20 -0
  62. package/dist/testing/set-input-signal.test.js.map +1 -0
  63. package/dist/ui/components/action-sheet/action-sheet.test.ts +48 -1
  64. package/dist/ui/components/action-sheet/action-sheet.ts +37 -9
  65. package/dist/ui/components/alert-dialog/alert-dialog.test.ts +49 -2
  66. package/dist/ui/components/alert-dialog/alert-dialog.ts +43 -12
  67. package/dist/ui/components/area-chart/area-chart-render.test.ts +52 -110
  68. package/dist/ui/components/area-chart/area-chart.test.ts +58 -123
  69. package/dist/ui/components/area-chart/area-chart.ts +100 -315
  70. package/dist/ui/components/area-chart/index.ts +2 -3
  71. package/dist/ui/components/bar-chart/bar-chart-render.test.ts +47 -163
  72. package/dist/ui/components/bar-chart/bar-chart.test.ts +83 -37
  73. package/dist/ui/components/bar-chart/bar-chart.ts +140 -294
  74. package/dist/ui/components/bar-chart/index.ts +3 -3
  75. package/dist/ui/components/bottom-sheet/bottom-sheet.test.ts +191 -9
  76. package/dist/ui/components/bottom-sheet/bottom-sheet.ts +136 -20
  77. package/dist/ui/components/button/button-render.test.ts +19 -0
  78. package/dist/ui/components/button/button.ts +18 -2
  79. package/dist/ui/components/candlestick-chart/candlestick-chart-render.test.ts +48 -163
  80. package/dist/ui/components/candlestick-chart/candlestick-chart.test.ts +106 -62
  81. package/dist/ui/components/candlestick-chart/candlestick-chart.ts +150 -323
  82. package/dist/ui/components/candlestick-chart/index.ts +3 -4
  83. package/dist/ui/components/chart/chart-focus.test.ts +132 -0
  84. package/dist/ui/components/chart/chart-focus.ts +115 -0
  85. package/dist/ui/components/chart/chart-presets.test.ts +139 -0
  86. package/dist/ui/components/chart/chart-presets.ts +271 -0
  87. package/dist/ui/components/chart/chart-render.test.ts +730 -0
  88. package/dist/ui/components/chart/chart-scene.test.ts +589 -0
  89. package/dist/ui/components/chart/chart-scene.ts +483 -0
  90. package/dist/ui/components/chart/chart-theme.test.ts +85 -0
  91. package/dist/ui/components/chart/chart-theme.ts +198 -0
  92. package/dist/ui/components/chart/chart-zoom.test.ts +159 -0
  93. package/dist/ui/components/chart/chart-zoom.ts +162 -0
  94. package/dist/ui/components/chart/chart.ts +921 -0
  95. package/dist/ui/components/chart/index.ts +24 -0
  96. package/dist/ui/components/dialog/dialog.test.ts +49 -2
  97. package/dist/ui/components/dialog/dialog.ts +43 -12
  98. package/dist/ui/components/icon/icon-theme.test.ts +133 -0
  99. package/dist/ui/components/icon/icon-theme.ts +204 -0
  100. package/dist/ui/components/icon/icon.test.ts +51 -2
  101. package/dist/ui/components/icon/icon.ts +38 -21
  102. package/dist/ui/components/line-chart/index.ts +2 -3
  103. package/dist/ui/components/line-chart/line-chart-render.test.ts +69 -107
  104. package/dist/ui/components/line-chart/line-chart.test.ts +63 -45
  105. package/dist/ui/components/line-chart/line-chart.ts +83 -241
  106. package/dist/ui/components/list/list.test.ts +69 -2
  107. package/dist/ui/components/list/list.ts +21 -15
  108. package/dist/ui/components/nav-drawer/nav-drawer.test.ts +80 -1
  109. package/dist/ui/components/nav-drawer/nav-drawer.ts +66 -11
  110. package/dist/ui/components/pagination/pagination.test.ts +62 -0
  111. package/dist/ui/components/pagination/pagination.ts +55 -8
  112. package/dist/ui/components/scatter-chart/index.ts +2 -3
  113. package/dist/ui/components/scatter-chart/scatter-chart-render.test.ts +51 -144
  114. package/dist/ui/components/scatter-chart/scatter-chart.test.ts +57 -25
  115. package/dist/ui/components/scatter-chart/scatter-chart.ts +104 -250
  116. package/dist/ui/components/scroll-area/scroll-area.test.ts +37 -2
  117. package/dist/ui/components/scroll-area/scroll-area.ts +8 -8
  118. package/dist/ui/components/spinner/spinner.test.ts +27 -0
  119. package/dist/ui/components/spinner/spinner.ts +33 -23
  120. package/dist/ui/components/toast/toast.test.ts +37 -0
  121. package/dist/ui/components/toast/toast.ts +20 -4
  122. package/dist/ui/theme/chart-colors.test.ts +30 -0
  123. package/dist/ui/theme/dark.css +8 -0
  124. package/dist/ui/theme/default.css +8 -0
  125. package/dist/ui/theme/icon-colors.test.ts +30 -0
  126. package/dist/ui/theme/tailwind-plugin.ts +10 -1
  127. package/dist/utils/installed.d.ts +17 -0
  128. package/dist/utils/installed.js +27 -0
  129. package/dist/utils/installed.js.map +1 -0
  130. package/dist/utils/installed.test.d.ts +1 -0
  131. package/dist/utils/installed.test.js +41 -0
  132. package/dist/utils/installed.test.js.map +1 -0
  133. package/dist/utils/interactive.d.ts +9 -0
  134. package/dist/utils/interactive.js +10 -0
  135. package/dist/utils/interactive.js.map +1 -0
  136. package/dist/utils/interactive.test.d.ts +1 -0
  137. package/dist/utils/interactive.test.js +24 -0
  138. package/dist/utils/interactive.test.js.map +1 -0
  139. package/dist/utils/packages.d.ts +36 -0
  140. package/dist/utils/packages.js +70 -0
  141. package/dist/utils/packages.js.map +1 -0
  142. package/dist/utils/packages.test.d.ts +1 -0
  143. package/dist/utils/packages.test.js +89 -0
  144. package/dist/utils/packages.test.js.map +1 -0
  145. package/dist/utils/resolve-paths.d.ts +17 -1
  146. package/dist/utils/resolve-paths.js +23 -3
  147. package/dist/utils/resolve-paths.js.map +1 -1
  148. package/dist/utils/resolve-paths.test.js +34 -2
  149. package/dist/utils/resolve-paths.test.js.map +1 -1
  150. package/package.json +5 -1
  151. package/dist/ui/components/cartesian-chart/cartesian-chart-render.test.ts +0 -188
  152. package/dist/ui/components/cartesian-chart/cartesian-chart.test.ts +0 -525
  153. package/dist/ui/components/cartesian-chart/cartesian-chart.ts +0 -1140
  154. package/dist/ui/components/cartesian-chart/index.ts +0 -18
@@ -1,174 +1,58 @@
1
- import { render, waitForUpdate } from '@blotch/angular-lynx-testing-library';
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';
2
9
  import { describe, expect, it, vi } from 'vitest';
3
10
  import { setInputSignal } from '../../../test-utils/set-input-signal';
4
- import { UiCartesianChart } from '../cartesian-chart/cartesian-chart';
5
- import { UiBarChart, UiBarSeries } from './bar-chart';
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
+ };
6
32
 
7
33
  describe('UiBarChart', () => {
8
- it('renders with default configuration', async () => {
9
- const { container } = await render(UiBarChart);
10
- expect(container).toBeTruthy();
11
- });
12
-
13
- it('folds the baseline into the y-axis domain', async () => {
14
- const { componentRef } = await render(UiBarChart);
15
- const inst = componentRef.instance as UiBarChart;
16
- setInputSignal(inst.data, [
17
- { x: 0, y: 5 },
18
- { x: 1, y: 10 },
19
- { x: 2, y: 8 },
20
- ]);
21
- setInputSignal(inst.baseline, 0);
22
- await waitForUpdate();
23
- const cast = inst as unknown as {
24
- xAxis: () => { domain: readonly [number, number] };
25
- yAxis: () => { domain: readonly [number, number] };
26
- effectivePadding: () => { left?: number; right?: number };
27
- };
28
- expect(cast.yAxis().domain[0]).toBeLessThanOrEqual(0);
29
- expect(cast.yAxis().domain[1]).toBeGreaterThanOrEqual(10);
30
- // 3 bars → half-bar inset = 0.5 / (3-1) = 0.25
31
- expect(cast.effectivePadding().left).toBeCloseTo(0.25);
32
- expect(cast.effectivePadding().right).toBeCloseTo(0.25);
33
- });
34
-
35
- it('honors explicit xMin / xMax / yMin / yMax overrides', async () => {
36
- const { componentRef } = await render(UiBarChart);
37
- const inst = componentRef.instance as UiBarChart;
38
- setInputSignal(inst.data, [
39
- { x: 0, y: 0 },
40
- { x: 10, y: 10 },
41
- ]);
42
- setInputSignal(inst.xMin, -5);
43
- setInputSignal(inst.xMax, 20);
44
- setInputSignal(inst.yMin, -1);
45
- setInputSignal(inst.yMax, 15);
46
- await waitForUpdate();
47
- const cast = inst as unknown as {
48
- xAxis: () => { domain: readonly [number, number] };
49
- yAxis: () => { domain: readonly [number, number] };
50
- };
51
- expect(cast.xAxis().domain[0]).toBeLessThanOrEqual(-5);
52
- expect(cast.xAxis().domain[1]).toBeGreaterThanOrEqual(20);
53
- expect(cast.yAxis().domain[0]).toBeLessThanOrEqual(-1);
54
- expect(cast.yAxis().domain[1]).toBeGreaterThanOrEqual(15);
55
- });
56
-
57
- it('single-datum series drops the half-bar padding', async () => {
58
- const { componentRef } = await render(UiBarChart);
59
- const inst = componentRef.instance as UiBarChart;
60
- setInputSignal(inst.data, [{ x: 0, y: 5 }]);
61
- await waitForUpdate();
62
- const cast = inst as unknown as {
63
- effectivePadding: () => { left?: number; right?: number };
64
- };
65
- // n === 1 → half === 0
66
- expect(cast.effectivePadding().left).toBe(0);
67
- expect(cast.effectivePadding().right).toBe(0);
68
- });
34
+ type Internals = {
35
+ definition: () => ChartDefinition<any, any, any>;
36
+ onSelect(point: ChartPoint | null): void;
37
+ };
69
38
 
70
- it('exposes the default tick formatter used by the child cartesian chart', async () => {
39
+ it('builds its definition from its inputs', async () => {
71
40
  const { componentRef } = await render(UiBarChart);
72
- const inst = componentRef.instance as UiBarChart;
73
- expect(inst.xTickFormat()(3.14159)).toBe('3.14');
74
- expect(inst.yTickFormat()(1.005)).toBe('1');
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');
75
46
  });
76
47
 
77
- it('user padding overrides the auto half-bar inset per side', async () => {
48
+ it('emits the tapped datum', async () => {
78
49
  const { componentRef } = await render(UiBarChart);
79
- const inst = componentRef.instance as UiBarChart;
80
- setInputSignal(inst.data, [
81
- { x: 0, y: 5 },
82
- { x: 1, y: 10 },
83
- ]);
84
- setInputSignal(inst.padding, { left: 0.1 });
85
- await waitForUpdate();
86
- const cast = inst as unknown as {
87
- effectivePadding: () => { left?: number; right?: number };
88
- };
89
- // left explicitly set → wins; right still auto = 0.5
90
- expect(cast.effectivePadding().left).toBeCloseTo(0.1);
91
- expect(cast.effectivePadding().right).toBeCloseTo(0.5);
92
- });
93
- });
94
-
95
- describe('UiBarSeries', () => {
96
- const renderSeries = async () => {
97
- const parentResult = await render(UiCartesianChart);
98
- const parent = parentResult.componentRef.instance as UiCartesianChart;
99
- setInputSignal(parent.xDomain, [0, 10]);
100
- setInputSignal(parent.yDomain, [0, 10]);
101
- await waitForUpdate();
102
- const seriesResult = await render(UiBarSeries, {
103
- providers: [{ provide: UiCartesianChart, useValue: parent }],
104
- });
105
- const series = seriesResult.componentRef.instance as UiBarSeries;
106
- setInputSignal(series.data, [
107
- { x: 0, y: 2 },
108
- { x: 5, y: 8 },
109
- { x: 10, y: 5 },
110
- ]);
111
- await waitForUpdate();
112
- return { parent, series };
113
- };
114
-
115
- it('renders a rectangle per datum with the fallback color', async () => {
116
- const { series } = await renderSeries();
117
- const cast = series as unknown as {
118
- bars: () => { style: string; point: { x: number; y: number } }[];
119
- };
120
- const bars = cast.bars();
121
- expect(bars.length).toBe(3);
122
- for (const b of bars) {
123
- expect(b.style).toContain('background-color: var(--primary)');
124
- }
125
- });
126
-
127
- it('cycles through the per-bar palette when colors are provided', async () => {
128
- const { series } = await renderSeries();
129
- setInputSignal(series.colors, ['#f00', '#0f0']);
130
- await waitForUpdate();
131
- const cast = series as unknown as { bars: () => { style: string }[] };
132
- const bars = cast.bars();
133
- expect(bars[0].style).toContain('#f00');
134
- expect(bars[1].style).toContain('#0f0');
135
- // wraps around
136
- expect(bars[2].style).toContain('#f00');
137
- });
138
-
139
- it('emits barTap with the source point when a bar is tapped', async () => {
140
- const { series } = await renderSeries();
141
- const cb = vi.fn();
142
- series.barTap.subscribe(cb);
143
- (
144
- series as unknown as { onBarTap: (p: { x: number; y: number }) => void }
145
- ).onBarTap({ x: 1, y: 2 });
146
- expect(cb).toHaveBeenCalledWith({ x: 1, y: 2 });
147
- });
148
-
149
- it('single-datum series uses the fallback bar width', async () => {
150
- const parentResult = await render(UiCartesianChart);
151
- const parent = parentResult.componentRef.instance as UiCartesianChart;
152
- setInputSignal(parent.xDomain, [0, 10]);
153
- setInputSignal(parent.yDomain, [0, 10]);
154
- await waitForUpdate();
155
- const seriesResult = await render(UiBarSeries, {
156
- providers: [{ provide: UiCartesianChart, useValue: parent }],
157
- });
158
- const series = seriesResult.componentRef.instance as UiBarSeries;
159
- setInputSignal(series.data, [{ x: 5, y: 5 }]);
160
- await waitForUpdate();
161
- const cast = series as unknown as { bars: () => { style: string }[] };
162
- const [bar] = cast.bars();
163
- // fallback = 24px
164
- expect(bar.style).toContain('width: 24.00px');
165
- });
166
-
167
- it('clamps the baseline into the plot when it lies outside the domain', async () => {
168
- const { series } = await renderSeries();
169
- setInputSignal(series.baseline, 999);
170
- await waitForUpdate();
171
- const cast = series as unknown as { bars: () => { style: string }[] };
172
- expect(cast.bars().length).toBe(3);
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 }]]);
173
57
  });
174
58
  });
@@ -1,51 +1,97 @@
1
+ import { createChartRuntime } from '@tanstack/charts/runtime';
2
+ import type {
3
+ ChartDefinition,
4
+ SceneNode,
5
+ SceneRect,
6
+ } from '@tanstack/charts/types';
1
7
  import { describe, expect, it } from 'vitest';
2
- import { computeBars } from './bar-chart';
3
-
4
- // Screen y grows downward, so a value ABOVE the baseline has a SMALLER pixel y
5
- // than baseY. Baseline pixel y = 100 in these cases (bottom of the plot).
6
- describe('computeBars', () => {
7
- it('draws a positive bar from the baseline up to the value, centered on cx', () => {
8
- // value projects to y=30 (above the baseline at y=100).
9
- const [bar] = computeBars([{ cx: 50, valueY: 30 }], 100, 12);
10
- expect(bar.top).toBe(30); // min(valueY, baseY) — the higher edge
11
- expect(bar.height).toBe(70); // |valueY - baseY|
12
- expect(bar.width).toBe(12);
13
- expect(bar.left).toBe(50 - 6); // cx - barWidth/2
8
+ import { barChartDefinition } from './bar-chart';
9
+
10
+ /**
11
+ * Every bar in a definition's scene.
12
+ */
13
+ const bars = (definition: ChartDefinition<any, any, any>) => {
14
+ const scene = createChartRuntime().render(definition, {
15
+ width: 300,
16
+ height: 200,
14
17
  });
18
+ const found: SceneRect[] = [];
19
+ const walk = (nodes: readonly SceneNode[]) => {
20
+ for (const node of nodes) {
21
+ if (node.kind === 'group') {
22
+ if (!node.focus) walk(node.children);
23
+ } else if (node.kind === 'rect') found.push(node);
24
+ }
25
+ };
26
+ walk(scene.nodes);
27
+ return { scene, found };
28
+ };
29
+
30
+ describe('barChartDefinition', () => {
31
+ const week = [
32
+ { x: 'Mon', y: 5 },
33
+ { x: 'Tue', y: 8 },
34
+ { x: 'Wed', y: 3 },
35
+ ];
15
36
 
16
- it('draws a negative bar growing downward from the baseline', () => {
17
- // value projects BELOW the baseline, so valueY (140) > baseY (100).
18
- const [bar] = computeBars([{ cx: 20, valueY: 140 }], 100, 10);
19
- expect(bar.top).toBe(100); // min(valueY, baseY) = baseY here
20
- expect(bar.height).toBe(40); // grows down to the value
37
+ it('puts category labels on a band scale', () => {
38
+ const { scene, found } = bars(
39
+ barChartDefinition({ data: week, radius: 4 }),
40
+ );
41
+ expect(found).toHaveLength(3);
42
+ expect(scene.scales['x']!.bandwidth).toBeGreaterThan(0);
43
+ expect(found[0]!.style?.fill).toBe('var(--primary)');
21
44
  });
22
45
 
23
- it('draws nothing (zero height) for a value exactly on the baseline', () => {
24
- // A bar's height is its datum: on the baseline there is nothing to draw, so
25
- // the default minBarHeight of 0 leaves it invisible rather than a sliver.
26
- const [bar] = computeBars([{ cx: 0, valueY: 100 }], 100, 12);
27
- expect(bar.height).toBe(0);
46
+ it('cycles per-bar colors on categories', () => {
47
+ const { found } = bars(
48
+ barChartDefinition({ data: week, colors: ['red', 'blue'] }),
49
+ );
50
+ expect(found.map((bar) => bar.style?.fill)).toEqual(['red', 'blue', 'red']);
28
51
  });
29
52
 
30
- it('honors a custom minimum bar height', () => {
31
- const [bar] = computeBars([{ cx: 0, valueY: 100 }], 100, 12, 3);
32
- expect(bar.height).toBe(3);
53
+ it('sizes bars on a band scale by barWidthRatio, clamped to 0–1', () => {
54
+ const wide = bars(
55
+ barChartDefinition({
56
+ data: week,
57
+ barWidthRatio: 2,
58
+ showXGrid: true,
59
+ xAxisLabel: 'Day',
60
+ }),
61
+ );
62
+ const narrow = bars(barChartDefinition({ data: week, barWidthRatio: 0.2 }));
63
+ expect(narrow.found[0]!.width).toBeLessThan(wide.found[0]!.width);
33
64
  });
34
65
 
35
- it('centers every bar on its own cx', () => {
36
- const bars = computeBars(
37
- [
38
- { cx: 10, valueY: 40 },
39
- { cx: 60, valueY: 20 },
40
- ],
41
- 100,
42
- 8,
66
+ const series = [
67
+ { x: 0, y: 4 },
68
+ { x: 1, y: -2 },
69
+ { x: 3, y: 6 },
70
+ ];
71
+
72
+ it('places numeric bars at their values, the ratio of the smallest gap wide', () => {
73
+ const { scene, found } = bars(
74
+ barChartDefinition({ data: series, barWidthRatio: 0.5 }),
43
75
  );
44
- expect(bars[0].left).toBe(10 - 4);
45
- expect(bars[1].left).toBe(60 - 4);
76
+ const x = scene.scales['x']!;
77
+ expect(x.bandwidth).toBe(0);
78
+ // The x axis has half a gap of room either side for the edge bars.
79
+ expect(x.domain[0]).toBeLessThanOrEqual(-0.5);
80
+ const unit = Math.abs(x.map(1) - x.map(0));
81
+ // rect trims a hair off each edge, so allow a couple of pixels.
82
+ expect(Math.abs(found[0]!.width - unit * 0.5)).toBeLessThan(2);
83
+ // Negative values grow down from the baseline.
84
+ expect(Math.abs(found[1]!.y - scene.scales['y']!.map(0))).toBeLessThan(1);
46
85
  });
47
86
 
48
- it('returns an empty array for no bars', () => {
49
- expect(computeBars([], 100, 12)).toEqual([]);
87
+ it('colors numeric bars through the color scale', () => {
88
+ const { found } = bars(
89
+ barChartDefinition({
90
+ data: series,
91
+ colors: ['red', 'blue'],
92
+ tooltip: false,
93
+ }),
94
+ );
95
+ expect(found.map((bar) => bar.style?.fill)).toEqual(['red', 'blue', 'red']);
50
96
  });
51
97
  });