@choice-ui/react 1.8.9 → 1.9.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.
Files changed (26) hide show
  1. package/dist/components/colors/dist/index.d.ts +39 -6
  2. package/dist/components/colors/src/color-gradients-paint/color-gradient-combined.js +1 -4
  3. package/dist/components/colors/src/color-gradients-paint/color-gradient-slider.d.ts +4 -4
  4. package/dist/components/colors/src/color-gradients-paint/color-gradient-slider.js +9 -8
  5. package/dist/components/colors/src/color-slider/color-slider.d.ts +14 -6
  6. package/dist/components/colors/src/color-slider/color-slider.js +124 -46
  7. package/dist/components/colors/src/color-slider/components/index.d.ts +2 -0
  8. package/dist/components/colors/src/color-slider/components/thumb.d.ts +8 -0
  9. package/dist/components/colors/src/color-slider/components/thumb.js +49 -0
  10. package/dist/components/colors/src/color-slider/components/track.d.ts +18 -0
  11. package/dist/components/colors/src/color-slider/components/track.js +19 -0
  12. package/dist/components/colors/src/color-slider/context.d.ts +23 -0
  13. package/dist/components/colors/src/color-slider/context.js +13 -0
  14. package/dist/components/colors/src/color-slider/index.d.ts +2 -0
  15. package/dist/components/colors/src/color-slider/tv.d.ts +3 -0
  16. package/dist/components/colors/src/color-slider/tv.js +2 -1
  17. package/dist/components/colors/src/color-solid-paint/color-solid-paint.js +4 -7
  18. package/dist/components/colors/src/color-solid-paint/solid-paint-alpha-slider.js +2 -2
  19. package/dist/components/colors/src/color-solid-paint/solid-paint-hue-slider.js +2 -2
  20. package/dist/components/colors/src/simple-color-picker/simple-color-picker.js +4 -7
  21. package/dist/components/dropdown/dist/index.js +8 -2
  22. package/dist/components/dropdown/src/dropdown.js +8 -2
  23. package/dist/components/menus/dist/index.js +14 -2
  24. package/dist/components/menus/src/context/menu-context-sub-trigger.js +6 -1
  25. package/dist/components/menus/src/hooks/use-menu-tree.js +8 -1
  26. package/package.json +1 -1
@@ -452,8 +452,37 @@ interface ColorAreaProps {
452
452
  }
453
453
  declare const ColorArea: react.MemoExoticComponent<react.ForwardRefExoticComponent<ColorAreaProps & react.RefAttributes<HTMLDivElement>>>;
454
454
 
455
+ interface ColorSliderThumbProps {
456
+ className?: string;
457
+ size?: number;
458
+ }
459
+ declare function ColorSliderThumb(props: ColorSliderThumbProps): react_jsx_runtime.JSX.Element;
460
+ declare namespace ColorSliderThumb {
461
+ var displayName: string;
462
+ }
463
+
464
+ interface ColorSliderTrackProps {
465
+ className?: string;
466
+ children?: React.ReactNode;
467
+ /**
468
+ * Height of the track in pixels.
469
+ * This prop is extracted by the parent ColorSlider and passed via context.
470
+ */
471
+ height?: number;
472
+ }
473
+ /**
474
+ * ColorSliderTrack - The track background of the color slider.
475
+ * Renders the gradient background based on slider type (hue, alpha, etc.)
476
+ * Can contain custom children for additional visual elements.
477
+ */
478
+ declare function ColorSliderTrack(props: ColorSliderTrackProps): react_jsx_runtime.JSX.Element;
479
+ declare namespace ColorSliderTrack {
480
+ var displayName: string;
481
+ }
482
+
455
483
  interface ColorSliderProps {
456
484
  backgroundStyle?: CSSProperties;
485
+ children?: React.ReactNode;
457
486
  className?: string;
458
487
  disabled?: boolean;
459
488
  hue?: number;
@@ -461,14 +490,18 @@ interface ColorSliderProps {
461
490
  onChangeEnd?: () => void;
462
491
  onChangeStart?: () => void;
463
492
  position: number;
464
- thumbSize?: number;
465
- trackSize?: {
466
- height?: number;
467
- width?: number;
468
- };
469
493
  type: PickerSliderType;
494
+ /**
495
+ * Width of the slider track in pixels.
496
+ * If not provided (undefined or false), the width will be auto-calculated from the container.
497
+ */
498
+ width?: number | boolean;
499
+ }
500
+ interface ColorSliderComponent extends React.MemoExoticComponent<React.ForwardRefExoticComponent<ColorSliderProps & React.RefAttributes<HTMLDivElement>>> {
501
+ Thumb: typeof ColorSliderThumb;
502
+ Track: typeof ColorSliderTrack;
470
503
  }
471
- declare const ColorSlider: react.MemoExoticComponent<react.ForwardRefExoticComponent<ColorSliderProps & react.RefAttributes<HTMLDivElement>>>;
504
+ declare const ColorSlider: ColorSliderComponent;
472
505
 
473
506
  interface ColorSwatchProps extends Omit<HTMLProps<HTMLDivElement>, "color"> {
474
507
  alpha?: number;
@@ -24,10 +24,7 @@ const ColorGradientCombined = (props) => {
24
24
  onChangeEnd,
25
25
  controlledSelectedStopId: selectedStopId,
26
26
  onSelectedStopIdChange,
27
- trackSize: {
28
- width: containerWidth - 32,
29
- height: 16
30
- },
27
+ width: containerWidth - 32,
31
28
  className: "min-w-0 px-4 pb-4"
32
29
  }
33
30
  ),
@@ -8,10 +8,10 @@ interface ColorGradientSliderProps {
8
8
  onChangeStart?: () => void;
9
9
  onSelectedStopIdChange?: (id: string) => void;
10
10
  stopSize?: number;
11
- trackSize?: {
12
- height?: number;
13
- width?: number;
14
- };
11
+ /**
12
+ * Width of the gradient slider track in pixels.
13
+ */
14
+ width?: number;
15
15
  value?: GradientPaint["gradientStops"];
16
16
  }
17
17
  export declare const ColorGradientSlider: import('react').ForwardRefExoticComponent<ColorGradientSliderProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -18,10 +18,11 @@ const ColorGradientSlider = forwardRef(
18
18
  controlledSelectedStopId,
19
19
  onSelectedStopIdChange,
20
20
  disabled = false,
21
- trackSize = { width: 224, height: 16 },
21
+ width: trackWidth = 224,
22
22
  stopSize = 18,
23
23
  className
24
24
  } = props;
25
+ const trackHeight = 16;
25
26
  const { colorProfile } = useColors();
26
27
  const sliderRef = useRef(null);
27
28
  const stopsContainerRef = useRef(null);
@@ -182,15 +183,15 @@ const ColorGradientSlider = forwardRef(
182
183
  });
183
184
  const trackStyle = useMemo(() => {
184
185
  return {
185
- width: trackSize == null ? void 0 : trackSize.width,
186
- height: trackSize == null ? void 0 : trackSize.height,
186
+ width: trackWidth,
187
+ height: trackHeight,
187
188
  boxShadow: "inset 0 0 0 1px rgba(0,0,0,0.1)",
188
189
  background: gradientBackground
189
190
  };
190
- }, [gradientBackground, trackSize]);
191
+ }, [gradientBackground, trackWidth, trackHeight]);
191
192
  const stopStyle = useCallback(
192
193
  (stop) => {
193
- const position = stop.position * ((trackSize == null ? void 0 : trackSize.width) ?? 0);
194
+ const position = stop.position * trackWidth;
194
195
  return {
195
196
  width: stopSize,
196
197
  height: stopSize,
@@ -198,12 +199,12 @@ const ColorGradientSlider = forwardRef(
198
199
  willChange: isDragging.current ? "transform" : "auto"
199
200
  };
200
201
  },
201
- [stopSize, trackSize == null ? void 0 : trackSize.width]
202
+ [stopSize, trackWidth]
202
203
  );
203
204
  const handleMouseMove = useEventCallback((e) => {
204
205
  if (disabled || isDragging.current) return;
205
206
  const position = calculatePosition(e.clientX);
206
- setHoverPosition(position * ((trackSize == null ? void 0 : trackSize.width) ?? 0));
207
+ setHoverPosition(position * trackWidth);
207
208
  });
208
209
  const handleMouseLeave = useEventCallback(() => {
209
210
  setHoverPosition(null);
@@ -221,7 +222,7 @@ const ColorGradientSlider = forwardRef(
221
222
  className: "relative",
222
223
  style: {
223
224
  height: 24,
224
- width: trackSize == null ? void 0 : trackSize.width
225
+ width: trackWidth
225
226
  },
226
227
  children: stops.map((stop) => /* @__PURE__ */ jsx(
227
228
  "div",
@@ -1,7 +1,10 @@
1
1
  import { CSSProperties } from 'react';
2
2
  import { PickerSliderType } from '../types/colors';
3
+ import { ColorSliderThumb, ColorSliderThumbProps } from './components/thumb';
4
+ import { ColorSliderTrack, ColorSliderTrackProps } from './components/track';
3
5
  export interface ColorSliderProps {
4
6
  backgroundStyle?: CSSProperties;
7
+ children?: React.ReactNode;
5
8
  className?: string;
6
9
  disabled?: boolean;
7
10
  hue?: number;
@@ -9,11 +12,16 @@ export interface ColorSliderProps {
9
12
  onChangeEnd?: () => void;
10
13
  onChangeStart?: () => void;
11
14
  position: number;
12
- thumbSize?: number;
13
- trackSize?: {
14
- height?: number;
15
- width?: number;
16
- };
17
15
  type: PickerSliderType;
16
+ /**
17
+ * Width of the slider track in pixels.
18
+ * If not provided (undefined or false), the width will be auto-calculated from the container.
19
+ */
20
+ width?: number | boolean;
18
21
  }
19
- export declare const ColorSlider: import('react').MemoExoticComponent<import('react').ForwardRefExoticComponent<ColorSliderProps & import('react').RefAttributes<HTMLDivElement>>>;
22
+ interface ColorSliderComponent extends React.MemoExoticComponent<React.ForwardRefExoticComponent<ColorSliderProps & React.RefAttributes<HTMLDivElement>>> {
23
+ Thumb: typeof ColorSliderThumb;
24
+ Track: typeof ColorSliderTrack;
25
+ }
26
+ export declare const ColorSlider: ColorSliderComponent;
27
+ export type { ColorSliderThumbProps, ColorSliderTrackProps };
@@ -1,19 +1,22 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { clamp } from "es-toolkit";
3
- import { memo, forwardRef, useRef, useCallback, useEffect, useMemo } from "react";
3
+ import { memo, forwardRef, useRef, useState, useMemo, Children, isValidElement, useCallback, useEffect } from "react";
4
4
  import { useEventCallback } from "usehooks-ts";
5
5
  import { useColors } from "../context/colots-context.js";
6
+ import { ColorSliderThumb } from "./components/thumb.js";
7
+ import { ColorSliderTrack } from "./components/track.js";
8
+ import { ColorSliderContext } from "./context.js";
6
9
  import { ColorSliderTv } from "./tv.js";
7
10
  import { positionToSliderValue } from "../utils/position.js";
8
11
  import { getSliderBackground } from "../utils/background.js";
12
+ import { useIsomorphicLayoutEffect } from "../../../../shared/hooks/use-isomorphic-layout-effect/use-isomorphic-layout-effect.js";
9
13
  import { tcx } from "../../../../shared/utils/tcx/tcx.js";
10
14
  import { mergeRefs } from "../../../../shared/utils/merge-refs/merge-refs.js";
11
- import { translation } from "../contents/translation.js";
12
15
  const KEYBOARD_STEPS = {
13
16
  NORMAL: 0.01,
14
17
  SHIFT: 0.1
15
18
  };
16
- const ColorSlider = memo(
19
+ const ColorSliderRoot = memo(
17
20
  forwardRef(function ColorSlider2(props, ref) {
18
21
  const {
19
22
  position,
@@ -24,18 +27,68 @@ const ColorSlider = memo(
24
27
  hue = 0,
25
28
  backgroundStyle,
26
29
  disabled = false,
27
- trackSize = {
28
- width: 256,
29
- height: 16
30
- },
31
- thumbSize = 14,
32
- className
30
+ width: propsWidth = 256,
31
+ className,
32
+ children
33
33
  } = props;
34
34
  const { colorProfile } = useColors();
35
35
  const sliderRef = useRef(null);
36
36
  const thumbRef = useRef(null);
37
37
  const inputRef = useRef(null);
38
38
  const isDragging = useRef(false);
39
+ const [actualTrackWidth, setActualTrackWidth] = useState();
40
+ const trackWidth = typeof propsWidth === "number" ? propsWidth : actualTrackWidth;
41
+ const { hasCustomChildren, extractedThumbSize, extractedTrackHeight } = useMemo(() => {
42
+ const childArray = Children.toArray(children);
43
+ let hasCustom = false;
44
+ let thumbSizeFromChild;
45
+ let trackHeightFromChild;
46
+ for (const child of childArray) {
47
+ if (isValidElement(child)) {
48
+ const childType = child.type;
49
+ if (child.type === ColorSliderThumb || (childType == null ? void 0 : childType.displayName) === "ColorSliderThumb") {
50
+ hasCustom = true;
51
+ const childProps = child.props;
52
+ if (childProps.size !== void 0) {
53
+ thumbSizeFromChild = childProps.size;
54
+ }
55
+ } else if (child.type === ColorSliderTrack || (childType == null ? void 0 : childType.displayName) === "ColorSliderTrack") {
56
+ hasCustom = true;
57
+ const childProps = child.props;
58
+ if (childProps.height !== void 0) {
59
+ trackHeightFromChild = childProps.height;
60
+ }
61
+ }
62
+ }
63
+ }
64
+ return {
65
+ hasCustomChildren: hasCustom,
66
+ extractedThumbSize: thumbSizeFromChild,
67
+ extractedTrackHeight: trackHeightFromChild
68
+ };
69
+ }, [children]);
70
+ const trackHeight = extractedTrackHeight ?? 16;
71
+ const thumbSize = extractedThumbSize ?? trackHeight;
72
+ useIsomorphicLayoutEffect(() => {
73
+ if (typeof propsWidth !== "number" && sliderRef.current) {
74
+ const updateWidth = () => {
75
+ if (sliderRef.current) {
76
+ const width = sliderRef.current.getBoundingClientRect().width;
77
+ if (width > 0) {
78
+ setActualTrackWidth(width);
79
+ }
80
+ }
81
+ };
82
+ updateWidth();
83
+ const resizeObserver = new ResizeObserver(() => {
84
+ updateWidth();
85
+ });
86
+ resizeObserver.observe(sliderRef.current);
87
+ return () => {
88
+ resizeObserver.disconnect();
89
+ };
90
+ }
91
+ }, [propsWidth]);
39
92
  const updatePosition = useEventCallback((clientX, isEnd) => {
40
93
  var _a;
41
94
  const rect = (_a = sliderRef.current) == null ? void 0 : _a.getBoundingClientRect();
@@ -117,69 +170,94 @@ const ColorSlider = memo(
117
170
  (_a = inputRef.current) == null ? void 0 : _a.blur();
118
171
  }
119
172
  }, [disabled]);
120
- const thumbStyle = useMemo(() => {
121
- const minTransform = 1;
122
- const maxTransform = ((trackSize == null ? void 0 : trackSize.width) ?? 0) - thumbSize - 1;
173
+ const computedTrackWidth = trackWidth ?? 256;
174
+ const thumbWrapperStyle = useMemo(() => {
175
+ const minTransform = 0;
176
+ const maxTransform = computedTrackWidth - thumbSize;
123
177
  const transformX = minTransform + position * (maxTransform - minTransform);
124
178
  return {
125
179
  width: thumbSize,
126
180
  height: thumbSize,
127
181
  transform: `translate(${transformX}px, -50%)`,
182
+ willChange: isDragging.current ? "transform" : "auto"
183
+ };
184
+ }, [position, thumbSize, computedTrackWidth]);
185
+ const thumbStyle = useMemo(() => {
186
+ return {
187
+ "--thumb-size": `${thumbSize}px`,
128
188
  backgroundColor: positionToSliderValue(position, type, hue),
129
- willChange: isDragging.current ? "transform" : "auto",
130
189
  boxShadow: `
131
190
  inset 0 0 0 3px white,
132
191
  inset 0 0 0 4px rgba(0,0,0,0.2),
133
192
  0 0 0 1px rgba(0,0,0,0.2)
134
193
  `
135
194
  };
136
- }, [position, thumbSize, trackSize, type, hue]);
137
- const computedBackgroundStyle = useMemo(
195
+ }, [position, type, hue]);
196
+ const trackStyle = useMemo(
138
197
  () => ({
139
198
  ...getSliderBackground(type, hue, colorProfile),
140
- ...backgroundStyle
199
+ ...backgroundStyle,
200
+ boxShadow: "inset 0 0 0 1px rgba(0,0,0,0.1)"
141
201
  }),
142
202
  [type, hue, colorProfile, backgroundStyle]
143
203
  );
144
- const styles = ColorSliderTv({ disabled });
145
- return /* @__PURE__ */ jsx(
204
+ const tv = useMemo(() => ColorSliderTv({ disabled }), [disabled]);
205
+ const contextValue = useMemo(
206
+ () => ({
207
+ position,
208
+ disabled,
209
+ type,
210
+ hue,
211
+ thumbSize,
212
+ trackWidth: computedTrackWidth,
213
+ trackHeight,
214
+ thumbWrapperStyle,
215
+ thumbStyle,
216
+ trackStyle,
217
+ thumbRef,
218
+ inputRef,
219
+ isDragging,
220
+ handlePointerDown,
221
+ handleKeyDown,
222
+ tv
223
+ }),
224
+ [
225
+ position,
226
+ disabled,
227
+ type,
228
+ hue,
229
+ thumbSize,
230
+ computedTrackWidth,
231
+ trackHeight,
232
+ thumbWrapperStyle,
233
+ thumbStyle,
234
+ trackStyle,
235
+ handlePointerDown,
236
+ handleKeyDown,
237
+ tv
238
+ ]
239
+ );
240
+ return /* @__PURE__ */ jsx(ColorSliderContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
146
241
  "div",
147
242
  {
148
243
  ref: mergeRefs(ref, sliderRef),
149
244
  onPointerDown: handleSliderPointerDown,
150
245
  style: {
151
- ...computedBackgroundStyle,
152
- boxShadow: "inset 0 0 0 1px rgba(0,0,0,0.1)",
153
- height: trackSize == null ? void 0 : trackSize.height,
154
- width: trackSize == null ? void 0 : trackSize.width
246
+ ...trackStyle,
247
+ height: trackHeight,
248
+ width: typeof propsWidth === "number" ? propsWidth : void 0
155
249
  },
156
- className: tcx(styles.root(), className),
157
- children: /* @__PURE__ */ jsx(
158
- "div",
159
- {
160
- ref: thumbRef,
161
- onPointerDown: handlePointerDown,
162
- className: styles.thumb(),
163
- style: thumbStyle,
164
- children: /* @__PURE__ */ jsx(
165
- "input",
166
- {
167
- ref: inputRef,
168
- type: "text",
169
- onKeyDown: handleKeyDown,
170
- className: styles.thumbInput(),
171
- "aria-label": translation.slider.ARIA_LABEL,
172
- tabIndex: disabled ? -1 : 0,
173
- readOnly: true
174
- }
175
- )
176
- }
177
- )
250
+ className: tcx(tv.root(), className),
251
+ children: hasCustomChildren ? children : /* @__PURE__ */ jsx(ColorSliderThumb, {})
178
252
  }
179
- );
253
+ ) });
180
254
  })
181
255
  );
182
- ColorSlider.displayName = "ColorSlider";
256
+ ColorSliderRoot.displayName = "ColorSlider";
257
+ const ColorSlider = Object.assign(ColorSliderRoot, {
258
+ Thumb: ColorSliderThumb,
259
+ Track: ColorSliderTrack
260
+ });
183
261
  export {
184
262
  ColorSlider
185
263
  };
@@ -0,0 +1,2 @@
1
+ export * from './thumb';
2
+ export * from './track';
@@ -0,0 +1,8 @@
1
+ export interface ColorSliderThumbProps {
2
+ className?: string;
3
+ size?: number;
4
+ }
5
+ export declare function ColorSliderThumb(props: ColorSliderThumbProps): import("react/jsx-runtime").JSX.Element;
6
+ export declare namespace ColorSliderThumb {
7
+ var displayName: string;
8
+ }
@@ -0,0 +1,49 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useColorSlider } from "../context.js";
3
+ import { tcx } from "../../../../../shared/utils/tcx/tcx.js";
4
+ import { translation } from "../../contents/translation.js";
5
+ function ColorSliderThumb(props) {
6
+ const { className } = props;
7
+ const {
8
+ thumbRef,
9
+ inputRef,
10
+ thumbWrapperStyle,
11
+ thumbStyle,
12
+ disabled,
13
+ handlePointerDown,
14
+ handleKeyDown,
15
+ tv
16
+ } = useColorSlider();
17
+ return /* @__PURE__ */ jsx(
18
+ "div",
19
+ {
20
+ ref: thumbRef,
21
+ onPointerDown: handlePointerDown,
22
+ className: tv.thumbWrapper(),
23
+ style: thumbWrapperStyle,
24
+ children: /* @__PURE__ */ jsx(
25
+ "div",
26
+ {
27
+ className: tcx(tv.thumb(), className),
28
+ style: thumbStyle,
29
+ children: /* @__PURE__ */ jsx(
30
+ "input",
31
+ {
32
+ ref: inputRef,
33
+ type: "text",
34
+ onKeyDown: handleKeyDown,
35
+ className: tv.thumbInput(),
36
+ "aria-label": translation.slider.ARIA_LABEL,
37
+ tabIndex: disabled ? -1 : 0,
38
+ readOnly: true
39
+ }
40
+ )
41
+ }
42
+ )
43
+ }
44
+ );
45
+ }
46
+ ColorSliderThumb.displayName = "ColorSliderThumb";
47
+ export {
48
+ ColorSliderThumb
49
+ };
@@ -0,0 +1,18 @@
1
+ export interface ColorSliderTrackProps {
2
+ className?: string;
3
+ children?: React.ReactNode;
4
+ /**
5
+ * Height of the track in pixels.
6
+ * This prop is extracted by the parent ColorSlider and passed via context.
7
+ */
8
+ height?: number;
9
+ }
10
+ /**
11
+ * ColorSliderTrack - The track background of the color slider.
12
+ * Renders the gradient background based on slider type (hue, alpha, etc.)
13
+ * Can contain custom children for additional visual elements.
14
+ */
15
+ export declare function ColorSliderTrack(props: ColorSliderTrackProps): import("react/jsx-runtime").JSX.Element;
16
+ export declare namespace ColorSliderTrack {
17
+ var displayName: string;
18
+ }
@@ -0,0 +1,19 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useColorSlider } from "../context.js";
3
+ import { tcx } from "../../../../../shared/utils/tcx/tcx.js";
4
+ function ColorSliderTrack(props) {
5
+ const { className, children, height: _height } = props;
6
+ const { trackStyle } = useColorSlider();
7
+ return /* @__PURE__ */ jsx(
8
+ "div",
9
+ {
10
+ className: tcx("absolute inset-0 rounded-full", className),
11
+ style: trackStyle,
12
+ children
13
+ }
14
+ );
15
+ }
16
+ ColorSliderTrack.displayName = "ColorSliderTrack";
17
+ export {
18
+ ColorSliderTrack
19
+ };
@@ -0,0 +1,23 @@
1
+ import { CSSProperties, MutableRefObject, RefObject } from 'react';
2
+ import { PickerSliderType } from '../types/colors';
3
+ import { ColorSliderTv } from './tv';
4
+ export interface ColorSliderContextValue {
5
+ position: number;
6
+ disabled: boolean;
7
+ type: PickerSliderType;
8
+ hue: number;
9
+ thumbSize: number;
10
+ trackWidth: number;
11
+ trackHeight: number;
12
+ thumbWrapperStyle: CSSProperties;
13
+ thumbStyle: CSSProperties;
14
+ trackStyle: CSSProperties;
15
+ thumbRef: RefObject<HTMLDivElement>;
16
+ inputRef: RefObject<HTMLInputElement>;
17
+ isDragging: MutableRefObject<boolean>;
18
+ handlePointerDown: (e: React.PointerEvent) => void;
19
+ handleKeyDown: (e: React.KeyboardEvent) => void;
20
+ tv: ReturnType<typeof ColorSliderTv>;
21
+ }
22
+ export declare const ColorSliderContext: import('react').Context<ColorSliderContextValue | null>;
23
+ export declare function useColorSlider(): ColorSliderContextValue;
@@ -0,0 +1,13 @@
1
+ import { createContext, useContext } from "react";
2
+ const ColorSliderContext = createContext(null);
3
+ function useColorSlider() {
4
+ const context = useContext(ColorSliderContext);
5
+ if (!context) {
6
+ throw new Error("ColorSlider compound components must be used within ColorSlider");
7
+ }
8
+ return context;
9
+ }
10
+ export {
11
+ ColorSliderContext,
12
+ useColorSlider
13
+ };
@@ -1 +1,3 @@
1
1
  export * from './color-slider';
2
+ export * from './context';
3
+ export * from './components';
@@ -6,6 +6,7 @@ export declare const ColorSliderTv: import('tailwind-variants').TVReturnType<{
6
6
  };
7
7
  }, {
8
8
  root: string;
9
+ thumbWrapper: string;
9
10
  thumb: string;
10
11
  thumbInput: string;
11
12
  }, undefined, {
@@ -16,6 +17,7 @@ export declare const ColorSliderTv: import('tailwind-variants').TVReturnType<{
16
17
  };
17
18
  }, {
18
19
  root: string;
20
+ thumbWrapper: string;
19
21
  thumb: string;
20
22
  thumbInput: string;
21
23
  }, import('tailwind-variants').TVReturnType<{
@@ -26,6 +28,7 @@ export declare const ColorSliderTv: import('tailwind-variants').TVReturnType<{
26
28
  };
27
29
  }, {
28
30
  root: string;
31
+ thumbWrapper: string;
29
32
  thumb: string;
30
33
  thumbInput: string;
31
34
  }, undefined, unknown, unknown, undefined>>;
@@ -2,7 +2,8 @@ import { tcv } from "../../../../shared/utils/tcx/tcx.js";
2
2
  const ColorSliderTv = tcv({
3
3
  slots: {
4
4
  root: "relative touch-none rounded-full select-none",
5
- thumb: "absolute top-1/2 box-border origin-center rounded-full",
5
+ thumbWrapper: "absolute top-1/2 box-border origin-center",
6
+ thumb: "rounded-full absolute -translate-y-1/2 -translate-x-1/2 left-1/2 top-1/2 w-[calc(var(--thumb-size)-2px)] h-[calc(var(--thumb-size)-2px)]",
6
7
  thumbInput: "absolute inset-0 cursor-default opacity-0"
7
8
  },
8
9
  variants: {
@@ -59,7 +59,7 @@ const ColorSolidPaint = forwardRef(
59
59
  const handleNativeColorChange = useEventCallback((rgb) => {
60
60
  onColorChange == null ? void 0 : onColorChange(rgb);
61
61
  });
62
- const sliderTrackSize = useMemo(() => {
62
+ const sliderWidth = useMemo(() => {
63
63
  const getPadding = () => {
64
64
  if (!features.alpha && !features.nativePicker) {
65
65
  return 32;
@@ -69,10 +69,7 @@ const ColorSolidPaint = forwardRef(
69
69
  padding += features.nativePicker ? 48 : 0;
70
70
  return padding;
71
71
  };
72
- return {
73
- width: ((features == null ? void 0 : features.containerWidth) ?? 240) - getPadding(),
74
- height: 16
75
- };
72
+ return ((features == null ? void 0 : features.containerWidth) ?? 240) - getPadding();
76
73
  }, [features.containerWidth, features.alpha, features.nativePicker]);
77
74
  const styles = ColorSolidPaintTv({
78
75
  alpha: features.alpha,
@@ -235,7 +232,7 @@ const ColorSolidPaint = forwardRef(
235
232
  onChangeEnd,
236
233
  onChange: onChangeEnd,
237
234
  type: "hue",
238
- trackSize: sliderTrackSize,
235
+ width: sliderWidth,
239
236
  updateSourceRef
240
237
  }
241
238
  ),
@@ -246,7 +243,7 @@ const ColorSolidPaint = forwardRef(
246
243
  alpha: opacity,
247
244
  onAlphaChange,
248
245
  type: "alpha",
249
- trackSize: sliderTrackSize,
246
+ width: sliderWidth,
250
247
  onChangeStart,
251
248
  onChangeEnd
252
249
  }
@@ -1,7 +1,7 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { ColorSlider } from "../color-slider/color-slider.js";
3
3
  const SolidPaintAlphaSlider = (props) => {
4
- const { hue, alpha, onAlphaChange, onChangeStart, onChangeEnd, trackSize } = props;
4
+ const { hue, alpha, onAlphaChange, onChangeStart, onChangeEnd, width } = props;
5
5
  return /* @__PURE__ */ jsx(
6
6
  ColorSlider,
7
7
  {
@@ -9,7 +9,7 @@ const SolidPaintAlphaSlider = (props) => {
9
9
  onChange: onAlphaChange,
10
10
  type: "alpha",
11
11
  hue,
12
- trackSize,
12
+ width,
13
13
  onChangeStart,
14
14
  onChangeEnd
15
15
  }
@@ -9,7 +9,7 @@ const SolidPaintHueSlider = (props) => {
9
9
  setHue,
10
10
  color,
11
11
  onColorChange,
12
- trackSize,
12
+ width,
13
13
  onChangeStart,
14
14
  onChangeEnd,
15
15
  updateSourceRef
@@ -32,7 +32,7 @@ const SolidPaintHueSlider = (props) => {
32
32
  position: hue / 360,
33
33
  onChange: handleHueChange,
34
34
  type: "hue",
35
- trackSize,
35
+ width,
36
36
  onChangeStart,
37
37
  onChangeEnd: () => {
38
38
  onChangeEnd == null ? void 0 : onChangeEnd();
@@ -43,16 +43,13 @@ const SimpleColorPicker = forwardRef(
43
43
  hsb: true,
44
44
  ...featureProps
45
45
  };
46
- const sliderTrackSize = useMemo(() => {
46
+ const sliderWidth = useMemo(() => {
47
47
  const getPadding = () => {
48
48
  let padding = 0;
49
49
  padding += 32;
50
50
  return padding;
51
51
  };
52
- return {
53
- width: 240 - getPadding(),
54
- height: 16
55
- };
52
+ return 240 - getPadding();
56
53
  }, []);
57
54
  const styles = ColorSolidPaintTv({
58
55
  alpha: true,
@@ -104,7 +101,7 @@ const SimpleColorPicker = forwardRef(
104
101
  onChangeEnd,
105
102
  onChange: onChangeEnd,
106
103
  type: "hue",
107
- trackSize: sliderTrackSize,
104
+ width: sliderWidth,
108
105
  updateSourceRef
109
106
  }
110
107
  ),
@@ -115,7 +112,7 @@ const SimpleColorPicker = forwardRef(
115
112
  alpha: opacity,
116
113
  onAlphaChange,
117
114
  type: "alpha",
118
- trackSize: sliderTrackSize,
115
+ width: sliderWidth,
119
116
  onChangeStart,
120
117
  onChangeEnd
121
118
  }
@@ -54,7 +54,7 @@ var DropdownComponent = memo(function DropdownComponent2(props) {
54
54
  }
55
55
  onOpenChange == null ? void 0 : onOpenChange(newOpen);
56
56
  });
57
- const { nodeId, item, isNested } = useMenuTree({
57
+ const { nodeId, item, isNested, tree } = useMenuTree({
58
58
  disabledNested,
59
59
  handleOpenChange,
60
60
  isControlledOpen
@@ -169,11 +169,17 @@ var DropdownComponent = memo(function DropdownComponent2(props) {
169
169
  bubbles: true,
170
170
  escapeKey: true
171
171
  });
172
+ const handleNavigate = useEventCallback((index) => {
173
+ setActiveIndex(index);
174
+ if (tree && index !== null) {
175
+ tree.events.emit("navigate", { nodeId, index });
176
+ }
177
+ });
172
178
  const listNavigation = useListNavigation(context, {
173
179
  listRef: elementsRef,
174
180
  activeIndex,
175
181
  nested: isNested,
176
- onNavigate: setActiveIndex,
182
+ onNavigate: handleNavigate,
177
183
  loop: true
178
184
  });
179
185
  const typeahead = useTypeahead(context, {
@@ -54,7 +54,7 @@ const DropdownComponent = memo(function DropdownComponent2(props) {
54
54
  }
55
55
  onOpenChange == null ? void 0 : onOpenChange(newOpen);
56
56
  });
57
- const { nodeId, item, isNested } = useMenuTree({
57
+ const { nodeId, item, isNested, tree } = useMenuTree({
58
58
  disabledNested,
59
59
  handleOpenChange,
60
60
  isControlledOpen
@@ -169,11 +169,17 @@ const DropdownComponent = memo(function DropdownComponent2(props) {
169
169
  bubbles: true,
170
170
  escapeKey: true
171
171
  });
172
+ const handleNavigate = useEventCallback((index) => {
173
+ setActiveIndex(index);
174
+ if (tree && index !== null) {
175
+ tree.events.emit("navigate", { nodeId, index });
176
+ }
177
+ });
172
178
  const listNavigation = useListNavigation(context, {
173
179
  listRef: elementsRef,
174
180
  activeIndex,
175
181
  nested: isNested,
176
- onNavigate: setActiveIndex,
182
+ onNavigate: handleNavigate,
177
183
  loop: true
178
184
  });
179
185
  const typeahead = useTypeahead(context, {
@@ -843,18 +843,25 @@ function useMenuTree(config) {
843
843
  handleOpenChange(false);
844
844
  }
845
845
  });
846
+ const handleParentNavigate = useEventCallback((event) => {
847
+ if (event.nodeId === parentId && event.index !== item.index && isControlledOpen) {
848
+ handleOpenChange(false);
849
+ }
850
+ });
846
851
  const cleanupTreeEvents = useEventCallback(() => {
847
852
  if (tree) {
848
853
  tree.events.off("click", handleTreeClick);
849
854
  tree.events.off("menuopen", handleSubMenuOpen);
855
+ tree.events.off("navigate", handleParentNavigate);
850
856
  }
851
857
  });
852
858
  useEffect(() => {
853
859
  if (!tree) return;
854
860
  tree.events.on("click", handleTreeClick);
855
861
  tree.events.on("menuopen", handleSubMenuOpen);
862
+ tree.events.on("navigate", handleParentNavigate);
856
863
  return cleanupTreeEvents;
857
- }, [tree, nodeId, parentId, handleTreeClick, handleSubMenuOpen, cleanupTreeEvents]);
864
+ }, [tree, nodeId, parentId, handleTreeClick, handleSubMenuOpen, handleParentNavigate, cleanupTreeEvents]);
858
865
  useEffect(() => {
859
866
  if (isControlledOpen && tree) {
860
867
  tree.events.emit("menuopen", { parentId, nodeId });
@@ -1075,7 +1082,12 @@ var MenuContextSubTrigger = memo(
1075
1082
  throw new Error("MenuContextSubTrigger must be used within a MenuContext component");
1076
1083
  }
1077
1084
  const isActive = useMemo(
1078
- () => item.index === menu.activeIndex || !!active,
1085
+ () => {
1086
+ if (menu.activeIndex !== null && menu.activeIndex !== void 0) {
1087
+ return item.index === menu.activeIndex;
1088
+ }
1089
+ return !!active;
1090
+ },
1079
1091
  [item.index, menu.activeIndex, active]
1080
1092
  );
1081
1093
  const handleFocus = useEventCallback((event) => {
@@ -26,7 +26,12 @@ const MenuContextSubTrigger = memo(
26
26
  throw new Error("MenuContextSubTrigger must be used within a MenuContext component");
27
27
  }
28
28
  const isActive = useMemo(
29
- () => item.index === menu.activeIndex || !!active,
29
+ () => {
30
+ if (menu.activeIndex !== null && menu.activeIndex !== void 0) {
31
+ return item.index === menu.activeIndex;
32
+ }
33
+ return !!active;
34
+ },
30
35
  [item.index, menu.activeIndex, active]
31
36
  );
32
37
  const handleFocus = useEventCallback((event) => {
@@ -16,18 +16,25 @@ function useMenuTree(config) {
16
16
  handleOpenChange(false);
17
17
  }
18
18
  });
19
+ const handleParentNavigate = useEventCallback((event) => {
20
+ if (event.nodeId === parentId && event.index !== item.index && isControlledOpen) {
21
+ handleOpenChange(false);
22
+ }
23
+ });
19
24
  const cleanupTreeEvents = useEventCallback(() => {
20
25
  if (tree) {
21
26
  tree.events.off("click", handleTreeClick);
22
27
  tree.events.off("menuopen", handleSubMenuOpen);
28
+ tree.events.off("navigate", handleParentNavigate);
23
29
  }
24
30
  });
25
31
  useEffect(() => {
26
32
  if (!tree) return;
27
33
  tree.events.on("click", handleTreeClick);
28
34
  tree.events.on("menuopen", handleSubMenuOpen);
35
+ tree.events.on("navigate", handleParentNavigate);
29
36
  return cleanupTreeEvents;
30
- }, [tree, nodeId, parentId, handleTreeClick, handleSubMenuOpen, cleanupTreeEvents]);
37
+ }, [tree, nodeId, parentId, handleTreeClick, handleSubMenuOpen, handleParentNavigate, cleanupTreeEvents]);
31
38
  useEffect(() => {
32
39
  if (isControlledOpen && tree) {
33
40
  tree.events.emit("menuopen", { parentId, nodeId });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@choice-ui/react",
3
- "version": "1.8.9",
3
+ "version": "1.9.1",
4
4
  "description": "A desktop-first React UI component library built for professional desktop applications with comprehensive documentation",
5
5
  "sideEffects": false,
6
6
  "type": "module",