zds-pickers 4.1.8 → 4.2.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.
@@ -1,6 +1,35 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  const MEASUREMENT_ELEMENT_ID = '__react_svg_text_measurement_id';
4
+ /**
5
+ * The only computed properties that affect measured text geometry. Copying
6
+ * the full computed style (~300 properties) onto the measurement node per
7
+ * instance forced a style flush that dominated initial render in hosts
8
+ * with many SvgText instances.
9
+ */
10
+ const FONT_PROPERTIES = [
11
+ 'font-family',
12
+ 'font-feature-settings',
13
+ 'font-kerning',
14
+ 'font-size',
15
+ 'font-stretch',
16
+ 'font-style',
17
+ 'font-variant',
18
+ 'font-weight',
19
+ 'letter-spacing',
20
+ 'text-transform',
21
+ 'word-spacing',
22
+ ];
23
+ const fontSignature = (style) => FONT_PROPERTIES.map(key => style.getPropertyValue(key)).join('|');
24
+ /**
25
+ * Word widths only depend on the word and the font it renders in, so they
26
+ * are cached module-wide by font signature. Text that repeats across
27
+ * instances (labels, numbers) measures once per font, ever.
28
+ */
29
+ const fontMetricsCache = new Map();
30
+ const __resetFontMetricsCacheForTests = () => {
31
+ fontMetricsCache.clear();
32
+ };
4
33
  const calculateWordsByLines = (text, wordWidths, maxWidth, maxHeight) => {
5
34
  const { lineHeight, spaceWidth, wordsWithComputedWidth } = wordWidths;
6
35
  return text.split(/\s+/).reduce((result, word) => {
@@ -27,19 +56,39 @@ const calculateWordsByLines = (text, wordWidths, maxWidth, maxHeight) => {
27
56
  };
28
57
  const calculateWordWidths = (style, textNode, text) => {
29
58
  if (style && textNode) {
30
- // biome-ignore lint/complexity/noForEach: <explanation>
31
- Array.from(style).forEach(key => textNode.style.setProperty(key, style.getPropertyValue(key), style.getPropertyPriority(key)));
59
+ const signature = fontSignature(style);
60
+ let metrics = fontMetricsCache.get(signature);
32
61
  const wordArray = [...new Set(String(text).split(/\s+/))];
33
- const wordsWithComputedWidth = wordArray.reduce((wordMap, word) => {
34
- textNode.textContent = word;
35
- // biome-ignore lint/performance/noAccumulatingSpread: <explanation>
36
- return { ...wordMap, [word]: textNode.getBBox().width };
37
- }, {});
38
- textNode.textContent = '\u00A0';
39
- const spaceWidth = textNode?.getComputedTextLength?.() || 8;
40
- const lineHeight = textNode.getBBox().height;
41
- textNode.setAttribute('style', '');
42
- return { wordsWithComputedWidth, spaceWidth, lineHeight };
62
+ const knownWidths = metrics?.widths;
63
+ const missingWords = knownWidths
64
+ ? wordArray.filter(word => !knownWidths.has(word))
65
+ : wordArray;
66
+ if (!metrics || missingWords.length) {
67
+ for (const key of FONT_PROPERTIES) {
68
+ textNode.style.setProperty(key, style.getPropertyValue(key), style.getPropertyPriority(key));
69
+ }
70
+ if (!metrics) {
71
+ textNode.textContent = '\u00A0';
72
+ const spaceWidth = textNode?.getComputedTextLength?.() || 8;
73
+ const lineHeight = textNode.getBBox().height;
74
+ metrics = { widths: new Map(), spaceWidth, lineHeight };
75
+ fontMetricsCache.set(signature, metrics);
76
+ }
77
+ for (const word of missingWords) {
78
+ textNode.textContent = word;
79
+ metrics.widths.set(word, textNode.getBBox().width);
80
+ }
81
+ textNode.setAttribute('style', '');
82
+ }
83
+ const wordsWithComputedWidth = {};
84
+ for (const word of wordArray) {
85
+ wordsWithComputedWidth[word] = metrics.widths.get(word) ?? 0;
86
+ }
87
+ return {
88
+ wordsWithComputedWidth,
89
+ spaceWidth: metrics.spaceWidth,
90
+ lineHeight: metrics.lineHeight,
91
+ };
43
92
  }
44
93
  return undefined;
45
94
  };
@@ -67,14 +116,28 @@ const SvgText = (props) => {
67
116
  if (el === null) {
68
117
  const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
69
118
  svg.setAttribute('id', MEASUREMENT_ELEMENT_ID);
119
+ svg.setAttribute('aria-hidden', 'true');
120
+ // Rendered but invisible: getBBox returns zeros under display:none,
121
+ // so park it offscreen instead. Being outside any host SVG also
122
+ // keeps per-word getBBox from forcing layout of live content.
123
+ svg.style.position = 'fixed';
124
+ svg.style.left = '-9999px';
125
+ svg.style.top = '0';
126
+ const textEl = document.createElementNS('http://www.w3.org/2000/svg', 'text');
127
+ svg.appendChild(textEl);
70
128
  document.body.appendChild(svg);
71
- svg.appendChild(document.createElementNS('http://www.w3.org/2000/svg', 'text'));
72
- measureRef.current = svg;
73
- return () => {
74
- document.body.removeChild(svg);
75
- };
129
+ // Measure against the <text> child — pointing at the <svg> container
130
+ // made every measurement return the svg's own box.
131
+ measureRef.current = textEl;
132
+ // Deliberately no cleanup: the element is a shared singleton and
133
+ // other mounted instances may still hold it as their measure target.
134
+ return;
76
135
  }
77
- measureRef.current = el;
136
+ // Hosts may provide either the <text> itself or a container around one.
137
+ measureRef.current =
138
+ el.tagName.toLowerCase() === 'text'
139
+ ? el
140
+ : (el.querySelector('text') ?? el);
78
141
  }, []);
79
142
  useEffect(() => {
80
143
  const wordWithWidths = calculateWordWidths(style, measureRef.current, text);
@@ -105,4 +168,4 @@ const SvgText = (props) => {
105
168
  // textAnchor={textAnchor}
106
169
  transform: transform, ...rest, children: _jsxs(_Fragment, { children: [displayedLines.map((line, idx) => (_jsx("tspan", { dx: x + dx, dy: idx === 0 ? startDy + dy : wordWidths?.lineHeight || 0, x: 0, children: line.words.join(' ') }, idx))), textLines.length && displayedLines.length !== textLines.length && (_jsxs(_Fragment, { children: [_jsx("tspan", { children: "..." }), _jsx("title", { children: text })] }))] }) }));
107
170
  };
108
- export { SvgText, MEASUREMENT_ELEMENT_ID };
171
+ export { __resetFontMetricsCacheForTests, calculateWordsByLines, calculateWordWidths, MEASUREMENT_ELEMENT_ID, SvgText, };
@@ -5,7 +5,7 @@ import { RotaryKnob } from '../rotaryKnob';
5
5
  import { assertRange } from '../utils';
6
6
  import { knobSkin10 } from './knobSkin10';
7
7
  const Knob = (props) => {
8
- const { disabled = false, max = 127, min = 0, onChange, value: initialValue = 0, wheelEnabled = false, wheelSensitivity = 0.1, ...rest } = props;
8
+ const { centered = false, disabled = false, max = 127, min = 0, onChange, value: initialValue = 0, wheelEnabled = false, wheelSensitivity = 0.1, ...rest } = props;
9
9
  const [value, setValue] = useStateWithDynamicDefault(initialValue);
10
10
  const handleChange = (val) => {
11
11
  if (disabled)
@@ -36,7 +36,7 @@ const Knob = (props) => {
36
36
  onChange,
37
37
  setValue,
38
38
  ]);
39
- return (_jsx(RotaryKnob, { clampMax: 320, clampMin: 40, className: "zds-pickers__knob-container", disabled: disabled, onChange: handleChange, onWheel: wheelEnabled ? handleWheel : undefined, preciseMode: false, rotateDegrees: 180,
39
+ return (_jsx(RotaryKnob, { centered: centered, clampMax: 320, clampMin: 40, className: "zds-pickers__knob-container", disabled: disabled, onChange: handleChange, onWheel: wheelEnabled ? handleWheel : undefined, preciseMode: false, rotateDegrees: 180,
40
40
  /**
41
41
  * To see all skins:
42
42
  * http://react-rotary-knob-skins-preview.surge.sh/
@@ -4,7 +4,7 @@ import { arraySequence } from '../utils';
4
4
  import { Knob } from './Knob';
5
5
  import { Select } from './Select';
6
6
  const KnobPicker = forwardRef((props, ref) => {
7
- const { disabled, highToLow, includeLabel, includePicker, knobProps, label, max = 127, min = 0, onChange, shrinkLabel, value = 0, wheelEnabled, wheelSensitivity = 0.1, ...rest } = props;
7
+ const { centered, disabled, highToLow, includeLabel, includePicker, knobProps, label, max = 127, min = 0, onChange, shrinkLabel, value = 0, wheelEnabled, wheelSensitivity = 0.1, ...rest } = props;
8
8
  const options = useMemo(() => {
9
9
  const result = arraySequence(max - min + 1)
10
10
  .map(i => min + i)
@@ -17,7 +17,8 @@ const KnobPicker = forwardRef((props, ref) => {
17
17
  onChange,
18
18
  options,
19
19
  ref,
20
- value })), _jsx(Knob, { disabled,
20
+ value })), _jsx(Knob, { centered,
21
+ disabled,
21
22
  max,
22
23
  min,
23
24
  onChange,
@@ -1,3 +1,9 @@
1
+ import { buildValueArcPath } from '../rotaryKnob/arcPath';
2
+ /** Value-arc geometry in the skin's fixed group: knob center and a radius in
3
+ * the dark bezel ring between the face plate (r≈86) and outer edge (r≈99). */
4
+ const ARC_CX = 100;
5
+ const ARC_CY = 100;
6
+ const ARC_R = 93;
1
7
  const knobSkin10 = {
2
8
  knobX: 71.44,
3
9
  knobY: 71.44,
@@ -60,13 +66,15 @@ const knobSkin10 = {
60
66
  <path d="M72.4209282,3.63066376 L88.6786876,16.869789 C81.585496,18.1548295 76.1662428,18.7973498 72.4209282,18.7973498 C68.6756135,18.7973498 63.2563604,18.1548295 56.1631688,16.869789 L72.4209282,3.63066376 Z" id="Rectangle" fill="#E6D7D7" transform="translate(72.420928, 11.214007) scale(1, -1) translate(-72.420928, -11.214007) "/>
61
67
  </g>
62
68
 
69
+ <!-- Value arc: anchor->value fill in the bezel ring; path data is
70
+ computed per-render via updateAttributes (see below).
71
+ Consumers can restyle it via the knob-value-arc class. -->
72
+ <path id="valueArc" class="knob-value-arc" d="" stroke="#35619F" stroke-width="7" fill="none" opacity="0.85" stroke-linecap="round" pointer-events="none"/>
73
+
63
74
  <!-- Fixed position marks (outside the rotating knob group) -->
64
75
  <!-- 12:00 position mark (more prominent) -->
65
76
  <line x1="100.0098534" y1="15" x2="100.0098534" y2="35" stroke="#CCCCCC" stroke-width="4" opacity="0.9"/>
66
77
 
67
- <!-- Arc fill between end position marks -->
68
- <!-- <path d="M 35 165 A 65 65 0 0 1 165 165" stroke="#666666" stroke-width="8" fill="none" opacity="0.3"/> -->
69
-
70
78
  <!-- End position marks (0 and 127) -->
71
79
  <!-- 0 position mark (40 degrees from top, clockwise) - at outer radius beyond knob edge -->
72
80
  <!-- This should be at the bottom-left where the value indicator points when at 0 -->
@@ -106,6 +114,26 @@ const knobSkin10 = {
106
114
  },
107
115
  ],
108
116
  },
117
+ {
118
+ element: '#valueArc',
119
+ attrs: [
120
+ {
121
+ name: 'd',
122
+ value: (props, value) => buildValueArcPath({
123
+ value,
124
+ min: props.min ?? 0,
125
+ max: props.max ?? 127,
126
+ centered: props.centered ?? false,
127
+ cx: ARC_CX,
128
+ cy: ARC_CY,
129
+ r: ARC_R,
130
+ clampMin: props.clampMin ?? 40,
131
+ clampMax: props.clampMax ?? 320,
132
+ rotateDegrees: props.rotateDegrees ?? 180,
133
+ }),
134
+ },
135
+ ],
136
+ },
109
137
  ],
110
138
  };
111
139
  export { knobSkin10 };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Pure geometry for the knob's value-arc fill.
3
+ *
4
+ * Angle convention matches RotaryKnob's convertValueToAngle: a value maps
5
+ * linearly onto [clampMin, clampMax] sweep degrees, then rotateDegrees is
6
+ * added (mod 360). The resulting angle is measured clockwise from 12 o'clock,
7
+ * because the skin's #knob indicator points up at rotation 0.
8
+ *
9
+ * With Knob's constants (clampMin 40, clampMax 320, rotateDegrees 180):
10
+ * min → 220° (bottom-left), max → 140° (bottom-right), midpoint → 0° (top).
11
+ */
12
+ /** Below this many sweep degrees no arc is drawn (avoids zero-length paths). */
13
+ const MIN_ARC_DEGREES = 0.5;
14
+ const point = (cx, cy, r, clockwiseFromTopDeg) => {
15
+ const rad = (clockwiseFromTopDeg * Math.PI) / 180;
16
+ return [cx + r * Math.sin(rad), cy - r * Math.cos(rad)];
17
+ };
18
+ const fmt = (n) => String(Math.round(n * 1000) / 1000);
19
+ /**
20
+ * SVG path `d` for the arc from the anchor (min, or sweep midpoint when
21
+ * centered) to the current value. Empty string when there is nothing to draw.
22
+ */
23
+ const buildValueArcPath = ({ value, min, max, centered = false, cx = 100, cy = 100, r = 93, clampMin = 40, clampMax = 320, rotateDegrees = 180, }) => {
24
+ if (max === min)
25
+ return '';
26
+ const ratio = Math.min(1, Math.max(0, (value - min) / (max - min)));
27
+ const sweepValue = clampMin + ratio * (clampMax - clampMin);
28
+ const sweepAnchor = centered ? (clampMin + clampMax) / 2 : clampMin;
29
+ const delta = sweepValue - sweepAnchor;
30
+ if (Math.abs(delta) < MIN_ARC_DEGREES)
31
+ return '';
32
+ const angleOf = (sweep) => (((sweep + rotateDegrees) % 360) + 360) % 360;
33
+ const [x1, y1] = point(cx, cy, r, angleOf(sweepAnchor));
34
+ const [x2, y2] = point(cx, cy, r, angleOf(sweepValue));
35
+ const largeArc = Math.abs(delta) > 180 ? 1 : 0;
36
+ const sweepFlag = delta > 0 ? 1 : 0;
37
+ return `M ${fmt(x1)} ${fmt(y1)} A ${fmt(r)} ${fmt(r)} 0 ${largeArc} ${sweepFlag} ${fmt(x2)} ${fmt(y2)}`;
38
+ };
39
+ export { buildValueArcPath };
@@ -25,7 +25,10 @@ import { getAngleForPoint } from './utils';
25
25
  * Generic knob component
26
26
  */
27
27
  const RotaryKnob = (props) => {
28
- const { clampMax = 360, clampMin = 0, defaultValue = 0, disabled = false, format = (val) => val.toFixed(0), max = 100, min = 0, onChange = () => { }, onEnd = () => { }, onStart = () => { }, preciseMode = true, rotateDegrees = 0, skin = defaultSkin, step = 1, style, unlockDistance = 100, value, ...rest } = props;
28
+ const {
29
+ // Consumed by skins via updateAttributes; destructured so it doesn't
30
+ // leak onto the container <div> through ...rest.
31
+ centered: _centered, clampMax = 360, clampMin = 0, defaultValue = 0, disabled = false, format = (val) => val.toFixed(0), max = 100, min = 0, onChange = () => { }, onEnd = () => { }, onStart = () => { }, preciseMode = true, rotateDegrees = 0, skin = defaultSkin, step = 1, style, unlockDistance = 100, value, ...rest } = props;
29
32
  const [isControlled, setIsControlled] = useState(value !== undefined);
30
33
  const container = useRef(null);
31
34
  const inputRef = useRef(null);
@@ -1,14 +1,17 @@
1
1
  declare const MEASUREMENT_ELEMENT_ID = "__react_svg_text_measurement_id";
2
+ declare const __resetFontMetricsCacheForTests: () => void;
2
3
  type WordsByLine = {
3
4
  words: string[];
4
5
  width: number;
5
6
  showLine: boolean;
6
7
  };
8
+ declare const calculateWordsByLines: (text: string, wordWidths: WordWidths, maxWidth: number, maxHeight: number) => WordsByLine[];
7
9
  type WordWidths = {
8
10
  wordsWithComputedWidth: Record<string, number>;
9
11
  spaceWidth: number;
10
12
  lineHeight: number;
11
13
  };
14
+ declare const calculateWordWidths: (style?: CSSStyleDeclaration, textNode?: SVGGraphicsElement | null, text?: string) => WordWidths | undefined;
12
15
  type TextProps = Partial<HTMLOrSVGElement> & {
13
16
  className?: string;
14
17
  dx?: number;
@@ -23,5 +26,5 @@ type TextProps = Partial<HTMLOrSVGElement> & {
23
26
  y?: number;
24
27
  };
25
28
  declare const SvgText: (props: TextProps) => import("react/jsx-runtime").JSX.Element;
26
- export { SvgText, MEASUREMENT_ELEMENT_ID };
29
+ export { __resetFontMetricsCacheForTests, calculateWordsByLines, calculateWordWidths, MEASUREMENT_ELEMENT_ID, SvgText, };
27
30
  export type { TextProps, WordWidths, WordsByLine };
@@ -1,4 +1,6 @@
1
1
  type KnobProps = {
2
+ /** Anchor the value arc at 12 o'clock (bipolar display) instead of min. */
3
+ centered?: boolean;
2
4
  disabled?: boolean;
3
5
  max?: number;
4
6
  min?: number;
@@ -1,10 +1,12 @@
1
1
  import type { GroupBase, SelectInstance } from 'react-select';
2
+ import type { KnobProps } from './Knob';
2
3
  import type { Option, SelectProps } from './Select';
3
4
  type KnobPickerProps = SelectProps<number> & {
5
+ centered?: boolean;
4
6
  highToLow?: boolean;
5
7
  includeLabel?: boolean;
6
8
  includePicker?: boolean;
7
- knobProps?: Partial<KnobPickerProps>;
9
+ knobProps?: Partial<KnobProps>;
8
10
  max?: number;
9
11
  min?: number;
10
12
  wheelEnabled?: boolean;
@@ -39,10 +41,11 @@ declare const KnobPicker: import("react").ForwardRefExoticComponent<Partial<impo
39
41
  shrinkLabel?: boolean;
40
42
  value?: number | undefined;
41
43
  } & {
44
+ centered?: boolean;
42
45
  highToLow?: boolean;
43
46
  includeLabel?: boolean;
44
47
  includePicker?: boolean;
45
- knobProps?: Partial<KnobPickerProps>;
48
+ knobProps?: Partial<KnobProps>;
46
49
  max?: number;
47
50
  min?: number;
48
51
  wheelEnabled?: boolean;
@@ -1,14 +1,22 @@
1
+ import type { RotaryKnobProps } from '../rotaryKnob';
1
2
  declare const knobSkin10: {
2
3
  knobX: number;
3
4
  knobY: number;
4
5
  svg: string;
5
- updateAttributes: {
6
+ updateAttributes: ({
6
7
  element: string;
7
- content: (_props: React.CSSProperties, value: number) => string;
8
+ content: (_props: RotaryKnobProps, value: number) => string;
8
9
  attrs: {
9
10
  name: string;
10
11
  value: () => string;
11
12
  }[];
12
- }[];
13
+ } | {
14
+ element: string;
15
+ attrs: {
16
+ name: string;
17
+ value: (props: RotaryKnobProps, value: number) => string;
18
+ }[];
19
+ content?: undefined;
20
+ })[];
13
21
  };
14
22
  export { knobSkin10 };
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Pure geometry for the knob's value-arc fill.
3
+ *
4
+ * Angle convention matches RotaryKnob's convertValueToAngle: a value maps
5
+ * linearly onto [clampMin, clampMax] sweep degrees, then rotateDegrees is
6
+ * added (mod 360). The resulting angle is measured clockwise from 12 o'clock,
7
+ * because the skin's #knob indicator points up at rotation 0.
8
+ *
9
+ * With Knob's constants (clampMin 40, clampMax 320, rotateDegrees 180):
10
+ * min → 220° (bottom-left), max → 140° (bottom-right), midpoint → 0° (top).
11
+ */
12
+ type ValueArcOptions = {
13
+ value: number;
14
+ min: number;
15
+ max: number;
16
+ /** Anchor the arc at the sweep midpoint (12 o'clock) instead of min. */
17
+ centered?: boolean;
18
+ cx?: number;
19
+ cy?: number;
20
+ r?: number;
21
+ clampMin?: number;
22
+ clampMax?: number;
23
+ rotateDegrees?: number;
24
+ };
25
+ /**
26
+ * SVG path `d` for the arc from the anchor (min, or sweep midpoint when
27
+ * centered) to the current value. Empty string when there is nothing to draw.
28
+ */
29
+ declare const buildValueArcPath: ({ value, min, max, centered, cx, cy, r, clampMin, clampMax, rotateDegrees, }: ValueArcOptions) => string;
30
+ export { buildValueArcPath };
31
+ export type { ValueArcOptions };
@@ -2,28 +2,8 @@
2
2
  * Show the rotation circle and marker
3
3
  * dispatches drag events
4
4
  */
5
- /**
6
- * type definition for the skin system attribute modification element
7
- */
8
- type AttributeSetValue = {
9
- name: string;
10
- value: (props: unknown, value: unknown) => string;
11
- };
12
- /**
13
- * Type definition for the skin element manipulation block
14
- */
15
- interface UpdateElement {
16
- element: string;
17
- content: (_props: React.CSSProperties, value: number) => string;
18
- attrs: AttributeSetValue[];
19
- }
20
- interface Skin {
21
- svg: string;
22
- knobX: number;
23
- knobY: number;
24
- updateAttributes: UpdateElement[];
25
- }
26
5
  type KnobProps = Omit<React.ComponentProps<'div'>, 'onChange'> & {
6
+ centered?: boolean;
27
7
  clampMax?: number;
28
8
  clampMin?: number;
29
9
  defaultValue?: number;
@@ -42,8 +22,32 @@ type KnobProps = Omit<React.ComponentProps<'div'>, 'onChange'> & {
42
22
  unlockDistance?: number;
43
23
  value?: number;
44
24
  };
25
+ /**
26
+ * type definition for the skin system attribute modification element.
27
+ * Skins receive the knob's full props (min/max/centered/clamp*, etc.) plus
28
+ * the current value, so they can derive geometry like the value arc.
29
+ */
30
+ type AttributeSetValue = {
31
+ name: string;
32
+ value: (props: KnobProps, value: number) => string;
33
+ };
34
+ /**
35
+ * Type definition for the skin element manipulation block
36
+ */
37
+ interface UpdateElement {
38
+ element: string;
39
+ content?: (props: KnobProps, value: number) => string;
40
+ attrs: AttributeSetValue[];
41
+ }
42
+ interface Skin {
43
+ svg: string;
44
+ knobX: number;
45
+ knobY: number;
46
+ updateAttributes: UpdateElement[];
47
+ }
45
48
  /**
46
49
  * Generic knob component
47
50
  */
48
51
  declare const RotaryKnob: (props: KnobProps) => import("react/jsx-runtime").JSX.Element;
49
52
  export { RotaryKnob };
53
+ export type { KnobProps as RotaryKnobProps, Skin, UpdateElement };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zds-pickers",
3
- "version": "4.1.8",
3
+ "version": "4.2.1",
4
4
  "main": "./dist/index.cjs.js",
5
5
  "module": "./dist/index.es.js",
6
6
  "types": "./dist/types/index.d.ts",
@@ -21,25 +21,24 @@
21
21
  },
22
22
  "sideEffects": ["lib/soundfonts/*.js", "dist/soundfonts/*.js"],
23
23
  "files": ["dist", "lib/soundfonts"],
24
- "homepage": "https://github.com/dkadrios/zds-pickers#readme",
24
+ "homepage": "https://github.com/nebiru-software/zds-pickers#readme",
25
25
  "license": "MIT",
26
26
  "author": "Darin Kadrioski <dkadrios@gmail.com>",
27
27
  "bugs": {
28
- "url": "https://github.com/dkadrios/zds-pickers/issues"
28
+ "url": "https://github.com/nebiru-software/zds-pickers/issues"
29
29
  },
30
30
  "description": "Picker controls that are common to Zendrum Studio apps",
31
31
  "repository": {
32
32
  "type": "git",
33
- "url": "git+https://github.com/dkadrios/zds-pickers.git"
33
+ "url": "git+https://github.com/nebiru-software/zds-pickers.git"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@biomejs/biome": "1.9.4",
37
- "@storybook/addon-docs": "8.6.18",
38
- "@storybook/addon-essentials": "8.6.18",
39
- "@storybook/addon-links": "8.6.18",
40
- "@storybook/builder-vite": "10.4.6",
41
- "@storybook/react": "8.6.18",
42
- "@storybook/react-vite": "10.4.6",
37
+ "@storybook/addon-docs": "10.5.5",
38
+ "@storybook/addon-links": "10.5.5",
39
+ "@storybook/builder-vite": "10.5.5",
40
+ "@storybook/react": "10.5.5",
41
+ "@storybook/react-vite": "10.5.5",
43
42
  "@types/d3-drag": "3.0.7",
44
43
  "@types/d3-scale": "4.0.9",
45
44
  "@types/d3-selection": "3.0.11",
@@ -49,19 +48,19 @@
49
48
  "classnames": "2.5.1",
50
49
  "globals": "15.15.0",
51
50
  "immer": "10.1.1",
52
- "nodemon": "3.1.9",
51
+ "nodemon": "3.1.14",
53
52
  "prop-types": "15.8.1",
54
53
  "rc-slider": "11.1.8",
55
54
  "react": "18.3.1",
56
55
  "react-dom": "18.3.1",
57
56
  "react-select": "5.10.1",
58
- "storybook": "8.6.18",
57
+ "storybook": "10.5.5",
59
58
  "typescript": "5.8.2",
60
59
  "vite": "^8.0.16",
60
+ "vitest": "4.1.10",
61
61
  "zds-mappings": "1.4.9"
62
62
  },
63
63
  "dependencies": {
64
- "caniuse-lite": "1.0.30001741",
65
64
  "d3-drag": "3.0.0",
66
65
  "d3-scale": "4.0.2",
67
66
  "d3-selection": "3.0.0",
@@ -75,7 +74,7 @@
75
74
  "react": ">=18.0.0",
76
75
  "react-dom": ">=18.0.0",
77
76
  "react-select": ">=5.10.0",
78
- "zds-mappings": "1.4.9"
77
+ "zds-mappings": "^1.4.9"
79
78
  },
80
79
  "scripts": {
81
80
  "dev": "vite",
@@ -85,6 +84,11 @@
85
84
  "preview": "vite preview",
86
85
  "sb": "storybook dev --quiet -p 6006 --no-open",
87
86
  "sb:watch": "nodemon --watch .storybook -e ts,tsx,js,jsx --exec 'npm run sb'",
88
- "prepublishOnly": "npm run build"
87
+ "prepublishOnly": "npm run build",
88
+ "lint:ci": "biome check",
89
+ "test": "vitest run"
90
+ },
91
+ "engines": {
92
+ "node": ">=22"
89
93
  }
90
94
  }