@ceed/cds 1.40.3-next.1 → 1.40.3-next.2

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.
package/dist/index.js CHANGED
@@ -187,7 +187,7 @@ function Alert(inProps) {
187
187
  Alert.displayName = "Alert";
188
188
 
189
189
  // src/components/Autocomplete/Autocomplete.tsx
190
- import React5, { useCallback as useCallback2, useEffect as useEffect2, useMemo, useRef as useRef2 } from "react";
190
+ import React5, { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2 } from "react";
191
191
  import {
192
192
  Autocomplete as JoyAutocomplete,
193
193
  AutocompleteOption as JoyAutocompleteOption,
@@ -294,6 +294,37 @@ function useControlledState(controlledValue, defaultValue, onChange) {
294
294
  return [displayValue, handleChange, isControlled];
295
295
  }
296
296
 
297
+ // src/libs/slot-props.ts
298
+ import { useMemo } from "react";
299
+ function assignRef(ref, value) {
300
+ if (typeof ref === "function") ref(value);
301
+ else if (ref) ref.current = value;
302
+ }
303
+ function mergeRefs(...refs) {
304
+ const live = refs.filter((r) => r != null);
305
+ if (live.length === 0) return void 0;
306
+ if (live.length === 1) return live[0];
307
+ return (value) => live.forEach((r) => assignRef(r, value));
308
+ }
309
+ function useMergedRef(a, b) {
310
+ return useMemo(() => mergeRefs(a, b), [a, b]);
311
+ }
312
+ function useSlotRef(slotProp, ref) {
313
+ const isFunctionForm = typeof slotProp === "function";
314
+ const slotRef = isFunctionForm ? void 0 : slotProp?.ref;
315
+ const mergedRef = useMergedRef(slotRef, ref);
316
+ return useMemo(() => {
317
+ if (isFunctionForm) {
318
+ return ((ownerState) => {
319
+ const resolved = slotProp(ownerState);
320
+ const merged = mergeRefs(resolved.ref, ref);
321
+ return merged ? { ...resolved, ref: merged } : { ...resolved };
322
+ });
323
+ }
324
+ return mergedRef ? { ...slotProp, ref: mergedRef } : { ...slotProp };
325
+ }, [isFunctionForm, slotProp, mergedRef, ref]);
326
+ }
327
+
297
328
  // src/components/Autocomplete/Autocomplete.tsx
298
329
  var AutocompletePopper = styled3(Popper, {
299
330
  name: "Autocomplete",
@@ -318,11 +349,11 @@ var AutocompleteListBox = React5.forwardRef((props, ref) => {
318
349
  } = props;
319
350
  const parentRef = useRef2(null);
320
351
  const isGrouped = children[0].every((child) => child.hasOwnProperty("group"));
321
- const itemHeight = useMemo(() => {
352
+ const itemHeight = useMemo2(() => {
322
353
  const heights = itemHeightMap[fontSize ?? "md"];
323
354
  return hasSecondaryText ? heights.secondary : heights.default;
324
355
  }, [fontSize, hasSecondaryText]);
325
- const renderTargets = useMemo(() => {
356
+ const renderTargets = useMemo2(() => {
326
357
  if (loading) {
327
358
  return [children[1]];
328
359
  }
@@ -414,7 +445,7 @@ var autocompleteFilterOptions = createFilterOptions({
414
445
  }
415
446
  });
416
447
  var getOptionLabel = (option) => `${option.label ?? ""}`;
417
- function Autocomplete(props) {
448
+ function AutocompleteInner(props, ref) {
418
449
  const {
419
450
  label,
420
451
  error,
@@ -444,7 +475,7 @@ function Autocomplete(props) {
444
475
  )
445
476
  );
446
477
  const _value = rawValue ?? (props.multiple ? EMPTY_MULTIPLE_VALUE : "");
447
- const options = useMemo(
478
+ const options = useMemo2(
448
479
  () => props.options.map((option) => {
449
480
  if (typeof option !== "object") {
450
481
  return {
@@ -456,14 +487,14 @@ function Autocomplete(props) {
456
487
  }),
457
488
  [props.options]
458
489
  );
459
- const optionMap = useMemo(() => {
490
+ const optionMap = useMemo2(() => {
460
491
  const map = /* @__PURE__ */ new Map();
461
492
  options.forEach((option) => {
462
493
  map.set(option.value, option);
463
494
  });
464
495
  return map;
465
496
  }, [options]);
466
- const value = useMemo(() => {
497
+ const value = useMemo2(() => {
467
498
  if (props.loading) {
468
499
  return {
469
500
  value: "",
@@ -482,23 +513,25 @@ function Autocomplete(props) {
482
513
  },
483
514
  [size, props.loading]
484
515
  );
485
- const startDecorator = useMemo(
516
+ const startDecorator = useMemo2(
486
517
  () => applySize(value?.startDecorator || props.startDecorator),
487
518
  [value, applySize, props.startDecorator]
488
519
  );
489
- const endDecorator = useMemo(
520
+ const endDecorator = useMemo2(
490
521
  () => applySize(value?.endDecorator || props.endDecorator),
491
522
  [value, applySize, props.endDecorator]
492
523
  );
493
- const slotProps = useMemo(
524
+ const inputSlotProps = useSlotRef(props.slotProps?.input, ref);
525
+ const slotProps = useMemo2(
494
526
  () => ({
495
527
  ...props.slotProps,
496
528
  listbox: {
497
529
  ...props.slotProps?.listbox,
498
530
  hasSecondaryText: options.some((opt) => opt.secondaryText)
499
- }
531
+ },
532
+ input: inputSlotProps
500
533
  }),
501
- [options, props.slotProps]
534
+ [options, props.slotProps, inputSlotProps]
502
535
  );
503
536
  const handleChange = useCallback2(
504
537
  (event, value2) => {
@@ -532,9 +565,9 @@ function Autocomplete(props) {
532
565
  endDecorator,
533
566
  getOptionLabel,
534
567
  renderTags: (tags, getTagProps) => tags.map((tag, index) => {
535
- const { onClick, ...rest } = getTagProps({ index });
568
+ const { onClick, key, ...rest } = getTagProps({ index });
536
569
  return applySize(
537
- /* @__PURE__ */ React5.createElement(Chip_default, { color: "primary", ...rest }, /* @__PURE__ */ React5.createElement(Stack_default, { direction: "row", alignItems: "center", gap: 2, py: 0.5 }, tag.value, applySize(
570
+ /* @__PURE__ */ React5.createElement(Chip_default, { key, color: "primary", ...rest }, /* @__PURE__ */ React5.createElement(Stack_default, { direction: "row", alignItems: "center", gap: 2, py: 0.5 }, tag.value, applySize(
538
571
  /* @__PURE__ */ React5.createElement(AutocompleteTagDelete, { color: "primary", variant: "soft", onClick }, /* @__PURE__ */ React5.createElement(CloseIcon, null))
539
572
  )))
540
573
  );
@@ -544,26 +577,29 @@ function Autocomplete(props) {
544
577
  },
545
578
  slotProps,
546
579
  filterOptions: autocompleteFilterOptions,
547
- renderOption: (props2, option) => /* @__PURE__ */ React5.createElement(JoyAutocompleteOption, { ...props2 }, option.startDecorator && /* @__PURE__ */ React5.createElement(
548
- ListItemDecorator,
549
- {
550
- sx: (theme) => ({
551
- marginInlineEnd: `var(--Input-gap, ${theme.spacing(1)})`
552
- })
553
- },
554
- applySize(option.startDecorator)
555
- ), option.secondaryText ? /* @__PURE__ */ React5.createElement(ListItemContent, { sx: { gap: 0.5 } }, /* @__PURE__ */ React5.createElement(Typography2, { level: "inherit" }, applySize(option.label)), /* @__PURE__ */ React5.createElement(Typography2, { level: secondaryTextLevelMap[size ?? "md"], textColor: "text.tertiary" }, option.secondaryText)) : (
556
- // TODO: haulla에서 사용할 때, label을 ReactNode로 넘기면 에러가 발생함....
557
- applySize(option.label)
558
- ), option.endDecorator && /* @__PURE__ */ React5.createElement(
559
- ListItemDecorator,
560
- {
561
- sx: (theme) => ({
562
- marginInlineStart: `var(--Input-gap, ${theme.spacing(1)})`
563
- })
564
- },
565
- applySize(option.endDecorator)
566
- )),
580
+ renderOption: (props2, option) => {
581
+ const { key, ...optionProps } = props2;
582
+ return /* @__PURE__ */ React5.createElement(JoyAutocompleteOption, { key, ...optionProps }, option.startDecorator && /* @__PURE__ */ React5.createElement(
583
+ ListItemDecorator,
584
+ {
585
+ sx: (theme) => ({
586
+ marginInlineEnd: `var(--Input-gap, ${theme.spacing(1)})`
587
+ })
588
+ },
589
+ applySize(option.startDecorator)
590
+ ), option.secondaryText ? /* @__PURE__ */ React5.createElement(ListItemContent, { sx: { gap: 0.5 } }, /* @__PURE__ */ React5.createElement(Typography2, { level: "inherit" }, applySize(option.label)), /* @__PURE__ */ React5.createElement(Typography2, { level: secondaryTextLevelMap[size ?? "md"], textColor: "text.tertiary" }, option.secondaryText)) : (
591
+ // TODO: haulla에서 사용할 때, label을 ReactNode로 넘기면 에러가 발생함....
592
+ applySize(option.label)
593
+ ), option.endDecorator && /* @__PURE__ */ React5.createElement(
594
+ ListItemDecorator,
595
+ {
596
+ sx: (theme) => ({
597
+ marginInlineStart: `var(--Input-gap, ${theme.spacing(1)})`
598
+ })
599
+ },
600
+ applySize(option.endDecorator)
601
+ ));
602
+ },
567
603
  renderGroup: (params) => params
568
604
  }
569
605
  );
@@ -583,13 +619,14 @@ function Autocomplete(props) {
583
619
  helperText && /* @__PURE__ */ React5.createElement(FormHelperText_default, null, helperText)
584
620
  );
585
621
  }
622
+ var Autocomplete = React5.forwardRef(AutocompleteInner);
586
623
  Autocomplete.displayName = "Autocomplete";
587
624
 
588
625
  // src/components/Autocomplete/index.ts
589
626
  var Autocomplete_default = Autocomplete;
590
627
 
591
628
  // src/components/Avatar/Avatar.tsx
592
- import React6, { forwardRef as forwardRef2, useMemo as useMemo2 } from "react";
629
+ import React6, { forwardRef as forwardRef2, useMemo as useMemo3 } from "react";
593
630
  import { Avatar as JoyAvatar, AvatarGroup, styled as styled4, useThemeProps as useThemeProps2 } from "@mui/joy";
594
631
  var StyledAvatar = styled4(JoyAvatar, {
595
632
  name: "Avatar",
@@ -617,7 +654,7 @@ var Avatar = forwardRef2(function Avatar2(inProps, ref) {
617
654
  name: "Avatar"
618
655
  });
619
656
  const { children, getInitial = defaultGetInitial, ...inheritProps } = props;
620
- const calcChildren = useMemo2(() => {
657
+ const calcChildren = useMemo3(() => {
621
658
  if (typeof children === "string") {
622
659
  return getInitial?.(children) ?? "";
623
660
  }
@@ -659,7 +696,7 @@ var MenuItem = JoyMenuItem;
659
696
  var Menu_default = Menu;
660
697
 
661
698
  // src/components/Dropdown/Dropdown.tsx
662
- import React8, { createContext, useCallback as useCallback3, useMemo as useMemo3, useState as useState2 } from "react";
699
+ import React8, { createContext, useCallback as useCallback3, useMemo as useMemo4, useState as useState2 } from "react";
663
700
  import { Dropdown as JoyDropdown } from "@mui/joy";
664
701
  import { MenuButton } from "@mui/joy";
665
702
  import { useMenuButton } from "@mui/base/useMenuButton";
@@ -667,7 +704,7 @@ var DropdownNestedRegistryContext = createContext(null);
667
704
  function Dropdown({ open: openProp, defaultOpen = false, onOpenChange, ...rest }) {
668
705
  const [nestedCount, setNestedCount] = useState2(0);
669
706
  const [open, setOpen] = useControlledState(openProp, defaultOpen);
670
- const registry = useMemo3(
707
+ const registry = useMemo4(
671
708
  () => ({
672
709
  register: () => setNestedCount((c) => c + 1),
673
710
  unregister: () => setNestedCount((c) => Math.max(0, c - 1))
@@ -737,7 +774,7 @@ Button.displayName = "Button";
737
774
  var Button_default = Button;
738
775
 
739
776
  // src/components/Calendar/Calendar.tsx
740
- import React13, { Fragment, forwardRef as forwardRef4, useCallback as useCallback6, useEffect as useEffect3, useMemo as useMemo5, useRef as useRef3, useState as useState5 } from "react";
777
+ import React13, { Fragment, forwardRef as forwardRef4, useCallback as useCallback6, useEffect as useEffect3, useMemo as useMemo6, useRef as useRef3, useState as useState5 } from "react";
741
778
  import { styled as styled5 } from "@mui/joy";
742
779
  import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
743
780
  import ChevronRightIcon from "@mui/icons-material/ChevronRight";
@@ -831,7 +868,7 @@ var isSameMonth = (date1, date2) => {
831
868
  };
832
869
 
833
870
  // src/components/Calendar/hooks/use-calendar-props.ts
834
- import { useCallback as useCallback4, useMemo as useMemo4, useState as useState3 } from "react";
871
+ import { useCallback as useCallback4, useMemo as useMemo5, useState as useState3 } from "react";
835
872
  import { useThemeProps as useThemeProps3 } from "@mui/joy";
836
873
  var resolveView = (view, views) => {
837
874
  return views.includes(view) ? view : views[0];
@@ -851,12 +888,12 @@ var useCalendarProps = (inProps) => {
851
888
  });
852
889
  const [[page, direction], setPage] = useState3([0, 0]);
853
890
  const resolvedView = inProps.view ?? uncontrolledView;
854
- const resolvedMinDate = useMemo4(() => {
891
+ const resolvedMinDate = useMemo5(() => {
855
892
  const minDate = inProps.minDate || /* @__PURE__ */ new Date(0);
856
893
  minDate.setHours(0, 0, 0, 0);
857
894
  return minDate;
858
895
  }, [inProps.minDate]);
859
- const resolvedMaxDate = useMemo4(() => {
896
+ const resolvedMaxDate = useMemo5(() => {
860
897
  const maxDate = inProps.maxDate || /* @__PURE__ */ new Date(864e13);
861
898
  maxDate.setHours(0, 0, 0, 0);
862
899
  return maxDate;
@@ -915,7 +952,7 @@ var useCalendarProps = (inProps) => {
915
952
  },
916
953
  name: "Calendar"
917
954
  });
918
- const ownerState = useMemo4(() => ({ ...props, viewMonth, direction }), [props, viewMonth, direction]);
955
+ const ownerState = useMemo5(() => ({ ...props, viewMonth, direction }), [props, viewMonth, direction]);
919
956
  return [props, ownerState];
920
957
  };
921
958
 
@@ -1347,8 +1384,8 @@ var swipePower = (offset, velocity) => {
1347
1384
  var PickerDays = (props) => {
1348
1385
  const { ownerState } = props;
1349
1386
  const { getPickerDayProps, getDayCellProps } = useCalendar(ownerState);
1350
- const calendarDates = useMemo5(() => getCalendarDates(ownerState.viewMonth), [ownerState.viewMonth]);
1351
- const weekdayNames = useMemo5(() => getWeekdayNames(ownerState.locale || "default"), [ownerState.locale]);
1387
+ const calendarDates = useMemo6(() => getCalendarDates(ownerState.viewMonth), [ownerState.viewMonth]);
1388
+ const weekdayNames = useMemo6(() => getWeekdayNames(ownerState.locale || "default"), [ownerState.locale]);
1352
1389
  return /* @__PURE__ */ React13.createElement(CalendarViewContainer, { calendarType: "datePicker" }, /* @__PURE__ */ React13.createElement(AnimatePresence, { initial: false, custom: ownerState.direction }, /* @__PURE__ */ React13.createElement(
1353
1390
  CalendarViewTable,
1354
1391
  {
@@ -1432,8 +1469,8 @@ var PickerMonths = (props) => {
1432
1469
  };
1433
1470
  var PlainPickerDays = ({ ownerState }) => {
1434
1471
  const { getPickerDayProps, getDayCellProps } = useCalendar(ownerState);
1435
- const calendarDates = useMemo5(() => getCalendarDates(ownerState.viewMonth), [ownerState.viewMonth]);
1436
- const weekdayNames = useMemo5(() => getWeekdayNames(ownerState.locale || "default"), [ownerState.locale]);
1472
+ const calendarDates = useMemo6(() => getCalendarDates(ownerState.viewMonth), [ownerState.viewMonth]);
1473
+ const weekdayNames = useMemo6(() => getWeekdayNames(ownerState.locale || "default"), [ownerState.locale]);
1437
1474
  return /* @__PURE__ */ React13.createElement(StaticCalendarViewTable, null, /* @__PURE__ */ React13.createElement(CalendarWeekHeaderContainer, null, /* @__PURE__ */ React13.createElement("tr", null, weekdayNames.map((name, i) => /* @__PURE__ */ React13.createElement(Fragment, { key: `${ownerState.viewMonth}_${name}_${i}` }, /* @__PURE__ */ React13.createElement("th", null, /* @__PURE__ */ React13.createElement(Typography_default, { level: "body-xs", textAlign: "center" }, name)), i < 6 && /* @__PURE__ */ React13.createElement("th", { style: { width: 4 }, "aria-hidden": "true", "aria-description": "cell-gap" }))))), /* @__PURE__ */ React13.createElement(CalendarDayPickerContainer, null, calendarDates.map((weekDates, rowIndex) => /* @__PURE__ */ React13.createElement(Fragment, { key: `${ownerState.viewMonth}_${rowIndex}` }, /* @__PURE__ */ React13.createElement("tr", null, weekDates.map(
1438
1475
  (date, i) => date ? /* @__PURE__ */ React13.createElement(Fragment, { key: `${ownerState.viewMonth}_${date}_${i}` }, /* @__PURE__ */ React13.createElement(CalendarDayCell, { ...getDayCellProps(date) }, /* @__PURE__ */ React13.createElement(CalendarDay, { size: "sm", variant: "plain", color: "neutral", ...getPickerDayProps(date) }, date)), i < 6 && /* @__PURE__ */ React13.createElement("td", { "aria-hidden": "true", "aria-description": "cell-gap" })) : /* @__PURE__ */ React13.createElement(Fragment, { key: `${ownerState.viewMonth}_${i}` }, /* @__PURE__ */ React13.createElement("td", null), i < 6 && /* @__PURE__ */ React13.createElement("td", { "aria-hidden": "true", "aria-description": "cell-gap" }))
1439
1476
  )), rowIndex < calendarDates.length - 1 && /* @__PURE__ */ React13.createElement("tr", { "aria-hidden": "true", "aria-description": "row-gap" }, /* @__PURE__ */ React13.createElement("td", { colSpan: 13, style: { height: 4 } }))))));
@@ -1812,7 +1849,7 @@ var Container = forwardRef5(function Container2(props, ref) {
1812
1849
  Container.displayName = "Container";
1813
1850
 
1814
1851
  // src/components/CurrencyInput/CurrencyInput.tsx
1815
- import React17, { useCallback as useCallback8, useMemo as useMemo6 } from "react";
1852
+ import React17, { useCallback as useCallback8, useMemo as useMemo7 } from "react";
1816
1853
  import { NumericFormat } from "react-number-format";
1817
1854
 
1818
1855
  // src/components/Input/Input.tsx
@@ -2146,19 +2183,19 @@ var CurrencyInput = React17.forwardRef(function CurrencyInput2(inProps, ref) {
2146
2183
  props.defaultValue ?? null,
2147
2184
  useCallback8((value2) => onChange?.({ target: { name, value: value2 } }), [onChange, name])
2148
2185
  );
2149
- const value = useMemo6(() => {
2186
+ const value = useMemo7(() => {
2150
2187
  if (_value && useMinorUnit) {
2151
2188
  return _value / Math.pow(10, decimalScale);
2152
2189
  }
2153
2190
  return _value;
2154
2191
  }, [_value, useMinorUnit, decimalScale]);
2155
- const max = useMemo6(() => {
2192
+ const max = useMemo7(() => {
2156
2193
  if (props.max && useMinorUnit) {
2157
2194
  return props.max / Math.pow(10, decimalScale);
2158
2195
  }
2159
2196
  return props.max;
2160
2197
  }, [props.max, useMinorUnit, decimalScale]);
2161
- const isOverLimit = useMemo6(() => max != null && value != null && value > max, [max, value]);
2198
+ const isOverLimit = useMemo7(() => max != null && value != null && value > max, [max, value]);
2162
2199
  const handleChange = useCallback8(
2163
2200
  (event) => {
2164
2201
  if (event.target.value === "") {
@@ -2209,7 +2246,7 @@ var CurrencyInput_default = CurrencyInput;
2209
2246
  // src/components/DataTable/DataTable.tsx
2210
2247
  import React26, {
2211
2248
  useCallback as useCallback13,
2212
- useMemo as useMemo11,
2249
+ useMemo as useMemo12,
2213
2250
  useRef as useRef7,
2214
2251
  useId,
2215
2252
  forwardRef as forwardRef7,
@@ -2443,6 +2480,9 @@ function computeAutoFitWidth(params) {
2443
2480
  if (!isNaN(maxPx) && maxPx > 0) finalWidth = Math.min(finalWidth, maxPx);
2444
2481
  return finalWidth;
2445
2482
  }
2483
+ function getHeaderCellId(tableId, columnId) {
2484
+ return `${tableId}_header_${columnId}`.trim();
2485
+ }
2446
2486
 
2447
2487
  // src/components/DataTable/styled.tsx
2448
2488
  import React18 from "react";
@@ -2634,7 +2674,7 @@ import React23, {
2634
2674
  useRef as useRef5,
2635
2675
  useState as useState8,
2636
2676
  useLayoutEffect,
2637
- useMemo as useMemo9,
2677
+ useMemo as useMemo10,
2638
2678
  useCallback as useCallback10,
2639
2679
  useEffect as useEffect5,
2640
2680
  memo,
@@ -3118,7 +3158,7 @@ import React20 from "react";
3118
3158
  import { Textarea as JoyTextarea } from "@mui/joy";
3119
3159
  import { motion as motion19 } from "framer-motion";
3120
3160
  var MotionTextarea = motion19(JoyTextarea);
3121
- var Textarea = (props) => {
3161
+ var TextareaBase = (props) => {
3122
3162
  const {
3123
3163
  label,
3124
3164
  error,
@@ -3162,13 +3202,17 @@ var Textarea = (props) => {
3162
3202
  helperText && /* @__PURE__ */ React20.createElement(FormHelperText_default, null, helperText)
3163
3203
  );
3164
3204
  };
3205
+ var Textarea = React20.forwardRef((props, ref) => {
3206
+ const textareaSlotProps = useSlotRef(props.slotProps?.textarea, ref);
3207
+ return /* @__PURE__ */ React20.createElement(TextareaBase, { ...props, slotProps: { ...props.slotProps, textarea: textareaSlotProps } });
3208
+ });
3165
3209
  Textarea.displayName = "Textarea";
3166
3210
 
3167
3211
  // src/components/Textarea/index.ts
3168
3212
  var Textarea_default = Textarea;
3169
3213
 
3170
3214
  // src/components/Select/Select.tsx
3171
- import React21, { useMemo as useMemo8 } from "react";
3215
+ import React21, { useMemo as useMemo9 } from "react";
3172
3216
  import {
3173
3217
  Select as JoySelect,
3174
3218
  Option as JoyOption,
@@ -3184,7 +3228,7 @@ var secondaryTextLevelMap2 = {
3184
3228
  lg: "body-md"
3185
3229
  };
3186
3230
  Option.displayName = "Option";
3187
- function Select(props) {
3231
+ function SelectInner(props, ref) {
3188
3232
  const {
3189
3233
  label,
3190
3234
  helperText,
@@ -3210,7 +3254,7 @@ function Select(props) {
3210
3254
  formHelperText: formHelperTextProps,
3211
3255
  ...joySlotProps
3212
3256
  } = slotProps ?? {};
3213
- const options = useMemo8(
3257
+ const options = useMemo9(
3214
3258
  () => props.options.map((option) => {
3215
3259
  if (option.hasOwnProperty("value") && option.hasOwnProperty("label")) {
3216
3260
  return option;
@@ -3235,13 +3279,14 @@ function Select(props) {
3235
3279
  };
3236
3280
  onChange?.(newEvent, newValue);
3237
3281
  };
3238
- const optionMap = useMemo8(() => {
3282
+ const optionMap = useMemo9(() => {
3239
3283
  const map = /* @__PURE__ */ new Map();
3240
3284
  options.forEach((option) => {
3241
3285
  map.set(option.value, option);
3242
3286
  });
3243
3287
  return map;
3244
3288
  }, [options]);
3289
+ const buttonSlotProps = useSlotRef(joySlotProps.button, ref);
3245
3290
  const select = /* @__PURE__ */ React21.createElement(
3246
3291
  JoySelect,
3247
3292
  {
@@ -3250,7 +3295,7 @@ function Select(props) {
3250
3295
  disabled,
3251
3296
  size,
3252
3297
  color: error ? "danger" : color,
3253
- slotProps: joySlotProps,
3298
+ slotProps: { ...joySlotProps, button: buttonSlotProps },
3254
3299
  onChange: handleChange,
3255
3300
  renderValue: (selected) => {
3256
3301
  if (!selected) return null;
@@ -3280,6 +3325,7 @@ function Select(props) {
3280
3325
  helperText && /* @__PURE__ */ React21.createElement(FormHelperText_default, { ...formHelperTextProps }, helperText)
3281
3326
  );
3282
3327
  }
3328
+ var Select = React21.forwardRef(SelectInner);
3283
3329
  Select.displayName = "Select";
3284
3330
 
3285
3331
  // src/components/Select/index.ts
@@ -3394,7 +3440,8 @@ var HeadCell = (props) => {
3394
3440
  tableColRef,
3395
3441
  headerClassName,
3396
3442
  headerLineClamp,
3397
- onAutoFit
3443
+ onAutoFit,
3444
+ columnId
3398
3445
  } = props;
3399
3446
  const theme = useTheme();
3400
3447
  const ref = headerRef;
@@ -3405,23 +3452,20 @@ var HeadCell = (props) => {
3405
3452
  }, [ref]);
3406
3453
  const [isHovered, setIsHovered] = useState8(false);
3407
3454
  const sortable = type === "actions" ? false : _sortable;
3408
- const headId = useMemo9(
3409
- () => `${tableId}_header_${headerName ?? field}`.trim(),
3410
- [tableId, headerName, field]
3411
- );
3455
+ const headId = useMemo10(() => getHeaderCellId(tableId, columnId ?? field), [tableId, columnId, field]);
3412
3456
  const isResizingRef = useRef5(false);
3413
- const resizer = useMemo9(
3457
+ const resizer = useMemo10(
3414
3458
  () => resizable ?? true ? Resizer(
3415
3459
  ref,
3416
3460
  colRef,
3417
3461
  (isResizing) => {
3418
3462
  isResizingRef.current = isResizing;
3419
3463
  },
3420
- onAutoFit ? () => onAutoFit(field) : void 0
3464
+ onAutoFit ? () => onAutoFit(columnId ?? String(field)) : void 0
3421
3465
  ) : null,
3422
- [resizable, ref, colRef, onAutoFit, field]
3466
+ [resizable, ref, colRef, onAutoFit, columnId, field]
3423
3467
  );
3424
- const style = useMemo9(
3468
+ const style = useMemo10(
3425
3469
  () => ({
3426
3470
  width,
3427
3471
  minWidth: minWidth ?? "50px",
@@ -3439,7 +3483,7 @@ var HeadCell = (props) => {
3439
3483
  );
3440
3484
  const textAlign = getTextAlign(props);
3441
3485
  const initialSort = sortOrder[0];
3442
- const sortIcon = useMemo9(() => {
3486
+ const sortIcon = useMemo10(() => {
3443
3487
  const isSorted = !!sort;
3444
3488
  const isVisible = sortable && (isSorted || isHovered);
3445
3489
  return /* @__PURE__ */ React23.createElement(AnimatePresence2, { mode: "wait" }, isVisible && /* @__PURE__ */ React23.createElement(
@@ -3470,17 +3514,17 @@ var HeadCell = (props) => {
3470
3514
  }
3471
3515
  ));
3472
3516
  }, [headId, initialSort, sort, sortable, isHovered]);
3473
- const infoSign = useMemo9(
3517
+ const infoSign = useMemo10(
3474
3518
  () => description ? /* @__PURE__ */ React23.createElement(InfoSign_default, { message: description, placement: "bottom" }) : null,
3475
3519
  [description]
3476
3520
  );
3477
- const params = useMemo9(
3521
+ const params = useMemo10(
3478
3522
  () => ({
3479
3523
  field
3480
3524
  }),
3481
3525
  [field]
3482
3526
  );
3483
- const computedHeaderClassName = useMemo9(
3527
+ const computedHeaderClassName = useMemo10(
3484
3528
  () => (typeof headerClassName === "function" ? headerClassName(params) : headerClassName) || void 0,
3485
3529
  [headerClassName, params]
3486
3530
  );
@@ -3534,7 +3578,7 @@ var BodyCell = (props) => {
3534
3578
  const theme = useTheme();
3535
3579
  const [value, setValue] = useState8(row[field]);
3536
3580
  const cellRef = useRef5(null);
3537
- const params = useMemo9(
3581
+ const params = useMemo10(
3538
3582
  () => ({
3539
3583
  row,
3540
3584
  value,
@@ -3543,20 +3587,20 @@ var BodyCell = (props) => {
3543
3587
  }),
3544
3588
  [row, rowId, value, field]
3545
3589
  );
3546
- const editMode = useMemo9(
3590
+ const editMode = useMemo10(
3547
3591
  () => !!(props.editMode && (typeof isCellEditable === "function" ? isCellEditable(params) : isCellEditable ?? true)),
3548
3592
  [props.editMode, isCellEditable, params]
3549
3593
  );
3550
3594
  const propsComponentProps = "componentProps" in props ? props.componentProps : null;
3551
3595
  const hasComponentProps = "componentProps" in props;
3552
- const componentProps = useMemo9(
3596
+ const componentProps = useMemo10(
3553
3597
  () => ({
3554
3598
  ...hasComponentProps && (typeof propsComponentProps === "function" ? propsComponentProps(params) : propsComponentProps || {}),
3555
3599
  size: "sm"
3556
3600
  }),
3557
3601
  [hasComponentProps, propsComponentProps, params]
3558
3602
  );
3559
- const editModeComponentProps = useMemo9(
3603
+ const editModeComponentProps = useMemo10(
3560
3604
  () => ({
3561
3605
  ...componentProps,
3562
3606
  onChange: (e) => {
@@ -3618,9 +3662,9 @@ var BodyCell = (props) => {
3618
3662
  }),
3619
3663
  [params, row, field, value, componentProps, type, onCellEditStop, onCellEditStart]
3620
3664
  );
3621
- const MemoizedRenderEditCell = useMemo9(() => renderEditCell ? memo(renderEditCell) : null, [renderEditCell]);
3622
- const MemoizedRenderCell = useMemo9(() => renderCell ? memo(renderCell) : null, [renderCell]);
3623
- const EditModeComponent = useMemo9(() => {
3665
+ const MemoizedRenderEditCell = useMemo10(() => renderEditCell ? memo(renderEditCell) : null, [renderEditCell]);
3666
+ const MemoizedRenderCell = useMemo10(() => renderCell ? memo(renderCell) : null, [renderCell]);
3667
+ const EditModeComponent = useMemo10(() => {
3624
3668
  if (MemoizedRenderEditCell) {
3625
3669
  return createElement(MemoizedRenderEditCell, params);
3626
3670
  }
@@ -3655,7 +3699,7 @@ var BodyCell = (props) => {
3655
3699
  }[type || "text"];
3656
3700
  }, [value, editModeComponentProps, type, MemoizedRenderEditCell, params]);
3657
3701
  const linkComponentFromProps = props.component;
3658
- const ReadModeComponent = useMemo9(() => {
3702
+ const ReadModeComponent = useMemo10(() => {
3659
3703
  if (MemoizedRenderCell) {
3660
3704
  return createElement(MemoizedRenderCell, params);
3661
3705
  }
@@ -3669,15 +3713,15 @@ var BodyCell = (props) => {
3669
3713
  return typedComponent || innerText;
3670
3714
  }, [value, MemoizedRenderCell, params, type, componentProps, linkComponentFromProps]);
3671
3715
  const getActions = props.getActions;
3672
- const CellComponent = useMemo9(() => {
3716
+ const CellComponent = useMemo10(() => {
3673
3717
  if (type === "actions") {
3674
3718
  return /* @__PURE__ */ React23.createElement(Stack_default, { direction: "row", gap: 1, justifyContent: "center", alignItems: "center" }, getActions?.(params));
3675
3719
  }
3676
3720
  return editMode && EditModeComponent ? EditModeComponent : ReadModeComponent;
3677
3721
  }, [type, getActions, params, editMode, EditModeComponent, ReadModeComponent]);
3678
- const showTooltip = useMemo9(() => noWrap && type === "longText", [noWrap, type]);
3722
+ const showTooltip = useMemo10(() => noWrap && type === "longText", [noWrap, type]);
3679
3723
  const isBoundary = props.isLastStartPinnedColumn || props.isLastEndPinnedColumn;
3680
- const computedCellClassName = useMemo9(
3724
+ const computedCellClassName = useMemo10(
3681
3725
  () => (typeof cellClassName === "function" ? cellClassName(params) : cellClassName) || "",
3682
3726
  [cellClassName, params]
3683
3727
  );
@@ -3689,7 +3733,7 @@ var BodyCell = (props) => {
3689
3733
  {
3690
3734
  ref: cellRef,
3691
3735
  key: field,
3692
- headers: `${tableId}_header_${props.headerName ?? field}`,
3736
+ headers: getHeaderCellId(tableId, props.columnId ?? field),
3693
3737
  sx: {
3694
3738
  textAlign: getTextAlign({ type }),
3695
3739
  verticalAlign: editMode ? "top" : "middle",
@@ -3701,7 +3745,7 @@ var BodyCell = (props) => {
3701
3745
  },
3702
3746
  className: [isLastStartPinnedColumn && "is-last-left", isLastEndPinnedColumn && "is-last-right", computedCellClassName].filter(Boolean).join(" ") || ""
3703
3747
  },
3704
- useMemo9(
3748
+ useMemo10(
3705
3749
  () => showTooltip ? /* @__PURE__ */ React23.createElement(CellTextEllipsis, null, CellComponent) : CellComponent,
3706
3750
  [CellComponent, showTooltip]
3707
3751
  )
@@ -3754,36 +3798,44 @@ var VirtualizedTableRow = memo(StyledTableRow2, (prevProps, nextProps) => {
3754
3798
  });
3755
3799
 
3756
3800
  // src/components/DataTable/hooks.ts
3757
- import { useState as useState9, useLayoutEffect as useLayoutEffect2, useRef as useRef6, useMemo as useMemo10, useCallback as useCallback11, useEffect as useEffect6, createRef } from "react";
3758
- function useColumnWidths(columnsByField) {
3801
+ import { useState as useState9, useLayoutEffect as useLayoutEffect2, useRef as useRef6, useMemo as useMemo11, useCallback as useCallback11, useEffect as useEffect6, createRef } from "react";
3802
+ function useColumnWidths(columnsById) {
3759
3803
  const [widths, setWidths] = useState9({});
3760
3804
  const roRef = useRef6();
3761
3805
  useLayoutEffect2(() => {
3762
3806
  if (roRef.current) roRef.current.disconnect();
3763
3807
  roRef.current = new ResizeObserver((entries) => {
3764
- let changed = false;
3765
3808
  setWidths((prev) => {
3809
+ let changed = false;
3766
3810
  const next = { ...prev };
3767
3811
  entries.forEach((entry) => {
3768
- const field = entry.target.dataset.field;
3812
+ const columnId = entry.target.dataset.hdsColumnId;
3769
3813
  const w = Math.round(entry.target.getBoundingClientRect().width);
3770
- if (next[field] !== w) {
3771
- next[field] = w;
3814
+ if (next[columnId] !== w) {
3815
+ next[columnId] = w;
3772
3816
  changed = true;
3773
3817
  }
3774
3818
  });
3775
3819
  return changed ? next : prev;
3776
3820
  });
3777
3821
  });
3778
- Object.entries(columnsByField).forEach(([field, def]) => {
3822
+ const measured = {};
3823
+ Object.entries(columnsById).forEach(([columnId, def]) => {
3779
3824
  const el = def.headerRef.current;
3780
3825
  if (el) {
3781
- el.dataset.field = field;
3826
+ el.dataset.hdsColumnId = columnId;
3827
+ el.dataset.field = String(def.field);
3828
+ measured[columnId] = Math.round(el.getBoundingClientRect().width);
3782
3829
  roRef.current.observe(el);
3783
3830
  }
3784
3831
  });
3832
+ setWidths((prev) => {
3833
+ const keys = Object.keys(measured);
3834
+ const same = keys.length === Object.keys(prev).length && keys.every((key) => prev[key] === measured[key]);
3835
+ return same ? prev : measured;
3836
+ });
3785
3837
  return () => roRef.current?.disconnect();
3786
- }, [columnsByField]);
3838
+ }, [columnsById]);
3787
3839
  return widths;
3788
3840
  }
3789
3841
  function useDataTableRenderer({
@@ -3832,16 +3884,16 @@ function useDataTableRenderer({
3832
3884
  [onColumnVisibilityModelChange]
3833
3885
  )
3834
3886
  );
3835
- const reorderedColumns = useMemo10(() => {
3887
+ const reorderedColumns = useMemo11(() => {
3836
3888
  if (!columnGroupingModel) return columnsProp;
3837
3889
  return reorderColumnsByGroupingModel(columnsProp, columnGroupingModel);
3838
3890
  }, [columnsProp, columnGroupingModel]);
3839
- const visibleColumns = useMemo10(
3891
+ const visibleColumns = useMemo11(
3840
3892
  () => reorderedColumns.filter((col) => visibilityModel[col.field] !== false),
3841
3893
  [reorderedColumns, visibilityModel]
3842
3894
  );
3843
- const visibleFieldSet = useMemo10(() => new Set(visibleColumns.map((c) => c.field)), [visibleColumns]);
3844
- const tableMinWidth = useMemo10(() => {
3895
+ const visibleFieldSet = useMemo11(() => new Set(visibleColumns.map((c) => c.field)), [visibleColumns]);
3896
+ const tableMinWidth = useMemo11(() => {
3845
3897
  const DEFAULT_MIN = 50;
3846
3898
  let total = checkboxSelection ? 40 : 0;
3847
3899
  for (const col of visibleColumns) {
@@ -3849,7 +3901,7 @@ function useDataTableRenderer({
3849
3901
  }
3850
3902
  return total;
3851
3903
  }, [visibleColumns, checkboxSelection]);
3852
- const allColumnsByField = useMemo10(
3904
+ const allColumnsByField = useMemo11(
3853
3905
  () => reorderedColumns.reduce(
3854
3906
  (acc, curr) => ({
3855
3907
  ...acc,
@@ -3859,19 +3911,34 @@ function useDataTableRenderer({
3859
3911
  ),
3860
3912
  [reorderedColumns]
3861
3913
  );
3862
- const visibleColumnsByField = useMemo10(
3863
- () => visibleColumns.reduce(
3864
- (acc, curr) => ({
3865
- ...acc,
3866
- [curr.field]: {
3867
- ...curr,
3914
+ const columnIds = useMemo11(() => {
3915
+ const taken = new Set(visibleColumns.map((column) => String(column.field)));
3916
+ const ids = [];
3917
+ visibleColumns.forEach((column) => {
3918
+ const field = String(column.field);
3919
+ if (!ids.includes(field)) {
3920
+ ids.push(field);
3921
+ return;
3922
+ }
3923
+ let n = 2;
3924
+ while (taken.has(`${field}__${n}`)) n += 1;
3925
+ taken.add(`${field}__${n}`);
3926
+ ids.push(`${field}__${n}`);
3927
+ });
3928
+ return ids;
3929
+ }, [visibleColumns]);
3930
+ const visibleColumnsById = useMemo11(
3931
+ () => Object.fromEntries(
3932
+ visibleColumns.map((column, index) => [
3933
+ columnIds[index],
3934
+ {
3935
+ ...column,
3868
3936
  headerRef: createRef(),
3869
3937
  tableColRef: createRef()
3870
3938
  }
3871
- }),
3872
- {}
3939
+ ])
3873
3940
  ),
3874
- [visibleColumns]
3941
+ [visibleColumns, columnIds]
3875
3942
  );
3876
3943
  const sortComparator = useCallback11(
3877
3944
  (rowA, rowB) => {
@@ -3902,11 +3969,11 @@ function useDataTableRenderer({
3902
3969
  },
3903
3970
  [sortModel, allColumnsByField]
3904
3971
  );
3905
- const rows = useMemo10(
3972
+ const rows = useMemo11(
3906
3973
  () => sortModel.length ? [..._rows].sort(sortComparator) : _rows,
3907
3974
  [_rows, sortModel, sortComparator]
3908
3975
  );
3909
- const sortOrder = useMemo10(
3976
+ const sortOrder = useMemo11(
3910
3977
  () => Array.from(new Set(_sortOrder || ["asc", "desc", null])),
3911
3978
  [_sortOrder]
3912
3979
  );
@@ -3916,12 +3983,12 @@ function useDataTableRenderer({
3916
3983
  (row, index) => _getId?.(row) ?? row.id ?? `${(index || 0) + (page - 1) * pageSize}`,
3917
3984
  [_getId, page, pageSize]
3918
3985
  );
3919
- const selectedModelSet = useMemo10(() => new Set(selectionModel || []), [selectionModel]);
3920
- const dataInPage = useMemo10(
3986
+ const selectedModelSet = useMemo11(() => new Set(selectionModel || []), [selectionModel]);
3987
+ const dataInPage = useMemo11(
3921
3988
  () => !pagination || paginationMode === "server" ? rows : rows.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize),
3922
3989
  [rows, page, pageSize, paginationMode, pagination]
3923
3990
  );
3924
- const selectableDataInPage = useMemo10(
3991
+ const selectableDataInPage = useMemo11(
3925
3992
  () => dataInPage.filter((row, i) => {
3926
3993
  if (!isRowSelectable) return true;
3927
3994
  return isRowSelectable({ row, id: getId(row, i) });
@@ -3951,51 +4018,60 @@ function useDataTableRenderer({
3951
4018
  },
3952
4019
  [dataInPage, getId, isRowSelectable, selectionModel, onSelectionModelChange]
3953
4020
  );
3954
- const isAllSelected = useMemo10(
4021
+ const isAllSelected = useMemo11(
3955
4022
  () => selectableDataInPage.length > 0 && selectableDataInPage.every((row, i) => selectedModelSet.has(getId(row, i))),
3956
4023
  [selectableDataInPage, selectedModelSet, getId]
3957
4024
  );
3958
4025
  const rowCount = totalRowsProp || rows.length;
3959
- const selectableRowCount = useMemo10(() => {
4026
+ const selectableRowCount = useMemo11(() => {
3960
4027
  if (!isRowSelectable) return rowCount;
3961
4028
  return rows.filter((row, i) => isRowSelectable({ row, id: getId(row, i) })).length;
3962
4029
  }, [rows, isRowSelectable, getId, rowCount]);
3963
- const isTotalSelected = useMemo10(
4030
+ const isTotalSelected = useMemo11(
3964
4031
  () => _isTotalSelected ?? (selectableRowCount > 0 && (selectionModel?.length || 0) === selectableRowCount),
3965
4032
  [_isTotalSelected, selectionModel, selectableRowCount]
3966
4033
  );
3967
- const columnWidths = useColumnWidths(visibleColumnsByField);
4034
+ const columnWidths = useColumnWidths(visibleColumnsById);
4035
+ const measuredWidthByField = useMemo11(
4036
+ () => Object.fromEntries(
4037
+ Object.entries(visibleColumnsById).map(([columnId, column]) => [column.field, columnWidths[columnId]])
4038
+ ),
4039
+ [visibleColumnsById, columnWidths]
4040
+ );
3968
4041
  const getWidth = useCallback11(
3969
- (f) => columnWidths[f] ?? allColumnsByField[f]?.width ?? // Column prop 으로 지정된 width
3970
- allColumnsByField[f]?.minWidth ?? 0,
3971
- [columnWidths, allColumnsByField]
4042
+ // 반환값은 pinned offset으로 더해지므로 반드시 숫자여야 한다. width/minWidth는 '500px' 같은 문자열.
4043
+ (f) => measuredWidthByField[f] ?? parsePxValue(allColumnsByField[f]?.width) ?? // Column prop 으로 지정된 width
4044
+ parsePxValue(allColumnsByField[f]?.minWidth) ?? 0,
4045
+ [measuredWidthByField, allColumnsByField]
3972
4046
  );
3973
- const processedColumnGroups = useMemo10(() => {
4047
+ const processedColumnGroups = useMemo11(() => {
3974
4048
  if (!columnGroupingModel) return null;
3975
4049
  return calculateColumnGroups(columnGroupingModel, visibleColumns, visibleFieldSet);
3976
4050
  }, [columnGroupingModel, visibleColumns, visibleFieldSet]);
3977
- const effectivePinnedLeft = useMemo10(
4051
+ const effectivePinnedLeft = useMemo11(
3978
4052
  () => pinnedColumns?.left?.filter((f) => visibleFieldSet.has(f)),
3979
4053
  [pinnedColumns?.left, visibleFieldSet]
3980
4054
  );
3981
- const effectivePinnedRight = useMemo10(
4055
+ const effectivePinnedRight = useMemo11(
3982
4056
  () => pinnedColumns?.right?.filter((f) => visibleFieldSet.has(f)),
3983
4057
  [pinnedColumns?.right, visibleFieldSet]
3984
4058
  );
3985
4059
  const inferredFieldsKey = JSON.stringify(Object.keys(rows[0] || {}));
3986
- const inferredFields = useMemo10(() => JSON.parse(inferredFieldsKey), [inferredFieldsKey]);
3987
- const columns = useMemo10(() => {
4060
+ const inferredFields = useMemo11(() => JSON.parse(inferredFieldsKey), [inferredFieldsKey]);
4061
+ const columns = useMemo11(() => {
3988
4062
  const baseColumns = visibleColumns.length > 0 ? visibleColumns : reorderedColumns.length > 0 ? [] : inferredFields.map((key) => ({
3989
4063
  field: key
3990
4064
  }));
3991
- return baseColumns.map((column) => {
4065
+ return baseColumns.map((column, index) => {
4066
+ const columnId = columnIds[index] ?? String(column.field);
3992
4067
  const isLeftPinned = effectivePinnedLeft?.includes(column.field);
3993
4068
  const isRightPinned = effectivePinnedRight?.includes(column.field);
3994
4069
  const isPinned = isLeftPinned || isRightPinned;
3995
4070
  return {
3996
4071
  ...column,
3997
- headerRef: visibleColumnsByField[column.field]?.headerRef,
3998
- tableColRef: visibleColumnsByField[column.field]?.tableColRef,
4072
+ columnId,
4073
+ headerRef: visibleColumnsById[columnId]?.headerRef,
4074
+ tableColRef: visibleColumnsById[columnId]?.tableColRef,
3999
4075
  isCellEditable: editMode && (typeof column.isCellEditable === "function" ? column.isCellEditable : column.isCellEditable ?? true),
4000
4076
  sort: sortModel.find((sort) => sort.field === column.field)?.sort,
4001
4077
  sortOrder: allColumnsByField[column.field]?.sortOrder || sortOrder,
@@ -4012,7 +4088,8 @@ function useDataTableRenderer({
4012
4088
  inferredFields,
4013
4089
  effectivePinnedLeft,
4014
4090
  effectivePinnedRight,
4015
- visibleColumnsByField,
4091
+ columnIds,
4092
+ visibleColumnsById,
4016
4093
  allColumnsByField,
4017
4094
  editMode,
4018
4095
  sortModel,
@@ -4072,15 +4149,14 @@ function useDataTableRenderer({
4072
4149
  }
4073
4150
  }, [_rows]);
4074
4151
  const handleAutoFit = useCallback11(
4075
- (field) => {
4076
- const colDef = visibleColumnsByField[field];
4152
+ (columnId) => {
4153
+ const colDef = visibleColumnsById[columnId];
4077
4154
  if (!colDef?.headerRef.current) return;
4078
- const column = allColumnsByField[field];
4079
- const columnType = column && "type" in column ? column.type : void 0;
4155
+ const columnType = "type" in colDef ? colDef.type : void 0;
4080
4156
  if (columnType === "actions") return;
4081
4157
  const optimalWidth = computeAutoFitWidth({
4082
4158
  headerEl: colDef.headerRef.current,
4083
- field,
4159
+ field: colDef.field,
4084
4160
  dataInPage
4085
4161
  });
4086
4162
  if (optimalWidth == null) return;
@@ -4088,7 +4164,7 @@ function useDataTableRenderer({
4088
4164
  colDef.headerRef.current.style.width = widthPx;
4089
4165
  if (colDef.tableColRef.current) colDef.tableColRef.current.style.width = widthPx;
4090
4166
  },
4091
- [visibleColumnsByField, allColumnsByField, dataInPage]
4167
+ [visibleColumnsById, dataInPage]
4092
4168
  );
4093
4169
  return {
4094
4170
  rowCount,
@@ -4563,9 +4639,9 @@ function Component(props, apiRef) {
4563
4639
  measureElement: (element) => element.clientHeight,
4564
4640
  overscan: 10
4565
4641
  });
4566
- const paginationModel = useMemo11(() => ({ page, pageSize }), [page, pageSize]);
4642
+ const paginationModel = useMemo12(() => ({ page, pageSize }), [page, pageSize]);
4567
4643
  const columnsKey = getObjectVersion(columns);
4568
- const headerCheckboxElement = useMemo11(
4644
+ const headerCheckboxElement = useMemo12(
4569
4645
  () => /* @__PURE__ */ React26.createElement(
4570
4646
  RenderCheckbox,
4571
4647
  {
@@ -4775,7 +4851,7 @@ function Component(props, apiRef) {
4775
4851
  "col",
4776
4852
  {
4777
4853
  ref: c.tableColRef,
4778
- key: `${c.field.toString()}_${c.width}`,
4854
+ key: c.columnId,
4779
4855
  style: {
4780
4856
  width: c.width,
4781
4857
  minWidth: c.minWidth ?? "50px"
@@ -4961,7 +5037,7 @@ var DataTable = forwardRef7(Component);
4961
5037
  DataTable.displayName = "DataTable";
4962
5038
 
4963
5039
  // src/components/DateRangePicker/DateRangePicker.tsx
4964
- import React27, { forwardRef as forwardRef8, useCallback as useCallback14, useEffect as useEffect8, useImperativeHandle as useImperativeHandle3, useMemo as useMemo12, useRef as useRef8, useState as useState10 } from "react";
5040
+ import React27, { forwardRef as forwardRef8, useCallback as useCallback14, useEffect as useEffect8, useImperativeHandle as useImperativeHandle3, useMemo as useMemo13, useRef as useRef8, useState as useState10 } from "react";
4965
5041
  import { IMaskInput as IMaskInput2, IMask as IMask2 } from "react-imask";
4966
5042
  import CalendarTodayIcon2 from "@mui/icons-material/CalendarToday";
4967
5043
  import { styled as styled14, useThemeProps as useThemeProps7 } from "@mui/joy";
@@ -5183,7 +5259,7 @@ var DateRangePicker = forwardRef8((inProps, ref) => {
5183
5259
  );
5184
5260
  const [anchorEl, setAnchorEl] = useState10(null);
5185
5261
  const open = Boolean(anchorEl);
5186
- const calendarValue = useMemo12(
5262
+ const calendarValue = useMemo13(
5187
5263
  () => value ? parseDates(value, format) : void 0,
5188
5264
  [value, format]
5189
5265
  );
@@ -5500,10 +5576,10 @@ var ModalClose = JoyModalClose;
5500
5576
  var MotionModalOverflow = motion24(JoyModalOverflow);
5501
5577
  var ModalOverflow = MotionModalOverflow;
5502
5578
  ModalOverflow.displayName = "ModalOverflow";
5503
- function ModalFrame(props) {
5579
+ var ModalFrame = React29.forwardRef((props, ref) => {
5504
5580
  const { title, children, titleStartDecorator, onClose, ...innerProps } = props;
5505
- return /* @__PURE__ */ React29.createElement(StyledModalDialog, { ...innerProps }, /* @__PURE__ */ React29.createElement(ModalClose, { onClick: onClose }), /* @__PURE__ */ React29.createElement(DialogTitle_default, null, titleStartDecorator, title), /* @__PURE__ */ React29.createElement(DialogContent_default, null, children));
5506
- }
5581
+ return /* @__PURE__ */ React29.createElement(StyledModalDialog, { ref, ...innerProps }, /* @__PURE__ */ React29.createElement(ModalClose, { onClick: onClose }), /* @__PURE__ */ React29.createElement(DialogTitle_default, null, titleStartDecorator, title), /* @__PURE__ */ React29.createElement(DialogContent_default, null, children));
5582
+ });
5507
5583
  ModalFrame.displayName = "ModalFrame";
5508
5584
 
5509
5585
  // src/components/DialogFrame/DialogFrame.tsx
@@ -5548,7 +5624,7 @@ var InsetDrawer = styled20(JoyDrawer2)(({ theme }) => ({
5548
5624
  }));
5549
5625
 
5550
5626
  // src/components/FilterableCheckboxGroup/FilterableCheckboxGroup.tsx
5551
- import React32, { useCallback as useCallback15, useEffect as useEffect9, useMemo as useMemo13, useRef as useRef9, useState as useState11 } from "react";
5627
+ import React32, { useCallback as useCallback15, useEffect as useEffect9, useMemo as useMemo14, useRef as useRef9, useState as useState11 } from "react";
5552
5628
  import SearchIcon from "@mui/icons-material/Search";
5553
5629
  import { useThemeProps as useThemeProps8 } from "@mui/joy";
5554
5630
  import { useVirtualizer as useVirtualizer3 } from "@tanstack/react-virtual";
@@ -5609,11 +5685,11 @@ function FilterableCheckboxGroup(inProps) {
5609
5685
  const parentRef = useRef9(null);
5610
5686
  const isInitialSortRef = useRef9(false);
5611
5687
  const prevOptionsRef = useRef9([...options]);
5612
- const filteredOptions = useMemo13(() => {
5688
+ const filteredOptions = useMemo14(() => {
5613
5689
  if (!searchTerm) return sortedOptions;
5614
5690
  return sortedOptions.filter((option) => option.label.toLowerCase().includes(searchTerm.toLowerCase()));
5615
5691
  }, [sortedOptions, searchTerm]);
5616
- const itemSize = useMemo13(() => {
5692
+ const itemSize = useMemo14(() => {
5617
5693
  switch (size) {
5618
5694
  case "sm":
5619
5695
  return 28;
@@ -5687,7 +5763,7 @@ function FilterableCheckboxGroup(inProps) {
5687
5763
  },
5688
5764
  [filteredOptions, internalValue, setInternalValue]
5689
5765
  );
5690
- const enabledFilteredOptions = useMemo13(() => filteredOptions.filter((option) => !option.disabled), [filteredOptions]);
5766
+ const enabledFilteredOptions = useMemo14(() => filteredOptions.filter((option) => !option.disabled), [filteredOptions]);
5691
5767
  const isAllSelected = enabledFilteredOptions.length > 0 && enabledFilteredOptions.every((option) => internalValue.includes(option.value));
5692
5768
  const isIndeterminate = !isAllSelected && enabledFilteredOptions.some((option) => internalValue.includes(option.value));
5693
5769
  return /* @__PURE__ */ React32.createElement("div", { style: { width: "100%" } }, /* @__PURE__ */ React32.createElement(
@@ -5783,7 +5859,10 @@ import {
5783
5859
  MenuButton as JoyMenuButton2,
5784
5860
  IconButton as JoyIconButton2
5785
5861
  } from "@mui/joy";
5786
- function IconMenuButton(props) {
5862
+ var MenuButtonRootSlot = React33.forwardRef(function MenuButtonRootSlot2({ as, ...rest }, ref) {
5863
+ return /* @__PURE__ */ React33.createElement(JoyIconButton2, { ...rest, component: as ?? "button", ref });
5864
+ });
5865
+ function IconMenuButtonInner(props, ref) {
5787
5866
  const {
5788
5867
  size,
5789
5868
  icon,
@@ -5794,6 +5873,8 @@ function IconMenuButton(props) {
5794
5873
  variant = "plain",
5795
5874
  placement = "bottom"
5796
5875
  } = props;
5876
+ const { ref: buttonComponentRef, ...buttonComponentProps } = props.buttonComponentProps ?? {};
5877
+ const mergedButtonRef = useMergedRef(buttonComponentRef, ref);
5797
5878
  if (!items.length) {
5798
5879
  return /* @__PURE__ */ React33.createElement(
5799
5880
  JoyIconButton2,
@@ -5804,7 +5885,8 @@ function IconMenuButton(props) {
5804
5885
  color,
5805
5886
  disabled,
5806
5887
  loading,
5807
- ...props.buttonComponentProps ?? {}
5888
+ ...buttonComponentProps,
5889
+ ref: mergedButtonRef
5808
5890
  },
5809
5891
  icon
5810
5892
  );
@@ -5812,7 +5894,7 @@ function IconMenuButton(props) {
5812
5894
  return /* @__PURE__ */ React33.createElement(Dropdown_default, null, /* @__PURE__ */ React33.createElement(
5813
5895
  JoyMenuButton2,
5814
5896
  {
5815
- slots: { root: JoyIconButton2 },
5897
+ slots: { root: MenuButtonRootSlot },
5816
5898
  slotProps: {
5817
5899
  root: {
5818
5900
  component: props.buttonComponent ?? "button",
@@ -5821,13 +5903,16 @@ function IconMenuButton(props) {
5821
5903
  color,
5822
5904
  disabled,
5823
5905
  loading,
5824
- ...props.buttonComponentProps ?? {}
5906
+ ...buttonComponentProps,
5907
+ // Joy의 useSlot이 내부 ref와 이 ref를 합쳐준다. 위 no-items 분기와 같은 경로로 ref를 넘긴다.
5908
+ ref: mergedButtonRef
5825
5909
  }
5826
5910
  }
5827
5911
  },
5828
5912
  icon
5829
5913
  ), /* @__PURE__ */ React33.createElement(Menu, { placement, size }, items.map((i) => /* @__PURE__ */ React33.createElement(MenuItem, { key: i.text, component: i.component, ...i.componentProps ?? {} }, i.text))));
5830
5914
  }
5915
+ var IconMenuButton = React33.forwardRef(IconMenuButtonInner);
5831
5916
  IconMenuButton.displayName = "IconMenuButton";
5832
5917
 
5833
5918
  // src/components/Markdown/Markdown.tsx
@@ -6277,7 +6362,7 @@ var MonthPicker = forwardRef9((inProps, ref) => {
6277
6362
  });
6278
6363
 
6279
6364
  // src/components/MonthRangePicker/MonthRangePicker.tsx
6280
- import React37, { forwardRef as forwardRef10, useCallback as useCallback17, useEffect as useEffect12, useImperativeHandle as useImperativeHandle5, useMemo as useMemo14, useRef as useRef11, useState as useState14 } from "react";
6365
+ import React37, { forwardRef as forwardRef10, useCallback as useCallback17, useEffect as useEffect12, useImperativeHandle as useImperativeHandle5, useMemo as useMemo15, useRef as useRef11, useState as useState14 } from "react";
6281
6366
  import { IMaskInput as IMaskInput3, IMask as IMask3 } from "react-imask";
6282
6367
  import CalendarTodayIcon4 from "@mui/icons-material/CalendarToday";
6283
6368
  import { styled as styled22, useThemeProps as useThemeProps10 } from "@mui/joy";
@@ -6408,7 +6493,7 @@ var MonthRangePicker = forwardRef10((inProps, ref) => {
6408
6493
  );
6409
6494
  const [anchorEl, setAnchorEl] = useState14(null);
6410
6495
  const open = Boolean(anchorEl);
6411
- const calendarValue = useMemo14(() => value ? parseDates2(value) : void 0, [value]);
6496
+ const calendarValue = useMemo15(() => value ? parseDates2(value) : void 0, [value]);
6412
6497
  useEffect12(() => {
6413
6498
  if (value) {
6414
6499
  try {
@@ -6691,7 +6776,7 @@ function Navigator(props) {
6691
6776
  Navigator.displayName = "Navigator";
6692
6777
 
6693
6778
  // src/components/PercentageInput/PercentageInput.tsx
6694
- import React41, { useCallback as useCallback18, useMemo as useMemo15 } from "react";
6779
+ import React41, { useCallback as useCallback18, useMemo as useMemo16 } from "react";
6695
6780
  import { NumericFormat as NumericFormat2 } from "react-number-format";
6696
6781
  import { styled as styled25, useThemeProps as useThemeProps11 } from "@mui/joy";
6697
6782
  var padDecimal = (value, decimalScale) => {
@@ -6750,13 +6835,13 @@ var PercentageInput = React41.forwardRef(
6750
6835
  props.defaultValue ?? null,
6751
6836
  useCallback18((value2) => onChange?.({ target: { name, value: value2 } }), [onChange, name])
6752
6837
  );
6753
- const value = useMemo15(() => {
6838
+ const value = useMemo16(() => {
6754
6839
  if (_value && useMinorUnit) {
6755
6840
  return _value / Math.pow(10, maxDecimalScale);
6756
6841
  }
6757
6842
  return _value;
6758
6843
  }, [_value, useMinorUnit, maxDecimalScale]);
6759
- const internalError = useMemo15(
6844
+ const internalError = useMemo16(
6760
6845
  () => value != null && (max != null && value > max || min != null && value < min),
6761
6846
  [max, min, value]
6762
6847
  );
@@ -7522,7 +7607,7 @@ function ThemeProvider(props) {
7522
7607
  ThemeProvider.displayName = "ThemeProvider";
7523
7608
 
7524
7609
  // src/components/Uploader/Uploader.tsx
7525
- import React49, { useCallback as useCallback19, useEffect as useEffect13, useMemo as useMemo16, useRef as useRef12, useState as useState16 } from "react";
7610
+ import React49, { useCallback as useCallback19, useEffect as useEffect13, useMemo as useMemo17, useRef as useRef12, useState as useState16 } from "react";
7526
7611
  import { styled as styled31, Input as Input2 } from "@mui/joy";
7527
7612
  import MuiFileUploadIcon from "@mui/icons-material/CloudUploadRounded";
7528
7613
  import MuiUploadFileIcon from "@mui/icons-material/UploadFileRounded";
@@ -7662,8 +7747,8 @@ var Uploader = React49.memo((props) => {
7662
7747
  const [files, setFiles] = useState16([]);
7663
7748
  const [uploaded, setUploaded] = useState16(props.uploaded || []);
7664
7749
  const [previewState, setPreviewState] = useState16("idle");
7665
- const accepts = useMemo16(() => accept.split(",").map((accept2) => accept2.trim()), [accept]);
7666
- const parsedAccepts = useMemo16(
7750
+ const accepts = useMemo17(() => accept.split(",").map((accept2) => accept2.trim()), [accept]);
7751
+ const parsedAccepts = useMemo17(
7667
7752
  () => accepts.flatMap((type) => {
7668
7753
  if (["image/*", "video/*", "audio/*"].includes(type)) {
7669
7754
  return ALL_EXTENSIONS_BY_TYPE[type];
@@ -7672,7 +7757,7 @@ var Uploader = React49.memo((props) => {
7672
7757
  }),
7673
7758
  [accepts]
7674
7759
  );
7675
- const helperText = useMemo16(() => {
7760
+ const helperText = useMemo17(() => {
7676
7761
  if (helperTextProp) {
7677
7762
  return helperTextProp;
7678
7763
  }
@@ -7702,8 +7787,8 @@ var Uploader = React49.memo((props) => {
7702
7787
  }
7703
7788
  return helperTexts.join(", ");
7704
7789
  }, [accepts, maxFileTotalSize, maxCount, helperTextProp]);
7705
- const error = useMemo16(() => !!errorText || errorProp, [errorProp, errorText]);
7706
- const showDropZone = useMemo16(
7790
+ const error = useMemo17(() => !!errorText || errorProp, [errorProp, errorText]);
7791
+ const showDropZone = useMemo17(
7707
7792
  () => !maxCount || maxCount && [...uploaded, ...files].length !== maxCount,
7708
7793
  [files, maxCount, uploaded]
7709
7794
  );