panelui-native 0.68.0 → 0.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/README.md +13 -2
  2. package/lib/module/components/accordion/index.js +38 -13
  3. package/lib/module/components/accordion/index.js.map +1 -1
  4. package/lib/module/components/area-chart/index.js +1 -0
  5. package/lib/module/components/area-chart/index.js.map +1 -1
  6. package/lib/module/components/breadcrumb/index.js +2 -1
  7. package/lib/module/components/breadcrumb/index.js.map +1 -1
  8. package/lib/module/components/button/index.js +21 -12
  9. package/lib/module/components/button/index.js.map +1 -1
  10. package/lib/module/components/carousel/index.js +1 -1
  11. package/lib/module/components/carousel/index.js.map +1 -1
  12. package/lib/module/components/chip/index.js +2 -2
  13. package/lib/module/components/chip/index.js.map +1 -1
  14. package/lib/module/components/code-block/index.js.map +1 -1
  15. package/lib/module/components/collapsible/index.js +284 -0
  16. package/lib/module/components/collapsible/index.js.map +1 -0
  17. package/lib/module/components/color-picker/index.js.map +1 -1
  18. package/lib/module/components/fab/index.js +7 -6
  19. package/lib/module/components/fab/index.js.map +1 -1
  20. package/lib/module/components/flow/index.js +67 -4
  21. package/lib/module/components/flow/index.js.map +1 -1
  22. package/lib/module/components/frame/index.js +2 -2
  23. package/lib/module/components/frame/index.js.map +1 -1
  24. package/lib/module/components/grid-item/index.js +2 -2
  25. package/lib/module/components/grid-item/index.js.map +1 -1
  26. package/lib/module/components/heatmap-chart/index.js +1 -0
  27. package/lib/module/components/heatmap-chart/index.js.map +1 -1
  28. package/lib/module/components/hex-chart/index.js +1 -0
  29. package/lib/module/components/hex-chart/index.js.map +1 -1
  30. package/lib/module/components/input-group/index.js +7 -2
  31. package/lib/module/components/input-group/index.js.map +1 -1
  32. package/lib/module/components/item/index.js +2 -2
  33. package/lib/module/components/item/index.js.map +1 -1
  34. package/lib/module/components/line-chart/index.js +1 -0
  35. package/lib/module/components/line-chart/index.js.map +1 -1
  36. package/lib/module/components/live-line-chart/index.js +103 -9
  37. package/lib/module/components/live-line-chart/index.js.map +1 -1
  38. package/lib/module/components/live-line-chart/live-line-accessibility.js +47 -0
  39. package/lib/module/components/live-line-chart/live-line-accessibility.js.map +1 -0
  40. package/lib/module/components/live-line-chart/live-line-lifecycle.js +33 -0
  41. package/lib/module/components/live-line-chart/live-line-lifecycle.js.map +1 -0
  42. package/lib/module/components/marker/index.js +2 -2
  43. package/lib/module/components/marker/index.js.map +1 -1
  44. package/lib/module/components/marquee/index.js +191 -0
  45. package/lib/module/components/marquee/index.js.map +1 -0
  46. package/lib/module/components/marquee/marquee-math.js +39 -0
  47. package/lib/module/components/marquee/marquee-math.js.map +1 -0
  48. package/lib/module/components/menu/index.js +11 -3
  49. package/lib/module/components/menu/index.js.map +1 -1
  50. package/lib/module/components/meter/index.js +38 -20
  51. package/lib/module/components/meter/index.js.map +1 -1
  52. package/lib/module/components/meter/meter-scale.js +62 -8
  53. package/lib/module/components/meter/meter-scale.js.map +1 -1
  54. package/lib/module/components/pagination/index.js +27 -11
  55. package/lib/module/components/pagination/index.js.map +1 -1
  56. package/lib/module/components/panelside/index.js +7 -2
  57. package/lib/module/components/panelside/index.js.map +1 -1
  58. package/lib/module/components/planner/index.js +159 -64
  59. package/lib/module/components/planner/index.js.map +1 -1
  60. package/lib/module/components/planner/planner-announcement.js +30 -0
  61. package/lib/module/components/planner/planner-announcement.js.map +1 -0
  62. package/lib/module/components/planner/planner-entries.js +15 -7
  63. package/lib/module/components/planner/planner-entries.js.map +1 -1
  64. package/lib/module/components/planner/planner-grid-navigation.js +33 -0
  65. package/lib/module/components/planner/planner-grid-navigation.js.map +1 -0
  66. package/lib/module/components/planner/planner-lifecycle.js +45 -0
  67. package/lib/module/components/planner/planner-lifecycle.js.map +1 -0
  68. package/lib/module/components/plot/index.js +105 -42
  69. package/lib/module/components/plot/index.js.map +1 -1
  70. package/lib/module/components/popover/index.js +2 -2
  71. package/lib/module/components/popover/index.js.map +1 -1
  72. package/lib/module/components/post/index.js +4 -4
  73. package/lib/module/components/post/index.js.map +1 -1
  74. package/lib/module/components/search-bar/index.js +331 -0
  75. package/lib/module/components/search-bar/index.js.map +1 -0
  76. package/lib/module/components/table/index.js +3 -4
  77. package/lib/module/components/table/index.js.map +1 -1
  78. package/lib/module/components/timeline/index.js +288 -39
  79. package/lib/module/components/timeline/index.js.map +1 -1
  80. package/lib/module/components/toggle-button/index.js +1 -1
  81. package/lib/module/components/toggle-button/index.js.map +1 -1
  82. package/lib/module/components/tree/index.js +13 -8
  83. package/lib/module/components/tree/index.js.map +1 -1
  84. package/lib/module/hooks/use-keyboard-avoidance.js.map +1 -1
  85. package/lib/module/index.js +3 -0
  86. package/lib/module/index.js.map +1 -1
  87. package/lib/module/primitives/focus-restoration-store.js +52 -0
  88. package/lib/module/primitives/focus-restoration-store.js.map +1 -0
  89. package/lib/module/primitives/portal.js +36 -2
  90. package/lib/module/primitives/portal.js.map +1 -1
  91. package/lib/module/utils/chart.js +50 -7
  92. package/lib/module/utils/chart.js.map +1 -1
  93. package/lib/typescript/src/components/accordion/index.d.ts +6 -2
  94. package/lib/typescript/src/components/accordion/index.d.ts.map +1 -1
  95. package/lib/typescript/src/components/area-chart/index.d.ts.map +1 -1
  96. package/lib/typescript/src/components/breadcrumb/index.d.ts.map +1 -1
  97. package/lib/typescript/src/components/button/index.d.ts.map +1 -1
  98. package/lib/typescript/src/components/code-block/index.d.ts +3 -3
  99. package/lib/typescript/src/components/code-block/index.d.ts.map +1 -1
  100. package/lib/typescript/src/components/collapsible/index.d.ts +76 -0
  101. package/lib/typescript/src/components/collapsible/index.d.ts.map +1 -0
  102. package/lib/typescript/src/components/color-picker/index.d.ts.map +1 -1
  103. package/lib/typescript/src/components/fab/index.d.ts +4 -2
  104. package/lib/typescript/src/components/fab/index.d.ts.map +1 -1
  105. package/lib/typescript/src/components/flow/index.d.ts +7 -1
  106. package/lib/typescript/src/components/flow/index.d.ts.map +1 -1
  107. package/lib/typescript/src/components/heatmap-chart/index.d.ts.map +1 -1
  108. package/lib/typescript/src/components/hex-chart/index.d.ts.map +1 -1
  109. package/lib/typescript/src/components/input-group/index.d.ts.map +1 -1
  110. package/lib/typescript/src/components/line-chart/index.d.ts.map +1 -1
  111. package/lib/typescript/src/components/live-line-chart/index.d.ts +21 -7
  112. package/lib/typescript/src/components/live-line-chart/index.d.ts.map +1 -1
  113. package/lib/typescript/src/components/live-line-chart/live-line-accessibility.d.ts +22 -0
  114. package/lib/typescript/src/components/live-line-chart/live-line-accessibility.d.ts.map +1 -0
  115. package/lib/typescript/src/components/live-line-chart/live-line-lifecycle.d.ts +23 -0
  116. package/lib/typescript/src/components/live-line-chart/live-line-lifecycle.d.ts.map +1 -0
  117. package/lib/typescript/src/components/marquee/index.d.ts +73 -0
  118. package/lib/typescript/src/components/marquee/index.d.ts.map +1 -0
  119. package/lib/typescript/src/components/marquee/marquee-math.d.ts +21 -0
  120. package/lib/typescript/src/components/marquee/marquee-math.d.ts.map +1 -0
  121. package/lib/typescript/src/components/menu/index.d.ts +1 -1
  122. package/lib/typescript/src/components/menu/index.d.ts.map +1 -1
  123. package/lib/typescript/src/components/meter/index.d.ts +7 -4
  124. package/lib/typescript/src/components/meter/index.d.ts.map +1 -1
  125. package/lib/typescript/src/components/meter/meter-scale.d.ts +39 -0
  126. package/lib/typescript/src/components/meter/meter-scale.d.ts.map +1 -1
  127. package/lib/typescript/src/components/pagination/index.d.ts.map +1 -1
  128. package/lib/typescript/src/components/panelside/index.d.ts +1 -1
  129. package/lib/typescript/src/components/panelside/index.d.ts.map +1 -1
  130. package/lib/typescript/src/components/plan/index.d.ts +2 -2
  131. package/lib/typescript/src/components/planner/index.d.ts.map +1 -1
  132. package/lib/typescript/src/components/planner/planner-announcement.d.ts +15 -0
  133. package/lib/typescript/src/components/planner/planner-announcement.d.ts.map +1 -0
  134. package/lib/typescript/src/components/planner/planner-entries.d.ts +1 -1
  135. package/lib/typescript/src/components/planner/planner-entries.d.ts.map +1 -1
  136. package/lib/typescript/src/components/planner/planner-grid-navigation.d.ts +4 -0
  137. package/lib/typescript/src/components/planner/planner-grid-navigation.d.ts.map +1 -0
  138. package/lib/typescript/src/components/planner/planner-lifecycle.d.ts +20 -0
  139. package/lib/typescript/src/components/planner/planner-lifecycle.d.ts.map +1 -0
  140. package/lib/typescript/src/components/plot/index.d.ts +59 -5
  141. package/lib/typescript/src/components/plot/index.d.ts.map +1 -1
  142. package/lib/typescript/src/components/search-bar/index.d.ts +216 -0
  143. package/lib/typescript/src/components/search-bar/index.d.ts.map +1 -0
  144. package/lib/typescript/src/components/timeline/index.d.ts +35 -2
  145. package/lib/typescript/src/components/timeline/index.d.ts.map +1 -1
  146. package/lib/typescript/src/components/tree/index.d.ts +3 -4
  147. package/lib/typescript/src/components/tree/index.d.ts.map +1 -1
  148. package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts +2 -2
  149. package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts.map +1 -1
  150. package/lib/typescript/src/index.d.ts +4 -1
  151. package/lib/typescript/src/index.d.ts.map +1 -1
  152. package/lib/typescript/src/primitives/focus-restoration-store.d.ts +24 -0
  153. package/lib/typescript/src/primitives/focus-restoration-store.d.ts.map +1 -0
  154. package/lib/typescript/src/primitives/portal.d.ts +4 -0
  155. package/lib/typescript/src/primitives/portal.d.ts.map +1 -1
  156. package/lib/typescript/src/utils/chart.d.ts +28 -3
  157. package/lib/typescript/src/utils/chart.d.ts.map +1 -1
  158. package/package.json +36 -3
  159. package/src/components/accordion/index.tsx +48 -15
  160. package/src/components/area-chart/index.tsx +8 -0
  161. package/src/components/breadcrumb/index.tsx +2 -1
  162. package/src/components/button/index.tsx +14 -6
  163. package/src/components/carousel/index.tsx +1 -1
  164. package/src/components/chip/index.tsx +2 -2
  165. package/src/components/code-block/index.tsx +3 -3
  166. package/src/components/collapsible/index.tsx +287 -0
  167. package/src/components/color-picker/index.tsx +3 -2
  168. package/src/components/fab/index.tsx +21 -11
  169. package/src/components/flow/index.tsx +94 -15
  170. package/src/components/frame/index.tsx +2 -2
  171. package/src/components/grid-item/index.tsx +2 -2
  172. package/src/components/heatmap-chart/index.tsx +7 -1
  173. package/src/components/hex-chart/index.tsx +7 -1
  174. package/src/components/input-group/index.tsx +7 -2
  175. package/src/components/item/index.tsx +2 -2
  176. package/src/components/line-chart/index.tsx +9 -0
  177. package/src/components/live-line-chart/index.tsx +130 -13
  178. package/src/components/live-line-chart/live-line-accessibility.ts +61 -0
  179. package/src/components/live-line-chart/live-line-lifecycle.ts +63 -0
  180. package/src/components/marker/index.tsx +2 -2
  181. package/src/components/marquee/index.tsx +234 -0
  182. package/src/components/marquee/marquee-math.ts +37 -0
  183. package/src/components/menu/index.tsx +11 -3
  184. package/src/components/meter/index.tsx +49 -26
  185. package/src/components/meter/meter-scale.ts +84 -8
  186. package/src/components/pagination/index.tsx +26 -13
  187. package/src/components/panelside/index.tsx +7 -2
  188. package/src/components/plan/index.tsx +2 -2
  189. package/src/components/planner/index.tsx +202 -76
  190. package/src/components/planner/planner-announcement.ts +37 -0
  191. package/src/components/planner/planner-entries.ts +16 -7
  192. package/src/components/planner/planner-grid-navigation.ts +45 -0
  193. package/src/components/planner/planner-lifecycle.ts +76 -0
  194. package/src/components/plot/index.tsx +183 -39
  195. package/src/components/popover/index.tsx +3 -3
  196. package/src/components/post/index.tsx +4 -4
  197. package/src/components/search-bar/index.tsx +436 -0
  198. package/src/components/table/index.tsx +2 -2
  199. package/src/components/timeline/index.tsx +335 -39
  200. package/src/components/toggle-button/index.tsx +1 -1
  201. package/src/components/tree/index.tsx +17 -12
  202. package/src/hooks/use-keyboard-avoidance.ts +7 -2
  203. package/src/index.ts +15 -0
  204. package/src/primitives/focus-restoration-store.ts +70 -0
  205. package/src/primitives/portal.tsx +34 -2
  206. package/src/utils/chart.ts +66 -7
package/src/index.ts CHANGED
@@ -416,6 +416,14 @@ export {
416
416
  type ChipVariant,
417
417
  type ChipSize,
418
418
  } from './components/chip';
419
+ export {
420
+ Collapsible,
421
+ type CollapsibleProps,
422
+ type CollapsibleTriggerProps,
423
+ type CollapsibleIndicatorProps,
424
+ type CollapsibleContentProps,
425
+ type CollapsibleVariant,
426
+ } from './components/collapsible';
419
427
  export {
420
428
  ColorPicker,
421
429
  type ColorPickerProps,
@@ -514,6 +522,7 @@ export {
514
522
  type NumberInputProps,
515
523
  } from './components/number-input';
516
524
  export { OtpInput, type OtpInputProps } from './components/otp-input';
525
+ export { SearchBar, type SearchBarProps } from './components/search-bar';
517
526
  export {
518
527
  Panelside,
519
528
  usePanelside,
@@ -728,6 +737,11 @@ export {
728
737
  type MarkerIconProps,
729
738
  type MarkerContentProps,
730
739
  } from './components/marker';
740
+ export {
741
+ Marquee,
742
+ type MarqueeProps,
743
+ type MarqueeDirection,
744
+ } from './components/marquee';
731
745
  export {
732
746
  Menu,
733
747
  type MenuProps,
@@ -1055,6 +1069,7 @@ export {
1055
1069
  type TimelineStatProps,
1056
1070
  type TimelineVariant,
1057
1071
  type TimelineTone,
1072
+ type TimelineOrientation,
1058
1073
  } from './components/timeline';
1059
1074
  export {
1060
1075
  Toast,
@@ -0,0 +1,70 @@
1
+ interface FocusDocument {
2
+ activeElement?: FocusTarget | null;
3
+ body?: FocusTarget | null;
4
+ documentElement?: FocusTarget | null;
5
+ }
6
+
7
+ interface FocusTarget {
8
+ disabled?: boolean;
9
+ isConnected?: boolean;
10
+ focus: (options?: { preventScroll?: boolean }) => void;
11
+ getAttribute?: (name: string) => string | null;
12
+ }
13
+
14
+ type RestoreFocus = () => boolean;
15
+
16
+ interface FocusOwner {
17
+ owner: string;
18
+ released: boolean;
19
+ restore: RestoreFocus;
20
+ }
21
+
22
+ /** Restores nested overlays in last-opened order, even when parents close first. */
23
+ export class FocusRestorationStore {
24
+ private owners: FocusOwner[] = [];
25
+
26
+ acquire(owner: string, restore: RestoreFocus): (() => void) {
27
+ const entry = { owner, released: false, restore };
28
+ this.owners.push(entry);
29
+
30
+ return () => {
31
+ if (entry.released) return;
32
+ entry.released = true;
33
+ this.restoreReleasedOwners();
34
+ };
35
+ }
36
+
37
+ private restoreReleasedOwners() {
38
+ const candidates: RestoreFocus[] = [];
39
+ while (this.owners.at(-1)?.released) {
40
+ const entry = this.owners.pop();
41
+ if (entry) candidates.push(entry.restore);
42
+ }
43
+ candidates.some((restore) => restore());
44
+ }
45
+ }
46
+
47
+ /** Captures the current browser focus without evaluating DOM APIs on native. */
48
+ export function captureFocusRestore(
49
+ document = (globalThis as { document?: FocusDocument }).document
50
+ ): RestoreFocus {
51
+ const target = document?.activeElement;
52
+ if (!target || target === document?.body || target === document?.documentElement) {
53
+ return () => false;
54
+ }
55
+
56
+ return () => {
57
+ if (target.isConnected === false || target.disabled) return false;
58
+ if (target.getAttribute?.('aria-disabled') === 'true') return false;
59
+ try {
60
+ target.focus({ preventScroll: true });
61
+ } catch {
62
+ try {
63
+ target.focus();
64
+ } catch {
65
+ return false;
66
+ }
67
+ }
68
+ return document?.activeElement === target;
69
+ };
70
+ }
@@ -8,6 +8,7 @@ import {
8
8
  type ReactNode,
9
9
  } from 'react';
10
10
  import { ModalIsolationStore } from './modal-isolation-store';
11
+ import { captureFocusRestore, FocusRestorationStore } from './focus-restoration-store';
11
12
 
12
13
  type PortalMap = ReadonlyMap<string, ReactNode>;
13
14
 
@@ -41,16 +42,21 @@ class PortalStore {
41
42
 
42
43
  const PortalContext = createContext<PortalStore | null>(null);
43
44
  const ModalIsolationContext = createContext<ModalIsolationStore | null>(null);
45
+ const FocusRestorationContext = createContext<FocusRestorationStore | null>(null);
44
46
 
45
47
  export function PortalProvider({ children }: { children: ReactNode }) {
46
48
  const portalStoreRef = useRef<PortalStore | null>(null);
47
49
  const modalStoreRef = useRef<ModalIsolationStore | null>(null);
50
+ const focusStoreRef = useRef<FocusRestorationStore | null>(null);
48
51
  portalStoreRef.current ??= new PortalStore();
49
52
  modalStoreRef.current ??= new ModalIsolationStore();
53
+ focusStoreRef.current ??= new FocusRestorationStore();
50
54
  return (
51
55
  <PortalContext.Provider value={portalStoreRef.current}>
52
56
  <ModalIsolationContext.Provider value={modalStoreRef.current}>
53
- {children}
57
+ <FocusRestorationContext.Provider value={focusStoreRef.current}>
58
+ {children}
59
+ </FocusRestorationContext.Provider>
54
60
  </ModalIsolationContext.Provider>
55
61
  </PortalContext.Provider>
56
62
  );
@@ -80,9 +86,27 @@ export function Portal({ children }: { children: ReactNode }) {
80
86
  /** A portal that owns modal focus until it unmounts. */
81
87
  export function ModalPortal({ children }: { children: ReactNode }) {
82
88
  const store = useModalIsolationStore('ModalPortal');
89
+ const focusStore = useFocusRestorationStore('ModalPortal');
83
90
  const owner = useId();
84
91
 
85
- useEffect(() => store.acquire(owner), [owner, store]);
92
+ useEffect(() => {
93
+ const releaseIsolation = store.acquire(owner);
94
+ const releaseFocus = focusStore.acquire(owner, captureFocusRestore());
95
+ return () => {
96
+ releaseIsolation();
97
+ releaseFocus();
98
+ };
99
+ }, [focusStore, owner, store]);
100
+
101
+ return <Portal>{children}</Portal>;
102
+ }
103
+
104
+ /** A non-isolating portal that returns browser focus to what opened it. */
105
+ export function FocusRestorePortal({ children }: { children: ReactNode }) {
106
+ const store = useFocusRestorationStore('FocusRestorePortal');
107
+ const owner = useId();
108
+
109
+ useEffect(() => store.acquire(owner, captureFocusRestore()), [owner, store]);
86
110
 
87
111
  return <Portal>{children}</Portal>;
88
112
  }
@@ -101,6 +125,14 @@ function useModalIsolationStore(component: string): ModalIsolationStore {
101
125
  return store;
102
126
  }
103
127
 
128
+ function useFocusRestorationStore(component: string): FocusRestorationStore {
129
+ const store = useContext(FocusRestorationContext);
130
+ if (!store) {
131
+ throw new Error(`${component} must be used within a <PanelUIProvider>`);
132
+ }
133
+ return store;
134
+ }
135
+
104
136
  /** Mount point for portaled content. PanelUIProvider renders one automatically. */
105
137
  export function PortalHost() {
106
138
  const store = usePortalStore('PortalHost');
@@ -264,6 +264,50 @@ export function yOf(value: number, plot: Plot, min: number, max: number): number
264
264
  return plot.top + plot.height - ((value - min) / span) * plot.height;
265
265
  }
266
266
 
267
+ /**
268
+ * Widens a domain out to round numbers.
269
+ *
270
+ * An axis derived from the data ends wherever the data happened to end, so it
271
+ * gets labelled 34,650 — a number that is true and that nobody was looking for.
272
+ * Rounding the ends out to a step of 1, 2 or 5 times a power of ten gives the
273
+ * axis labels somebody can actually read a value off, and it can only ever add
274
+ * room, never crop.
275
+ *
276
+ * Zero survives: any step divides it, so a baseline pinned there stays there.
277
+ */
278
+ export function niceDomain(
279
+ min: number,
280
+ max: number,
281
+ ticks = 5
282
+ ): [number, number] {
283
+ if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) {
284
+ return [min, max];
285
+ }
286
+
287
+ const rough = (max - min) / Math.max(1, ticks);
288
+ const magnitude = 10 ** Math.floor(Math.log10(rough));
289
+ const error = rough / magnitude;
290
+
291
+ /*
292
+ * 1, 2, 5 or 10 times the magnitude — the steps a reader can divide in their
293
+ * head. The thresholds are geometric means rather than the steps themselves,
294
+ * so each candidate wins over the span it is genuinely closest to. Rounding at
295
+ * the steps instead pushes anything above 5 up to a full decade, which turns a
296
+ * top of 31,500 into an axis ending at 40,000 and hands a quarter of the plot
297
+ * to empty space.
298
+ */
299
+ const step =
300
+ (error >= Math.sqrt(50)
301
+ ? 10
302
+ : error >= Math.sqrt(10)
303
+ ? 5
304
+ : error >= Math.sqrt(2)
305
+ ? 2
306
+ : 1) * magnitude;
307
+
308
+ return [Math.floor(min / step) * step, Math.ceil(max / step) * step];
309
+ }
310
+
267
311
  /**
268
312
  * A value's x on a *measured* axis, with `min` at the left edge and `max` at
269
313
  * the right.
@@ -356,7 +400,16 @@ export function runsOf(
356
400
  min: number,
357
401
  max: number,
358
402
  /** Baselines to stack each point on top of, for a stacked area. */
359
- baselines?: number[]
403
+ baselines?: number[],
404
+ /**
405
+ * Place points at band centres rather than spreading them edge to edge.
406
+ *
407
+ * A line drawn over columns has to agree with them about where a row sits,
408
+ * and a column owns a slice of the axis rather than a position on it. Spread
409
+ * evenly, the first point lands half a slice left of the bar it describes and
410
+ * every point after it is wrong by the same amount.
411
+ */
412
+ banded?: boolean
360
413
  ): ChartPoint[][] {
361
414
  'worklet';
362
415
  const runs: ChartPoint[][] = [];
@@ -370,7 +423,8 @@ export function runsOf(
370
423
  continue;
371
424
  }
372
425
  const stacked = value + (baselines?.[i] ?? 0);
373
- run.push({ x: xOf(i, values.length, plot), y: yOf(stacked, plot, min, max) });
426
+ const x = banded ? bandOf(i, values.length, plot) : xOf(i, values.length, plot);
427
+ run.push({ x, y: yOf(stacked, plot, min, max) });
374
428
  }
375
429
  if (run.length) runs.push(run);
376
430
  return runs;
@@ -404,7 +458,9 @@ export function linePath(
404
458
  max: number,
405
459
  curve: ChartCurve,
406
460
  loading: boolean,
407
- baselines?: number[]
461
+ baselines?: number[],
462
+ /** Place points at band centres, for a line drawn over columns. */
463
+ banded?: boolean
408
464
  ): string {
409
465
  'worklet';
410
466
  if (loading || plot.width <= 0) {
@@ -413,7 +469,7 @@ export function linePath(
413
469
  const y = plot.top + plot.height / 2;
414
470
  return `M${plot.left},${y} L${plot.left + plot.width},${y}`;
415
471
  }
416
- return runsOf(values, plot, min, max, baselines)
472
+ return runsOf(values, plot, min, max, baselines, banded)
417
473
  .map((run) => segment(run, curve))
418
474
  .join(' ');
419
475
  }
@@ -433,13 +489,15 @@ export function areaPath(
433
489
  max: number,
434
490
  curve: ChartCurve,
435
491
  loading: boolean,
436
- baselines?: number[]
492
+ baselines?: number[],
493
+ /** Place points at band centres, for an area drawn against columns. */
494
+ banded?: boolean
437
495
  ): string {
438
496
  'worklet';
439
497
  if (loading || plot.width <= 0) return '';
440
498
 
441
499
  const bottom = plot.top + plot.height;
442
- const runs = runsOf(values, plot, min, max, baselines);
500
+ const runs = runsOf(values, plot, min, max, baselines, banded);
443
501
 
444
502
  if (!baselines) {
445
503
  return runs
@@ -460,7 +518,8 @@ export function areaPath(
460
518
  plot,
461
519
  min,
462
520
  max,
463
- baselines
521
+ baselines,
522
+ banded
464
523
  );
465
524
 
466
525
  return runs