@dschz/solid-uplot 0.3.0 → 0.5.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.
@@ -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
  })();
@@ -384,6 +384,30 @@ type TooltipConfigOptions = {
384
384
  * @default false
385
385
  */
386
386
  readonly fixed?: boolean;
387
+ /**
388
+ * Optional callback to process or modify the calculated tooltip position.
389
+ * Receives the calculated position and placement preference, and should return a position object with the same structure.
390
+ * Use this to implement custom positioning logic or constraints.
391
+ *
392
+ * @param position - The calculated position with left and top coordinates
393
+ * @param placement - The placement preference that was used for calculation
394
+ * @returns Modified position object with left and top coordinates
395
+ *
396
+ * @example
397
+ * ```ts
398
+ * onPositionCalculated: (position, placement) => ({
399
+ * left: Math.max(0, position.left), // Prevent negative positioning
400
+ * top: placement.includes('top') ? position.top - 5 : position.top + 10
401
+ * })
402
+ * ```
403
+ */
404
+ readonly onPositionCalculated?: (position: {
405
+ left: number;
406
+ top: number;
407
+ }, placement: TooltipCursorPlacement) => {
408
+ left: number;
409
+ top: number;
410
+ };
387
411
  };
388
412
  /**
389
413
  * Combined options for the tooltip plugin including container props and behavior config.
@@ -400,6 +424,7 @@ type TooltipPluginOptions = TooltipRootProps & TooltipConfigOptions;
400
424
  * - Automatic positioning with edge detection and flipping
401
425
  * - Scroll-aware positioning that works with page scrolling
402
426
  * - Configurable placement preferences
427
+ * - Position callback for custom positioning logic or overrides
403
428
  * - Accessible tooltip with proper ARIA attributes
404
429
  * - Automatic cleanup and memory management
405
430
  *
@@ -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;
@@ -279,7 +279,7 @@ var tooltip = (Component, options = {}) => {
279
279
  zIndex: 20
280
280
  }, options);
281
281
  const chartCursorData = () => bus.data.cursor?.state[u.root.id];
282
- const [tooltipOptions, containerProps] = splitProps(_options, ["placement", "fixed"]);
282
+ const [tooltipOptions, containerProps] = splitProps(_options, ["placement", "fixed", "onPositionCalculated"]);
283
283
  return createComponent(Show, {
284
284
  get when() {
285
285
  return chartCursorData();
@@ -287,13 +287,22 @@ 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
- return 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);
305
+ return tooltipOptions.onPositionCalculated ? tooltipOptions.onPositionCalculated(calculatedPosition, tooltipOptions.placement) : calculatedPosition;
297
306
  };
298
307
  return (() => {
299
308
  var _el$ = _tmpl$2();
@@ -313,7 +322,6 @@ var tooltip = (Component, options = {}) => {
313
322
  var _v$ = containerProps.id, _v$2 = containerProps.class, _v$3 = {
314
323
  position: tooltipOptions.fixed ? "fixed" : "absolute",
315
324
  "z-index": containerProps.zIndex,
316
- "pointer-events": "none",
317
325
  left: `${position().left}px`,
318
326
  top: `${position().top}px`,
319
327
  ...containerProps.style
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dschz/solid-uplot",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
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
  }