sellmate-design-system-react 9.0.0-beta.17 → 9.0.0-beta.18

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
@@ -1175,6 +1175,45 @@ var Icon_close = (p) => {
1175
1175
  }
1176
1176
  );
1177
1177
  };
1178
+ var Icon_company = (p) => {
1179
+ const { size = 24, ...rest } = p;
1180
+ return /* @__PURE__ */ jsxs(
1181
+ "svg",
1182
+ {
1183
+ width: size,
1184
+ height: size,
1185
+ viewBox: "0 0 24 24",
1186
+ fill: "none",
1187
+ xmlns: "http://www.w3.org/2000/svg",
1188
+ ...rest,
1189
+ children: [
1190
+ /* @__PURE__ */ jsx(
1191
+ "path",
1192
+ {
1193
+ d: "M14.25 8.5C14.6642 8.5 15 8.83579 15 9.25C15 9.66421 14.6642 10 14.25 10H9.75C9.33579 10 9 9.66421 9 9.25C9 8.83579 9.33579 8.5 9.75 8.5H14.25Z",
1194
+ fill: "currentColor"
1195
+ }
1196
+ ),
1197
+ /* @__PURE__ */ jsx(
1198
+ "path",
1199
+ {
1200
+ d: "M14.25 5.5C14.6642 5.5 15 5.83579 15 6.25C15 6.66421 14.6642 7 14.25 7H9.75C9.33579 7 9 6.66421 9 6.25C9 5.83579 9.33579 5.5 9.75 5.5H14.25Z",
1201
+ fill: "currentColor"
1202
+ }
1203
+ ),
1204
+ /* @__PURE__ */ jsx(
1205
+ "path",
1206
+ {
1207
+ fillRule: "evenodd",
1208
+ clipRule: "evenodd",
1209
+ d: "M16 2.25C16.9665 2.25 17.75 3.0335 17.75 4V6.25H20.25C21.2165 6.25 22 7.0335 22 8V20C22 20.9665 21.2165 21.75 20.25 21.75H3.75C2.7835 21.75 2 20.9665 2 20V10C2 9.0335 2.7835 8.25 3.75 8.25H6.25V4C6.25 3.0335 7.0335 2.25 8 2.25H16ZM3.75 9.75C3.61193 9.75 3.5 9.86193 3.5 10V20C3.5 20.1381 3.61193 20.25 3.75 20.25H6.25V9.75H3.75ZM8 3.75C7.86193 3.75 7.75 3.86193 7.75 4V20.25H9.25V16C9.25 15.0335 10.0335 14.25 11 14.25H13C13.9665 14.25 14.75 15.0335 14.75 16V20.25H16.25V4C16.25 3.86193 16.1381 3.75 16 3.75H8ZM11 15.75C10.8619 15.75 10.75 15.8619 10.75 16V20.25H13.25V16C13.25 15.8619 13.1381 15.75 13 15.75H11ZM17.75 20.25H20.25C20.3881 20.25 20.5 20.1381 20.5 20V8C20.5 7.86193 20.3881 7.75 20.25 7.75H17.75V20.25Z",
1210
+ fill: "currentColor"
1211
+ }
1212
+ )
1213
+ ]
1214
+ }
1215
+ );
1216
+ };
1178
1217
  var Icon_copy = (p) => {
1179
1218
  const { size = 24, ...rest } = p;
1180
1219
  return /* @__PURE__ */ jsxs(
@@ -2398,6 +2437,27 @@ var Icon_row = (p) => {
2398
2437
  }
2399
2438
  );
2400
2439
  };
2440
+ var Icon_rowDense = (p) => {
2441
+ const { size = 24, ...rest } = p;
2442
+ return /* @__PURE__ */ jsx(
2443
+ "svg",
2444
+ {
2445
+ width: size,
2446
+ height: size,
2447
+ viewBox: "0 0 24 24",
2448
+ fill: "none",
2449
+ xmlns: "http://www.w3.org/2000/svg",
2450
+ ...rest,
2451
+ children: /* @__PURE__ */ jsx(
2452
+ "path",
2453
+ {
2454
+ d: "M7.25 2C7.66421 2 8 2.33579 8 2.75V21.25C8 21.6642 7.66421 22 7.25 22H5.75C5.33579 22 5 21.6642 5 21.25V2.75C5 2.33579 5.33579 2 5.75 2H7.25ZM12.75 2C13.1642 2 13.5 2.33579 13.5 2.75V21.25C13.5 21.6642 13.1642 22 12.75 22H11.25C10.8358 22 10.5 21.6642 10.5 21.25V2.75C10.5 2.33579 10.8358 2 11.25 2H12.75ZM18.25 2C18.6642 2 19 2.33579 19 2.75V21.25C19 21.6642 18.6642 22 18.25 22H16.75C16.3358 22 16 21.6642 16 21.25V2.75C16 2.33579 16.3358 2 16.75 2H18.25Z",
2455
+ fill: "currentColor"
2456
+ }
2457
+ )
2458
+ }
2459
+ );
2460
+ };
2401
2461
  var Icon_save = (p) => {
2402
2462
  const { size = 24, ...rest } = p;
2403
2463
  return /* @__PURE__ */ jsx(
@@ -3046,6 +3106,7 @@ var ICONS = {
3046
3106
  clockFill: Icon_clockFill,
3047
3107
  clockOutline: Icon_clockOutline,
3048
3108
  close: Icon_close,
3109
+ company: Icon_company,
3049
3110
  copy: Icon_copy,
3050
3111
  coupon: Icon_coupon,
3051
3112
  dashboard: Icon_dashboard,
@@ -3083,6 +3144,7 @@ var ICONS = {
3083
3144
  reset: Icon_reset,
3084
3145
  robot: Icon_robot,
3085
3146
  row: Icon_row,
3147
+ rowDense: Icon_rowDense,
3086
3148
  save: Icon_save,
3087
3149
  search: Icon_search,
3088
3150
  send: Icon_send,
@@ -6076,6 +6138,7 @@ var STextLink = /* @__PURE__ */ forwardRef(function STextLink2({
6076
6138
  label = "",
6077
6139
  icon,
6078
6140
  iconColor,
6141
+ iconRotate,
6079
6142
  labelClass,
6080
6143
  rightArrow = "none",
6081
6144
  underline = false,
@@ -6118,7 +6181,7 @@ var STextLink = /* @__PURE__ */ forwardRef(function STextLink2({
6118
6181
  style: { gap: s.gap, color: contentColor, ...style },
6119
6182
  ...rest,
6120
6183
  children: [
6121
- icon && /* @__PURE__ */ jsx(SIcon, { name: icon, size: s.iconSize, color: resolvedIconColor }),
6184
+ icon && /* @__PURE__ */ jsx(SIcon, { name: icon, size: s.iconSize, color: resolvedIconColor, rotate: iconRotate }),
6122
6185
  /* @__PURE__ */ jsx(
6123
6186
  "span",
6124
6187
  {
@@ -11096,11 +11159,13 @@ var STable = /* @__PURE__ */ forwardRef(function STable2({
11096
11159
  noDataSlot,
11097
11160
  isLoading = false,
11098
11161
  dense = false,
11162
+ onDenseChange,
11099
11163
  noHover = false,
11100
11164
  pagination,
11101
11165
  onPageChange,
11102
11166
  useInternalPagination = false,
11103
11167
  useRowsPerPageSelect = false,
11168
+ useDensityToggle = false,
11104
11169
  rowsPerPageOption = DEFAULT_ROWS_PER_PAGE_OPTION,
11105
11170
  onRowsPerPageChange,
11106
11171
  useVirtualScroll = false,
@@ -11496,21 +11561,7 @@ var STable = /* @__PURE__ */ forwardRef(function STable2({
11496
11561
  col.align === "right" && "justify-end"
11497
11562
  ),
11498
11563
  children: col.renderHeader ? col.renderHeader(col, i) : /* @__PURE__ */ jsxs(Fragment, { children: [
11499
- col.icon && /* @__PURE__ */ jsx(SIcon, { name: col.icon, size: 16, color: col.iconColor }),
11500
11564
  /* @__PURE__ */ jsx("span", { className: "truncate", children: col.label }),
11501
- isSortable && // 미정렬은 updown 을 default(회색)로 — 정렬할 수 있다는 것 자체가
11502
- // 헤더에 보여야 한다. 정렬 중이면 action 색으로 올려 활성임을 알린다.
11503
- // 라벨이 truncate 돼도 버튼은 남도록 shrink-0.
11504
- /* @__PURE__ */ jsx("span", { className: "inline-flex shrink-0", children: /* @__PURE__ */ jsx(
11505
- SGhostButton,
11506
- {
11507
- size: "xxs",
11508
- intent: sortDir ? "action" : "default",
11509
- icon: sortDir === "asc" ? "arrowUp" : sortDir === "desc" ? "arrowDown" : "updown",
11510
- ariaLabel: `${col.label} \uC815\uB82C`,
11511
- onClick: () => toggleSort(col)
11512
- }
11513
- ) }),
11514
11565
  col.helpText && col.helpText.length > 0 && // 라벨이 좁아져 truncate 되더라도 아이콘까지 함께 줄어들면 안 되므로
11515
11566
  // shrink-0 래퍼로 감싼다 (STooltip 의 className 은 본문 쪽으로 간다).
11516
11567
  // 아이콘·크기·색은 SKeyValueTable 헤더 도움말과 동일하게 맞춘다.
@@ -11524,6 +11575,50 @@ var STable = /* @__PURE__ */ forwardRef(function STable2({
11524
11575
  placement: "top",
11525
11576
  message: col.helpText
11526
11577
  }
11578
+ ) }),
11579
+ col.editable && /* @__PURE__ */ jsx(
11580
+ SIcon,
11581
+ {
11582
+ name: "pageEdit",
11583
+ size: 12,
11584
+ color: "var(--sys-color-link-accent)",
11585
+ label: "\uC218\uC815 \uAC00\uB2A5",
11586
+ className: "shrink-0"
11587
+ }
11588
+ ),
11589
+ col.navigable && /* @__PURE__ */ jsx(
11590
+ SIcon,
11591
+ {
11592
+ name: "pageMove",
11593
+ size: 12,
11594
+ color: "var(--sys-color-link-accent)",
11595
+ label: "\uB2E4\uB978 \uD654\uBA74\uC73C\uB85C \uC774\uB3D9",
11596
+ className: "shrink-0"
11597
+ }
11598
+ ),
11599
+ col.required && // 라벨이 truncate 돼도 필수 표시는 남아야 하므로 shrink-0.
11600
+ // 아이콘·크기·색은 SKeyValueTable 헤더 필수 표시와 동일하게 맞춘다.
11601
+ /* @__PURE__ */ jsx(
11602
+ SIcon,
11603
+ {
11604
+ name: "asterisk",
11605
+ size: 12,
11606
+ color: "var(--sys-color-fg-accent)",
11607
+ className: "shrink-0"
11608
+ }
11609
+ ),
11610
+ isSortable && // 미정렬은 updown 을 default(회색)로 — 정렬할 수 있다는 것 자체가
11611
+ // 헤더에 보여야 한다. 정렬 중이면 action 색으로 올려 활성임을 알린다.
11612
+ // 라벨이 truncate 돼도 버튼은 남도록 shrink-0.
11613
+ /* @__PURE__ */ jsx("span", { className: "inline-flex shrink-0", children: /* @__PURE__ */ jsx(
11614
+ SGhostButton,
11615
+ {
11616
+ size: "xxs",
11617
+ intent: sortDir ? "action" : "default",
11618
+ icon: sortDir === "asc" ? "arrowUp" : sortDir === "desc" ? "arrowDown" : "updown",
11619
+ ariaLabel: `${col.label} \uC815\uB82C`,
11620
+ onClick: () => toggleSort(col)
11621
+ }
11527
11622
  ) })
11528
11623
  ] })
11529
11624
  }
@@ -11681,16 +11776,32 @@ var STable = /* @__PURE__ */ forwardRef(function STable2({
11681
11776
  ),
11682
11777
  children: [
11683
11778
  /* @__PURE__ */ jsx(SPagination, { currentPage: displayPage, lastPage, onPageChange: changePage }),
11684
- useRowsPerPageSelect && /* @__PURE__ */ jsx("div", { className: "absolute right-[10px] top-1/2 -translate-y-1/2", children: /* @__PURE__ */ jsx(
11685
- SSelect2,
11686
- {
11687
- options: rowsPerPageOption,
11688
- value: useInternalPagination ? innerRowsPerPage : pagination?.rowsPerPage,
11689
- emitValue: true,
11690
- onValueChange: (v) => changeRowsPerPage(Number(v)),
11691
- width: 128
11692
- }
11693
- ) })
11779
+ (useDensityToggle || useRowsPerPageSelect) && /* @__PURE__ */ jsxs("div", { className: "absolute right-[10px] top-1/2 flex -translate-y-1/2 items-center gap-[12px]", children: [
11780
+ useDensityToggle && // 라벨·아이콘은 현재 밀도가 아니라 **누르면 되는 상태**를 가리킨다 (dense 면 "넓게 보기").
11781
+ // row·rowDense 는 세로 막대라 90도 돌려 가로 행으로 쓴다.
11782
+ /* @__PURE__ */ jsx(
11783
+ STextLink,
11784
+ {
11785
+ size: "sm",
11786
+ icon: dense ? "row" : "rowDense",
11787
+ iconRotate: 90,
11788
+ iconColor: "var(--sys-color-fg-quaternary)",
11789
+ label: dense ? "\uB113\uAC8C \uBCF4\uAE30" : "\uC881\uAC8C \uBCF4\uAE30",
11790
+ onClick: () => onDenseChange?.(!dense)
11791
+ }
11792
+ ),
11793
+ useDensityToggle && useRowsPerPageSelect && /* @__PURE__ */ jsx(SDivider, { vertical: true, className: "my-[6px]" }),
11794
+ useRowsPerPageSelect && /* @__PURE__ */ jsx(
11795
+ SSelect2,
11796
+ {
11797
+ options: rowsPerPageOption,
11798
+ value: useInternalPagination ? innerRowsPerPage : pagination?.rowsPerPage,
11799
+ emitValue: true,
11800
+ onValueChange: (v) => changeRowsPerPage(Number(v)),
11801
+ width: 128
11802
+ }
11803
+ )
11804
+ ] })
11694
11805
  ]
11695
11806
  }
11696
11807
  )
@@ -12786,6 +12897,11 @@ function SCalendar({
12786
12897
  }
12787
12898
  );
12788
12899
  }
12900
+ var MODE_NOUN = {
12901
+ date: "\uB0A0\uC9DC",
12902
+ month: "\uC6D4",
12903
+ year: "\uC5F0\uB3C4"
12904
+ };
12789
12905
  var DATEPICKER_MODE_LIST_HEIGHT = 240;
12790
12906
  var DATEPICKER_MODE_ITEM_HEIGHT = 28;
12791
12907
  var YEAR_LIST_EDGE_BUFFER = 24;
@@ -13057,7 +13173,9 @@ function SDatePicker({
13057
13173
  placeholder,
13058
13174
  selectable,
13059
13175
  disabled = false,
13176
+ clearable = false,
13060
13177
  width,
13178
+ maxWidth,
13061
13179
  name,
13062
13180
  rules,
13063
13181
  status,
@@ -13100,7 +13218,8 @@ function SDatePicker({
13100
13218
  fieldMinW: 168,
13101
13219
  // 값 길이가 YYYY-MM-DD 로 정해져 있어, width="100%" 를 받아도 행 전체로
13102
13220
  // 늘어나지 않게 상한을 건다 (SKeyValueTable 이 모든 컨트롤에 100% 를 넘긴다).
13103
- // px 가 아니라 등급이라 --cmp-field-width-* 가 바뀌면 함께 따라간다
13221
+ // px 가 아니라 등급이라 --cmp-field-width-* 가 바뀌면 함께 따라간다.
13222
+ // 이 기본 상한이 걸리적거리는 자리(폭이 이미 좁게 정해진 팝오버 등)는 maxWidth prop 으로 덮는다
13104
13223
  fieldMaxW: "lg",
13105
13224
  fontSize: 14,
13106
13225
  lineHeight: 24,
@@ -13121,6 +13240,10 @@ function SDatePicker({
13121
13240
  if (rules && rules.length > 0) setRuleError(runRules(date, rules));
13122
13241
  setOpen(false);
13123
13242
  };
13243
+ const clear = () => {
13244
+ onValueChange?.(null);
13245
+ if (rules && rules.length > 0) setRuleError(runRules(null, rules));
13246
+ };
13124
13247
  const selectListboxValue = (nextValue) => {
13125
13248
  onValueChange?.(nextValue);
13126
13249
  if (rules && rules.length > 0) setRuleError(runRules(nextValue, rules));
@@ -13144,20 +13267,31 @@ function SDatePicker({
13144
13267
  errorMessage: ruleError !== "" ? ruleError : errorMessage,
13145
13268
  width,
13146
13269
  minWidth: dims.fieldMinW,
13147
- maxWidth: dims.fieldMaxW,
13270
+ maxWidth: maxWidth ?? dims.fieldMaxW,
13148
13271
  disabled,
13149
13272
  className,
13150
13273
  style,
13151
13274
  children: /* @__PURE__ */ jsxs(RPopover10.Root, { open, onOpenChange: (o) => !disabled && setOpen(o), children: [
13152
13275
  /* @__PURE__ */ jsx(RPopover10.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
13153
- "button",
13276
+ "div",
13154
13277
  {
13155
- type: "button",
13156
- name,
13157
- disabled,
13278
+ role: "button",
13279
+ "aria-disabled": disabled,
13280
+ tabIndex: disabled ? -1 : 0,
13281
+ "data-name": name,
13158
13282
  onFocus: () => setFocused(true),
13159
13283
  onBlur: () => setFocused(false),
13160
- className: "flex h-full w-full items-center overflow-hidden bg-transparent outline-none disabled:cursor-not-allowed",
13284
+ onKeyDown: (event) => {
13285
+ if (disabled) return;
13286
+ if (event.key === "Enter" || event.key === " ") {
13287
+ event.preventDefault();
13288
+ setOpen(!open);
13289
+ }
13290
+ },
13291
+ className: cn(
13292
+ "flex h-full w-full items-center overflow-hidden bg-transparent outline-none",
13293
+ disabled ? "cursor-not-allowed" : "cursor-pointer"
13294
+ ),
13161
13295
  style: { padding: `0 ${dims.padX}px`, gap: dims.gap, borderRadius: dims.radius },
13162
13296
  children: [
13163
13297
  /* @__PURE__ */ jsx(
@@ -13181,6 +13315,18 @@ function SDatePicker({
13181
13315
  },
13182
13316
  children: hasValue ? value : resolvedPlaceholder
13183
13317
  }
13318
+ ),
13319
+ clearable && hasValue && !disabled && /* @__PURE__ */ jsx(
13320
+ SGhostButton,
13321
+ {
13322
+ icon: "close",
13323
+ size: "xxs",
13324
+ ariaLabel: `${MODE_NOUN[mode]} \uC9C0\uC6B0\uAE30`,
13325
+ onClick: (event) => {
13326
+ event.stopPropagation();
13327
+ clear();
13328
+ }
13329
+ }
13184
13330
  )
13185
13331
  ]
13186
13332
  }
@@ -13560,6 +13706,7 @@ function SDateRangePicker({
13560
13706
  maxRange,
13561
13707
  useTimePicker = false,
13562
13708
  disabled = false,
13709
+ clearable = false,
13563
13710
  width,
13564
13711
  name,
13565
13712
  rules,
@@ -13627,6 +13774,11 @@ function SDateRangePicker({
13627
13774
  if (rules && rules.length > 0) setRuleError(runRules(r, rules));
13628
13775
  if (!useTimePicker) setOpen(false);
13629
13776
  };
13777
+ const clear = () => {
13778
+ setPendingStart(null);
13779
+ onValueChange?.(null);
13780
+ if (rules && rules.length > 0) setRuleError(runRules(null, rules));
13781
+ };
13630
13782
  const resolvedPlaceholder = useTimePicker && placeholder === "YYYY-MM-DD ~ YYYY-MM-DD" ? "YYYY-MM-DD HH:mm ~ YYYY-MM-DD HH:mm" : placeholder;
13631
13783
  return /* @__PURE__ */ jsx(
13632
13784
  SField,
@@ -13662,12 +13814,23 @@ function SDateRangePicker({
13662
13814
  },
13663
13815
  children: [
13664
13816
  /* @__PURE__ */ jsx(RPopover10.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
13665
- "button",
13817
+ "div",
13666
13818
  {
13667
- type: "button",
13668
- name,
13669
- disabled,
13670
- className: "flex h-full w-full items-center overflow-hidden bg-transparent outline-none disabled:cursor-not-allowed",
13819
+ role: "button",
13820
+ "aria-disabled": disabled,
13821
+ tabIndex: disabled ? -1 : 0,
13822
+ "data-name": name,
13823
+ onKeyDown: (event) => {
13824
+ if (disabled) return;
13825
+ if (event.key === "Enter" || event.key === " ") {
13826
+ event.preventDefault();
13827
+ setOpen(!open);
13828
+ }
13829
+ },
13830
+ className: cn(
13831
+ "flex h-full w-full items-center overflow-hidden bg-transparent outline-none",
13832
+ disabled ? "cursor-not-allowed" : "cursor-pointer"
13833
+ ),
13671
13834
  style: { padding: `0 ${dims.padX}px`, gap: dims.gap, borderRadius: dims.radius },
13672
13835
  children: [
13673
13836
  /* @__PURE__ */ jsx(
@@ -13698,6 +13861,18 @@ function SDateRangePicker({
13698
13861
  /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: endText })
13699
13862
  ] }) : resolvedPlaceholder
13700
13863
  }
13864
+ ),
13865
+ clearable && hasDisplay && !disabled && /* @__PURE__ */ jsx(
13866
+ SGhostButton,
13867
+ {
13868
+ icon: "close",
13869
+ size: "xxs",
13870
+ ariaLabel: "\uAE30\uAC04 \uC9C0\uC6B0\uAE30",
13871
+ onClick: (event) => {
13872
+ event.stopPropagation();
13873
+ clear();
13874
+ }
13875
+ }
13701
13876
  )
13702
13877
  ]
13703
13878
  }
@@ -14962,6 +15137,7 @@ var SChipFilter = /* @__PURE__ */ forwardRef(function SChipFilter2({
14962
15137
  );
14963
15138
  const [openKey, setOpenKey] = useState(null);
14964
15139
  const [addOpen, setAddOpen] = useState(false);
15140
+ const pendingOpenKeyRef = useRef(null);
14965
15141
  const triggerRefs = useRef(/* @__PURE__ */ new Map());
14966
15142
  const initializedDefaultsRef = useRef(/* @__PURE__ */ new Set());
14967
15143
  const prevOpenKeyRef = useRef(null);
@@ -15037,6 +15213,7 @@ var SChipFilter = /* @__PURE__ */ forwardRef(function SChipFilter2({
15037
15213
  const hasAddButton = fields.some(isAddableField);
15038
15214
  const hasRightActions = hasAddButton || showReset;
15039
15215
  const currentOpenField = fields.find((field) => field.key === openKey);
15216
+ const menuOpen = openKey != null || addOpen;
15040
15217
  const editorPopoverStyle = useMemo(() => {
15041
15218
  if (currentOpenField?.type === "keyword") {
15042
15219
  return { width: CHIPFILTER_LISTBOX_WIDTH };
@@ -15095,7 +15272,13 @@ var SChipFilter = /* @__PURE__ */ forwardRef(function SChipFilter2({
15095
15272
  onAddFilter?.(key);
15096
15273
  setAddOpen(false);
15097
15274
  const field = fields.find((f) => f.key === key);
15098
- if (field && !isInlineField(field)) requestAnimationFrame(() => setOpenKey(key));
15275
+ if (field && !isInlineField(field)) {
15276
+ pendingOpenKeyRef.current = key;
15277
+ requestAnimationFrame(() => {
15278
+ triggerRefs.current.get(key)?.focus();
15279
+ setOpenKey(key);
15280
+ });
15281
+ }
15099
15282
  };
15100
15283
  const rootStyle = useMemo(
15101
15284
  () => ({
@@ -15138,6 +15321,7 @@ var SChipFilter = /* @__PURE__ */ forwardRef(function SChipFilter2({
15138
15321
  {
15139
15322
  message,
15140
15323
  open: invalidGroups.has(runGroupIndex),
15324
+ placement: menuOpen ? "top" : "bottom",
15141
15325
  children: runBuffer
15142
15326
  },
15143
15327
  `group-${runGroupIndex}`
@@ -15151,14 +15335,16 @@ var SChipFilter = /* @__PURE__ */ forwardRef(function SChipFilter2({
15151
15335
  activeFields.forEach((field, index) => {
15152
15336
  const inline = isInlineField(field);
15153
15337
  const groupIndex = groupIndexByKey.get(field.key) ?? 0;
15154
- const warning = field.warning || invalidGroups.has(groupIndex);
15338
+ const warning = invalidGroups.has(groupIndex);
15155
15339
  const prevField = index > 0 ? activeFields[index - 1] : null;
15156
15340
  const prevGroupIndex = prevField ? groupIndexByKey.get(prevField.key) ?? 0 : null;
15157
15341
  const needsLeadingDivider = index === 0 ? false : inline || prevField != null && isInlineField(prevField) || groupIndex !== prevGroupIndex && groups[groupIndex]?.divider === true;
15342
+ const hoistDivider = needsLeadingDivider && groupIndex !== runGroupIndex;
15158
15343
  if (groupIndex !== runGroupIndex) {
15159
15344
  flushRun();
15160
15345
  runGroupIndex = groupIndex;
15161
15346
  }
15347
+ if (hoistDivider) nodes.push(/* @__PURE__ */ jsx(Divider, { inset: true }, `${field.key}-divider`));
15162
15348
  const addable = isAddableField(field);
15163
15349
  const showClear = addable || !isAtDefaultValue(field, values[field.key]);
15164
15350
  const handleClear = () => {
@@ -15222,7 +15408,7 @@ var SChipFilter = /* @__PURE__ */ forwardRef(function SChipFilter2({
15222
15408
  field.key
15223
15409
  );
15224
15410
  runBuffer.push(
15225
- needsLeadingDivider ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
15411
+ needsLeadingDivider && !hoistDivider ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
15226
15412
  /* @__PURE__ */ jsx(Divider, { inset: true }),
15227
15413
  node
15228
15414
  ] }, `${field.key}-wrap`) : node
@@ -15270,6 +15456,11 @@ var SChipFilter = /* @__PURE__ */ forwardRef(function SChipFilter2({
15270
15456
  side: "bottom",
15271
15457
  align: "start",
15272
15458
  sideOffset: 4,
15459
+ onCloseAutoFocus: (event) => {
15460
+ if (pendingOpenKeyRef.current == null) return;
15461
+ pendingOpenKeyRef.current = null;
15462
+ event.preventDefault();
15463
+ },
15273
15464
  className: cn("z-50 min-w-[180px]", FLOATING_SLIDE_ANIM),
15274
15465
  children: /* @__PURE__ */ jsx(ListBox, { children: inactiveFields.length > 0 ? inactiveFields.map((field) => /* @__PURE__ */ jsx(MenuItem, { onClick: () => addField(field.key), children: field.label }, field.key)) : /* @__PURE__ */ jsx(EmptyItem, { children: "\uCD94\uAC00\uD560 \uD544\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4." }) })
15275
15466
  }
@@ -15320,6 +15511,7 @@ var SChipFilter = /* @__PURE__ */ forwardRef(function SChipFilter2({
15320
15511
  value: values[currentOpenField.key],
15321
15512
  disabled: disabled || currentOpenField.disabled,
15322
15513
  onValueChange: (next) => emitValue(currentOpenField.key, next),
15514
+ onValueCommit: (next) => emitValueAndSearch(currentOpenField.key, next),
15323
15515
  onClose: () => setOpenKey(null)
15324
15516
  }
15325
15517
  )
@@ -15347,9 +15539,20 @@ function Divider({ inset, top } = {}) {
15347
15539
  function GroupTooltip({
15348
15540
  message,
15349
15541
  open,
15542
+ placement,
15350
15543
  children
15351
15544
  }) {
15352
- return /* @__PURE__ */ jsx(STooltip2, { trigger: "none", open, placement: "top", tooltipType: "warning", message: [message], children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-[var(--cmp-chipFilter-chip-group)]", children }) });
15545
+ return /* @__PURE__ */ jsx(
15546
+ STooltip2,
15547
+ {
15548
+ trigger: "none",
15549
+ open,
15550
+ placement,
15551
+ tooltipType: "warning",
15552
+ message: [message],
15553
+ children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-[var(--cmp-chipFilter-chip-group)]", children })
15554
+ }
15555
+ );
15353
15556
  }
15354
15557
  function FilterChip({
15355
15558
  field,
@@ -15459,6 +15662,7 @@ function EditorPanel({
15459
15662
  value,
15460
15663
  disabled,
15461
15664
  onValueChange,
15665
+ onValueCommit,
15462
15666
  onClose
15463
15667
  }) {
15464
15668
  const wrapsInPaddedTop = field.type === "date" || field.type === "period";
@@ -15478,7 +15682,8 @@ function EditorPanel({
15478
15682
  field,
15479
15683
  value,
15480
15684
  disabled,
15481
- onValueChange
15685
+ onValueChange,
15686
+ onValueCommit
15482
15687
  }
15483
15688
  ) }) : /* @__PURE__ */ jsx(
15484
15689
  FilterEditor,
@@ -15486,7 +15691,8 @@ function EditorPanel({
15486
15691
  field,
15487
15692
  value,
15488
15693
  disabled,
15489
- onValueChange
15694
+ onValueChange,
15695
+ onValueCommit
15490
15696
  }
15491
15697
  ),
15492
15698
  /* @__PURE__ */ jsxs(
@@ -15538,7 +15744,8 @@ function FilterEditor({
15538
15744
  field,
15539
15745
  value,
15540
15746
  disabled,
15541
- onValueChange
15747
+ onValueChange,
15748
+ onValueCommit
15542
15749
  }) {
15543
15750
  if (field.type === "period") {
15544
15751
  return /* @__PURE__ */ jsx(
@@ -15569,7 +15776,8 @@ function FilterEditor({
15569
15776
  field,
15570
15777
  value: isKeywordValue(value) ? value : keywordEntries(value),
15571
15778
  disabled,
15572
- onValueChange
15779
+ onValueChange,
15780
+ onValueCommit
15573
15781
  }
15574
15782
  );
15575
15783
  }
@@ -15611,7 +15819,9 @@ function DatePresetEditor({
15611
15819
  onValueChange,
15612
15820
  selectable: field.selectable,
15613
15821
  disabled,
15614
- placeholder: field.placeholder
15822
+ placeholder: field.placeholder,
15823
+ width: "100%",
15824
+ maxWidth: "100%"
15615
15825
  }
15616
15826
  );
15617
15827
  }
@@ -15671,7 +15881,8 @@ function PeriodPresetEditor({
15671
15881
  onValueChange: updateInputValue,
15672
15882
  selectable: field.selectable,
15673
15883
  disabled,
15674
- width: "100%"
15884
+ width: "100%",
15885
+ maxWidth: "100%"
15675
15886
  }
15676
15887
  );
15677
15888
  }
@@ -15684,7 +15895,8 @@ function PeriodPresetEditor({
15684
15895
  onValueChange: updateInputValue,
15685
15896
  selectable: field.selectable,
15686
15897
  disabled,
15687
- width: "100%"
15898
+ width: "100%",
15899
+ maxWidth: "100%"
15688
15900
  }
15689
15901
  );
15690
15902
  }
@@ -15731,7 +15943,8 @@ function PeriodPresetEditor({
15731
15943
  onValueChange: updateInputValue,
15732
15944
  selectable: field.selectable,
15733
15945
  disabled,
15734
- width: "100%"
15946
+ width: "100%",
15947
+ maxWidth: "100%"
15735
15948
  }
15736
15949
  );
15737
15950
  }
@@ -15881,6 +16094,7 @@ function InlineDatePresetFilter({
15881
16094
  ) : badge)
15882
16095
  ] });
15883
16096
  }
16097
+ var CSV_PASTE_SEPARATOR = /[,\r\n\t]+/;
15884
16098
  var MATCH_MODE_OPTIONS = [
15885
16099
  { value: "contains", label: "\uD3EC\uD568" },
15886
16100
  { value: "exact", label: "\uC77C\uCE58" }
@@ -15893,20 +16107,61 @@ function KeywordEditor({
15893
16107
  field,
15894
16108
  value,
15895
16109
  disabled,
15896
- onValueChange
16110
+ onValueChange,
16111
+ onValueCommit
15897
16112
  }) {
15898
16113
  const entries3 = keywordEntries(value);
15899
16114
  const [draft, setDraft] = useState("");
15900
16115
  const [mode, setMode] = useState(
15901
16116
  isKeywordValue(value) ? value.mode : "contains"
15902
16117
  );
15903
- const emit3 = (nextEntries) => {
15904
- onValueChange(field.matchModes ? { keywords: nextEntries, mode } : nextEntries);
16118
+ const inputRef = useRef(null);
16119
+ useEffect(() => {
16120
+ if (disabled) return;
16121
+ inputRef.current?.focus();
16122
+ }, [disabled]);
16123
+ const emit3 = (nextEntries, nextMode = mode) => {
16124
+ onValueChange(field.matchModes ? { keywords: nextEntries, mode: nextMode } : nextEntries);
15905
16125
  };
15906
- const addEntry = (raw) => {
16126
+ const commit = (nextEntries) => {
16127
+ onValueCommit(field.matchModes ? { keywords: nextEntries, mode } : nextEntries);
16128
+ };
16129
+ const changeMode = (next) => {
16130
+ setMode(next);
16131
+ emit3(entries3, next);
16132
+ };
16133
+ const newEntries = (candidates) => candidates.reduce((acc, raw) => {
15907
16134
  const next = raw.trim();
15908
- if (next === "" || entries3.includes(next)) return;
15909
- emit3([...entries3, next]);
16135
+ if (next === "" || entries3.includes(next) || acc.includes(next)) return acc;
16136
+ return [...acc, next];
16137
+ }, []);
16138
+ const addEntry = (raw) => {
16139
+ const added = newEntries([raw]);
16140
+ if (added.length === 0) {
16141
+ setDraft("");
16142
+ return;
16143
+ }
16144
+ commit([...entries3, ...added]);
16145
+ setDraft("");
16146
+ };
16147
+ const changeDraft = (next) => {
16148
+ if (field.input !== "csv" || !next.includes(",")) {
16149
+ setDraft(next);
16150
+ return;
16151
+ }
16152
+ const parts = next.split(",");
16153
+ const tail = parts.pop() ?? "";
16154
+ const added = newEntries(parts);
16155
+ if (added.length > 0) commit([...entries3, ...added]);
16156
+ setDraft(tail);
16157
+ };
16158
+ const onPaste = (event) => {
16159
+ if (field.input !== "csv") return;
16160
+ const text = event.clipboardData.getData("text");
16161
+ if (!CSV_PASTE_SEPARATOR.test(text)) return;
16162
+ event.preventDefault();
16163
+ const added = newEntries((draft + text).split(CSV_PASTE_SEPARATOR));
16164
+ if (added.length > 0) commit([...entries3, ...added]);
15910
16165
  setDraft("");
15911
16166
  };
15912
16167
  const removeEntry = (entry) => {
@@ -15938,7 +16193,7 @@ function KeywordEditor({
15938
16193
  options: field.excludeMode ? [...MATCH_MODE_OPTIONS, EXCLUDE_MATCH_MODE_OPTION] : MATCH_MODE_OPTIONS,
15939
16194
  value: mode,
15940
16195
  disabled,
15941
- onValueChange: (next) => setMode(next)
16196
+ onValueChange: (next) => changeMode(next)
15942
16197
  }
15943
16198
  )
15944
16199
  ] }),
@@ -15947,10 +16202,12 @@ function KeywordEditor({
15947
16202
  /* @__PURE__ */ jsx(
15948
16203
  "input",
15949
16204
  {
16205
+ ref: inputRef,
15950
16206
  value: draft,
15951
16207
  disabled,
15952
- placeholder: field.placeholder ?? "\uC785\uB825 \uD6C4 Enter\uB85C \uCD94\uAC00",
15953
- onChange: (event) => setDraft(event.target.value),
16208
+ placeholder: field.placeholder ?? (field.input === "csv" ? "\uB2E4\uC911 \uD0A4\uC6CC\uB4DC\uB294 \uCF64\uB9C8(,)\uB85C \uAD6C\uBD84" : "\uC785\uB825 \uD6C4 Enter\uB85C \uCD94\uAC00"),
16209
+ onChange: (event) => changeDraft(event.target.value),
16210
+ onPaste,
15954
16211
  onKeyDown,
15955
16212
  className: "min-w-0 flex-1 border-none bg-transparent text-[12px] leading-[20px] text-[color:var(--sys-color-field-text-default)] outline-none placeholder:text-[color:var(--sys-color-field-text-placeholder)] disabled:cursor-not-allowed"
15956
16213
  }