@dschz/solid-uplot 0.4.0 → 0.5.1

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/README.md CHANGED
@@ -33,6 +33,30 @@ yarn install solid-js uplot @dschz/solid-uplot
33
33
  bun install solid-js uplot @dschz/solid-uplot
34
34
  ```
35
35
 
36
+ ## 🎮 Live Demo
37
+
38
+ This repo ships with a **live, running playground** — a full showcase of every feature in the library. It's the fastest way to see `solid-uplot` in action and explore real, working examples of charts, plugins, responsive sizing, and external integrations.
39
+
40
+ ### Running the Playground
41
+
42
+ ```bash
43
+ git clone https://github.com/dsnchz/solid-uplot.git
44
+ cd solid-uplot
45
+
46
+ # Install dependencies
47
+ bun install
48
+
49
+ # Start the playground
50
+ bun start
51
+ ```
52
+
53
+ The playground runs at `http://localhost:3000` and includes interactive demos for:
54
+
55
+ - All built-in plugins (cursor, tooltip, legend, focus series)
56
+ - Responsive and auto-resize chart patterns
57
+ - Custom plugin development
58
+ - External component integration via the plugin bus
59
+
36
60
  ## 📁 Package Structure
37
61
 
38
62
  This package provides three main export paths for different functionality:
@@ -187,6 +211,29 @@ import { AutoSizer } from "@dschz/solid-auto-sizer";
187
211
  </AutoSizer>;
188
212
  ```
189
213
 
214
+ Alternatively, you can use [`createElementSize`](https://github.com/solidjs-community/solid-primitives/tree/main/packages/resize-observer) from `@solid-primitives/resize-observer` for a signal-based approach:
215
+
216
+ ```bash
217
+ npm install @solid-primitives/resize-observer
218
+ ```
219
+
220
+ ```tsx
221
+ import { createElementSize } from "@solid-primitives/resize-observer";
222
+
223
+ const ResponsiveChart = () => {
224
+ let container!: HTMLDivElement;
225
+ const size = createElementSize(() => container);
226
+
227
+ return (
228
+ <div style={{ width: "100%", height: "400px" }}>
229
+ <div ref={container} style={{ width: "100%", height: "100%" }}>
230
+ <SolidUplot data={data} width={size.width ?? 0} height={size.height ?? 0} series={series} />
231
+ </div>
232
+ </div>
233
+ );
234
+ };
235
+ ```
236
+
190
237
  ## 🔌 Enhanced Plugin System
191
238
 
192
239
  The cornerstone feature of `SolidUplot` is its refined plugin system that enables extensible functionality and inter-plugin communication through a reactive message bus.
@@ -721,55 +768,6 @@ const Dashboard = () => {
721
768
  };
722
769
  ```
723
770
 
724
- ## 🎮 Interactive Playground
725
-
726
- This library includes a comprehensive playground application that demonstrates all features and provides interactive examples. The playground showcases:
727
-
728
- - **Basic Charts**: Simple line charts with different configurations
729
- - **Plugin Examples**: All built-in plugins working together
730
- - **Legend Showcase**: Various legend patterns and interactions
731
- - **Responsive Sizing**: Auto-resize and manual sizing examples
732
- - **Custom Plugins**: Examples of creating your own plugins
733
- - **External Integration**: Charts interacting with external components
734
-
735
- ### Running the Playground Locally
736
-
737
- To explore the playground and see the library in action:
738
-
739
- ```bash
740
- # Clone the repository
741
- git clone https://github.com/dsnchz/solid-uplot.git
742
- cd solid-uplot
743
-
744
- # Install dependencies
745
- npm install
746
- # or
747
- pnpm install
748
- # or
749
- yarn install
750
- # or
751
- bun install
752
-
753
- # Start the playground development server
754
- npm run start
755
- # or
756
- pnpm start
757
- # or
758
- yarn start
759
- # or
760
- bun start
761
- ```
762
-
763
- The playground will be available at `http://localhost:3000` and includes:
764
-
765
- - **Live code examples** with syntax highlighting
766
- - **Interactive demos** you can modify in real-time
767
- - **Performance comparisons** between different configurations
768
- - **Best practices** and common patterns
769
- - **Plugin development examples** with step-by-step guides
770
-
771
- The playground source code also serves as a comprehensive reference for implementing various chart patterns and plugin combinations.
772
-
773
771
  ## 🤝 Contributing
774
772
 
775
773
  Contributions are welcome! Please feel free to submit a Pull Request.
@@ -1,7 +1,6 @@
1
1
  import { V as VoidStruct, S as SolidUplotPluginBus, U as UplotPluginFactory } from '../createPluginBus-DdrjQANs.js';
2
2
  export { a as UplotPluginFactoryContext, c as createPluginBus } from '../createPluginBus-DdrjQANs.js';
3
- import { Ref } from '@solid-primitives/refs';
4
- import { ParentProps, JSX } from 'solid-js';
3
+ import { ParentProps, JSX, Ref } from 'solid-js';
5
4
  import uPlot$1 from 'uplot';
6
5
  import { C as CursorData, S as SeriesDatum } from '../getSeriesData-04wGQord.js';
7
6
  import 'solid-js/store';
@@ -31,9 +30,25 @@ type SolidUplotPlugin<T extends VoidStruct = VoidStruct> = uPlot$1.Plugin | Uplo
31
30
  * @template T - The type of the plugin bus data structure
32
31
  */
33
32
  type SolidUplotOptions<T extends VoidStruct = VoidStruct> = Omit<uPlot$1.Options, "plugins" | "width" | "height" | "data"> & {
34
- /** Chart width in pixels */
33
+ /**
34
+ * Chart width in pixels.
35
+ *
36
+ * Used as a fixed dimension when `autoResize` is disabled.
37
+ * Ignored when `autoResize` is enabled — the chart fills its
38
+ * container's width automatically.
39
+ *
40
+ * @default 600
41
+ */
35
42
  readonly width?: number;
36
- /** Chart height in pixels */
43
+ /**
44
+ * Chart height in pixels.
45
+ *
46
+ * Used as a fixed dimension when `autoResize` is disabled.
47
+ * Ignored when `autoResize` is enabled — the chart fills its
48
+ * container's height automatically.
49
+ *
50
+ * @default 300
51
+ */
37
52
  readonly height?: number;
38
53
  /** Chart data - accepts AlignedData or number[][] */
39
54
  readonly data?: uPlot$1.AlignedData | number[][];
@@ -73,10 +88,13 @@ type SolidUplotProps<T extends VoidStruct = VoidStruct> = SolidUplotOptions<T> &
73
88
  /**
74
89
  * Enable automatic resizing to fit container.
75
90
  *
76
- * When true:
77
- * - Chart uses width/height props for initial render
78
- * - Then automatically adapts to container size changes
79
- * - If no width/height provided, uses sensible defaults (600x300)
91
+ * When enabled, the chart uses a ResizeObserver to continuously
92
+ * match its container's dimensions. The `width` and `height` props
93
+ * are ignored the chart fills whatever space its container provides.
94
+ *
95
+ * The container **must** have defined dimensions (explicit height/width,
96
+ * flex layout, grid layout, etc.). If the container has no height, the
97
+ * chart will render at 0px and a development-mode warning will be logged.
80
98
  *
81
99
  * @default false
82
100
  */
@@ -109,16 +127,22 @@ type SolidUplotProps<T extends VoidStruct = VoidStruct> = SolidUplotOptions<T> &
109
127
  *
110
128
  * @example
111
129
  * ```tsx
130
+ * // Fixed size
112
131
  * <SolidUplot
113
132
  * data={chartData}
133
+ * width={600}
114
134
  * height={400}
115
- * autoResize
116
- * series={[
117
- * {},
118
- * { label: "Series 1", stroke: "red" }
119
- * ]}
120
- * onCreate={(chart) => console.log("Chart created:", chart)}
135
+ * series={[{}, { label: "Series 1", stroke: "red" }]}
121
136
  * />
137
+ *
138
+ * // Auto resize (container must have dimensions)
139
+ * <div style={{ height: "400px" }}>
140
+ * <SolidUplot
141
+ * data={chartData}
142
+ * autoResize
143
+ * series={[{}, { label: "Series 1", stroke: "red" }]}
144
+ * />
145
+ * </div>
122
146
  * ```
123
147
  */
124
148
  declare const SolidUplot: <T extends VoidStruct = VoidStruct>(props: ParentProps<SolidUplotProps<T>>) => JSX.Element;
@@ -1,9 +1,8 @@
1
1
  import '../chunk/IV6D7K4M.js';
2
2
  import { getSeriesData, getCursorData } from '../chunk/QELYARMN.js';
3
3
  import { createStore } from 'solid-js/store';
4
- import { template, use, insert, effect, className, style } from 'solid-js/web';
4
+ import { use, insert, effect, className, style, template } from 'solid-js/web';
5
5
  import 'uplot/dist/uPlot.min.css';
6
- import { mergeRefs } from '@solid-primitives/refs';
7
6
  import { mergeProps, createUniqueId, splitProps, createMemo, createEffect, untrack, onCleanup } from 'solid-js';
8
7
  import uPlot from 'uplot';
9
8
 
@@ -26,7 +25,7 @@ var createCursorMovePlugin = (onCursorMove) => {
26
25
  };
27
26
 
28
27
  // src/SolidUplot.tsx
29
- var _tmpl$ = /* @__PURE__ */ template(`<div id=solid-uplot-root>`);
28
+ var _tmpl$ = /* @__PURE__ */ template(`<div id=solid-uplot-root style=display:flex><div class=solid-uplot-chart style=position:relative>`);
30
29
  var SolidUplot = (props) => {
31
30
  let container;
32
31
  const _props = mergeProps({
@@ -111,29 +110,42 @@ var SolidUplot = (props) => {
111
110
  });
112
111
  const classes = () => local.class ? `solid-uplot ${local.class}` : "solid-uplot";
113
112
  return (() => {
114
- var _el$ = _tmpl$();
115
- var _ref$ = mergeRefs(local.ref, (el) => container = el);
116
- typeof _ref$ === "function" && use(_ref$, _el$);
117
- insert(_el$, () => local.children);
113
+ var _el$ = _tmpl$(), _el$2 = _el$.firstChild;
114
+ var _ref$ = local.ref;
115
+ typeof _ref$ === "function" ? use(_ref$, _el$) : local.ref = _el$;
116
+ insert(_el$, () => local.children, _el$2);
117
+ var _ref$2 = container;
118
+ typeof _ref$2 === "function" ? use(_ref$2, _el$2) : container = _el$2;
118
119
  effect((_p$) => {
119
120
  var _v$ = classes(), _v$2 = {
120
- display: "flex",
121
121
  "flex-direction": local.childrenPlacement === "top" ? "column" : "column-reverse",
122
122
  // When autoResize is enabled, fill the parent container
123
123
  ...local.autoResize && {
124
124
  width: "100%",
125
125
  height: "100%",
126
- "min-width": "0",
127
- "min-height": "0"
126
+ "min-width": "0"
128
127
  },
129
128
  ...local.style
129
+ }, _v$3 = {
130
+ // When autoResize is enabled, use flex to fill remaining space.
131
+ // flex-basis: 0 prevents content from dictating size (fixes infinite height bug).
132
+ // min-width/min-height: 0 allow the chart to shrink freely within
133
+ // the flex container. The parent must provide dimensions — if it
134
+ // doesn't, the chart collapses to 0px (with a dev-mode warning).
135
+ ...local.autoResize && {
136
+ flex: "1 1 0",
137
+ "min-height": "0",
138
+ "min-width": "0"
139
+ }
130
140
  };
131
141
  _v$ !== _p$.e && className(_el$, _p$.e = _v$);
132
142
  _p$.t = style(_el$, _v$2, _p$.t);
143
+ _p$.a = style(_el$2, _v$3, _p$.a);
133
144
  return _p$;
134
145
  }, {
135
146
  e: void 0,
136
- t: void 0
147
+ t: void 0,
148
+ a: void 0
137
149
  });
138
150
  return _el$;
139
151
  })();
@@ -1,6 +1,6 @@
1
1
  import { getCursorData, getSeriesData } from '../chunk/QELYARMN.js';
2
2
  import { createRoot, createEffect, mergeProps, splitProps, Show } from 'solid-js';
3
- import { render, createComponent, template, use, insert, effect, setAttribute, className, style } from 'solid-js/web';
3
+ import { render, createComponent, use, insert, effect, setAttribute, className, style, template } from 'solid-js/web';
4
4
 
5
5
  // src/plugins/cursor.ts
6
6
  var cursor = () => {
@@ -65,7 +65,7 @@ var seriesFocusRedraw = (u, options = {}) => {
65
65
  const target = focusTargets.find((t) => {
66
66
  if ("label" in t) return t.label === s.label;
67
67
  if ("zeroIndex" in t) return t.zeroIndex === i - 1;
68
- if ("index" in t) return t.index === i;
68
+ return "index" in t && t.index === i;
69
69
  });
70
70
  s.alpha = target ? focusedAlpha : unfocusedAlpha;
71
71
  }
@@ -230,14 +230,14 @@ var legend = (Component, options = {}) => {
230
230
  };
231
231
  };
232
232
  };
233
- var _tmpl$2 = /* @__PURE__ */ template(`<div role=tooltip aria-label="Chart tooltip">`);
233
+ var _tmpl$2 = /* @__PURE__ */ template(`<div role=tooltip aria-label="Chart tooltip"style=pointer-events:none>`);
234
234
  var TOOLTIP_OFFSET_X = 8;
235
235
  var TOOLTIP_OFFSET_Y = 8;
236
- var getTooltipPosition = (placement, left, top, tooltipWidth, tooltipHeight, isFixed = false) => {
236
+ var getTooltipPosition = (placement, left, top, tooltipWidth, tooltipHeight, rootOffset) => {
237
237
  const baseX = placement.includes("left") ? left - tooltipWidth - TOOLTIP_OFFSET_X : left + TOOLTIP_OFFSET_X;
238
238
  const baseY = placement.includes("top") ? top - tooltipHeight - TOOLTIP_OFFSET_Y : top + TOOLTIP_OFFSET_Y;
239
- const viewportX = isFixed ? baseX : baseX - window.scrollX;
240
- const viewportY = isFixed ? baseY : baseY - window.scrollY;
239
+ const viewportX = baseX + rootOffset.left;
240
+ const viewportY = baseY + rootOffset.top;
241
241
  const overflowsLeft = viewportX < 0;
242
242
  const overflowsRight = viewportX + tooltipWidth > window.innerWidth;
243
243
  const overflowsTop = viewportY < 0;
@@ -287,13 +287,21 @@ var tooltip = (Component, options = {}) => {
287
287
  children: (cursor2) => {
288
288
  const position = () => {
289
289
  const overRect = u.over.getBoundingClientRect();
290
+ const rootRect = u.root.getBoundingClientRect();
290
291
  const tooltipWidth = tooltipRoot.offsetWidth ?? 0;
291
292
  const tooltipHeight = tooltipRoot.offsetHeight ?? 0;
292
- const cursorLeft = overRect.left + cursor2().position.left;
293
- const cursorTop = overRect.top + cursor2().position.top;
294
- const absoluteLeft = tooltipOptions.fixed ? cursorLeft : cursorLeft + window.scrollX;
295
- const absoluteTop = tooltipOptions.fixed ? cursorTop : cursorTop + window.scrollY;
296
- const calculatedPosition = getTooltipPosition(tooltipOptions.placement, absoluteLeft, absoluteTop, tooltipWidth, tooltipHeight, tooltipOptions.fixed);
293
+ const cursorViewportLeft = overRect.left + cursor2().position.left;
294
+ const cursorViewportTop = overRect.top + cursor2().position.top;
295
+ const positionedLeft = tooltipOptions.fixed ? cursorViewportLeft : cursorViewportLeft - rootRect.left;
296
+ const positionedTop = tooltipOptions.fixed ? cursorViewportTop : cursorViewportTop - rootRect.top;
297
+ const rootOffset = tooltipOptions.fixed ? {
298
+ left: 0,
299
+ top: 0
300
+ } : {
301
+ left: rootRect.left,
302
+ top: rootRect.top
303
+ };
304
+ const calculatedPosition = getTooltipPosition(tooltipOptions.placement, positionedLeft, positionedTop, tooltipWidth, tooltipHeight, rootOffset);
297
305
  return tooltipOptions.onPositionCalculated ? tooltipOptions.onPositionCalculated(calculatedPosition, tooltipOptions.placement) : calculatedPosition;
298
306
  };
299
307
  return (() => {
@@ -314,7 +322,6 @@ var tooltip = (Component, options = {}) => {
314
322
  var _v$ = containerProps.id, _v$2 = containerProps.class, _v$3 = {
315
323
  position: tooltipOptions.fixed ? "fixed" : "absolute",
316
324
  "z-index": containerProps.zIndex,
317
- "pointer-events": "none",
318
325
  left: `${position().left}px`,
319
326
  top: `${position().top}px`,
320
327
  ...containerProps.style
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dschz/solid-uplot",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "SolidJS wrapper for uPlot — ultra-fast, tiny time-series & charting library",
5
5
  "type": "module",
6
6
  "author": "Daniel Sanchez <dsanc89@pm.me>",
@@ -42,7 +42,8 @@
42
42
  "homepage": "https://github.com/dsnchz/solid-uplot#readme",
43
43
  "repository": {
44
44
  "type": "git",
45
- "url": "https://github.com/dsnchz/solid-uplot.git"
45
+ "url": "https://github.com/dsnchz/solid-uplot.git",
46
+ "directory": "packages/solid-uplot"
46
47
  },
47
48
  "bugs": {
48
49
  "url": "https://github.com/dsnchz/solid-uplot/issues"
@@ -90,61 +91,32 @@
90
91
  "scripts": {
91
92
  "build": "tsup",
92
93
  "build:watch": "tsup --watch",
93
- "dev": "vite",
94
- "format": "prettier . --check",
95
- "format:fix": "prettier . --write",
96
- "lint": "eslint .",
97
- "lint:fix": "eslint . --fix",
98
- "pkg:changeset": "changeset",
99
- "pkg:version": "changeset version",
100
- "pkg:publish": "bun run build && changeset publish",
101
- "serve": "vite preview",
102
- "start": "vite",
103
94
  "test": "vitest run",
104
95
  "test:cov": "vitest run --coverage",
105
96
  "typecheck": "tsc --noEmit"
106
97
  },
98
+ "peerDependencies": {
99
+ "solid-js": ">=1.6.0",
100
+ "uplot": ">=1.6.32"
101
+ },
107
102
  "devDependencies": {
108
- "@changesets/cli": "^2.29.7",
109
- "@dschz/solid-auto-sizer": "^0.1.3",
110
- "@solidjs/router": "^0.15.4",
103
+ "@dschz/tsconfig": "workspace:*",
111
104
  "@solidjs/testing-library": "^0.8.10",
112
- "@tailwindcss/vite": "^4.1.17",
113
105
  "@testing-library/jest-dom": "^6.9.1",
114
106
  "@testing-library/user-event": "^14.6.1",
115
107
  "@types/bun": "^1.3.3",
116
- "@types/prismjs": "^1.26.5",
117
- "@typescript-eslint/eslint-plugin": "^8.47.0",
118
- "@typescript-eslint/parser": "^8.47.0",
119
108
  "@vitest/coverage-istanbul": "^4.0.13",
120
109
  "@wessberg/pointer-events": "^1.0.9",
121
110
  "canvas": "^3.2.0",
122
- "eslint": "^9.39.1",
123
- "eslint-plugin-simple-import-sort": "^12.1.1",
124
- "eslint-plugin-solid": "^0.14.5",
125
- "globals": "^16.5.0",
126
- "jiti": "^2.6.1",
127
111
  "jsdom": "^27.2.0",
128
112
  "path2d": "^0.3.1",
129
- "prettier": "^3.6.2",
130
- "prismjs": "^1.30.0",
131
113
  "solid-js": "^1.9.10",
132
- "solid-prism-editor": "^2.1.0",
133
- "tailwindcss": "^4.1.17",
134
114
  "tsup": "^8.5.1",
135
115
  "tsup-preset-solid": "^2.2.0",
136
116
  "typescript": "^5.9.3",
137
- "typescript-eslint": "^8.47.0",
138
117
  "uplot": "^1.6.32",
139
118
  "vite": "^7.2.4",
140
119
  "vite-plugin-solid": "^2.11.10",
141
120
  "vitest": "^4.0.13"
142
- },
143
- "peerDependencies": {
144
- "solid-js": ">=1.6.0",
145
- "uplot": ">=1.6.32"
146
- },
147
- "dependencies": {
148
- "@solid-primitives/refs": "^1.1.2"
149
121
  }
150
122
  }