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.cjs CHANGED
@@ -4175,7 +4175,14 @@ function useBody(content, message = []) {
4175
4175
  if (content != null) return content;
4176
4176
  if (message.length === 0) return null;
4177
4177
  const singleLine = message.length === 1;
4178
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: singleLine ? "leading-[24px]" : void 0, children: line }, i)) });
4178
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx(
4179
+ "div",
4180
+ {
4181
+ className: singleLine ? "leading-[24px]" : void 0,
4182
+ dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(line) }
4183
+ },
4184
+ i
4185
+ )) });
4179
4186
  }
4180
4187
  var STooltip = react.forwardRef(function STooltip2({
4181
4188
  content,
@@ -4233,7 +4240,7 @@ var STooltip = react.forwardRef(function STooltip2({
4233
4240
  if (disabled || body == null) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: triggerNode });
4234
4241
  const isHover = trigger === "hover";
4235
4242
  const contentClass = cn(
4236
- "z-50 max-w-xs rounded-[6px] px-[16px] py-[12px] text-[12px] leading-[20px]",
4243
+ "z-50 w-fit whitespace-nowrap rounded-[6px] px-[16px] py-[12px] text-[12px] leading-[20px]",
4237
4244
  FLOATING_SLIDE_ANIM,
4238
4245
  className
4239
4246
  );
@@ -6316,6 +6323,16 @@ function flattenOptions(options, depth = 1) {
6316
6323
  return out;
6317
6324
  }
6318
6325
  var selectableOptions = (flat) => flat.filter((o) => !o.isGroup && !o.disabled);
6326
+ function collectGroupLeafValues(flat, groupIndex) {
6327
+ const group = flat[groupIndex];
6328
+ if (group == null || !group.isGroup) return [];
6329
+ const values = [];
6330
+ for (let i = groupIndex + 1; i < flat.length; i++) {
6331
+ if (flat[i].depth <= group.depth) break;
6332
+ if (!flat[i].isGroup && !flat[i].disabled) values.push(flat[i].value);
6333
+ }
6334
+ return values;
6335
+ }
6319
6336
  var isHtmlLabel = (label) => /<[a-z][\s\S]*>/i.test(label);
6320
6337
  var extractText = (html) => html.replace(/<[^>]*>/g, "");
6321
6338
  var SEARCH_THRESHOLD = 11;
@@ -6441,16 +6458,31 @@ var SSelect = react.forwardRef(function SSelect2({
6441
6458
  const allValues = selectable.map((o) => o.value);
6442
6459
  const allSelected = allValues.length > 0 && allValues.every((v) => selected.includes(v));
6443
6460
  const hasItems = filtered.some((o) => !o.isGroup);
6461
+ const groupLeafValues = react.useMemo(() => {
6462
+ const map = /* @__PURE__ */ new Map();
6463
+ filtered.forEach((o, i) => {
6464
+ if (o.isGroup) map.set(i, collectGroupLeafValues(filtered, i));
6465
+ });
6466
+ return map;
6467
+ }, [filtered]);
6444
6468
  const navigableItems = react.useMemo(() => {
6445
6469
  const items = [];
6446
6470
  if (multi && useSelectAll && allValues.length > 0) {
6447
- items.push({ value: "__select_all__", isSelectAll: true });
6471
+ items.push({ key: "__select_all__", isSelectAll: true });
6448
6472
  }
6449
- filtered.forEach((o) => {
6450
- if (!o.isGroup && !o.disabled) items.push({ value: o.value });
6473
+ filtered.forEach((o, i) => {
6474
+ if (o.disabled) return;
6475
+ if (o.isGroup) {
6476
+ if (!multi) return;
6477
+ const leafValues = groupLeafValues.get(i) ?? [];
6478
+ if (leafValues.length === 0) return;
6479
+ items.push({ key: `__group_${i}__`, isGroup: true, leafValues });
6480
+ } else {
6481
+ items.push({ key: o.value, value: o.value });
6482
+ }
6451
6483
  });
6452
6484
  return items;
6453
- }, [allValues.length, filtered, multi, useSelectAll]);
6485
+ }, [allValues.length, filtered, groupLeafValues, multi, useSelectAll]);
6454
6486
  const triggerText = (() => {
6455
6487
  if (selected.length === 0) return placeholder;
6456
6488
  if (multi) {
@@ -6472,6 +6504,17 @@ var SSelect = react.forwardRef(function SSelect2({
6472
6504
  const handleSelectAll = () => {
6473
6505
  emit2(allSelected ? [] : allValues);
6474
6506
  };
6507
+ const handleToggleGroup = (leafValues) => {
6508
+ if (leafValues.length === 0) return;
6509
+ const selectedSet = new Set(selected);
6510
+ const allSelectedInGroup = leafValues.every((v) => selectedSet.has(v));
6511
+ if (allSelectedInGroup) {
6512
+ const remove = new Set(leafValues);
6513
+ emit2(selected.filter((v) => !remove.has(v)));
6514
+ } else {
6515
+ emit2([...selected, ...leafValues.filter((v) => !selectedSet.has(v))]);
6516
+ }
6517
+ };
6475
6518
  react.useEffect(() => {
6476
6519
  if (!open) {
6477
6520
  setFocusedIndex(-1);
@@ -6512,6 +6555,10 @@ var SSelect = react.forwardRef(function SSelect2({
6512
6555
  handleSelectAll();
6513
6556
  return;
6514
6557
  }
6558
+ if (focused.isGroup) {
6559
+ handleToggleGroup(focused.leafValues ?? []);
6560
+ return;
6561
+ }
6515
6562
  handleSelect(focused.value);
6516
6563
  };
6517
6564
  const handleKeyDown = (event) => {
@@ -6675,20 +6722,20 @@ var SSelect = react.forwardRef(function SSelect2({
6675
6722
  items: filtered,
6676
6723
  multi,
6677
6724
  selected,
6678
- focusedValue: navigableItems[focusedIndex]?.isSelectAll ? "__select_all__" : navigableItems[focusedIndex]?.value,
6725
+ groupLeafValues,
6726
+ focusedValue: navigableItems[focusedIndex]?.key,
6679
6727
  showSelectAll: multi && useSelectAll && allValues.length > 0,
6680
6728
  selectAllLabel: allSelectedLabel,
6681
6729
  selectAllSelected: allSelected,
6682
6730
  onSelectAll: handleSelectAll,
6683
6731
  onSelect: handleSelect,
6684
- onHoverValue: (value2) => {
6685
- if (value2 == null) {
6732
+ onToggleGroup: handleToggleGroup,
6733
+ onHoverValue: (key) => {
6734
+ if (key == null) {
6686
6735
  setFocusedIndex(-1);
6687
6736
  return;
6688
6737
  }
6689
- const index = navigableItems.findIndex(
6690
- (item) => item.isSelectAll ? value2 === "__select_all__" : item.value === value2
6691
- );
6738
+ const index = navigableItems.findIndex((item) => item.key === key);
6692
6739
  if (index >= 0) setFocusedIndex(index);
6693
6740
  }
6694
6741
  }
@@ -6707,20 +6754,23 @@ function ItemList({
6707
6754
  items,
6708
6755
  multi,
6709
6756
  selected,
6757
+ groupLeafValues,
6710
6758
  focusedValue,
6711
6759
  showSelectAll,
6712
6760
  selectAllLabel,
6713
6761
  selectAllSelected,
6714
6762
  onSelectAll,
6715
6763
  onSelect,
6764
+ onToggleGroup,
6716
6765
  onHoverValue
6717
6766
  }) {
6767
+ const selectedSet = react.useMemo(() => new Set(selected), [selected]);
6718
6768
  const itemBase = cn(
6719
6769
  "group flex w-full cursor-pointer select-none items-center gap-[8px] border-none bg-transparent text-left text-[12px] leading-[20px] outline-none",
6720
6770
  "text-[color:var(--cmp-listItem-content-default)]",
6721
6771
  "disabled:cursor-not-allowed disabled:text-[color:var(--cmp-listItem-content-disabled)]"
6722
6772
  );
6723
- 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)]";
6773
+ 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)]";
6724
6774
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "listbox", "aria-multiselectable": multi || void 0, children: [
6725
6775
  showSelectAll && /* @__PURE__ */ jsxRuntime.jsxs(
6726
6776
  "button",
@@ -6737,23 +6787,7 @@ function ItemList({
6737
6787
  onMouseLeave: () => onHoverValue(null),
6738
6788
  onClick: onSelectAll,
6739
6789
  children: [
6740
- /* @__PURE__ */ jsxRuntime.jsx(
6741
- "span",
6742
- {
6743
- className: cn(
6744
- "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
6745
- 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)]"
6746
- ),
6747
- children: selectAllSelected && /* @__PURE__ */ jsxRuntime.jsx(
6748
- SIcon,
6749
- {
6750
- name: "checkboxCheck",
6751
- size: 12,
6752
- color: "var(--cmp-checkbox-checked-icon-default)"
6753
- }
6754
- )
6755
- }
6756
- ),
6790
+ /* @__PURE__ */ jsxRuntime.jsx(CheckboxBox, { state: selectAllSelected, focused: focusedValue === "__select_all__" }),
6757
6791
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: selectAllLabel })
6758
6792
  ]
6759
6793
  }
@@ -6763,12 +6797,71 @@ function ItemList({
6763
6797
  const rowKey = `${o.value}-${idx}`;
6764
6798
  if (o.isGroup) {
6765
6799
  const isDepth1 = o.depth === 1;
6800
+ 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";
6801
+ if (multi) {
6802
+ const leafValues = groupLeafValues.get(idx) ?? [];
6803
+ const total = leafValues.length;
6804
+ const selectedCount = leafValues.reduce((n, v) => selectedSet.has(v) ? n + 1 : n, 0);
6805
+ const groupState = total === 0 || selectedCount === 0 ? false : selectedCount === total ? true : null;
6806
+ const groupDisabled = o.disabled || total === 0;
6807
+ const groupFocused = focusedValue === `__group_${idx}__`;
6808
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6809
+ "button",
6810
+ {
6811
+ type: "button",
6812
+ role: "option",
6813
+ "aria-selected": groupState === true,
6814
+ disabled: groupDisabled,
6815
+ "data-select-focused": groupFocused ? "true" : void 0,
6816
+ "data-select-active": groupFocused ? "true" : void 0,
6817
+ className: cn(
6818
+ "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)]",
6819
+ groupTone,
6820
+ groupDisabled ? "cursor-not-allowed text-[color:var(--cmp-listItem-content-disabled)]" : "cursor-pointer",
6821
+ groupDisabled && isDepth1 && "bg-[var(--cmp-listItem-depth1-bg-disabled)]",
6822
+ // 포커스 하이라이트는 depth 배경보다 뒤에 둬 tailwind-merge 로 이기게 한다.
6823
+ groupFocused && !groupDisabled && "bg-[var(--cmp-listItem-bg-hover)] text-[color:var(--cmp-listItem-content-hover)]"
6824
+ ),
6825
+ style: { paddingLeft: padLeft },
6826
+ onMouseEnter: () => onHoverValue(`__group_${idx}__`),
6827
+ onMouseLeave: () => onHoverValue(null),
6828
+ onClick: () => onToggleGroup(leafValues),
6829
+ children: [
6830
+ /* @__PURE__ */ jsxRuntime.jsx(CheckboxBox, { state: groupState, disabled: groupDisabled, focused: groupFocused }),
6831
+ isHtmlLabel(o.label) ? /* @__PURE__ */ jsxRuntime.jsx(
6832
+ "span",
6833
+ {
6834
+ className: "min-w-0 truncate",
6835
+ dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(o.label) }
6836
+ }
6837
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: o.label }),
6838
+ total > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
6839
+ "span",
6840
+ {
6841
+ className: cn(
6842
+ "shrink-0 font-medium",
6843
+ groupFocused ? "text-white" : "text-[color:var(--cmp-listItem-content-disabled)]"
6844
+ ),
6845
+ children: [
6846
+ "(",
6847
+ selectedCount,
6848
+ "/",
6849
+ total,
6850
+ ")"
6851
+ ]
6852
+ }
6853
+ )
6854
+ ]
6855
+ },
6856
+ rowKey
6857
+ );
6858
+ }
6766
6859
  return /* @__PURE__ */ jsxRuntime.jsx(
6767
6860
  "div",
6768
6861
  {
6769
6862
  className: cn(
6770
6863
  "select-none py-[4px] pr-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)]",
6771
- 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",
6864
+ groupTone,
6772
6865
  // 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
6773
6866
  // 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
6774
6867
  o.disabled && "cursor-not-allowed text-[color:var(--cmp-listItem-content-disabled)]",
@@ -6804,25 +6897,11 @@ function ItemList({
6804
6897
  onClick: () => onSelect(o.value),
6805
6898
  children: [
6806
6899
  multi && /* @__PURE__ */ jsxRuntime.jsx(
6807
- "span",
6900
+ CheckboxBox,
6808
6901
  {
6809
- className: cn(
6810
- "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
6811
- o.disabled ? (
6812
- // 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
6813
- "cursor-not-allowed border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
6814
- ) : cn(
6815
- 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)]"
6816
- )
6817
- ),
6818
- children: isSelected && /* @__PURE__ */ jsxRuntime.jsx(
6819
- SIcon,
6820
- {
6821
- name: "checkboxCheck",
6822
- size: 12,
6823
- color: o.disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
6824
- }
6825
- )
6902
+ state: isSelected,
6903
+ disabled: o.disabled,
6904
+ focused: focusedValue === o.value
6826
6905
  }
6827
6906
  ),
6828
6907
  isHtmlLabel(o.label) ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -6839,6 +6918,33 @@ function ItemList({
6839
6918
  })
6840
6919
  ] });
6841
6920
  }
6921
+ function CheckboxBox({
6922
+ state: state2,
6923
+ disabled = false,
6924
+ focused = false
6925
+ }) {
6926
+ const filled = state2 === true || state2 === null;
6927
+ return /* @__PURE__ */ jsxRuntime.jsx(
6928
+ "span",
6929
+ {
6930
+ className: cn(
6931
+ "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
6932
+ disabled ? (
6933
+ // 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
6934
+ "cursor-not-allowed border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
6935
+ ) : 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)]"
6936
+ ),
6937
+ children: filled && /* @__PURE__ */ jsxRuntime.jsx(
6938
+ SIcon,
6939
+ {
6940
+ name: state2 === null ? "checkboxIndeterminate" : "checkboxCheck",
6941
+ size: 12,
6942
+ color: disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
6943
+ }
6944
+ )
6945
+ }
6946
+ );
6947
+ }
6842
6948
  var DEFAULT_ROW_HEIGHT = 44;
6843
6949
  var DENSE_ROW_HEIGHT = 32;
6844
6950
  var SELECTABLE_COLUMN_WIDTH = 48;