@choice-ui/react 1.5.5 → 1.5.7

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.
@@ -279,27 +279,52 @@ var DropdownComponent = memo(function DropdownComponent2(props) {
279
279
  }),
280
280
  [activeIndex, getItemProps, handleClose, isControlledOpen, readOnly, selection, variant]
281
281
  );
282
+ const parentActiveIndex = parent == null ? void 0 : parent.activeIndex;
283
+ const parentGetItemProps = parent == null ? void 0 : parent.getItemProps;
284
+ const slotProps = useMemo(() => {
285
+ const referenceProps = getReferenceProps(
286
+ parentGetItemProps ? parentGetItemProps({
287
+ onFocus: handleFocus
288
+ }) : {}
289
+ );
290
+ return {
291
+ tabIndex: !isNested ? void 0 : parentActiveIndex === item.index ? 0 : -1,
292
+ role: isNested ? "menuitem" : void 0,
293
+ "data-open": isControlledOpen ? "" : void 0,
294
+ "data-nested": isNested ? "" : void 0,
295
+ "data-focus-inside": hasFocusInside ? "" : void 0,
296
+ onTouchStart: handleTouchStart,
297
+ onPointerMove: handlePointerMove,
298
+ "aria-haspopup": "menu",
299
+ "aria-expanded": isControlledOpen,
300
+ "aria-controls": menuId,
301
+ ...referenceProps
302
+ };
303
+ }, [
304
+ isNested,
305
+ parentActiveIndex,
306
+ parentGetItemProps,
307
+ item.index,
308
+ isControlledOpen,
309
+ hasFocusInside,
310
+ handleTouchStart,
311
+ handlePointerMove,
312
+ menuId,
313
+ getReferenceProps,
314
+ handleFocus
315
+ ]);
316
+ const slotChildren = useMemo(() => {
317
+ const element = isNested ? subTriggerElement : triggerElement;
318
+ if (!element) return null;
319
+ return cloneElement(element, { active: isControlledOpen });
320
+ }, [isNested, subTriggerElement, triggerElement, isControlledOpen]);
282
321
  return /* @__PURE__ */ jsxs(FloatingNode, { id: nodeId, children: [
283
322
  !isCoordinateMode && !hasExternalTrigger && /* @__PURE__ */ jsx(
284
323
  Slot,
285
324
  {
286
325
  ref: refs.setReference,
287
- tabIndex: !isNested ? void 0 : (parent == null ? void 0 : parent.activeIndex) === item.index ? 0 : -1,
288
- role: isNested ? "menuitem" : void 0,
289
- "data-open": isControlledOpen ? "" : void 0,
290
- "data-nested": isNested ? "" : void 0,
291
- "data-focus-inside": hasFocusInside ? "" : void 0,
292
- onTouchStart: handleTouchStart,
293
- onPointerMove: handlePointerMove,
294
- "aria-haspopup": "menu",
295
- "aria-expanded": isControlledOpen,
296
- "aria-controls": menuId,
297
- ...getReferenceProps(
298
- parent ? parent.getItemProps({
299
- onFocus: handleFocus
300
- }) : {}
301
- ),
302
- children: isNested ? subTriggerElement && cloneElement(subTriggerElement, { active: isControlledOpen }) : triggerElement && cloneElement(triggerElement, { active: isControlledOpen })
326
+ ...slotProps,
327
+ children: slotChildren
303
328
  }
304
329
  ),
305
330
  /* @__PURE__ */ jsx(
@@ -279,27 +279,52 @@ const DropdownComponent = memo(function DropdownComponent2(props) {
279
279
  }),
280
280
  [activeIndex, getItemProps, handleClose, isControlledOpen, readOnly, selection, variant]
281
281
  );
282
+ const parentActiveIndex = parent == null ? void 0 : parent.activeIndex;
283
+ const parentGetItemProps = parent == null ? void 0 : parent.getItemProps;
284
+ const slotProps = useMemo(() => {
285
+ const referenceProps = getReferenceProps(
286
+ parentGetItemProps ? parentGetItemProps({
287
+ onFocus: handleFocus
288
+ }) : {}
289
+ );
290
+ return {
291
+ tabIndex: !isNested ? void 0 : parentActiveIndex === item.index ? 0 : -1,
292
+ role: isNested ? "menuitem" : void 0,
293
+ "data-open": isControlledOpen ? "" : void 0,
294
+ "data-nested": isNested ? "" : void 0,
295
+ "data-focus-inside": hasFocusInside ? "" : void 0,
296
+ onTouchStart: handleTouchStart,
297
+ onPointerMove: handlePointerMove,
298
+ "aria-haspopup": "menu",
299
+ "aria-expanded": isControlledOpen,
300
+ "aria-controls": menuId,
301
+ ...referenceProps
302
+ };
303
+ }, [
304
+ isNested,
305
+ parentActiveIndex,
306
+ parentGetItemProps,
307
+ item.index,
308
+ isControlledOpen,
309
+ hasFocusInside,
310
+ handleTouchStart,
311
+ handlePointerMove,
312
+ menuId,
313
+ getReferenceProps,
314
+ handleFocus
315
+ ]);
316
+ const slotChildren = useMemo(() => {
317
+ const element = isNested ? subTriggerElement : triggerElement;
318
+ if (!element) return null;
319
+ return cloneElement(element, { active: isControlledOpen });
320
+ }, [isNested, subTriggerElement, triggerElement, isControlledOpen]);
282
321
  return /* @__PURE__ */ jsxs(FloatingNode, { id: nodeId, children: [
283
322
  !isCoordinateMode && !hasExternalTrigger && /* @__PURE__ */ jsx(
284
323
  Slot,
285
324
  {
286
325
  ref: refs.setReference,
287
- tabIndex: !isNested ? void 0 : (parent == null ? void 0 : parent.activeIndex) === item.index ? 0 : -1,
288
- role: isNested ? "menuitem" : void 0,
289
- "data-open": isControlledOpen ? "" : void 0,
290
- "data-nested": isNested ? "" : void 0,
291
- "data-focus-inside": hasFocusInside ? "" : void 0,
292
- onTouchStart: handleTouchStart,
293
- onPointerMove: handlePointerMove,
294
- "aria-haspopup": "menu",
295
- "aria-expanded": isControlledOpen,
296
- "aria-controls": menuId,
297
- ...getReferenceProps(
298
- parent ? parent.getItemProps({
299
- onFocus: handleFocus
300
- }) : {}
301
- ),
302
- children: isNested ? subTriggerElement && cloneElement(subTriggerElement, { active: isControlledOpen }) : triggerElement && cloneElement(triggerElement, { active: isControlledOpen })
326
+ ...slotProps,
327
+ children: slotChildren
303
328
  }
304
329
  ),
305
330
  /* @__PURE__ */ jsx(
@@ -6,8 +6,8 @@ import { Kbd } from "../../kbd/dist/index.js";
6
6
  import { flushSync } from "react-dom";
7
7
  import { SearchInput } from "../../search-input/dist/index.js";
8
8
  import { Slot } from "../../slot/dist/index.js";
9
- import { Input } from "../../input/dist/index.js";
10
9
  import { useEventCallback } from "usehooks-ts";
10
+ import { Input } from "../../input/dist/index.js";
11
11
  import { useListItem, useFloatingTree, useFloatingNodeId, useFloatingParentNodeId } from "@floating-ui/react";
12
12
  import { useIsomorphicLayoutEffect } from "../../../shared/hooks/use-isomorphic-layout-effect/use-isomorphic-layout-effect.js";
13
13
  import { tcv, tcx } from "../../../shared/utils/tcx/tcx.js";
@@ -638,24 +638,29 @@ var MenuTrigger = memo(
638
638
  isEmpty: empty,
639
639
  size: size2
640
640
  });
641
- const slotProps = enterForwardedProps ? {
642
- ...rest,
643
- active,
644
- selected,
645
- disabled,
646
- onClick: (e) => {
647
- e.stopPropagation();
648
- e.preventDefault();
649
- if (rest.onClick) {
650
- rest.onClick(e);
651
- }
641
+ const handleClick = useEventCallback((e) => {
642
+ var _a;
643
+ e.stopPropagation();
644
+ e.preventDefault();
645
+ (_a = rest.onClick) == null ? void 0 : _a.call(rest, e);
646
+ });
647
+ const slotProps = useMemo(() => {
648
+ if (enterForwardedProps) {
649
+ return {
650
+ ...rest,
651
+ active,
652
+ selected,
653
+ disabled,
654
+ onClick: handleClick
655
+ };
652
656
  }
653
- } : {
654
- ...rest,
655
- ...active !== void 0 ? { "data-active": active } : {},
656
- ...selected !== void 0 ? { "data-selected": selected } : {},
657
- ...disabled !== void 0 ? { "data-disabled": disabled } : {}
658
- };
657
+ return {
658
+ ...rest,
659
+ ...active !== void 0 ? { "data-active": active } : {},
660
+ ...selected !== void 0 ? { "data-selected": selected } : {},
661
+ ...disabled !== void 0 ? { "data-disabled": disabled } : {}
662
+ };
663
+ }, [enterForwardedProps, rest, active, selected, disabled, handleClick]);
659
664
  return asChild ? /* @__PURE__ */ jsx(
660
665
  Slot,
661
666
  {
@@ -2,7 +2,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { Button } from "../../../button/dist/index.js";
3
3
  import { Slot } from "../../../slot/dist/index.js";
4
4
  import { ChevronDownSmall } from "@choiceform/icons-react";
5
- import { memo, forwardRef } from "react";
5
+ import { memo, forwardRef, useMemo } from "react";
6
+ import { useEventCallback } from "usehooks-ts";
6
7
  import { MenuTriggerTv } from "../tv.js";
7
8
  import { tcx } from "../../../../shared/utils/tcx/tcx.js";
8
9
  const MenuTrigger = memo(
@@ -28,24 +29,29 @@ const MenuTrigger = memo(
28
29
  isEmpty: empty,
29
30
  size
30
31
  });
31
- const slotProps = enterForwardedProps ? {
32
- ...rest,
33
- active,
34
- selected,
35
- disabled,
36
- onClick: (e) => {
37
- e.stopPropagation();
38
- e.preventDefault();
39
- if (rest.onClick) {
40
- rest.onClick(e);
41
- }
32
+ const handleClick = useEventCallback((e) => {
33
+ var _a;
34
+ e.stopPropagation();
35
+ e.preventDefault();
36
+ (_a = rest.onClick) == null ? void 0 : _a.call(rest, e);
37
+ });
38
+ const slotProps = useMemo(() => {
39
+ if (enterForwardedProps) {
40
+ return {
41
+ ...rest,
42
+ active,
43
+ selected,
44
+ disabled,
45
+ onClick: handleClick
46
+ };
42
47
  }
43
- } : {
44
- ...rest,
45
- ...active !== void 0 ? { "data-active": active } : {},
46
- ...selected !== void 0 ? { "data-selected": selected } : {},
47
- ...disabled !== void 0 ? { "data-disabled": disabled } : {}
48
- };
48
+ return {
49
+ ...rest,
50
+ ...active !== void 0 ? { "data-active": active } : {},
51
+ ...selected !== void 0 ? { "data-selected": selected } : {},
52
+ ...disabled !== void 0 ? { "data-disabled": disabled } : {}
53
+ };
54
+ }, [enterForwardedProps, rest, active, selected, disabled, handleClick]);
49
55
  return asChild ? /* @__PURE__ */ jsx(
50
56
  Slot,
51
57
  {
@@ -740,6 +740,21 @@ var MultiSelectComponent = memo(
740
740
  chipVariant,
741
741
  valueDisabledMap
742
742
  ]);
743
+ const handleTouchStart = useEventCallback(() => {
744
+ setTouch(true);
745
+ });
746
+ const handlePointerMove = useEventCallback(({ pointerType }) => {
747
+ if (pointerType !== "touch") {
748
+ setTouch(false);
749
+ }
750
+ });
751
+ const slotProps = useMemo(() => {
752
+ return getReferenceProps({
753
+ disabled,
754
+ onTouchStart: handleTouchStart,
755
+ onPointerMove: handlePointerMove
756
+ });
757
+ }, [getReferenceProps, disabled, handleTouchStart, handlePointerMove]);
743
758
  if (!triggerElement || !contentElement) {
744
759
  console.error(
745
760
  "MultiSelect requires both MultiSelect.Trigger and MultiSelect.Content components as children"
@@ -751,17 +766,7 @@ var MultiSelectComponent = memo(
751
766
  Slot,
752
767
  {
753
768
  ref: refs.setReference,
754
- ...getReferenceProps({
755
- disabled,
756
- onTouchStart() {
757
- setTouch(true);
758
- },
759
- onPointerMove({ pointerType }) {
760
- if (pointerType !== "touch") {
761
- setTouch(false);
762
- }
763
- }
764
- }),
769
+ ...slotProps,
765
770
  children: enhancedTriggerElement
766
771
  }
767
772
  ),
@@ -355,6 +355,21 @@ const MultiSelectComponent = memo(
355
355
  chipVariant,
356
356
  valueDisabledMap
357
357
  ]);
358
+ const handleTouchStart = useEventCallback(() => {
359
+ setTouch(true);
360
+ });
361
+ const handlePointerMove = useEventCallback(({ pointerType }) => {
362
+ if (pointerType !== "touch") {
363
+ setTouch(false);
364
+ }
365
+ });
366
+ const slotProps = useMemo(() => {
367
+ return getReferenceProps({
368
+ disabled,
369
+ onTouchStart: handleTouchStart,
370
+ onPointerMove: handlePointerMove
371
+ });
372
+ }, [getReferenceProps, disabled, handleTouchStart, handlePointerMove]);
358
373
  if (!triggerElement || !contentElement) {
359
374
  console.error(
360
375
  "MultiSelect requires both MultiSelect.Trigger and MultiSelect.Content components as children"
@@ -366,17 +381,7 @@ const MultiSelectComponent = memo(
366
381
  Slot,
367
382
  {
368
383
  ref: refs.setReference,
369
- ...getReferenceProps({
370
- disabled,
371
- onTouchStart() {
372
- setTouch(true);
373
- },
374
- onPointerMove({ pointerType }) {
375
- if (pointerType !== "touch") {
376
- setTouch(false);
377
- }
378
- }
379
- }),
384
+ ...slotProps,
380
385
  children: enhancedTriggerElement
381
386
  }
382
387
  ),
@@ -1,7 +1,7 @@
1
1
  import { Slot } from "../../slot/dist/index.js";
2
2
  import { ModalFooter, ModalContent, ModalHeader, Modal } from "../../modal/dist/index.js";
3
3
  import { useFloatingParentNodeId, FloatingTree, useFloatingNodeId, FloatingNode, FloatingFocusManager, FloatingPortal, offset, flip, shift, size, useFloating, autoUpdate, useHover, safePolygon, useClick, useFocus, useDismiss, useRole, useInteractions } from "@floating-ui/react";
4
- import { memo, forwardRef, useId, useRef, useEffect, useMemo, useCallback, createContext, useContext, useState } from "react";
4
+ import { memo, forwardRef, useMemo, useId, useRef, useEffect, useCallback, createContext, useContext, useState } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { useEventCallback } from "usehooks-ts";
7
7
  import { findChildByType } from "../../../shared/utils/assertion.js";
@@ -37,11 +37,14 @@ var PopoverTrigger = memo(
37
37
  forwardRef((props, forwardedRef) => {
38
38
  const { children } = props;
39
39
  const { getReferenceProps, refs } = usePopoverContext();
40
+ const slotProps = useMemo(() => {
41
+ return getReferenceProps();
42
+ }, [getReferenceProps]);
40
43
  return /* @__PURE__ */ jsx(
41
44
  Slot,
42
45
  {
43
46
  ref: mergeRefs(refs.setReference, forwardedRef),
44
- ...getReferenceProps(),
47
+ ...slotProps,
45
48
  children
46
49
  }
47
50
  );
@@ -1,17 +1,20 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { Slot } from "../../../slot/dist/index.js";
3
- import { memo, forwardRef } from "react";
3
+ import { memo, forwardRef, useMemo } from "react";
4
4
  import { usePopoverContext } from "../popover-context.js";
5
5
  import { mergeRefs } from "../../../../shared/utils/merge-refs/merge-refs.js";
6
6
  const PopoverTrigger = memo(
7
7
  forwardRef((props, forwardedRef) => {
8
8
  const { children } = props;
9
9
  const { getReferenceProps, refs } = usePopoverContext();
10
+ const slotProps = useMemo(() => {
11
+ return getReferenceProps();
12
+ }, [getReferenceProps]);
10
13
  return /* @__PURE__ */ jsx(
11
14
  Slot,
12
15
  {
13
16
  ref: mergeRefs(refs.setReference, forwardedRef),
14
- ...getReferenceProps(),
17
+ ...slotProps,
15
18
  children
16
19
  }
17
20
  );
@@ -94,6 +94,7 @@ var SelectComponent = memo(function SelectComponent2(props) {
94
94
  const allowMouseUpRef = useRef(true);
95
95
  const selectTimeoutRef = useRef();
96
96
  const scrollRef = useRef(null);
97
+ const isMouseDownFromTriggerRef = useRef(false);
97
98
  const refs = useMemo(
98
99
  () => ({
99
100
  list: listRef,
@@ -102,7 +103,8 @@ var SelectComponent = memo(function SelectComponent2(props) {
102
103
  allowSelect: allowSelectRef,
103
104
  allowMouseUp: allowMouseUpRef,
104
105
  selectTimeout: selectTimeoutRef,
105
- scroll: scrollRef
106
+ scroll: scrollRef,
107
+ isMouseDownFromTrigger: isMouseDownFromTriggerRef
106
108
  }),
107
109
  []
108
110
  // refs are stable references, no dependencies needed
@@ -232,6 +234,7 @@ var SelectComponent = memo(function SelectComponent2(props) {
232
234
  } else {
233
235
  refs.allowSelect.current = false;
234
236
  refs.allowMouseUp.current = true;
237
+ refs.isMouseDownFromTrigger.current = false;
235
238
  }
236
239
  }, [isControlledOpen]);
237
240
  const { handleArrowScroll, handleArrowHide, scrollProps } = useMenuScroll({
@@ -319,6 +322,13 @@ var SelectComponent = memo(function SelectComponent2(props) {
319
322
  },
320
323
  onMouseUp: () => {
321
324
  if (!refs.allowMouseUp.current || customActive) return;
325
+ if (refs.isMouseDownFromTrigger.current) {
326
+ refs.isMouseDownFromTrigger.current = false;
327
+ if (!isDisabled) {
328
+ handleSelect(currentSelectableIndex);
329
+ }
330
+ return;
331
+ }
322
332
  if (refs.allowSelect.current) {
323
333
  handleSelect(currentSelectableIndex);
324
334
  }
@@ -363,6 +373,38 @@ var SelectComponent = memo(function SelectComponent2(props) {
363
373
  size: sizeProp
364
374
  });
365
375
  }, [triggerElement, isControlledOpen, sizeProp]);
376
+ const handleTouchStart = useEventCallback(() => {
377
+ setTouch(true);
378
+ });
379
+ const handleMouseDown = useEventCallback(() => {
380
+ refs.isMouseDownFromTrigger.current = true;
381
+ });
382
+ const handlePointerMove = useEventCallback(({ pointerType }) => {
383
+ if (pointerType !== "touch") {
384
+ setTouch(false);
385
+ }
386
+ });
387
+ const slotProps = useMemo(() => {
388
+ return {
389
+ "aria-haspopup": "listbox",
390
+ "aria-expanded": isControlledOpen,
391
+ "aria-controls": menuId,
392
+ ...getReferenceProps({
393
+ disabled,
394
+ onTouchStart: handleTouchStart,
395
+ onMouseDown: handleMouseDown,
396
+ onPointerMove: handlePointerMove
397
+ })
398
+ };
399
+ }, [
400
+ isControlledOpen,
401
+ menuId,
402
+ getReferenceProps,
403
+ disabled,
404
+ handleTouchStart,
405
+ handleMouseDown,
406
+ handlePointerMove
407
+ ]);
366
408
  if (!triggerElement || !contentElement) {
367
409
  console.error("Select requires both Select.Trigger and Select.Content components as children");
368
410
  return null;
@@ -372,20 +414,7 @@ var SelectComponent = memo(function SelectComponent2(props) {
372
414
  Slot,
373
415
  {
374
416
  ref: floating.refs.setReference,
375
- "aria-haspopup": "listbox",
376
- "aria-expanded": isControlledOpen,
377
- "aria-controls": menuId,
378
- ...getReferenceProps({
379
- disabled,
380
- onTouchStart() {
381
- setTouch(true);
382
- },
383
- onPointerMove({ pointerType }) {
384
- if (pointerType !== "touch") {
385
- setTouch(false);
386
- }
387
- }
388
- }),
417
+ ...slotProps,
389
418
  children: enhancedTriggerElement
390
419
  }
391
420
  ),
@@ -399,6 +428,9 @@ var SelectComponent = memo(function SelectComponent2(props) {
399
428
  {
400
429
  lockScroll: !touch,
401
430
  className: tcx("z-menu", focusManagerProps.modal ? "" : "pointer-events-none"),
431
+ onMouseUp: () => {
432
+ refs.isMouseDownFromTrigger.current = false;
433
+ },
402
434
  children: /* @__PURE__ */ jsx(
403
435
  FloatingFocusManager,
404
436
  {
@@ -94,6 +94,7 @@ const SelectComponent = memo(function SelectComponent2(props) {
94
94
  const allowMouseUpRef = useRef(true);
95
95
  const selectTimeoutRef = useRef();
96
96
  const scrollRef = useRef(null);
97
+ const isMouseDownFromTriggerRef = useRef(false);
97
98
  const refs = useMemo(
98
99
  () => ({
99
100
  list: listRef,
@@ -102,7 +103,8 @@ const SelectComponent = memo(function SelectComponent2(props) {
102
103
  allowSelect: allowSelectRef,
103
104
  allowMouseUp: allowMouseUpRef,
104
105
  selectTimeout: selectTimeoutRef,
105
- scroll: scrollRef
106
+ scroll: scrollRef,
107
+ isMouseDownFromTrigger: isMouseDownFromTriggerRef
106
108
  }),
107
109
  []
108
110
  // refs are stable references, no dependencies needed
@@ -232,6 +234,7 @@ const SelectComponent = memo(function SelectComponent2(props) {
232
234
  } else {
233
235
  refs.allowSelect.current = false;
234
236
  refs.allowMouseUp.current = true;
237
+ refs.isMouseDownFromTrigger.current = false;
235
238
  }
236
239
  }, [isControlledOpen]);
237
240
  const { handleArrowScroll, handleArrowHide, scrollProps } = useMenuScroll({
@@ -319,6 +322,13 @@ const SelectComponent = memo(function SelectComponent2(props) {
319
322
  },
320
323
  onMouseUp: () => {
321
324
  if (!refs.allowMouseUp.current || customActive) return;
325
+ if (refs.isMouseDownFromTrigger.current) {
326
+ refs.isMouseDownFromTrigger.current = false;
327
+ if (!isDisabled) {
328
+ handleSelect(currentSelectableIndex);
329
+ }
330
+ return;
331
+ }
322
332
  if (refs.allowSelect.current) {
323
333
  handleSelect(currentSelectableIndex);
324
334
  }
@@ -363,6 +373,38 @@ const SelectComponent = memo(function SelectComponent2(props) {
363
373
  size: sizeProp
364
374
  });
365
375
  }, [triggerElement, isControlledOpen, sizeProp]);
376
+ const handleTouchStart = useEventCallback(() => {
377
+ setTouch(true);
378
+ });
379
+ const handleMouseDown = useEventCallback(() => {
380
+ refs.isMouseDownFromTrigger.current = true;
381
+ });
382
+ const handlePointerMove = useEventCallback(({ pointerType }) => {
383
+ if (pointerType !== "touch") {
384
+ setTouch(false);
385
+ }
386
+ });
387
+ const slotProps = useMemo(() => {
388
+ return {
389
+ "aria-haspopup": "listbox",
390
+ "aria-expanded": isControlledOpen,
391
+ "aria-controls": menuId,
392
+ ...getReferenceProps({
393
+ disabled,
394
+ onTouchStart: handleTouchStart,
395
+ onMouseDown: handleMouseDown,
396
+ onPointerMove: handlePointerMove
397
+ })
398
+ };
399
+ }, [
400
+ isControlledOpen,
401
+ menuId,
402
+ getReferenceProps,
403
+ disabled,
404
+ handleTouchStart,
405
+ handleMouseDown,
406
+ handlePointerMove
407
+ ]);
366
408
  if (!triggerElement || !contentElement) {
367
409
  console.error("Select requires both Select.Trigger and Select.Content components as children");
368
410
  return null;
@@ -372,20 +414,7 @@ const SelectComponent = memo(function SelectComponent2(props) {
372
414
  Slot,
373
415
  {
374
416
  ref: floating.refs.setReference,
375
- "aria-haspopup": "listbox",
376
- "aria-expanded": isControlledOpen,
377
- "aria-controls": menuId,
378
- ...getReferenceProps({
379
- disabled,
380
- onTouchStart() {
381
- setTouch(true);
382
- },
383
- onPointerMove({ pointerType }) {
384
- if (pointerType !== "touch") {
385
- setTouch(false);
386
- }
387
- }
388
- }),
417
+ ...slotProps,
389
418
  children: enhancedTriggerElement
390
419
  }
391
420
  ),
@@ -399,6 +428,9 @@ const SelectComponent = memo(function SelectComponent2(props) {
399
428
  {
400
429
  lockScroll: !touch,
401
430
  className: tcx("z-menu", focusManagerProps.modal ? "" : "pointer-events-none"),
431
+ onMouseUp: () => {
432
+ refs.isMouseDownFromTrigger.current = false;
433
+ },
402
434
  children: /* @__PURE__ */ jsx(
403
435
  FloatingFocusManager,
404
436
  {
@@ -1,25 +1,21 @@
1
- import { default as React } from 'react';
1
+ import * as React from 'react';
2
+
2
3
  interface SlotProps extends React.HTMLAttributes<HTMLElement> {
3
4
  children?: React.ReactNode;
4
5
  }
5
6
  /**
6
- * 优化的 Slot 组件实现
7
+ * Slot component - Lightweight implementation
7
8
  *
8
- * 相比 @radix-ui/react-slot 的性能优化:
9
- * 1. 使用 useMemo 缓存 children 处理结果
10
- * 2. 简化 props 合并逻辑
11
- * 3. 避免不必要的深度遍历
12
- * 4. 更好的类型安全
9
+ * Based on @radix-ui/react-slot design, used for asChild pattern prop forwarding
10
+ * Performance optimization should be done at the consumer level (e.g., useMemo to cache props)
13
11
  */
14
12
  declare const Slot: React.ForwardRefExoticComponent<SlotProps & React.RefAttributes<HTMLElement>>;
15
13
  /**
16
- * Hook 版本的 Slot 逻辑
17
- * 用于需要更细粒度控制的场景
14
+ * Hook version of Slot logic
18
15
  */
19
16
  declare function useSlot(children: React.ReactNode, slotProps: Record<string, unknown>, forwardedRef?: React.Ref<unknown>): string | number | boolean | React.ReactElement<any, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined;
20
17
  /**
21
- * 性能优化的 asChild 模式 Hook
22
- * 用于替代 `const Component = asChild ? Slot : "button"` 模式
18
+ * asChild 模式 Hook
23
19
  */
24
20
  declare function useAsChild<T extends React.ElementType = "button">(asChild: boolean | undefined, defaultElement: T): T | typeof Slot;
25
21
 
@@ -1,68 +1,57 @@
1
- import React__default, { forwardRef, useMemo } from "react";
1
+ import * as React from "react";
2
+ import { forwardRef } from "react";
2
3
  import { jsx, Fragment } from "react/jsx-runtime";
3
4
  var Slot = forwardRef(
4
5
  ({ children, ...slotProps }, forwardedRef) => {
5
- const slottedChild = useMemo(() => {
6
- if (!React__default.isValidElement(children)) {
7
- return children;
8
- }
9
- const childRef = children.ref;
6
+ if (React.isValidElement(children)) {
7
+ const childrenRef = getElementRef(children);
10
8
  const mergedProps = mergeProps(slotProps, children.props);
11
- return React__default.cloneElement(children, {
9
+ return React.cloneElement(children, {
12
10
  ...mergedProps,
13
- ref: forwardedRef ? composeRefs(forwardedRef, childRef) : childRef
11
+ ref: forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef
14
12
  });
15
- }, [children, slotProps, forwardedRef]);
16
- return /* @__PURE__ */ jsx(Fragment, { children: slottedChild });
13
+ }
14
+ return /* @__PURE__ */ jsx(Fragment, { children });
17
15
  }
18
16
  );
19
17
  Slot.displayName = "Slot";
20
18
  var SlotClone = forwardRef(
21
19
  ({ children, ...slotProps }, forwardedRef) => {
22
- const slottedChild = useMemo(() => {
23
- if (!React__default.isValidElement(children)) {
24
- return children;
25
- }
26
- const childRef = children.ref;
20
+ if (React.isValidElement(children)) {
21
+ const childrenRef = getElementRef(children);
27
22
  const mergedProps = mergeProps(slotProps, children.props);
28
- return React__default.cloneElement(children, {
23
+ return React.cloneElement(children, {
29
24
  ...mergedProps,
30
- ref: forwardedRef ? composeRefs(forwardedRef, childRef) : childRef
25
+ ref: forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef
31
26
  });
32
- }, [children, slotProps, forwardedRef]);
33
- return /* @__PURE__ */ jsx(Fragment, { children: slottedChild });
27
+ }
28
+ return /* @__PURE__ */ jsx(Fragment, { children });
34
29
  }
35
30
  );
36
31
  SlotClone.displayName = "SlotClone";
37
32
  function mergeProps(slotProps, childProps) {
38
33
  const overrideProps = { ...childProps };
39
- if (slotProps.className && childProps.className) {
40
- overrideProps.className = `${slotProps.className} ${childProps.className}`;
41
- } else if (slotProps.className) {
42
- overrideProps.className = slotProps.className;
43
- }
44
- if (slotProps.style && childProps.style) {
45
- overrideProps.style = { ...slotProps.style, ...childProps.style };
46
- } else if (slotProps.style) {
47
- overrideProps.style = slotProps.style;
48
- }
49
- for (const propName in slotProps) {
50
- if (propName.startsWith("on") && typeof slotProps[propName] === "function") {
51
- const slotHandler = slotProps[propName];
52
- const childHandler = childProps[propName];
53
- if (childHandler && typeof childHandler === "function") {
34
+ for (const propName in childProps) {
35
+ const slotPropValue = slotProps[propName];
36
+ const childPropValue = childProps[propName];
37
+ const isHandler = /^on[A-Z]/.test(propName);
38
+ if (isHandler) {
39
+ if (slotPropValue && childPropValue) {
54
40
  overrideProps[propName] = (...args) => {
55
- childHandler(...args);
56
- slotHandler(...args);
41
+ const result = childPropValue(...args);
42
+ slotPropValue(...args);
43
+ return result;
57
44
  };
58
- } else {
59
- overrideProps[propName] = slotHandler;
45
+ } else if (slotPropValue) {
46
+ overrideProps[propName] = slotPropValue;
60
47
  }
61
- } else if (propName !== "className" && propName !== "style") {
62
- overrideProps[propName] = slotProps[propName];
48
+ } else if (propName === "style") {
49
+ overrideProps[propName] = { ...slotPropValue, ...childPropValue };
50
+ } else if (propName === "className") {
51
+ overrideProps[propName] = [slotPropValue, childPropValue].filter(Boolean).join(" ");
63
52
  }
64
53
  }
65
- return overrideProps;
54
+ return { ...slotProps, ...overrideProps };
66
55
  }
67
56
  function composeRefs(...refs) {
68
57
  return (node) => {
@@ -70,12 +59,25 @@ function composeRefs(...refs) {
70
59
  if (typeof ref === "function") {
71
60
  ref(node);
72
61
  } else if (ref != null) {
73
- const mutableRef = ref;
74
- mutableRef.current = node;
62
+ ref.current = node;
75
63
  }
76
64
  });
77
65
  };
78
66
  }
67
+ function getElementRef(element) {
68
+ var _a, _b;
69
+ let getter = (_a = Object.getOwnPropertyDescriptor(element.props, "ref")) == null ? void 0 : _a.get;
70
+ let mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
71
+ if (mayWarn) {
72
+ return element.ref;
73
+ }
74
+ getter = (_b = Object.getOwnPropertyDescriptor(element, "ref")) == null ? void 0 : _b.get;
75
+ mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
76
+ if (mayWarn) {
77
+ return element.props.ref;
78
+ }
79
+ return element.props.ref || element.ref;
80
+ }
79
81
  export {
80
82
  Slot
81
83
  };
@@ -1,4 +1,4 @@
1
- import { default as React } from 'react';
1
+ import * as React from "react";
2
2
  export interface SlotProps extends React.HTMLAttributes<HTMLElement> {
3
3
  children?: React.ReactNode;
4
4
  }
@@ -6,28 +6,22 @@ interface SlotCloneProps {
6
6
  children: React.ReactNode;
7
7
  }
8
8
  /**
9
- * 优化的 Slot 组件实现
9
+ * Slot component - Lightweight implementation
10
10
  *
11
- * 相比 @radix-ui/react-slot 的性能优化:
12
- * 1. 使用 useMemo 缓存 children 处理结果
13
- * 2. 简化 props 合并逻辑
14
- * 3. 避免不必要的深度遍历
15
- * 4. 更好的类型安全
11
+ * Based on @radix-ui/react-slot design, used for asChild pattern prop forwarding
12
+ * Performance optimization should be done at the consumer level (e.g., useMemo to cache props)
16
13
  */
17
14
  export declare const Slot: React.ForwardRefExoticComponent<SlotProps & React.RefAttributes<HTMLElement>>;
18
15
  /**
19
- * SlotClone 组件 - 用于深度克隆
20
- * 当需要处理嵌套结构时使用
16
+ * SlotClone 组件
21
17
  */
22
18
  export declare const SlotClone: React.ForwardRefExoticComponent<SlotCloneProps & React.RefAttributes<HTMLElement>>;
23
19
  /**
24
- * Hook 版本的 Slot 逻辑
25
- * 用于需要更细粒度控制的场景
20
+ * Hook version of Slot logic
26
21
  */
27
22
  export declare function useSlot(children: React.ReactNode, slotProps: Record<string, unknown>, forwardedRef?: React.Ref<unknown>): string | number | boolean | React.ReactElement<any, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined;
28
23
  /**
29
- * 性能优化的 asChild 模式 Hook
30
- * 用于替代 `const Component = asChild ? Slot : "button"` 模式
24
+ * asChild 模式 Hook
31
25
  */
32
26
  export declare function useAsChild<T extends React.ElementType = "button">(asChild: boolean | undefined, defaultElement: T): T | typeof Slot;
33
27
  export {};
@@ -1,68 +1,57 @@
1
1
  import { jsx, Fragment } from "react/jsx-runtime";
2
- import React__default, { forwardRef, useMemo } from "react";
2
+ import * as React from "react";
3
+ import { forwardRef, useMemo } from "react";
3
4
  const Slot = forwardRef(
4
5
  ({ children, ...slotProps }, forwardedRef) => {
5
- const slottedChild = useMemo(() => {
6
- if (!React__default.isValidElement(children)) {
7
- return children;
8
- }
9
- const childRef = children.ref;
6
+ if (React.isValidElement(children)) {
7
+ const childrenRef = getElementRef(children);
10
8
  const mergedProps = mergeProps(slotProps, children.props);
11
- return React__default.cloneElement(children, {
9
+ return React.cloneElement(children, {
12
10
  ...mergedProps,
13
- ref: forwardedRef ? composeRefs(forwardedRef, childRef) : childRef
11
+ ref: forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef
14
12
  });
15
- }, [children, slotProps, forwardedRef]);
16
- return /* @__PURE__ */ jsx(Fragment, { children: slottedChild });
13
+ }
14
+ return /* @__PURE__ */ jsx(Fragment, { children });
17
15
  }
18
16
  );
19
17
  Slot.displayName = "Slot";
20
18
  const SlotClone = forwardRef(
21
19
  ({ children, ...slotProps }, forwardedRef) => {
22
- const slottedChild = useMemo(() => {
23
- if (!React__default.isValidElement(children)) {
24
- return children;
25
- }
26
- const childRef = children.ref;
20
+ if (React.isValidElement(children)) {
21
+ const childrenRef = getElementRef(children);
27
22
  const mergedProps = mergeProps(slotProps, children.props);
28
- return React__default.cloneElement(children, {
23
+ return React.cloneElement(children, {
29
24
  ...mergedProps,
30
- ref: forwardedRef ? composeRefs(forwardedRef, childRef) : childRef
25
+ ref: forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef
31
26
  });
32
- }, [children, slotProps, forwardedRef]);
33
- return /* @__PURE__ */ jsx(Fragment, { children: slottedChild });
27
+ }
28
+ return /* @__PURE__ */ jsx(Fragment, { children });
34
29
  }
35
30
  );
36
31
  SlotClone.displayName = "SlotClone";
37
32
  function mergeProps(slotProps, childProps) {
38
33
  const overrideProps = { ...childProps };
39
- if (slotProps.className && childProps.className) {
40
- overrideProps.className = `${slotProps.className} ${childProps.className}`;
41
- } else if (slotProps.className) {
42
- overrideProps.className = slotProps.className;
43
- }
44
- if (slotProps.style && childProps.style) {
45
- overrideProps.style = { ...slotProps.style, ...childProps.style };
46
- } else if (slotProps.style) {
47
- overrideProps.style = slotProps.style;
48
- }
49
- for (const propName in slotProps) {
50
- if (propName.startsWith("on") && typeof slotProps[propName] === "function") {
51
- const slotHandler = slotProps[propName];
52
- const childHandler = childProps[propName];
53
- if (childHandler && typeof childHandler === "function") {
34
+ for (const propName in childProps) {
35
+ const slotPropValue = slotProps[propName];
36
+ const childPropValue = childProps[propName];
37
+ const isHandler = /^on[A-Z]/.test(propName);
38
+ if (isHandler) {
39
+ if (slotPropValue && childPropValue) {
54
40
  overrideProps[propName] = (...args) => {
55
- childHandler(...args);
56
- slotHandler(...args);
41
+ const result = childPropValue(...args);
42
+ slotPropValue(...args);
43
+ return result;
57
44
  };
58
- } else {
59
- overrideProps[propName] = slotHandler;
45
+ } else if (slotPropValue) {
46
+ overrideProps[propName] = slotPropValue;
60
47
  }
61
- } else if (propName !== "className" && propName !== "style") {
62
- overrideProps[propName] = slotProps[propName];
48
+ } else if (propName === "style") {
49
+ overrideProps[propName] = { ...slotPropValue, ...childPropValue };
50
+ } else if (propName === "className") {
51
+ overrideProps[propName] = [slotPropValue, childPropValue].filter(Boolean).join(" ");
63
52
  }
64
53
  }
65
- return overrideProps;
54
+ return { ...slotProps, ...overrideProps };
66
55
  }
67
56
  function composeRefs(...refs) {
68
57
  return (node) => {
@@ -70,22 +59,35 @@ function composeRefs(...refs) {
70
59
  if (typeof ref === "function") {
71
60
  ref(node);
72
61
  } else if (ref != null) {
73
- const mutableRef = ref;
74
- mutableRef.current = node;
62
+ ref.current = node;
75
63
  }
76
64
  });
77
65
  };
78
66
  }
67
+ function getElementRef(element) {
68
+ var _a, _b;
69
+ let getter = (_a = Object.getOwnPropertyDescriptor(element.props, "ref")) == null ? void 0 : _a.get;
70
+ let mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
71
+ if (mayWarn) {
72
+ return element.ref;
73
+ }
74
+ getter = (_b = Object.getOwnPropertyDescriptor(element, "ref")) == null ? void 0 : _b.get;
75
+ mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
76
+ if (mayWarn) {
77
+ return element.props.ref;
78
+ }
79
+ return element.props.ref || element.ref;
80
+ }
79
81
  function useSlot(children, slotProps, forwardedRef) {
80
82
  return useMemo(() => {
81
- if (!React__default.isValidElement(children)) {
83
+ if (!React.isValidElement(children)) {
82
84
  return children;
83
85
  }
84
- const childRef = children.ref;
86
+ const childrenRef = getElementRef(children);
85
87
  const mergedProps = mergeProps(slotProps, children.props);
86
- return React__default.cloneElement(children, {
88
+ return React.cloneElement(children, {
87
89
  ...mergedProps,
88
- ref: forwardedRef ? composeRefs(forwardedRef, childRef) : childRef
90
+ ref: forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef
89
91
  });
90
92
  }, [children, slotProps, forwardedRef]);
91
93
  }
@@ -184,12 +184,17 @@ var TooltipTrigger = forwardRef(
184
184
  function TooltipTrigger2({ children, ...props }, propRef) {
185
185
  const state = useTooltipState();
186
186
  const ref = useMergeRefs([state.refs.setReference, propRef]);
187
+ const slotProps = useMemo(() => {
188
+ return {
189
+ ...state.disabled && { disabled: true },
190
+ ...state.getReferenceProps(props)
191
+ };
192
+ }, [state.disabled, state.getReferenceProps, props]);
187
193
  return /* @__PURE__ */ jsx(
188
194
  Slot,
189
195
  {
190
196
  ref,
191
- ...state.disabled && { disabled: true },
192
- ...state.getReferenceProps(props),
197
+ ...slotProps,
193
198
  children
194
199
  }
195
200
  );
@@ -1,18 +1,23 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { Slot } from "../../../slot/dist/index.js";
3
3
  import { useMergeRefs } from "@floating-ui/react";
4
- import { forwardRef } from "react";
4
+ import { forwardRef, useMemo } from "react";
5
5
  import { useTooltipState } from "../context/tooltip-context.js";
6
6
  const TooltipTrigger = forwardRef(
7
7
  function TooltipTrigger2({ children, ...props }, propRef) {
8
8
  const state = useTooltipState();
9
9
  const ref = useMergeRefs([state.refs.setReference, propRef]);
10
+ const slotProps = useMemo(() => {
11
+ return {
12
+ ...state.disabled && { disabled: true },
13
+ ...state.getReferenceProps(props)
14
+ };
15
+ }, [state.disabled, state.getReferenceProps, props]);
10
16
  return /* @__PURE__ */ jsx(
11
17
  Slot,
12
18
  {
13
19
  ref,
14
- ...state.disabled && { disabled: true },
15
- ...state.getReferenceProps(props),
20
+ ...slotProps,
16
21
  children
17
22
  }
18
23
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@choice-ui/react",
3
- "version": "1.5.5",
3
+ "version": "1.5.7",
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",