sellmate-design-system-react 0.8.3 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/components/SBarcodeInput/SBarcodeInput.cjs +78 -2
  2. package/dist/components/SBarcodeInput/SBarcodeInput.cjs.map +1 -1
  3. package/dist/components/SBarcodeInput/SBarcodeInput.js +78 -2
  4. package/dist/components/SBarcodeInput/SBarcodeInput.js.map +1 -1
  5. package/dist/components/SChipInput/SChipInput.cjs +78 -2
  6. package/dist/components/SChipInput/SChipInput.cjs.map +1 -1
  7. package/dist/components/SChipInput/SChipInput.js +78 -2
  8. package/dist/components/SChipInput/SChipInput.js.map +1 -1
  9. package/dist/components/SDatePicker/SDatePicker.cjs +78 -2
  10. package/dist/components/SDatePicker/SDatePicker.cjs.map +1 -1
  11. package/dist/components/SDatePicker/SDatePicker.js +78 -2
  12. package/dist/components/SDatePicker/SDatePicker.js.map +1 -1
  13. package/dist/components/SDateRangePicker/SDateRangePicker.cjs +78 -2
  14. package/dist/components/SDateRangePicker/SDateRangePicker.cjs.map +1 -1
  15. package/dist/components/SDateRangePicker/SDateRangePicker.js +78 -2
  16. package/dist/components/SDateRangePicker/SDateRangePicker.js.map +1 -1
  17. package/dist/components/SField/SField.cjs +78 -2
  18. package/dist/components/SField/SField.cjs.map +1 -1
  19. package/dist/components/SField/SField.js +78 -2
  20. package/dist/components/SField/SField.js.map +1 -1
  21. package/dist/components/SFilePicker/SFilePicker.cjs +78 -2
  22. package/dist/components/SFilePicker/SFilePicker.cjs.map +1 -1
  23. package/dist/components/SFilePicker/SFilePicker.js +78 -2
  24. package/dist/components/SFilePicker/SFilePicker.js.map +1 -1
  25. package/dist/components/SGnb/SGnb.cjs +58 -16
  26. package/dist/components/SGnb/SGnb.cjs.map +1 -1
  27. package/dist/components/SGnb/SGnb.d.ts +15 -0
  28. package/dist/components/SGnb/SGnb.js +58 -16
  29. package/dist/components/SGnb/SGnb.js.map +1 -1
  30. package/dist/components/SInput/SInput.cjs +78 -2
  31. package/dist/components/SInput/SInput.cjs.map +1 -1
  32. package/dist/components/SInput/SInput.js +78 -2
  33. package/dist/components/SInput/SInput.js.map +1 -1
  34. package/dist/components/SKeyValueTable/SKeyValueTable.cjs +224 -118
  35. package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
  36. package/dist/components/SKeyValueTable/SKeyValueTable.js +224 -118
  37. package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
  38. package/dist/components/SNumberInput/SNumberInput.cjs +78 -2
  39. package/dist/components/SNumberInput/SNumberInput.cjs.map +1 -1
  40. package/dist/components/SNumberInput/SNumberInput.js +78 -2
  41. package/dist/components/SNumberInput/SNumberInput.js.map +1 -1
  42. package/dist/components/SSelect/SSelect.cjs +155 -49
  43. package/dist/components/SSelect/SSelect.cjs.map +1 -1
  44. package/dist/components/SSelect/SSelect.js +155 -49
  45. package/dist/components/SSelect/SSelect.js.map +1 -1
  46. package/dist/components/SSelect/select.config.d.ts +7 -0
  47. package/dist/components/STable/STable.cjs +155 -49
  48. package/dist/components/STable/STable.cjs.map +1 -1
  49. package/dist/components/STable/STable.js +155 -49
  50. package/dist/components/STable/STable.js.map +1 -1
  51. package/dist/components/STextarea/STextarea.cjs +78 -2
  52. package/dist/components/STextarea/STextarea.cjs.map +1 -1
  53. package/dist/components/STextarea/STextarea.js +78 -2
  54. package/dist/components/STextarea/STextarea.js.map +1 -1
  55. package/dist/components/STimePicker/STimePicker.cjs +78 -2
  56. package/dist/components/STimePicker/STimePicker.cjs.map +1 -1
  57. package/dist/components/STimePicker/STimePicker.js +78 -2
  58. package/dist/components/STimePicker/STimePicker.js.map +1 -1
  59. package/dist/components/STimeRangePicker/STimeRangePicker.cjs +78 -2
  60. package/dist/components/STimeRangePicker/STimeRangePicker.cjs.map +1 -1
  61. package/dist/components/STimeRangePicker/STimeRangePicker.js +78 -2
  62. package/dist/components/STimeRangePicker/STimeRangePicker.js.map +1 -1
  63. package/dist/components/STooltip/STooltip.cjs +78 -2
  64. package/dist/components/STooltip/STooltip.cjs.map +1 -1
  65. package/dist/components/STooltip/STooltip.d.ts +1 -1
  66. package/dist/components/STooltip/STooltip.js +78 -2
  67. package/dist/components/STooltip/STooltip.js.map +1 -1
  68. package/dist/index.cjs +209 -65
  69. package/dist/index.cjs.map +1 -1
  70. package/dist/index.js +209 -65
  71. package/dist/index.js.map +1 -1
  72. package/dist/styles.css +35 -8
  73. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4147,7 +4147,14 @@ function useBody(content, message = []) {
4147
4147
  if (content != null) return content;
4148
4148
  if (message.length === 0) return null;
4149
4149
  const singleLine = message.length === 1;
4150
- return /* @__PURE__ */ jsx(Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsx("div", { className: singleLine ? "leading-[24px]" : void 0, children: line }, i)) });
4150
+ return /* @__PURE__ */ jsx(Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsx(
4151
+ "div",
4152
+ {
4153
+ className: singleLine ? "leading-[24px]" : void 0,
4154
+ dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(line) }
4155
+ },
4156
+ i
4157
+ )) });
4151
4158
  }
4152
4159
  var STooltip = forwardRef(function STooltip2({
4153
4160
  content,
@@ -4205,7 +4212,7 @@ var STooltip = forwardRef(function STooltip2({
4205
4212
  if (disabled || body == null) return /* @__PURE__ */ jsx(Fragment, { children: triggerNode });
4206
4213
  const isHover = trigger === "hover";
4207
4214
  const contentClass = cn(
4208
- "z-50 max-w-xs rounded-[6px] px-[16px] py-[12px] text-[12px] leading-[20px]",
4215
+ "z-50 w-fit whitespace-nowrap rounded-[6px] px-[16px] py-[12px] text-[12px] leading-[20px]",
4209
4216
  FLOATING_SLIDE_ANIM,
4210
4217
  className
4211
4218
  );
@@ -5160,6 +5167,9 @@ var SGnb = forwardRef(function SGnb2({
5160
5167
  onFoldChange,
5161
5168
  onLauncherClick,
5162
5169
  logo,
5170
+ railFooter,
5171
+ menuFooter,
5172
+ foldedFooter,
5163
5173
  ariaLabel = "global navigation",
5164
5174
  className,
5165
5175
  style,
@@ -5313,7 +5323,7 @@ var SGnb = forwardRef(function SGnb2({
5313
5323
  className: "shrink-0"
5314
5324
  }
5315
5325
  ),
5316
- /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap flex flex-no-wrap items-center", children: [
5326
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap flex items-center", children: [
5317
5327
  depth > 1 && iconBranch ? /* @__PURE__ */ jsx(
5318
5328
  "div",
5319
5329
  {
@@ -5524,42 +5534,77 @@ var SGnb = forwardRef(function SGnb2({
5524
5534
  transition: `transform ${GNB_FOLD_MS}ms ease-out, ${hideAfterSlide(folded)}`
5525
5535
  },
5526
5536
  children: [
5527
- useRail && // 레일도 내비게이션 landmark nav 세워야 aria-label(레일) 스크린리더에 노출된다
5528
- // (role 없는 ul aria-label 영역명으로 읽히지 않는다). 메뉴 nav 와는 레이블로 구분된다.
5529
- /* @__PURE__ */ jsx(
5530
- "nav",
5537
+ useRail && // 레일 컬럼스크롤되는 아이템 목록(nav) 하단 고정 footer 를 한 컬럼에 담는다.
5538
+ // footer 내비게이션이 아니므로 nav(landmark) 밖에 두고, 컬럼 폭·구분선·배경은 래퍼가
5539
+ // 전체 높이에 걸쳐 책임진다(그래야 footer 자리까지 배경·오른쪽 선이 이어진다).
5540
+ /* @__PURE__ */ jsxs(
5541
+ "div",
5531
5542
  {
5532
- "aria-label": `${ariaLabel} rail`,
5533
- className: "flex shrink-0 flex-col overflow-y-auto",
5543
+ className: "flex shrink-0 flex-col overflow-hidden",
5534
5544
  style: {
5535
5545
  width: GNB_RAIL_WIDTH,
5536
- padding: GNB_RAIL.padding,
5537
5546
  borderRight: `1px solid ${C.topBorder}`,
5538
5547
  backgroundColor: C.panelBg,
5539
5548
  pointerEvents: "auto"
5540
5549
  },
5541
- children: /* @__PURE__ */ jsx("ul", { className: "m-0 flex list-none flex-col p-0", style: { gap: GNB_RAIL.gap }, children: railItems.map(renderRailItem) })
5550
+ children: [
5551
+ /* @__PURE__ */ jsx(
5552
+ "nav",
5553
+ {
5554
+ "aria-label": `${ariaLabel} rail`,
5555
+ className: cn(
5556
+ "flex min-h-0 flex-1 flex-col overflow-x-hidden overflow-y-auto",
5557
+ SCROLLBAR_CLASS
5558
+ ),
5559
+ style: { padding: GNB_RAIL.padding },
5560
+ children: /* @__PURE__ */ jsx("ul", { className: "m-0 flex list-none flex-col p-0", style: { gap: GNB_RAIL.gap }, children: railItems.map(renderRailItem) })
5561
+ }
5562
+ ),
5563
+ railFooter && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: railFooter })
5564
+ ]
5542
5565
  }
5543
5566
  ),
5544
- showMenu && /* @__PURE__ */ jsx(
5545
- "nav",
5567
+ showMenu && /* @__PURE__ */ jsxs(
5568
+ "div",
5546
5569
  {
5547
- "aria-label": ariaLabel,
5548
- className: "flex shrink-0 flex-col overflow-y-auto",
5570
+ className: "flex shrink-0 flex-col overflow-hidden",
5549
5571
  style: {
5550
5572
  width: GNB_MENU_WIDTH,
5551
- paddingTop: M.bodyPaddingY,
5552
- paddingBottom: M.bodyPaddingY,
5553
5573
  backgroundColor: C.panelBg,
5554
5574
  // full 은 상단바가 전폭이라 루트가 오른쪽 선을 못 그린다 → 메뉴 오른쪽(페이지 경계)이 대신 그린다.
5555
5575
  borderRight: header === "full" ? rightBorder : void 0,
5556
5576
  pointerEvents: "auto"
5557
5577
  },
5558
- children: /* @__PURE__ */ jsx("ul", { className: "m-0 flex list-none flex-col p-0", children: menuItems.map((item) => renderItem(item, 1)) })
5578
+ children: [
5579
+ /* @__PURE__ */ jsx(
5580
+ "nav",
5581
+ {
5582
+ "aria-label": ariaLabel,
5583
+ className: cn(
5584
+ "flex min-h-0 flex-1 flex-col overflow-x-hidden overflow-y-auto",
5585
+ SCROLLBAR_CLASS
5586
+ ),
5587
+ style: {
5588
+ paddingTop: M.bodyPaddingY,
5589
+ paddingBottom: M.bodyPaddingY
5590
+ },
5591
+ children: /* @__PURE__ */ jsx("ul", { className: "m-0 flex list-none flex-col p-0", children: menuItems.map((item) => renderItem(item, 1)) })
5592
+ }
5593
+ ),
5594
+ menuFooter && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: menuFooter })
5595
+ ]
5559
5596
  }
5560
5597
  )
5561
5598
  ]
5562
5599
  }
5600
+ ),
5601
+ railFolded && foldedFooter && /* @__PURE__ */ jsx(
5602
+ "div",
5603
+ {
5604
+ className: "flex shrink-0 items-center justify-center mb-[24px]",
5605
+ style: { pointerEvents: "auto" },
5606
+ children: foldedFooter
5607
+ }
5563
5608
  )
5564
5609
  ]
5565
5610
  }
@@ -6288,6 +6333,16 @@ function flattenOptions(options, depth = 1) {
6288
6333
  return out;
6289
6334
  }
6290
6335
  var selectableOptions = (flat) => flat.filter((o) => !o.isGroup && !o.disabled);
6336
+ function collectGroupLeafValues(flat, groupIndex) {
6337
+ const group = flat[groupIndex];
6338
+ if (group == null || !group.isGroup) return [];
6339
+ const values = [];
6340
+ for (let i = groupIndex + 1; i < flat.length; i++) {
6341
+ if (flat[i].depth <= group.depth) break;
6342
+ if (!flat[i].isGroup && !flat[i].disabled) values.push(flat[i].value);
6343
+ }
6344
+ return values;
6345
+ }
6291
6346
  var isHtmlLabel = (label) => /<[a-z][\s\S]*>/i.test(label);
6292
6347
  var extractText = (html) => html.replace(/<[^>]*>/g, "");
6293
6348
  var SEARCH_THRESHOLD = 11;
@@ -6413,16 +6468,31 @@ var SSelect = forwardRef(function SSelect2({
6413
6468
  const allValues = selectable.map((o) => o.value);
6414
6469
  const allSelected = allValues.length > 0 && allValues.every((v) => selected.includes(v));
6415
6470
  const hasItems = filtered.some((o) => !o.isGroup);
6471
+ const groupLeafValues = useMemo(() => {
6472
+ const map = /* @__PURE__ */ new Map();
6473
+ filtered.forEach((o, i) => {
6474
+ if (o.isGroup) map.set(i, collectGroupLeafValues(filtered, i));
6475
+ });
6476
+ return map;
6477
+ }, [filtered]);
6416
6478
  const navigableItems = useMemo(() => {
6417
6479
  const items = [];
6418
6480
  if (multi && useSelectAll && allValues.length > 0) {
6419
- items.push({ value: "__select_all__", isSelectAll: true });
6481
+ items.push({ key: "__select_all__", isSelectAll: true });
6420
6482
  }
6421
- filtered.forEach((o) => {
6422
- if (!o.isGroup && !o.disabled) items.push({ value: o.value });
6483
+ filtered.forEach((o, i) => {
6484
+ if (o.disabled) return;
6485
+ if (o.isGroup) {
6486
+ if (!multi) return;
6487
+ const leafValues = groupLeafValues.get(i) ?? [];
6488
+ if (leafValues.length === 0) return;
6489
+ items.push({ key: `__group_${i}__`, isGroup: true, leafValues });
6490
+ } else {
6491
+ items.push({ key: o.value, value: o.value });
6492
+ }
6423
6493
  });
6424
6494
  return items;
6425
- }, [allValues.length, filtered, multi, useSelectAll]);
6495
+ }, [allValues.length, filtered, groupLeafValues, multi, useSelectAll]);
6426
6496
  const triggerText = (() => {
6427
6497
  if (selected.length === 0) return placeholder;
6428
6498
  if (multi) {
@@ -6444,6 +6514,17 @@ var SSelect = forwardRef(function SSelect2({
6444
6514
  const handleSelectAll = () => {
6445
6515
  emit2(allSelected ? [] : allValues);
6446
6516
  };
6517
+ const handleToggleGroup = (leafValues) => {
6518
+ if (leafValues.length === 0) return;
6519
+ const selectedSet = new Set(selected);
6520
+ const allSelectedInGroup = leafValues.every((v) => selectedSet.has(v));
6521
+ if (allSelectedInGroup) {
6522
+ const remove = new Set(leafValues);
6523
+ emit2(selected.filter((v) => !remove.has(v)));
6524
+ } else {
6525
+ emit2([...selected, ...leafValues.filter((v) => !selectedSet.has(v))]);
6526
+ }
6527
+ };
6447
6528
  useEffect(() => {
6448
6529
  if (!open) {
6449
6530
  setFocusedIndex(-1);
@@ -6484,6 +6565,10 @@ var SSelect = forwardRef(function SSelect2({
6484
6565
  handleSelectAll();
6485
6566
  return;
6486
6567
  }
6568
+ if (focused.isGroup) {
6569
+ handleToggleGroup(focused.leafValues ?? []);
6570
+ return;
6571
+ }
6487
6572
  handleSelect(focused.value);
6488
6573
  };
6489
6574
  const handleKeyDown = (event) => {
@@ -6647,20 +6732,20 @@ var SSelect = forwardRef(function SSelect2({
6647
6732
  items: filtered,
6648
6733
  multi,
6649
6734
  selected,
6650
- focusedValue: navigableItems[focusedIndex]?.isSelectAll ? "__select_all__" : navigableItems[focusedIndex]?.value,
6735
+ groupLeafValues,
6736
+ focusedValue: navigableItems[focusedIndex]?.key,
6651
6737
  showSelectAll: multi && useSelectAll && allValues.length > 0,
6652
6738
  selectAllLabel: allSelectedLabel,
6653
6739
  selectAllSelected: allSelected,
6654
6740
  onSelectAll: handleSelectAll,
6655
6741
  onSelect: handleSelect,
6656
- onHoverValue: (value2) => {
6657
- if (value2 == null) {
6742
+ onToggleGroup: handleToggleGroup,
6743
+ onHoverValue: (key) => {
6744
+ if (key == null) {
6658
6745
  setFocusedIndex(-1);
6659
6746
  return;
6660
6747
  }
6661
- const index = navigableItems.findIndex(
6662
- (item) => item.isSelectAll ? value2 === "__select_all__" : item.value === value2
6663
- );
6748
+ const index = navigableItems.findIndex((item) => item.key === key);
6664
6749
  if (index >= 0) setFocusedIndex(index);
6665
6750
  }
6666
6751
  }
@@ -6679,20 +6764,23 @@ function ItemList({
6679
6764
  items,
6680
6765
  multi,
6681
6766
  selected,
6767
+ groupLeafValues,
6682
6768
  focusedValue,
6683
6769
  showSelectAll,
6684
6770
  selectAllLabel,
6685
6771
  selectAllSelected,
6686
6772
  onSelectAll,
6687
6773
  onSelect,
6774
+ onToggleGroup,
6688
6775
  onHoverValue
6689
6776
  }) {
6777
+ const selectedSet = useMemo(() => new Set(selected), [selected]);
6690
6778
  const itemBase = cn(
6691
6779
  "group flex w-full cursor-pointer select-none items-center gap-[8px] border-none bg-transparent text-left text-[12px] leading-[20px] outline-none",
6692
6780
  "text-[color:var(--cmp-listItem-content-default)]",
6693
6781
  "disabled:cursor-not-allowed disabled:text-[color:var(--cmp-listItem-content-disabled)]"
6694
6782
  );
6695
- const activeClass = "hover:bg-[var(--cmp-listItem-bg-hover)] hover:text-[color:var(--cmp-listItem-content-hover)] focus:bg-[var(--cmp-listItem-bg-hover)] focus:text-[color:var(--cmp-listItem-content-hover)]";
6783
+ const activeClass = "hover:bg-[var(--cmp-listItem-bg-hover)] hover:text-[color:var(--cmp-listItem-content-hover)] focus-visible:bg-[var(--cmp-listItem-bg-hover)] focus-visible:text-[color:var(--cmp-listItem-content-hover)]";
6696
6784
  return /* @__PURE__ */ jsxs("div", { role: "listbox", "aria-multiselectable": multi || void 0, children: [
6697
6785
  showSelectAll && /* @__PURE__ */ jsxs(
6698
6786
  "button",
@@ -6709,23 +6797,7 @@ function ItemList({
6709
6797
  onMouseLeave: () => onHoverValue(null),
6710
6798
  onClick: onSelectAll,
6711
6799
  children: [
6712
- /* @__PURE__ */ jsx(
6713
- "span",
6714
- {
6715
- className: cn(
6716
- "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
6717
- selectAllSelected ? focusedValue === "__select_all__" ? "border-[color:var(--cmp-checkbox-checked-border-inverse)] bg-[var(--cmp-checkbox-checked-bg-default)]" : "border-[color:var(--cmp-checkbox-checked-bg-default)] bg-[var(--cmp-checkbox-checked-bg-default)]" : "border-[color:var(--cmp-checkbox-unchecked-border-default)] bg-[var(--cmp-checkbox-unchecked-bg-default)]"
6718
- ),
6719
- children: selectAllSelected && /* @__PURE__ */ jsx(
6720
- SIcon,
6721
- {
6722
- name: "checkboxCheck",
6723
- size: 12,
6724
- color: "var(--cmp-checkbox-checked-icon-default)"
6725
- }
6726
- )
6727
- }
6728
- ),
6800
+ /* @__PURE__ */ jsx(CheckboxBox, { state: selectAllSelected, focused: focusedValue === "__select_all__" }),
6729
6801
  /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: selectAllLabel })
6730
6802
  ]
6731
6803
  }
@@ -6735,12 +6807,71 @@ function ItemList({
6735
6807
  const rowKey = `${o.value}-${idx}`;
6736
6808
  if (o.isGroup) {
6737
6809
  const isDepth1 = o.depth === 1;
6810
+ const groupTone = isDepth1 ? "border-t border-solid border-[color:var(--cmp-listItem-depth1-border-color)] bg-[var(--cmp-listItem-depth1-bg-default)] font-bold" : "bg-[var(--cmp-listItem-depth2-middle-bg)] font-medium";
6811
+ if (multi) {
6812
+ const leafValues = groupLeafValues.get(idx) ?? [];
6813
+ const total = leafValues.length;
6814
+ const selectedCount = leafValues.reduce((n, v) => selectedSet.has(v) ? n + 1 : n, 0);
6815
+ const groupState = total === 0 || selectedCount === 0 ? false : selectedCount === total ? true : null;
6816
+ const groupDisabled = o.disabled || total === 0;
6817
+ const groupFocused = focusedValue === `__group_${idx}__`;
6818
+ return /* @__PURE__ */ jsxs(
6819
+ "button",
6820
+ {
6821
+ type: "button",
6822
+ role: "option",
6823
+ "aria-selected": groupState === true,
6824
+ disabled: groupDisabled,
6825
+ "data-select-focused": groupFocused ? "true" : void 0,
6826
+ "data-select-active": groupFocused ? "true" : void 0,
6827
+ className: cn(
6828
+ "flex w-full select-none items-center gap-[8px] border-none py-[4px] pr-[12px] text-left text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)]",
6829
+ groupTone,
6830
+ groupDisabled ? "cursor-not-allowed text-[color:var(--cmp-listItem-content-disabled)]" : "cursor-pointer",
6831
+ groupDisabled && isDepth1 && "bg-[var(--cmp-listItem-depth1-bg-disabled)]",
6832
+ // 포커스 하이라이트는 depth 배경보다 뒤에 둬 tailwind-merge 로 이기게 한다.
6833
+ groupFocused && !groupDisabled && "bg-[var(--cmp-listItem-bg-hover)] text-[color:var(--cmp-listItem-content-hover)]"
6834
+ ),
6835
+ style: { paddingLeft: padLeft },
6836
+ onMouseEnter: () => onHoverValue(`__group_${idx}__`),
6837
+ onMouseLeave: () => onHoverValue(null),
6838
+ onClick: () => onToggleGroup(leafValues),
6839
+ children: [
6840
+ /* @__PURE__ */ jsx(CheckboxBox, { state: groupState, disabled: groupDisabled, focused: groupFocused }),
6841
+ isHtmlLabel(o.label) ? /* @__PURE__ */ jsx(
6842
+ "span",
6843
+ {
6844
+ className: "min-w-0 truncate",
6845
+ dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(o.label) }
6846
+ }
6847
+ ) : /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: o.label }),
6848
+ total > 0 && /* @__PURE__ */ jsxs(
6849
+ "span",
6850
+ {
6851
+ className: cn(
6852
+ "shrink-0 font-medium",
6853
+ groupFocused ? "text-white" : "text-[color:var(--cmp-listItem-content-disabled)]"
6854
+ ),
6855
+ children: [
6856
+ "(",
6857
+ selectedCount,
6858
+ "/",
6859
+ total,
6860
+ ")"
6861
+ ]
6862
+ }
6863
+ )
6864
+ ]
6865
+ },
6866
+ rowKey
6867
+ );
6868
+ }
6738
6869
  return /* @__PURE__ */ jsx(
6739
6870
  "div",
6740
6871
  {
6741
6872
  className: cn(
6742
6873
  "select-none py-[4px] pr-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)]",
6743
- isDepth1 ? "border-t border-solid border-[color:var(--cmp-listItem-depth1-border-color)] bg-[var(--cmp-listItem-depth1-bg-default)] font-bold" : "bg-[var(--cmp-listItem-depth2-middle-bg)] font-medium",
6874
+ groupTone,
6744
6875
  // 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
6745
6876
  // 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
6746
6877
  o.disabled && "cursor-not-allowed text-[color:var(--cmp-listItem-content-disabled)]",
@@ -6776,25 +6907,11 @@ function ItemList({
6776
6907
  onClick: () => onSelect(o.value),
6777
6908
  children: [
6778
6909
  multi && /* @__PURE__ */ jsx(
6779
- "span",
6910
+ CheckboxBox,
6780
6911
  {
6781
- className: cn(
6782
- "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
6783
- o.disabled ? (
6784
- // 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
6785
- "cursor-not-allowed border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
6786
- ) : cn(
6787
- isSelected ? focusedValue === o.value ? "border-[color:var(--cmp-checkbox-checked-border-inverse)] bg-[var(--cmp-checkbox-checked-bg-default)]" : "border-[color:var(--cmp-checkbox-checked-bg-default)] bg-[var(--cmp-checkbox-checked-bg-default)]" : "border-[color:var(--cmp-checkbox-unchecked-border-default)] bg-[var(--cmp-checkbox-unchecked-bg-default)]"
6788
- )
6789
- ),
6790
- children: isSelected && /* @__PURE__ */ jsx(
6791
- SIcon,
6792
- {
6793
- name: "checkboxCheck",
6794
- size: 12,
6795
- color: o.disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
6796
- }
6797
- )
6912
+ state: isSelected,
6913
+ disabled: o.disabled,
6914
+ focused: focusedValue === o.value
6798
6915
  }
6799
6916
  ),
6800
6917
  isHtmlLabel(o.label) ? /* @__PURE__ */ jsx(
@@ -6811,6 +6928,33 @@ function ItemList({
6811
6928
  })
6812
6929
  ] });
6813
6930
  }
6931
+ function CheckboxBox({
6932
+ state: state2,
6933
+ disabled = false,
6934
+ focused = false
6935
+ }) {
6936
+ const filled = state2 === true || state2 === null;
6937
+ return /* @__PURE__ */ jsx(
6938
+ "span",
6939
+ {
6940
+ className: cn(
6941
+ "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
6942
+ disabled ? (
6943
+ // 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
6944
+ "cursor-not-allowed border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
6945
+ ) : filled ? focused ? "border-[color:var(--cmp-checkbox-checked-border-inverse)] bg-[var(--cmp-checkbox-checked-bg-default)]" : "border-[color:var(--cmp-checkbox-checked-bg-default)] bg-[var(--cmp-checkbox-checked-bg-default)]" : "border-[color:var(--cmp-checkbox-unchecked-border-default)] bg-[var(--cmp-checkbox-unchecked-bg-default)]"
6946
+ ),
6947
+ children: filled && /* @__PURE__ */ jsx(
6948
+ SIcon,
6949
+ {
6950
+ name: state2 === null ? "checkboxIndeterminate" : "checkboxCheck",
6951
+ size: 12,
6952
+ color: disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
6953
+ }
6954
+ )
6955
+ }
6956
+ );
6957
+ }
6814
6958
  var DEFAULT_ROW_HEIGHT = 44;
6815
6959
  var DENSE_ROW_HEIGHT = 32;
6816
6960
  var SELECTABLE_COLUMN_WIDTH = 48;