sellmate-design-system-react 0.8.3 → 0.8.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.
Files changed (68) 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/SInput/SInput.cjs +78 -2
  26. package/dist/components/SInput/SInput.cjs.map +1 -1
  27. package/dist/components/SInput/SInput.js +78 -2
  28. package/dist/components/SInput/SInput.js.map +1 -1
  29. package/dist/components/SKeyValueTable/SKeyValueTable.cjs +224 -118
  30. package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
  31. package/dist/components/SKeyValueTable/SKeyValueTable.js +224 -118
  32. package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
  33. package/dist/components/SNumberInput/SNumberInput.cjs +78 -2
  34. package/dist/components/SNumberInput/SNumberInput.cjs.map +1 -1
  35. package/dist/components/SNumberInput/SNumberInput.js +78 -2
  36. package/dist/components/SNumberInput/SNumberInput.js.map +1 -1
  37. package/dist/components/SSelect/SSelect.cjs +155 -49
  38. package/dist/components/SSelect/SSelect.cjs.map +1 -1
  39. package/dist/components/SSelect/SSelect.js +155 -49
  40. package/dist/components/SSelect/SSelect.js.map +1 -1
  41. package/dist/components/SSelect/select.config.d.ts +7 -0
  42. package/dist/components/STable/STable.cjs +155 -49
  43. package/dist/components/STable/STable.cjs.map +1 -1
  44. package/dist/components/STable/STable.js +155 -49
  45. package/dist/components/STable/STable.js.map +1 -1
  46. package/dist/components/STextarea/STextarea.cjs +78 -2
  47. package/dist/components/STextarea/STextarea.cjs.map +1 -1
  48. package/dist/components/STextarea/STextarea.js +78 -2
  49. package/dist/components/STextarea/STextarea.js.map +1 -1
  50. package/dist/components/STimePicker/STimePicker.cjs +78 -2
  51. package/dist/components/STimePicker/STimePicker.cjs.map +1 -1
  52. package/dist/components/STimePicker/STimePicker.js +78 -2
  53. package/dist/components/STimePicker/STimePicker.js.map +1 -1
  54. package/dist/components/STimeRangePicker/STimeRangePicker.cjs +78 -2
  55. package/dist/components/STimeRangePicker/STimeRangePicker.cjs.map +1 -1
  56. package/dist/components/STimeRangePicker/STimeRangePicker.js +78 -2
  57. package/dist/components/STimeRangePicker/STimeRangePicker.js.map +1 -1
  58. package/dist/components/STooltip/STooltip.cjs +78 -2
  59. package/dist/components/STooltip/STooltip.cjs.map +1 -1
  60. package/dist/components/STooltip/STooltip.d.ts +1 -1
  61. package/dist/components/STooltip/STooltip.js +78 -2
  62. package/dist/components/STooltip/STooltip.js.map +1 -1
  63. package/dist/index.cjs +155 -49
  64. package/dist/index.cjs.map +1 -1
  65. package/dist/index.js +155 -49
  66. package/dist/index.js.map +1 -1
  67. package/dist/styles.css +4 -8
  68. 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
  );
@@ -6288,6 +6295,16 @@ function flattenOptions(options, depth = 1) {
6288
6295
  return out;
6289
6296
  }
6290
6297
  var selectableOptions = (flat) => flat.filter((o) => !o.isGroup && !o.disabled);
6298
+ function collectGroupLeafValues(flat, groupIndex) {
6299
+ const group = flat[groupIndex];
6300
+ if (group == null || !group.isGroup) return [];
6301
+ const values = [];
6302
+ for (let i = groupIndex + 1; i < flat.length; i++) {
6303
+ if (flat[i].depth <= group.depth) break;
6304
+ if (!flat[i].isGroup && !flat[i].disabled) values.push(flat[i].value);
6305
+ }
6306
+ return values;
6307
+ }
6291
6308
  var isHtmlLabel = (label) => /<[a-z][\s\S]*>/i.test(label);
6292
6309
  var extractText = (html) => html.replace(/<[^>]*>/g, "");
6293
6310
  var SEARCH_THRESHOLD = 11;
@@ -6413,16 +6430,31 @@ var SSelect = forwardRef(function SSelect2({
6413
6430
  const allValues = selectable.map((o) => o.value);
6414
6431
  const allSelected = allValues.length > 0 && allValues.every((v) => selected.includes(v));
6415
6432
  const hasItems = filtered.some((o) => !o.isGroup);
6433
+ const groupLeafValues = useMemo(() => {
6434
+ const map = /* @__PURE__ */ new Map();
6435
+ filtered.forEach((o, i) => {
6436
+ if (o.isGroup) map.set(i, collectGroupLeafValues(filtered, i));
6437
+ });
6438
+ return map;
6439
+ }, [filtered]);
6416
6440
  const navigableItems = useMemo(() => {
6417
6441
  const items = [];
6418
6442
  if (multi && useSelectAll && allValues.length > 0) {
6419
- items.push({ value: "__select_all__", isSelectAll: true });
6443
+ items.push({ key: "__select_all__", isSelectAll: true });
6420
6444
  }
6421
- filtered.forEach((o) => {
6422
- if (!o.isGroup && !o.disabled) items.push({ value: o.value });
6445
+ filtered.forEach((o, i) => {
6446
+ if (o.disabled) return;
6447
+ if (o.isGroup) {
6448
+ if (!multi) return;
6449
+ const leafValues = groupLeafValues.get(i) ?? [];
6450
+ if (leafValues.length === 0) return;
6451
+ items.push({ key: `__group_${i}__`, isGroup: true, leafValues });
6452
+ } else {
6453
+ items.push({ key: o.value, value: o.value });
6454
+ }
6423
6455
  });
6424
6456
  return items;
6425
- }, [allValues.length, filtered, multi, useSelectAll]);
6457
+ }, [allValues.length, filtered, groupLeafValues, multi, useSelectAll]);
6426
6458
  const triggerText = (() => {
6427
6459
  if (selected.length === 0) return placeholder;
6428
6460
  if (multi) {
@@ -6444,6 +6476,17 @@ var SSelect = forwardRef(function SSelect2({
6444
6476
  const handleSelectAll = () => {
6445
6477
  emit2(allSelected ? [] : allValues);
6446
6478
  };
6479
+ const handleToggleGroup = (leafValues) => {
6480
+ if (leafValues.length === 0) return;
6481
+ const selectedSet = new Set(selected);
6482
+ const allSelectedInGroup = leafValues.every((v) => selectedSet.has(v));
6483
+ if (allSelectedInGroup) {
6484
+ const remove = new Set(leafValues);
6485
+ emit2(selected.filter((v) => !remove.has(v)));
6486
+ } else {
6487
+ emit2([...selected, ...leafValues.filter((v) => !selectedSet.has(v))]);
6488
+ }
6489
+ };
6447
6490
  useEffect(() => {
6448
6491
  if (!open) {
6449
6492
  setFocusedIndex(-1);
@@ -6484,6 +6527,10 @@ var SSelect = forwardRef(function SSelect2({
6484
6527
  handleSelectAll();
6485
6528
  return;
6486
6529
  }
6530
+ if (focused.isGroup) {
6531
+ handleToggleGroup(focused.leafValues ?? []);
6532
+ return;
6533
+ }
6487
6534
  handleSelect(focused.value);
6488
6535
  };
6489
6536
  const handleKeyDown = (event) => {
@@ -6647,20 +6694,20 @@ var SSelect = forwardRef(function SSelect2({
6647
6694
  items: filtered,
6648
6695
  multi,
6649
6696
  selected,
6650
- focusedValue: navigableItems[focusedIndex]?.isSelectAll ? "__select_all__" : navigableItems[focusedIndex]?.value,
6697
+ groupLeafValues,
6698
+ focusedValue: navigableItems[focusedIndex]?.key,
6651
6699
  showSelectAll: multi && useSelectAll && allValues.length > 0,
6652
6700
  selectAllLabel: allSelectedLabel,
6653
6701
  selectAllSelected: allSelected,
6654
6702
  onSelectAll: handleSelectAll,
6655
6703
  onSelect: handleSelect,
6656
- onHoverValue: (value2) => {
6657
- if (value2 == null) {
6704
+ onToggleGroup: handleToggleGroup,
6705
+ onHoverValue: (key) => {
6706
+ if (key == null) {
6658
6707
  setFocusedIndex(-1);
6659
6708
  return;
6660
6709
  }
6661
- const index = navigableItems.findIndex(
6662
- (item) => item.isSelectAll ? value2 === "__select_all__" : item.value === value2
6663
- );
6710
+ const index = navigableItems.findIndex((item) => item.key === key);
6664
6711
  if (index >= 0) setFocusedIndex(index);
6665
6712
  }
6666
6713
  }
@@ -6679,20 +6726,23 @@ function ItemList({
6679
6726
  items,
6680
6727
  multi,
6681
6728
  selected,
6729
+ groupLeafValues,
6682
6730
  focusedValue,
6683
6731
  showSelectAll,
6684
6732
  selectAllLabel,
6685
6733
  selectAllSelected,
6686
6734
  onSelectAll,
6687
6735
  onSelect,
6736
+ onToggleGroup,
6688
6737
  onHoverValue
6689
6738
  }) {
6739
+ const selectedSet = useMemo(() => new Set(selected), [selected]);
6690
6740
  const itemBase = cn(
6691
6741
  "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
6742
  "text-[color:var(--cmp-listItem-content-default)]",
6693
6743
  "disabled:cursor-not-allowed disabled:text-[color:var(--cmp-listItem-content-disabled)]"
6694
6744
  );
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)]";
6745
+ 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
6746
  return /* @__PURE__ */ jsxs("div", { role: "listbox", "aria-multiselectable": multi || void 0, children: [
6697
6747
  showSelectAll && /* @__PURE__ */ jsxs(
6698
6748
  "button",
@@ -6709,23 +6759,7 @@ function ItemList({
6709
6759
  onMouseLeave: () => onHoverValue(null),
6710
6760
  onClick: onSelectAll,
6711
6761
  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
- ),
6762
+ /* @__PURE__ */ jsx(CheckboxBox, { state: selectAllSelected, focused: focusedValue === "__select_all__" }),
6729
6763
  /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: selectAllLabel })
6730
6764
  ]
6731
6765
  }
@@ -6735,12 +6769,71 @@ function ItemList({
6735
6769
  const rowKey = `${o.value}-${idx}`;
6736
6770
  if (o.isGroup) {
6737
6771
  const isDepth1 = o.depth === 1;
6772
+ 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";
6773
+ if (multi) {
6774
+ const leafValues = groupLeafValues.get(idx) ?? [];
6775
+ const total = leafValues.length;
6776
+ const selectedCount = leafValues.reduce((n, v) => selectedSet.has(v) ? n + 1 : n, 0);
6777
+ const groupState = total === 0 || selectedCount === 0 ? false : selectedCount === total ? true : null;
6778
+ const groupDisabled = o.disabled || total === 0;
6779
+ const groupFocused = focusedValue === `__group_${idx}__`;
6780
+ return /* @__PURE__ */ jsxs(
6781
+ "button",
6782
+ {
6783
+ type: "button",
6784
+ role: "option",
6785
+ "aria-selected": groupState === true,
6786
+ disabled: groupDisabled,
6787
+ "data-select-focused": groupFocused ? "true" : void 0,
6788
+ "data-select-active": groupFocused ? "true" : void 0,
6789
+ className: cn(
6790
+ "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)]",
6791
+ groupTone,
6792
+ groupDisabled ? "cursor-not-allowed text-[color:var(--cmp-listItem-content-disabled)]" : "cursor-pointer",
6793
+ groupDisabled && isDepth1 && "bg-[var(--cmp-listItem-depth1-bg-disabled)]",
6794
+ // 포커스 하이라이트는 depth 배경보다 뒤에 둬 tailwind-merge 로 이기게 한다.
6795
+ groupFocused && !groupDisabled && "bg-[var(--cmp-listItem-bg-hover)] text-[color:var(--cmp-listItem-content-hover)]"
6796
+ ),
6797
+ style: { paddingLeft: padLeft },
6798
+ onMouseEnter: () => onHoverValue(`__group_${idx}__`),
6799
+ onMouseLeave: () => onHoverValue(null),
6800
+ onClick: () => onToggleGroup(leafValues),
6801
+ children: [
6802
+ /* @__PURE__ */ jsx(CheckboxBox, { state: groupState, disabled: groupDisabled, focused: groupFocused }),
6803
+ isHtmlLabel(o.label) ? /* @__PURE__ */ jsx(
6804
+ "span",
6805
+ {
6806
+ className: "min-w-0 truncate",
6807
+ dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(o.label) }
6808
+ }
6809
+ ) : /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: o.label }),
6810
+ total > 0 && /* @__PURE__ */ jsxs(
6811
+ "span",
6812
+ {
6813
+ className: cn(
6814
+ "shrink-0 font-medium",
6815
+ groupFocused ? "text-white" : "text-[color:var(--cmp-listItem-content-disabled)]"
6816
+ ),
6817
+ children: [
6818
+ "(",
6819
+ selectedCount,
6820
+ "/",
6821
+ total,
6822
+ ")"
6823
+ ]
6824
+ }
6825
+ )
6826
+ ]
6827
+ },
6828
+ rowKey
6829
+ );
6830
+ }
6738
6831
  return /* @__PURE__ */ jsx(
6739
6832
  "div",
6740
6833
  {
6741
6834
  className: cn(
6742
6835
  "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",
6836
+ groupTone,
6744
6837
  // 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
6745
6838
  // 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
6746
6839
  o.disabled && "cursor-not-allowed text-[color:var(--cmp-listItem-content-disabled)]",
@@ -6776,25 +6869,11 @@ function ItemList({
6776
6869
  onClick: () => onSelect(o.value),
6777
6870
  children: [
6778
6871
  multi && /* @__PURE__ */ jsx(
6779
- "span",
6872
+ CheckboxBox,
6780
6873
  {
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
- )
6874
+ state: isSelected,
6875
+ disabled: o.disabled,
6876
+ focused: focusedValue === o.value
6798
6877
  }
6799
6878
  ),
6800
6879
  isHtmlLabel(o.label) ? /* @__PURE__ */ jsx(
@@ -6811,6 +6890,33 @@ function ItemList({
6811
6890
  })
6812
6891
  ] });
6813
6892
  }
6893
+ function CheckboxBox({
6894
+ state: state2,
6895
+ disabled = false,
6896
+ focused = false
6897
+ }) {
6898
+ const filled = state2 === true || state2 === null;
6899
+ return /* @__PURE__ */ jsx(
6900
+ "span",
6901
+ {
6902
+ className: cn(
6903
+ "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
6904
+ disabled ? (
6905
+ // 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
6906
+ "cursor-not-allowed border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
6907
+ ) : 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)]"
6908
+ ),
6909
+ children: filled && /* @__PURE__ */ jsx(
6910
+ SIcon,
6911
+ {
6912
+ name: state2 === null ? "checkboxIndeterminate" : "checkboxCheck",
6913
+ size: 12,
6914
+ color: disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
6915
+ }
6916
+ )
6917
+ }
6918
+ );
6919
+ }
6814
6920
  var DEFAULT_ROW_HEIGHT = 44;
6815
6921
  var DENSE_ROW_HEIGHT = 32;
6816
6922
  var SELECTABLE_COLUMN_WIDTH = 48;