@choice-ui/react 1.6.2 → 1.6.4

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,8 @@
1
1
  import { default as React__default } from 'react';
2
2
  import { Locale, Quarter as Quarter$1, Day, isSameDay, isSameMonth, isSameYear, addMonths, startOfMonth, endOfMonth, startOfWeek, endOfWeek } from 'date-fns';
3
3
  import { TextFieldProps } from '../../text-field/src';
4
+ import { DropdownProps } from '../../dropdown/src';
5
+ import { MenuTrigger } from '../../menus/src';
4
6
  import { TZDate } from '@date-fns/tz';
5
7
  import { Locale as Locale$1 } from 'date-fns/locale';
6
8
  import { PressMoveProps } from '../../../../../shared/src';
@@ -567,16 +569,21 @@ interface DateRangeInputProps extends Omit<TextFieldProps, "value" | "onChange"
567
569
  }
568
570
  declare const DateRangeInput: (props: DateRangeInputProps) => react_jsx_runtime.JSX.Element;
569
571
 
570
- interface TimeCalendarProps extends BaseTimeProps, StepProps {
572
+ interface TimeCalendarComponentType extends React__default.MemoExoticComponent<React__default.FC<TimeCalendarProps>> {
573
+ Trigger: typeof MenuTrigger;
574
+ }
575
+ interface TimeCalendarProps extends BaseTimeProps, StepProps, Pick<DropdownProps, "offset" | "placement" | "matchTriggerWidth" | "variant" | "readOnly"> {
571
576
  children?: React__default.ReactNode;
572
- /** Custom class name */
573
577
  className?: string;
574
- /** Hour step, default 1 hour */
575
578
  hourStep?: number;
576
- /** Minute step, default 15 minutes */
577
579
  minuteStep?: number;
580
+ open?: boolean;
581
+ onOpenChange?: (open: boolean) => void;
582
+ closeOnSelect?: boolean;
583
+ triggerRef?: React__default.RefObject<HTMLElement>;
584
+ triggerSelector?: string;
578
585
  }
579
- declare const TimeCalendar: React__default.NamedExoticComponent<TimeCalendarProps>;
586
+ declare const TimeCalendar: TimeCalendarComponentType;
580
587
 
581
588
  interface TimeInputProps extends Omit<TextFieldProps, "value" | "onChange" | "format" | "defaultValue" | "step">, BaseTimeProps, StepProps, TimeInteractionProps {
582
589
  prefixElement?: React__default.ReactNode;
@@ -10,7 +10,8 @@ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
10
10
  import { IconButton } from "../../icon-button/dist/index.js";
11
11
  import { FieldTypeDate, Undo, ChevronUpSmall, ChevronLeftSmall, ChevronDownSmall, ChevronRightSmall, Check, Clock } from "@choiceform/icons-react";
12
12
  import { TextField } from "../../text-field/dist/index.js";
13
- import { Menus } from "../../menus/dist/index.js";
13
+ import { Dropdown as Dropdown2 } from "../../dropdown/dist/index.js";
14
+ import { MenuTrigger } from "../../menus/dist/index.js";
14
15
  import { tcx, tcv } from "../../../shared/utils/tcx/tcx.js";
15
16
  import { useMergedValue } from "../../../shared/hooks/use-merged-value/use-merged-value.js";
16
17
  import { useModifierKeys } from "../../../shared/hooks/use-modifier-keys/use-modifier-keys.js";
@@ -1221,54 +1222,71 @@ function parseCompositeFormat(input, format10, locale) {
1221
1222
  }
1222
1223
  }
1223
1224
  function removeWeekdayFromFormat(format10) {
1224
- return format10.replace(/\s*[eEic]{1,4}\s*/g, "").replace(/\s+/g, " ").replace(/\s*([,,、])\s*/g, "$1").trim();
1225
+ return format10.replace(/\s*[eEic]{1,4}\s*/g, "").replace(/MMM(?!M)/g, "M月").replace(/\s+/g, " ").replace(/\s*([,,、])\s*/g, "$1").trim();
1225
1226
  }
1226
1227
  function removeWeekdayFromInput(input, locale) {
1227
1228
  try {
1228
- const weekdayNames = generateWeekdayNames2(locale);
1229
- if (weekdayNames.length === 0) {
1230
- return input;
1229
+ const { longNames, shortNames } = generateWeekdayNames2(locale);
1230
+ let result = input;
1231
+ if (longNames.length > 0) {
1232
+ const sortedLongNames = longNames.sort((a, b) => b.length - a.length);
1233
+ const longPattern = new RegExp(`\\s*(${sortedLongNames.join("|")})\\s*`, "gi");
1234
+ result = result.replace(longPattern, " ");
1235
+ }
1236
+ if (shortNames.length > 0) {
1237
+ const sortedShortNames = shortNames.sort((a, b) => b.length - a.length);
1238
+ const singleCharNames = sortedShortNames.filter((name) => name.length === 1);
1239
+ const multiCharNames = sortedShortNames.filter((name) => name.length > 1);
1240
+ if (multiCharNames.length > 0) {
1241
+ const multiPattern = new RegExp(`\\s*(${multiCharNames.join("|")})\\s*`, "gi");
1242
+ result = result.replace(multiPattern, " ");
1243
+ }
1244
+ if (singleCharNames.length > 0) {
1245
+ const singlePattern = new RegExp(
1246
+ `([((「【])(${singleCharNames.join("|")})([))」】])`,
1247
+ "gi"
1248
+ );
1249
+ result = result.replace(singlePattern, "$1$3");
1250
+ }
1231
1251
  }
1232
- const sortedNames = weekdayNames.sort((a, b) => b.length - a.length);
1233
- const pattern = new RegExp(`\\s*(${sortedNames.join("|")})\\s*`, "gi");
1234
- return input.replace(pattern, "").replace(/\s+/g, " ").trim();
1252
+ return result.replace(/\s+/g, " ").trim();
1235
1253
  } catch {
1236
1254
  return input.replace(/\s*(星期[一二三四五六日天]|周[一二三四五六日天])\s*/g, "").replace(/\s+/g, " ").trim();
1237
1255
  }
1238
1256
  }
1239
1257
  function generateWeekdayNames2(locale) {
1240
- const names = [];
1258
+ const longNames = [];
1259
+ const shortNames = [];
1241
1260
  try {
1242
1261
  const baseDate = new Date(2024, 0, 7);
1243
1262
  for (let i = 0; i < 7; i++) {
1244
1263
  const currentDate = new Date(baseDate);
1245
1264
  currentDate.setDate(baseDate.getDate() + i);
1246
1265
  const fullName = format(currentDate, "eeee", { locale });
1247
- if (fullName && fullName !== "eeee") {
1248
- names.push(fullName);
1266
+ if (fullName && fullName !== "eeee" && !fullName.includes("e")) {
1267
+ longNames.push(fullName);
1249
1268
  }
1250
1269
  const shortName = format(currentDate, "eee", { locale });
1251
- if (shortName && shortName !== "eee" && shortName !== fullName) {
1252
- names.push(shortName);
1253
- }
1254
- const veryShortName = format(currentDate, "ee", { locale });
1255
- if (veryShortName && veryShortName !== "ee" && veryShortName !== shortName && veryShortName !== fullName) {
1256
- names.push(veryShortName);
1270
+ if (shortName && shortName !== "eee" && shortName !== fullName && !shortName.includes("e")) {
1271
+ shortNames.push(shortName);
1257
1272
  }
1258
1273
  const localeKey = getLocaleKey(locale);
1259
- if (localeKey === "zh") {
1260
- const weekFormat = format(currentDate, "eeee", { locale }).replace("星期", "周");
1274
+ if (localeKey === "zh" && fullName) {
1275
+ const weekFormat = fullName.replace("星期", "周");
1261
1276
  if (weekFormat !== fullName) {
1262
- names.push(weekFormat);
1277
+ shortNames.push(weekFormat);
1263
1278
  }
1264
1279
  }
1265
1280
  }
1266
- return [...new Set(names)].filter(
1267
- (name) => name && name.length > 0 && !name.includes("e") && // 过滤掉格式化失败的情况
1268
- name !== "Invalid Date"
1281
+ const filterNames = (names) => [...new Set(names)].filter(
1282
+ (name) => name && name.length > 0 && !/^\d+$/.test(name) && name !== "Invalid Date"
1269
1283
  );
1284
+ return {
1285
+ longNames: filterNames(longNames),
1286
+ shortNames: filterNames(shortNames)
1287
+ };
1270
1288
  } catch {
1271
- return [];
1289
+ return { longNames: [], shortNames: [] };
1272
1290
  }
1273
1291
  }
1274
1292
  function parseInvalidFormattedDate(input, targetFormat, locale) {
@@ -1715,7 +1733,7 @@ var generateTimeOptions = (format10, step = 15) => {
1715
1733
  const minutes = i % 60;
1716
1734
  if (is12Hour) {
1717
1735
  const displayHour = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours;
1718
- const ampm = hours < 12 ? "AM" : "PM";
1736
+ const ampm = hours < 12 ? "am" : "pm";
1719
1737
  const value = `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
1720
1738
  const label = `${displayHour}:${minutes.toString().padStart(2, "0")} ${ampm}`;
1721
1739
  options.push({ value, label });
@@ -3034,7 +3052,7 @@ var DateInput = forwardRef((props, ref) => {
3034
3052
  );
3035
3053
  });
3036
3054
  DateInput.displayName = "DateInput";
3037
- var TimeCalendar = memo(function TimeCalendar2(props) {
3055
+ var TimeCalendarBase = memo(function TimeCalendar(props) {
3038
3056
  const {
3039
3057
  value,
3040
3058
  defaultValue,
@@ -3044,16 +3062,25 @@ var TimeCalendar = memo(function TimeCalendar2(props) {
3044
3062
  className,
3045
3063
  children,
3046
3064
  readOnly = false,
3065
+ open: controlledOpen,
3066
+ onOpenChange,
3067
+ closeOnSelect = true,
3068
+ triggerRef,
3069
+ triggerSelector,
3070
+ offset,
3071
+ placement,
3072
+ matchTriggerWidth,
3073
+ variant,
3047
3074
  ...rest
3048
3075
  } = props;
3049
- const scrollRef = useRef(null);
3050
- const elementsRef = useRef([]);
3051
- const customElementRef = useRef(null);
3052
- const hasInitialScrolled = useRef(false);
3053
- const lastSelectedIndexRef = useRef(null);
3054
- const isInternalOperationRef = useRef(false);
3055
- const [activeIndex, setActiveIndex] = useState(null);
3056
- const [isScrolling, setIsScrolling] = useState(false);
3076
+ const [internalOpen, setInternalOpen] = useState(false);
3077
+ const isOpen = controlledOpen ?? internalOpen;
3078
+ const handleOpenChange = useEventCallback((newOpen) => {
3079
+ if (controlledOpen === void 0) {
3080
+ setInternalOpen(newOpen);
3081
+ }
3082
+ onOpenChange == null ? void 0 : onOpenChange(newOpen);
3083
+ });
3057
3084
  const [innerValue, setValue] = useMergedValue({
3058
3085
  value,
3059
3086
  defaultValue,
@@ -3069,7 +3096,7 @@ var TimeCalendar = memo(function TimeCalendar2(props) {
3069
3096
  const formatTo12Hour = useCallback((timeStr) => {
3070
3097
  const [hour, minute] = timeStr.split(":").map(Number);
3071
3098
  const displayHour = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
3072
- const ampm = hour < 12 ? "AM" : "PM";
3099
+ const ampm = hour < 12 ? "am" : "pm";
3073
3100
  return `${displayHour}:${minute.toString().padStart(2, "0")} ${ampm}`;
3074
3101
  }, []);
3075
3102
  const customTimeOption = useMemo(() => {
@@ -3096,222 +3123,95 @@ var TimeCalendar = memo(function TimeCalendar2(props) {
3096
3123
  },
3097
3124
  [timeFormat]
3098
3125
  );
3099
- const selectedIndex = useMemo(() => {
3100
- if (!normalizedTimeString) return null;
3101
- const index = timeOptions.findIndex((option) => option.value === normalizedTimeString);
3102
- return index === -1 ? -1 : index;
3103
- }, [normalizedTimeString, timeOptions]);
3104
3126
  const needsDivider = useMemo(() => {
3105
3127
  const is12Hour = timeFormat.toLowerCase().includes("a") || timeFormat === "12h";
3106
3128
  if (!is12Hour) return () => false;
3107
3129
  return (index) => {
3108
- return index > 0 && timeOptions[index].label.includes("PM") && timeOptions[index - 1].label.includes("AM");
3130
+ return index > 0 && timeOptions[index].label.toLowerCase().includes("pm") && timeOptions[index - 1].label.toLowerCase().includes("am");
3109
3131
  };
3110
3132
  }, [timeFormat, timeOptions]);
3111
3133
  const createPrefixElement = useCallback((isSelected) => {
3112
3134
  return isSelected ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(Fragment, {});
3113
3135
  }, []);
3114
- const scrollTimeoutRef = useRef(null);
3115
- const mousePositionRef = useRef(null);
3116
- const handleScroll = useEventCallback(() => {
3117
- if (!isScrolling) {
3118
- setIsScrolling(true);
3119
- setActiveIndex(null);
3120
- }
3121
- if (scrollTimeoutRef.current) {
3122
- clearTimeout(scrollTimeoutRef.current);
3123
- }
3124
- scrollTimeoutRef.current = setTimeout(() => {
3125
- var _a;
3126
- setIsScrolling(false);
3127
- if (mousePositionRef.current) {
3128
- const elementUnderMouse = document.elementFromPoint(
3129
- mousePositionRef.current.x,
3130
- mousePositionRef.current.y
3131
- );
3132
- if (customElementRef.current && (customElementRef.current === elementUnderMouse || customElementRef.current.contains(elementUnderMouse))) {
3133
- setActiveIndex(-1);
3134
- return;
3135
- }
3136
- const elements = elementsRef.current;
3137
- for (let i = 0; i < elements.length; i++) {
3138
- if (elements[i] && (elements[i] === elementUnderMouse || ((_a = elements[i]) == null ? void 0 : _a.contains(elementUnderMouse)))) {
3139
- setActiveIndex(i);
3140
- break;
3141
- }
3142
- }
3143
- }
3144
- }, 200);
3145
- });
3146
- const handleMouseMove = useEventCallback((event) => {
3147
- mousePositionRef.current = { x: event.clientX, y: event.clientY };
3148
- });
3149
3136
  useEffect(() => {
3150
- return () => {
3151
- if (scrollTimeoutRef.current) {
3152
- clearTimeout(scrollTimeoutRef.current);
3137
+ if (!isOpen || !normalizedTimeString) return;
3138
+ let attempts = 0;
3139
+ const maxAttempts = 10;
3140
+ const scrollToSelected = () => {
3141
+ const selectedItem = document.querySelector(
3142
+ `[data-testid="${normalizedTimeString}"]`
3143
+ );
3144
+ if (selectedItem) {
3145
+ selectedItem.scrollIntoView({ block: "center" });
3146
+ } else if (attempts < maxAttempts) {
3147
+ attempts++;
3148
+ requestAnimationFrame(scrollToSelected);
3153
3149
  }
3154
3150
  };
3155
- }, []);
3156
- useEffect(() => {
3157
- var _a;
3158
- if (selectedIndex === -1) {
3159
- const customElement = customElementRef.current;
3160
- if (!customElement || !scrollRef.current) {
3161
- return;
3162
- }
3163
- const previousSelectedIndex2 = lastSelectedIndexRef.current;
3164
- const isSelectedIndexChanged2 = previousSelectedIndex2 !== selectedIndex;
3165
- lastSelectedIndexRef.current = selectedIndex;
3166
- const shouldScroll2 = !hasInitialScrolled.current || // Initial scrolling
3167
- isSelectedIndexChanged2 && !isInternalOperationRef.current;
3168
- if (shouldScroll2) {
3169
- const isInitialScroll = !hasInitialScrolled.current;
3170
- if (isInitialScroll) {
3171
- scrollRef.current.scrollTo({
3172
- top: 0,
3173
- behavior: "auto"
3174
- });
3175
- } else {
3176
- customElement.scrollIntoView({
3177
- block: "nearest",
3178
- behavior: "smooth"
3179
- });
3180
- }
3181
- if (!hasInitialScrolled.current) {
3182
- hasInitialScrolled.current = true;
3183
- }
3184
- }
3185
- if (isInternalOperationRef.current) {
3186
- isInternalOperationRef.current = false;
3187
- }
3188
- return;
3189
- }
3190
- if (selectedIndex === null || !scrollRef.current || !elementsRef.current[selectedIndex]) {
3191
- return;
3192
- }
3193
- const previousSelectedIndex = lastSelectedIndexRef.current;
3194
- const isSelectedIndexChanged = previousSelectedIndex !== selectedIndex;
3195
- lastSelectedIndexRef.current = selectedIndex;
3196
- const shouldScroll = !hasInitialScrolled.current || // Initial scrolling
3197
- isSelectedIndexChanged && !isInternalOperationRef.current;
3198
- if (shouldScroll) {
3199
- const isInitialScroll = !hasInitialScrolled.current;
3200
- if (isInitialScroll) {
3201
- (_a = elementsRef.current[selectedIndex]) == null ? void 0 : _a.scrollIntoView({
3202
- block: "center",
3203
- behavior: "auto"
3204
- });
3205
- } else {
3206
- const container = scrollRef.current;
3207
- const element = elementsRef.current[selectedIndex];
3208
- if (container && element) {
3209
- const containerRect = container.getBoundingClientRect();
3210
- const elementRect = element.getBoundingClientRect();
3211
- const margin = 8;
3212
- const elementTop = elementRect.top - containerRect.top + container.scrollTop;
3213
- const elementBottom = elementTop + elementRect.height;
3214
- const visibleTop = container.scrollTop + margin;
3215
- const visibleBottom = container.scrollTop + container.clientHeight - margin;
3216
- let targetScrollTop = container.scrollTop;
3217
- if (elementTop < visibleTop) {
3218
- targetScrollTop = elementTop - margin;
3219
- } else if (elementBottom > visibleBottom) {
3220
- targetScrollTop = elementBottom - container.clientHeight + margin;
3221
- }
3222
- if (targetScrollTop !== container.scrollTop) {
3223
- container.scrollTo({
3224
- top: targetScrollTop
3225
- });
3226
- }
3227
- }
3228
- }
3229
- if (!hasInitialScrolled.current) {
3230
- hasInitialScrolled.current = true;
3231
- }
3232
- }
3233
- if (isInternalOperationRef.current) {
3234
- isInternalOperationRef.current = false;
3235
- }
3236
- }, [selectedIndex]);
3151
+ requestAnimationFrame(scrollToSelected);
3152
+ }, [isOpen, normalizedTimeString]);
3237
3153
  const handleTimeSelect = useEventCallback((timeValue) => {
3238
3154
  if (readOnly) return;
3239
- isInternalOperationRef.current = true;
3240
3155
  const dateValue = timeStringToDate(timeValue);
3241
3156
  setValue(dateValue);
3242
- });
3243
- const handleMouseEnter = useEventCallback((index) => {
3244
- if (isScrolling) {
3245
- return;
3157
+ if (closeOnSelect) {
3158
+ handleOpenChange(false);
3246
3159
  }
3247
- setActiveIndex(index);
3248
- });
3249
- const handleMouseLeave = useEventCallback(() => {
3250
- setActiveIndex(null);
3251
- });
3252
- const handleClick = useEventCallback((timeValue) => {
3253
- handleTimeSelect(timeValue);
3254
3160
  });
3255
3161
  return /* @__PURE__ */ jsxs(
3256
- Menus,
3162
+ Dropdown2,
3257
3163
  {
3258
- ref: scrollRef,
3259
- onScroll: handleScroll,
3260
- onMouseLeave: handleMouseLeave,
3261
- onMouseMove: handleMouseMove,
3262
- className,
3263
- "data-testid": "time-calendar-menu",
3164
+ open: isOpen,
3165
+ onOpenChange: handleOpenChange,
3166
+ selection: true,
3167
+ triggerRef,
3168
+ triggerSelector,
3169
+ offset,
3170
+ placement,
3171
+ matchTriggerWidth,
3172
+ variant,
3173
+ readOnly,
3264
3174
  ...rest,
3265
3175
  children: [
3266
- customTimeOption && /* @__PURE__ */ jsxs(Fragment, { children: [
3267
- /* @__PURE__ */ jsx(
3268
- Menus.Item,
3269
- {
3270
- ref: (node) => {
3271
- customElementRef.current = node;
3272
- },
3273
- selected: selectedIndex === -1,
3274
- active: !isScrolling && activeIndex === -1,
3275
- onClick: () => handleClick(customTimeOption.value),
3276
- onMouseEnter: () => handleMouseEnter(-1),
3277
- prefixElement: createPrefixElement(selectedIndex === -1),
3278
- variant: "highlight",
3279
- "data-testid": "custom-time-item",
3280
- children: renderTimeLabel(customTimeOption.label)
3281
- }
3282
- ),
3283
- /* @__PURE__ */ jsx(Menus.Divider, { "data-testid": "custom-time-divider" })
3284
- ] }),
3285
- timeOptions.map((option, index) => {
3286
- const isAmToPmTransition = needsDivider(index);
3287
- const isItemSelected = selectedIndex === index;
3288
- const isItemActive = !isScrolling && activeIndex === index;
3289
- return /* @__PURE__ */ jsxs(React__default.Fragment, { children: [
3290
- isAmToPmTransition && /* @__PURE__ */ jsx(Menus.Divider, { "data-testid": "ampm-divider" }),
3176
+ children,
3177
+ /* @__PURE__ */ jsxs(Dropdown2.Content, { className, children: [
3178
+ customTimeOption && /* @__PURE__ */ jsxs(Fragment, { children: [
3291
3179
  /* @__PURE__ */ jsx(
3292
- Menus.Item,
3180
+ Dropdown2.Item,
3293
3181
  {
3294
- ref: (node) => {
3295
- elementsRef.current[index] = node;
3296
- },
3297
- selected: isItemSelected,
3298
- active: isItemActive,
3299
- onClick: () => handleClick(option.value),
3300
- onMouseEnter: () => handleMouseEnter(index),
3301
- prefixElement: createPrefixElement(isItemSelected),
3302
- variant: "highlight",
3303
- "data-testid": option.value,
3304
- children: renderTimeLabel(option.label)
3182
+ onMouseUp: () => handleTimeSelect(customTimeOption.value),
3183
+ prefixElement: createPrefixElement(normalizedTimeString === customTimeOption.value),
3184
+ "data-testid": "custom-time-item",
3185
+ children: renderTimeLabel(customTimeOption.label)
3305
3186
  }
3306
- )
3307
- ] }, option.value);
3308
- }),
3309
- children
3187
+ ),
3188
+ /* @__PURE__ */ jsx(Dropdown2.Divider, { "data-testid": "custom-time-divider" })
3189
+ ] }),
3190
+ timeOptions.map((option, index) => {
3191
+ const isAmToPmTransition = needsDivider(index);
3192
+ const isSelected = normalizedTimeString === option.value;
3193
+ return /* @__PURE__ */ jsxs(React__default.Fragment, { children: [
3194
+ isAmToPmTransition && /* @__PURE__ */ jsx(Dropdown2.Divider, { "data-testid": "ampm-divider" }),
3195
+ /* @__PURE__ */ jsx(
3196
+ Dropdown2.Item,
3197
+ {
3198
+ onMouseUp: () => handleTimeSelect(option.value),
3199
+ prefixElement: createPrefixElement(isSelected),
3200
+ "data-testid": option.value,
3201
+ children: renderTimeLabel(option.label)
3202
+ }
3203
+ )
3204
+ ] }, option.value);
3205
+ })
3206
+ ] })
3310
3207
  ]
3311
3208
  }
3312
3209
  );
3313
3210
  });
3314
- TimeCalendar.displayName = "TimeCalendar";
3211
+ TimeCalendarBase.displayName = "TimeCalendar";
3212
+ Object.assign(TimeCalendarBase, {
3213
+ Trigger: MenuTrigger
3214
+ });
3315
3215
  function useTimeInput(props) {
3316
3216
  const {
3317
3217
  value,
@@ -4529,7 +4429,6 @@ export {
4529
4429
  LOCALE_MAP,
4530
4430
  MonthCalendar,
4531
4431
  QuarterCalendar,
4532
- TimeCalendar,
4533
4432
  TimeInput,
4534
4433
  YearCalendar,
4535
4434
  calculateWeekNumbers,
@@ -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(
@@ -53,7 +53,7 @@ var mdRenderTv = tcv({
53
53
  },
54
54
  variant: {
55
55
  github: {
56
- root: "markdown-body",
56
+ root: "github-md",
57
57
  tableWrapper: "table-wrapper"
58
58
  },
59
59
  default: {
@@ -1,13 +1,13 @@
1
1
  import { Button } from "../../button/dist/index.js";
2
- import React__default, { memo, forwardRef, useContext, createContext, useMemo, startTransition, useCallback, useRef, useState, useEffect, Children, isValidElement, Fragment as Fragment$1 } from "react";
2
+ import React__default, { memo, forwardRef, useMemo, useContext, createContext, startTransition, useCallback, useRef, useState, useEffect, Children, isValidElement, Fragment as Fragment$1 } from "react";
3
3
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
4
4
  import { ChevronDownSmall, Check, ChevronRightSmall, ChevronUpSmall } from "@choiceform/icons-react";
5
5
  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
  {
@@ -717,7 +722,7 @@ var MenuValue = memo(({ children, ...rest }) => {
717
722
  });
718
723
  MenuValue.displayName = "MenuValue";
719
724
  var MenusBase = forwardRef((props, ref) => {
720
- const { children, className, matchTriggerWidth, variant, ...rest } = props;
725
+ const { children, className, matchTriggerWidth, variant = "default", ...rest } = props;
721
726
  const tv = MenusTv({ matchTriggerWidth, variant });
722
727
  const processChildren = (children2) => {
723
728
  return Children.map(children2, (child) => {
@@ -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
  ),
@@ -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
  {
@@ -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
- * Optimized Slot component implementation
7
+ * Slot component - Lightweight implementation
7
8
  *
8
- * Compared to performance optimization of @radix-ui/react-slot:
9
- * 1. Use useMemo to cache children processing results
10
- * 2. Simplify props merging logic
11
- * 3. Avoid unnecessary deep traversal
12
- * 4. Better type safety
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
14
  * Hook version of Slot logic
17
- * Used for scenarios that require more granular control
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
- * Performance optimized asChild mode Hook
22
- * Used to replace `const Component = asChild ? Slot : "button"` mode
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,76 +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
- var REACT_MAJOR = parseInt(React__default.version.split(".")[0], 10);
4
- var IS_REACT_19 = REACT_MAJOR >= 19;
5
- function getChildRef(children) {
6
- if (IS_REACT_19) {
7
- return children.props.ref;
8
- }
9
- return void 0;
10
- }
11
4
  var Slot = forwardRef(
12
5
  ({ children, ...slotProps }, forwardedRef) => {
13
- const slottedChild = useMemo(() => {
14
- if (!React__default.isValidElement(children)) {
15
- return children;
16
- }
17
- const childRef = getChildRef(children);
6
+ if (React.isValidElement(children)) {
7
+ const childrenRef = getElementRef(children);
18
8
  const mergedProps = mergeProps(slotProps, children.props);
19
- return React__default.cloneElement(children, {
9
+ return React.cloneElement(children, {
20
10
  ...mergedProps,
21
- ref: forwardedRef ? composeRefs(forwardedRef, childRef) : childRef
11
+ ref: forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef
22
12
  });
23
- }, [children, slotProps, forwardedRef]);
24
- return /* @__PURE__ */ jsx(Fragment, { children: slottedChild });
13
+ }
14
+ return /* @__PURE__ */ jsx(Fragment, { children });
25
15
  }
26
16
  );
27
17
  Slot.displayName = "Slot";
28
18
  var SlotClone = forwardRef(
29
19
  ({ children, ...slotProps }, forwardedRef) => {
30
- const slottedChild = useMemo(() => {
31
- if (!React__default.isValidElement(children)) {
32
- return children;
33
- }
34
- const childRef = getChildRef(children);
20
+ if (React.isValidElement(children)) {
21
+ const childrenRef = getElementRef(children);
35
22
  const mergedProps = mergeProps(slotProps, children.props);
36
- return React__default.cloneElement(children, {
23
+ return React.cloneElement(children, {
37
24
  ...mergedProps,
38
- ref: forwardedRef ? composeRefs(forwardedRef, childRef) : childRef
25
+ ref: forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef
39
26
  });
40
- }, [children, slotProps, forwardedRef]);
41
- return /* @__PURE__ */ jsx(Fragment, { children: slottedChild });
27
+ }
28
+ return /* @__PURE__ */ jsx(Fragment, { children });
42
29
  }
43
30
  );
44
31
  SlotClone.displayName = "SlotClone";
45
32
  function mergeProps(slotProps, childProps) {
46
33
  const overrideProps = { ...childProps };
47
- if (slotProps.className && childProps.className) {
48
- overrideProps.className = `${slotProps.className} ${childProps.className}`;
49
- } else if (slotProps.className) {
50
- overrideProps.className = slotProps.className;
51
- }
52
- if (slotProps.style && childProps.style) {
53
- overrideProps.style = { ...slotProps.style, ...childProps.style };
54
- } else if (slotProps.style) {
55
- overrideProps.style = slotProps.style;
56
- }
57
- for (const propName in slotProps) {
58
- if (propName.startsWith("on") && typeof slotProps[propName] === "function") {
59
- const slotHandler = slotProps[propName];
60
- const childHandler = childProps[propName];
61
- 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) {
62
40
  overrideProps[propName] = (...args) => {
63
- childHandler(...args);
64
- slotHandler(...args);
41
+ const result = childPropValue(...args);
42
+ slotPropValue(...args);
43
+ return result;
65
44
  };
66
- } else {
67
- overrideProps[propName] = slotHandler;
45
+ } else if (slotPropValue) {
46
+ overrideProps[propName] = slotPropValue;
68
47
  }
69
- } else if (propName !== "className" && propName !== "style") {
70
- 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(" ");
71
52
  }
72
53
  }
73
- return overrideProps;
54
+ return { ...slotProps, ...overrideProps };
74
55
  }
75
56
  function composeRefs(...refs) {
76
57
  return (node) => {
@@ -78,12 +59,25 @@ function composeRefs(...refs) {
78
59
  if (typeof ref === "function") {
79
60
  ref(node);
80
61
  } else if (ref != null) {
81
- const mutableRef = ref;
82
- mutableRef.current = node;
62
+ ref.current = node;
83
63
  }
84
64
  });
85
65
  };
86
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
+ }
87
81
  export {
88
82
  Slot
89
83
  };
@@ -13,7 +13,6 @@ const VirtualRowWrapper = memo(
13
13
  position: "absolute",
14
14
  top: 0,
15
15
  left: 0,
16
- right: 0,
17
16
  height,
18
17
  transform: `translateY(${start}px)`
19
18
  }),
@@ -16,7 +16,7 @@ interface TableRowInternalProps extends TableRowProps {
16
16
  onRowClickHandler: ((event: React.MouseEvent) => void) | undefined;
17
17
  onRowKeyDown: ((event: React.KeyboardEvent) => void) | undefined;
18
18
  }
19
- declare function TableRowPure({ rowKey, index, children, className, selectable, isSelected, isActive, consecutiveStyle, columnOrder, reorderable, hasRowClick, onCheckboxClick, onRowClickHandler, onRowKeyDown, }: TableRowInternalProps): ReactNode;
19
+ declare function TableRowPure({ rowKey: _rowKey, index, children, className, selectable, isSelected, isActive, consecutiveStyle, columnOrder, reorderable, hasRowClick, onCheckboxClick, onRowClickHandler, onRowKeyDown, }: TableRowInternalProps): ReactNode;
20
20
  declare const TableRowMemo: import('react').MemoExoticComponent<typeof TableRowPure>;
21
21
  export type { TableRowProps };
22
22
  export { TableRowMemo as TableRowPure };
@@ -7,7 +7,7 @@ import { tcx } from "../../../../shared/utils/tcx/tcx.js";
7
7
  const NOOP = () => {
8
8
  };
9
9
  function TableRowPure({
10
- rowKey,
10
+ rowKey: _rowKey,
11
11
  index,
12
12
  children,
13
13
  className,
@@ -89,9 +89,7 @@ function TableRowPure({
89
89
  }
90
90
  );
91
91
  }
92
- const TableRowMemo = memo(TableRowPure, (prev, next) => {
93
- return prev.rowKey === next.rowKey && prev.index === next.index && prev.className === next.className && prev.selectable === next.selectable && prev.isSelected === next.isSelected && prev.isActive === next.isActive && prev.consecutiveStyle === next.consecutiveStyle && prev.reorderable === next.reorderable && prev.hasRowClick === next.hasRowClick && prev.columnOrder === next.columnOrder;
94
- });
92
+ const TableRowMemo = memo(TableRowPure);
95
93
  function TableRow({
96
94
  rowKey,
97
95
  index,
@@ -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
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@choice-ui/react",
3
- "version": "1.6.2",
3
+ "version": "1.6.4",
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",
@@ -1,48 +0,0 @@
1
- import { MenuContextContent, MenuDivider, MenuEmpty, MenuContextItem, MenuSearch, MenuTrigger, MenuValue } from '../../menus/src';
2
- import { FloatingFocusManagerProps } from '@floating-ui/react';
3
- import { default as React } from 'react';
4
- interface VirtualSelectOption<T = unknown> {
5
- value: string;
6
- label: string;
7
- disabled?: boolean;
8
- data?: T;
9
- }
10
- interface VirtualSelectProps<T = unknown> {
11
- className?: string;
12
- closeOnEscape?: boolean;
13
- disabled?: boolean;
14
- emptyText?: string;
15
- focusManagerProps?: Partial<FloatingFocusManagerProps>;
16
- matchTriggerWidth?: boolean;
17
- maxHeight?: number;
18
- onChange?: (value: string) => void;
19
- onOpenChange?: (open: boolean) => void;
20
- open?: boolean;
21
- options: VirtualSelectOption<T>[];
22
- overscan?: number;
23
- placeholder?: string;
24
- placement?: "bottom-start" | "bottom-end";
25
- portalId?: string;
26
- readOnly?: boolean;
27
- renderOption?: (option: VirtualSelectOption<T>, isSelected: boolean) => React.ReactNode;
28
- renderValue?: (option: VirtualSelectOption<T> | null) => React.ReactNode;
29
- root?: HTMLElement | null;
30
- searchPlaceholder?: string;
31
- size?: "default" | "large";
32
- value?: string | null;
33
- variant?: "default" | "light" | "reset";
34
- }
35
- interface VirtualSelectComponentType {
36
- <T = unknown>(props: VirtualSelectProps<T>): React.ReactElement | null;
37
- displayName?: string;
38
- Content: typeof MenuContextContent;
39
- Divider: typeof MenuDivider;
40
- Empty: typeof MenuEmpty;
41
- Item: typeof MenuContextItem;
42
- Search: typeof MenuSearch;
43
- Trigger: typeof MenuTrigger;
44
- Value: typeof MenuValue;
45
- }
46
- declare const VirtualSelect: VirtualSelectComponentType;
47
-
48
- export { VirtualSelect, type VirtualSelectOption, type VirtualSelectProps };