@dschz/solid-uplot 0.1.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.
@@ -0,0 +1,15 @@
1
+ // src/utils/getCursorData.ts
2
+ var getCursorData = (u) => {
3
+ const idx = u.cursor.idx;
4
+ const xValues = u.data[0];
5
+ const isValid = idx != null && xValues && idx < xValues.length;
6
+ return !isValid ? void 0 : {
7
+ plotId: u.root.id,
8
+ idx,
9
+ xValue: xValues[idx],
10
+ visible: Boolean(u.cursor.show),
11
+ position: { left: u.cursor.left || 0, top: u.cursor.top || 0 }
12
+ };
13
+ };
14
+
15
+ export { getCursorData };
@@ -0,0 +1,27 @@
1
+ // src/utils/getSeriesData.ts
2
+ var getSeriesData = (u, options = {}) => {
3
+ const series = [];
4
+ for (let i = 1; i < u.series.length; i++) {
5
+ const s = u.series[i];
6
+ const stroke = typeof s.stroke === "function" ? s.stroke(u, i) : s.stroke;
7
+ const fill = typeof s.fill === "function" ? s.fill(u, i) : s.fill;
8
+ const label = options.labelTransform?.(s.label) || s.label?.toString() || `Series ${i}`;
9
+ series.push({
10
+ idx: i - 1,
11
+ seriesIdx: i,
12
+ label,
13
+ stroke: stroke ?? "#000",
14
+ fill: fill ?? "transparent",
15
+ width: s.width,
16
+ dash: s.dash,
17
+ scale: s.scale,
18
+ visible: Boolean(s.show)
19
+ });
20
+ }
21
+ return series;
22
+ };
23
+
24
+ export {
25
+ getSeriesData
26
+ };
27
+ // istanbul ignore next -- @preserve
@@ -0,0 +1,25 @@
1
+ // src/utils/getSeriesData.ts
2
+ var getSeriesData = (u, options = {}) => {
3
+ const series = [];
4
+ for (let i = 1; i < u.series.length; i++) {
5
+ const s = u.series[i];
6
+ const stroke = typeof s.stroke === "function" ? s.stroke(u, i) : s.stroke;
7
+ const fill = typeof s.fill === "function" ? s.fill(u, i) : s.fill;
8
+ const label = options.labelTransform?.(s.label) || s.label?.toString() || `Series ${i}`;
9
+ series.push({
10
+ idx: i - 1,
11
+ seriesIdx: i,
12
+ label,
13
+ stroke: stroke ?? "#000",
14
+ fill: fill ?? "transparent",
15
+ width: s.width,
16
+ dash: s.dash,
17
+ scale: s.scale,
18
+ visible: Boolean(s.show)
19
+ });
20
+ }
21
+ return series;
22
+ };
23
+ // istanbul ignore next -- @preserve
24
+
25
+ export { getSeriesData };
@@ -0,0 +1,21 @@
1
+ import { Store, SetStoreFunction } from 'solid-js/store';
2
+
3
+ type VoidStruct = Record<string, unknown>;
4
+ type PluginStore<T> = {
5
+ readonly data: Store<T>;
6
+ readonly setData: SetStoreFunction<T>;
7
+ };
8
+ /**
9
+ * Represents a reactive store shared across SolidUplot plugins.
10
+ *
11
+ * This store acts as a message bus, allowing plugins to publish and
12
+ * subscribe to typed messages based on agreed-upon keys (e.g., `tooltip`, `highlight`).
13
+ */
14
+ declare const createPluginBus: <T extends VoidStruct = VoidStruct>(initialData?: T) => PluginStore<T>;
15
+ type SolidUplotPluginBus<T extends VoidStruct = VoidStruct> = ReturnType<typeof createPluginBus<T>>;
16
+ type PluginFactoryContext<T extends VoidStruct = VoidStruct> = {
17
+ readonly bus?: SolidUplotPluginBus<T>;
18
+ };
19
+ type PluginFactory<T extends VoidStruct = VoidStruct> = (ctx: PluginFactoryContext<T>) => uPlot.Plugin;
20
+
21
+ export { type PluginFactory as P, type SolidUplotPluginBus as S, type VoidStruct as V, createPluginBus as c };
@@ -0,0 +1,44 @@
1
+ type CursorPosition = {
2
+ /**
3
+ * The cursor position left offset in CSS pixels (relative to plotting area)
4
+ */
5
+ readonly left: number;
6
+ /**
7
+ * The cursor position top offset in CSS pixels (relative to plotting area)
8
+ */
9
+ readonly top: number;
10
+ };
11
+ /**
12
+ * The cursor index data for a given uPlot instance.
13
+ */
14
+ type CursorData = {
15
+ /**
16
+ * The id of the plot instance that the cursor message originates from.
17
+ */
18
+ readonly plotId: string;
19
+ /**
20
+ * The closest x-axis data index to cursor (closestIdx)
21
+ */
22
+ readonly idx: number;
23
+ /**
24
+ * The x-axis value of the cursor idx.
25
+ */
26
+ readonly xValue: number;
27
+ /**
28
+ * The position of the cursor.
29
+ */
30
+ readonly position: CursorPosition;
31
+ /**
32
+ * The visibility of the cursor.
33
+ */
34
+ readonly visible: boolean;
35
+ };
36
+ /**
37
+ * Get the cursor index data for a given uPlot instance.
38
+ *
39
+ * @param u - The uPlot instance.
40
+ * @returns The cursor data.
41
+ */
42
+ declare const getCursorData: (u: uPlot) => CursorData | undefined;
43
+
44
+ export { type CursorData as C, getCursorData as g };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Summary data for a given series.
3
+ */
4
+ type SeriesDatum = {
5
+ /** The index of the series if you were treating this as a zero-indexed array */
6
+ readonly idx: number;
7
+ /** The index of the series in the uPlot instance */
8
+ readonly seriesIdx: number;
9
+ /** The display label of the series */
10
+ readonly label: string;
11
+ /** The series stroke color */
12
+ readonly stroke: string | CanvasGradient | CanvasPattern;
13
+ /** The fill color */
14
+ readonly fill: string | CanvasGradient | CanvasPattern;
15
+ /** The stroke width of the series line */
16
+ readonly width?: number;
17
+ /** The dash pattern used for the line */
18
+ readonly dash?: number[];
19
+ /** The name of the associated scale (e.g. "y", "y2") */
20
+ readonly scale?: string;
21
+ /** Whether the series is shown */
22
+ readonly visible?: boolean;
23
+ };
24
+ type GetSeriesDataOptions = {
25
+ /** The function to transform the series label */
26
+ readonly labelTransform?: (label?: string | HTMLElement) => string;
27
+ };
28
+ /**
29
+ * Get the y-series data for a given uPlot instance.
30
+ *
31
+ * @param u - The uPlot instance.
32
+ * @param options - The options for the series data.
33
+ * @returns The series data.
34
+ */
35
+ declare const getSeriesData: (u: uPlot, options?: GetSeriesDataOptions) => SeriesDatum[];
36
+
37
+ export { type SeriesDatum as S, getSeriesData as g };
@@ -0,0 +1,44 @@
1
+ import { V as VoidStruct, S as SolidUplotPluginBus, P as PluginFactory } from '../createPluginBus-B_Gp5BCB.js';
2
+ export { c as createPluginBus } from '../createPluginBus-B_Gp5BCB.js';
3
+ import { ParentProps, JSX } from 'solid-js';
4
+ import uPlot from 'uplot';
5
+ import { S as SeriesDatum } from '../getSeriesData-D1zBqQ9Y.js';
6
+ import 'solid-js/store';
7
+
8
+ type ChildrenPlacement = "top" | "bottom";
9
+ type SolidUplotPlugin<T extends VoidStruct = VoidStruct> = uPlot.Plugin | PluginFactory<T>;
10
+ type SolidUplotOptions<T extends VoidStruct = VoidStruct> = Omit<uPlot.Options, "plugins" | "width" | "height"> & {
11
+ readonly width?: number;
12
+ readonly height?: number;
13
+ readonly pluginBus?: SolidUplotPluginBus<T>;
14
+ readonly plugins?: SolidUplotPlugin<T>[];
15
+ };
16
+ type OnCreateMeta = {
17
+ readonly seriesData: SeriesDatum[];
18
+ };
19
+ type SolidUplotProps<T extends VoidStruct = VoidStruct> = SolidUplotOptions<T> & {
20
+ /** The ref of the uPlot instance */
21
+ readonly ref?: (el: HTMLDivElement) => void;
22
+ /** Callback when uPlot instance is created */
23
+ readonly onCreate?: (u: uPlot, meta: OnCreateMeta) => void;
24
+ /** Apply scale reset on redraw triggered by updated plot data (default: `true`) */
25
+ readonly resetScales?: boolean;
26
+ /** The style of the uPlot instance container */
27
+ readonly style?: Omit<JSX.CSSProperties, "position">;
28
+ /** The placement of the children container. Defaults to "top" */
29
+ readonly childrenPlacement?: ChildrenPlacement;
30
+ /**
31
+ * Enable automatic resizing to fit container.
32
+ *
33
+ * When true:
34
+ * - Chart uses width/height props for initial render
35
+ * - Then automatically adapts to container size changes
36
+ * - If no width/height provided, uses sensible defaults (600x300)
37
+ *
38
+ * @default false
39
+ */
40
+ readonly autoResize?: boolean;
41
+ };
42
+ declare const SolidUplot: <T extends VoidStruct = VoidStruct>(props: ParentProps<SolidUplotProps<T>>) => JSX.Element;
43
+
44
+ export { SolidUplot, SolidUplotPluginBus, VoidStruct };
@@ -0,0 +1,117 @@
1
+ import { getSeriesData } from '../chunk/ZISGD6FJ.js';
2
+ import { createStore } from 'solid-js/store';
3
+ import { template, use, insert, effect, style } from 'solid-js/web';
4
+ import 'uplot/dist/uPlot.min.css';
5
+ import { mergeProps, createUniqueId, splitProps, createMemo, createEffect, untrack, onCleanup } from 'solid-js';
6
+ import uPlot from 'uplot';
7
+
8
+ var createPluginBus = (initialData = {}) => {
9
+ const [data, setData] = createStore(initialData);
10
+ return {
11
+ data,
12
+ setData
13
+ };
14
+ };
15
+ var _tmpl$ = /* @__PURE__ */ template(`<div id=solid-uplot-root>`);
16
+ var SolidUplot = (props) => {
17
+ let container;
18
+ const _props = mergeProps({
19
+ id: createUniqueId(),
20
+ childrenPlacement: "top",
21
+ width: 600,
22
+ height: 300,
23
+ autoResize: false,
24
+ data: [],
25
+ resetScales: true,
26
+ plugins: [],
27
+ legend: {
28
+ show: false
29
+ }
30
+ }, props);
31
+ const [local, options] = splitProps(_props, ["children", "childrenPlacement", "autoResize", "onCreate", "style", "ref"]);
32
+ const [updateableOptions, newChartOptions] = splitProps(options, ["data", "width", "height", "resetScales"]);
33
+ const [system, chartOptions] = splitProps(newChartOptions, ["pluginBus", "plugins"]);
34
+ const size = () => ({
35
+ width: updateableOptions.width,
36
+ height: updateableOptions.height
37
+ });
38
+ const chartPlugins = createMemo(() => {
39
+ return system.plugins.map((plugin) => typeof plugin === "function" ? plugin({
40
+ bus: system.pluginBus
41
+ }) : plugin);
42
+ });
43
+ createEffect(() => {
44
+ const getInitialSize = () => {
45
+ if (local.autoResize) {
46
+ const rect = container.getBoundingClientRect();
47
+ return {
48
+ width: rect.width > 0 ? Math.floor(rect.width) : 600,
49
+ height: rect.height > 0 ? Math.floor(rect.height) : 300
50
+ };
51
+ }
52
+ return untrack(size);
53
+ };
54
+ const initialSize = getInitialSize();
55
+ const initialData = untrack(() => updateableOptions.data);
56
+ const chart = new uPlot({
57
+ ...chartOptions,
58
+ ...initialSize,
59
+ plugins: chartPlugins()
60
+ }, initialData, container);
61
+ local.onCreate?.(chart, {
62
+ seriesData: getSeriesData(chart)
63
+ });
64
+ createEffect(() => {
65
+ if (local.autoResize) return;
66
+ chart.setSize(size());
67
+ });
68
+ createEffect(() => {
69
+ if (!local.autoResize) return;
70
+ const resizeObserver = new ResizeObserver((entries) => {
71
+ for (const entry of entries) {
72
+ const {
73
+ width,
74
+ height
75
+ } = entry.contentRect;
76
+ chart.setSize({
77
+ width: Math.floor(width),
78
+ height: Math.floor(height)
79
+ });
80
+ }
81
+ });
82
+ resizeObserver.observe(container);
83
+ onCleanup(() => {
84
+ resizeObserver.disconnect();
85
+ });
86
+ });
87
+ createEffect(() => {
88
+ chart.setData(updateableOptions.data, updateableOptions.resetScales);
89
+ });
90
+ onCleanup(() => {
91
+ chart.destroy();
92
+ });
93
+ });
94
+ return (() => {
95
+ var _el$ = _tmpl$();
96
+ use((el) => {
97
+ container = el;
98
+ local.ref?.(el);
99
+ }, _el$);
100
+ insert(_el$, () => local.children);
101
+ effect((_$p) => style(_el$, {
102
+ display: "flex",
103
+ "flex-direction": local.childrenPlacement === "top" ? "column" : "column-reverse",
104
+ // When autoResize is enabled, fill the parent container
105
+ ...local.autoResize && {
106
+ width: "100%",
107
+ height: "100%",
108
+ "min-width": "0",
109
+ "min-height": "0"
110
+ },
111
+ ...local.style
112
+ }, _$p));
113
+ return _el$;
114
+ })();
115
+ };
116
+
117
+ export { SolidUplot, createPluginBus };
@@ -0,0 +1,135 @@
1
+ import {
2
+ getSeriesData
3
+ } from "../chunk/A3AZKFSW.jsx";
4
+
5
+ // src/createPluginBus.tsx
6
+ import { createStore } from "solid-js/store";
7
+ var createPluginBus = (initialData = {}) => {
8
+ const [data, setData] = createStore(initialData);
9
+ return { data, setData };
10
+ };
11
+
12
+ // src/SolidUplot.tsx
13
+ import "uplot/dist/uPlot.min.css";
14
+ import {
15
+ createEffect,
16
+ createMemo,
17
+ createUniqueId,
18
+ mergeProps,
19
+ onCleanup,
20
+ splitProps,
21
+ untrack
22
+ } from "solid-js";
23
+ import uPlot from "uplot";
24
+ var SolidUplot = (props) => {
25
+ let container;
26
+ const _props = mergeProps(
27
+ {
28
+ id: createUniqueId(),
29
+ childrenPlacement: "top",
30
+ width: 600,
31
+ height: 300,
32
+ autoResize: false,
33
+ data: [],
34
+ resetScales: true,
35
+ plugins: [],
36
+ legend: {
37
+ show: false
38
+ }
39
+ },
40
+ props
41
+ );
42
+ const [local, options] = splitProps(_props, [
43
+ "children",
44
+ "childrenPlacement",
45
+ "autoResize",
46
+ "onCreate",
47
+ "style",
48
+ "ref"
49
+ ]);
50
+ const [updateableOptions, newChartOptions] = splitProps(options, [
51
+ "data",
52
+ "width",
53
+ "height",
54
+ "resetScales"
55
+ ]);
56
+ const [system, chartOptions] = splitProps(newChartOptions, ["pluginBus", "plugins"]);
57
+ const size = () => ({ width: updateableOptions.width, height: updateableOptions.height });
58
+ const chartPlugins = createMemo(() => {
59
+ return system.plugins.map(
60
+ (plugin) => typeof plugin === "function" ? plugin({ bus: system.pluginBus }) : plugin
61
+ );
62
+ });
63
+ createEffect(() => {
64
+ const getInitialSize = () => {
65
+ if (local.autoResize) {
66
+ const rect = container.getBoundingClientRect();
67
+ return {
68
+ width: rect.width > 0 ? Math.floor(rect.width) : 600,
69
+ height: rect.height > 0 ? Math.floor(rect.height) : 300
70
+ };
71
+ }
72
+ return untrack(size);
73
+ };
74
+ const initialSize = getInitialSize();
75
+ const initialData = untrack(() => updateableOptions.data);
76
+ const chart = new uPlot(
77
+ {
78
+ ...chartOptions,
79
+ ...initialSize,
80
+ plugins: chartPlugins()
81
+ },
82
+ initialData,
83
+ container
84
+ );
85
+ local.onCreate?.(chart, { seriesData: getSeriesData(chart) });
86
+ createEffect(() => {
87
+ if (local.autoResize) return;
88
+ chart.setSize(size());
89
+ });
90
+ createEffect(() => {
91
+ if (!local.autoResize) return;
92
+ const resizeObserver = new ResizeObserver((entries) => {
93
+ for (const entry of entries) {
94
+ const { width, height } = entry.contentRect;
95
+ chart.setSize({ width: Math.floor(width), height: Math.floor(height) });
96
+ }
97
+ });
98
+ resizeObserver.observe(container);
99
+ onCleanup(() => {
100
+ resizeObserver.disconnect();
101
+ });
102
+ });
103
+ createEffect(() => {
104
+ chart.setData(updateableOptions.data, updateableOptions.resetScales);
105
+ });
106
+ onCleanup(() => {
107
+ chart.destroy();
108
+ });
109
+ });
110
+ return <div
111
+ id="solid-uplot-root"
112
+ style={{
113
+ display: "flex",
114
+ "flex-direction": local.childrenPlacement === "top" ? "column" : "column-reverse",
115
+ // When autoResize is enabled, fill the parent container
116
+ ...local.autoResize && {
117
+ width: "100%",
118
+ height: "100%",
119
+ "min-width": "0",
120
+ "min-height": "0"
121
+ },
122
+ ...local.style
123
+ }}
124
+ ref={(el) => {
125
+ container = el;
126
+ local.ref?.(el);
127
+ }}
128
+ >
129
+ {local.children}
130
+ </div>;
131
+ };
132
+ export {
133
+ SolidUplot,
134
+ createPluginBus
135
+ };