sellmate-design-system-react 9.0.0-beta.21 → 9.0.0-beta.24

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
@@ -3715,7 +3715,11 @@ var SDraggableItemView = /* @__PURE__ */ forwardRef(
3715
3715
  const paddingYClass = dense ? size === "sm" ? "py-(--cmp-listDraggableItem-paddingY-sm-dense)" : "py-(--cmp-listDraggableItem-paddingY-md-dense)" : size === "sm" ? "py-(--cmp-listDraggableItem-paddingY-sm-normal)" : "py-(--cmp-listDraggableItem-paddingY-md-normal)";
3716
3716
  const normalizedDepth = Math.max(1, Math.floor(depth));
3717
3717
  const depthOffset = (normalizedDepth - 1) * 20;
3718
- const depthStyle = depthOffset === 0 ? style : {
3718
+ const depthStyle = depthOffset === 0 ? style : bordered ? {
3719
+ ...style,
3720
+ marginLeft: depthOffset,
3721
+ width: `calc(100% - ${depthOffset}px)`
3722
+ } : {
3719
3723
  ...style,
3720
3724
  paddingLeft: `calc(var(--cmp-listDraggableItem-paddingX) + ${depthOffset}px)`
3721
3725
  };
@@ -3944,7 +3948,8 @@ var SDraggableItemImpl = /* @__PURE__ */ forwardRef(function SDraggableItem({
3944
3948
  ] });
3945
3949
  });
3946
3950
  var SDraggableItem2 = /* @__PURE__ */ withDisplayName(SDraggableItemImpl, "SDraggableItem");
3947
- var SDivider = /* @__PURE__ */ forwardRef(function SDivider2({ vertical = false, className, style, ...rest }, ref) {
3951
+ var SDivider = /* @__PURE__ */ forwardRef(function SDivider2({ vertical = false, height, className, style, ...rest }, ref) {
3952
+ const fixedHeight = vertical && height !== void 0;
3948
3953
  return /* @__PURE__ */ jsx(
3949
3954
  "hr",
3950
3955
  {
@@ -3952,10 +3957,14 @@ var SDivider = /* @__PURE__ */ forwardRef(function SDivider2({ vertical = false,
3952
3957
  "aria-orientation": vertical ? "vertical" : "horizontal",
3953
3958
  className: cn(
3954
3959
  "shrink-0 border-0",
3955
- vertical ? "inline-block h-auto w-px self-stretch" : "block h-px w-full",
3960
+ vertical ? cn("inline-block w-px", fixedHeight ? "self-center" : "h-auto self-stretch") : "block h-px w-full",
3956
3961
  className
3957
3962
  ),
3958
- style: { backgroundColor: "var(--sys-color-divider-default, #E1E1E1)", ...style },
3963
+ style: {
3964
+ backgroundColor: "var(--sys-color-divider-default, #E1E1E1)",
3965
+ ...fixedHeight ? { height: typeof height === "number" ? `${height}px` : height } : null,
3966
+ ...style
3967
+ },
3959
3968
  ...rest
3960
3969
  }
3961
3970
  );
@@ -4185,6 +4194,10 @@ function getSubtreeEnd(items, startIndex, getDepth) {
4185
4194
  }
4186
4195
  return endIndex;
4187
4196
  }
4197
+ function isDescendant(items, index, ancestorIndex, getDepth) {
4198
+ if (ancestorIndex == null || getDepth == null || index <= ancestorIndex) return false;
4199
+ return index < getSubtreeEnd(items, ancestorIndex, getDepth);
4200
+ }
4188
4201
  function getInsertionIndex(items, target, getDepth) {
4189
4202
  if (target.intent === "before") return target.index;
4190
4203
  if (target.intent === "inside") return target.index + 1;
@@ -4240,6 +4253,8 @@ function SDraggableListInner({
4240
4253
  const fromIndexRef = useRef(null);
4241
4254
  const currentSelectedKey = selectedKey ?? internalSelectedKey;
4242
4255
  const usesDepth = getDepth != null;
4256
+ const groupDragging = dragContext?.dragging;
4257
+ const draggedSubtreeStart = dragContext ? groupDragging?.listId === listId ? groupDragging?.index ?? null : null : draggingIndex;
4243
4258
  const startDrag = useCallback((event, index) => {
4244
4259
  event.preventDefault();
4245
4260
  fromIndexRef.current = index;
@@ -4371,7 +4386,7 @@ function SDraggableListInner({
4371
4386
  "data-draggable-list-id": dragContext ? listId : void 0,
4372
4387
  children: items.map((item, index) => {
4373
4388
  const itemKey = getKey(item, index);
4374
- const disabled = getDisabled?.(item, index) ?? false;
4389
+ const disabled = (getDisabled?.(item, index) ?? false) || isDescendant(items, index, draggedSubtreeStart, usesDepth ? readDepth : void 0);
4375
4390
  const depth = readDepth(item, index);
4376
4391
  const showBefore = isDropTarget && currentDropIndex === index && (dragContext || currentDropIntent === "before");
4377
4392
  const showInside = isDropTarget && currentDropIndex === index && !dragContext && usesDepth && currentDropIntent === "inside";
@@ -4404,6 +4419,7 @@ function SDraggableListInner({
4404
4419
  } else startDrag(event, index);
4405
4420
  },
4406
4421
  selected: currentSelectedKey === itemKey,
4422
+ disabled,
4407
4423
  depth
4408
4424
  })
4409
4425
  },
@@ -10399,7 +10415,11 @@ var SField = /* @__PURE__ */ forwardRef(function SField2({
10399
10415
  "div",
10400
10416
  {
10401
10417
  className: cn(
10402
- "relative box-border flex min-w-0 items-stretch overflow-hidden border border-solid border-(--field-bc)",
10418
+ "relative box-border flex min-w-0 items-stretch border border-solid border-(--field-bc)",
10419
+ // 둘 다 넘친 것을 잘라 내지만 clip 은 스크롤 상자를 만들지 않는다. hidden 이면
10420
+ // 이 상자가 스크롤포트가 되어 안쪽의 position:sticky 가 페이지 스크롤을 따라가지
10421
+ // 못한다 (SEditor 의 고정 툴바). 여러 줄 필드에서만 바꿔 파급을 좁힌다.
10422
+ multiline ? "overflow-clip" : "overflow-hidden",
10403
10423
  interactive && !borderless && "hover:border-(--sys-color-field-border-focus) hover:shadow-[0px_0px_4px_0px_#0071ff66] focus-within:border-(--sys-color-field-border-focus) focus-within:shadow-[0px_0px_4px_0px_#0071ff66]",
10404
10424
  disabled && "cursor-not-allowed"
10405
10425
  ),
@@ -10435,7 +10455,7 @@ var SField = /* @__PURE__ */ forwardRef(function SField2({
10435
10455
  ]
10436
10456
  }
10437
10457
  ),
10438
- /* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1", children })
10458
+ /* @__PURE__ */ jsx("div", { className: cn("flex min-w-0 flex-1", multiline && "bg-inherit"), children })
10439
10459
  ]
10440
10460
  }
10441
10461
  ),
@@ -11313,7 +11333,6 @@ var STable = /* @__PURE__ */ forwardRef(function STable2({
11313
11333
  onPageChange,
11314
11334
  useInternalPagination = false,
11315
11335
  useRowsPerPageSelect = false,
11316
- useDensityToggle = false,
11317
11336
  rowsPerPageOption = DEFAULT_ROWS_PER_PAGE_OPTION,
11318
11337
  onRowsPerPageChange,
11319
11338
  useVirtualScroll = false,
@@ -11329,10 +11348,18 @@ var STable = /* @__PURE__ */ forwardRef(function STable2({
11329
11348
  }, ref) {
11330
11349
  const autoId = useId();
11331
11350
  const resolvedTableId = tableId ?? autoId;
11351
+ const [innerDense, setInnerDense] = useState(dense);
11352
+ useEffect(() => {
11353
+ setInnerDense(dense);
11354
+ }, [dense]);
11355
+ const changeDense = (next) => {
11356
+ setInnerDense(next);
11357
+ onDenseChange?.(next);
11358
+ };
11332
11359
  const visibleCols = useMemo(() => columns.filter((c) => c.visible !== false), [columns]);
11333
11360
  const stickyLeft = stickyColumn?.left ?? 0;
11334
11361
  const stickyRight = stickyColumn?.right ?? 0;
11335
- const effectiveRowHeight = rowHeight ?? (dense ? DENSE_ROW_HEIGHT : DEFAULT_ROW_HEIGHT);
11362
+ const effectiveRowHeight = rowHeight ?? (innerDense ? DENSE_ROW_HEIGHT : DEFAULT_ROW_HEIGHT);
11336
11363
  const colSignature = useMemo(
11337
11364
  () => visibleCols.map((c) => `${c.name}:${c.width ?? ""}:${c.autoWidth ? 1 : 0}`).join("|"),
11338
11365
  [visibleCols]
@@ -11562,9 +11589,9 @@ var STable = /* @__PURE__ */ forwardRef(function STable2({
11562
11589
  else onSelectedChange?.([...selected, row]);
11563
11590
  };
11564
11591
  const radiusClass = radius === "full" ? "rounded-none" : radius === "useTop" ? "rounded-b-[var(--cmp-table-radius)] rounded-t-none" : "rounded-[var(--cmp-table-radius)]";
11565
- const cellPadY = dense ? "var(--cmp-table-body-paddingY-dense)" : "var(--cmp-table-body-paddingY-default)";
11592
+ const cellPadY = innerDense ? "var(--cmp-table-body-paddingY-dense)" : "var(--cmp-table-body-paddingY-default)";
11566
11593
  const cellPadXOf = (col) => col.contentType === "control" ? "var(--cmp-table-body-paddingX-default)" : "var(--cmp-table-body-paddingX-wide)";
11567
- const rowH = dense ? "var(--cmp-table-body-dense-height)" : "var(--cmp-table-body-default-height)";
11594
+ const rowH = innerDense ? "var(--cmp-table-body-dense-height)" : "var(--cmp-table-body-default-height)";
11568
11595
  const totalColSpan = visibleCols.length + (selectable ? 1 : 0);
11569
11596
  const stickyInfo = (i) => {
11570
11597
  const isLeft = i < stickyLeft;
@@ -11916,10 +11943,11 @@ var STable = /* @__PURE__ */ forwardRef(function STable2({
11916
11943
  ]
11917
11944
  }
11918
11945
  ),
11919
- showPagination && // 원본 sd-table__pagination: 테이블 하단에 이어붙는 회색 바(높이 48px, margin-top:-1px로 테두리 겹침).
11946
+ (showPagination || dense) && // 원본 sd-table__pagination: 테이블 하단에 이어붙는 회색 바(높이 48px, margin-top:-1px로 테두리 겹침).
11920
11947
  // SPagination은 전체 폭 기준 중앙, rows-per-page SSelect는 우측에 absolute 배치해 중앙 정렬을 유지한다.
11921
11948
  // 루트 높이가 확정된 경우(테이블이 남은 영역을 채우는 배치) 페이지네이션 바가
11922
11949
  // 눌리지 않도록 shrink-0으로 48px를 보장한다.
11950
+ // 페이지네이션이 없어도 dense 면 이 바를 그린다 — 밀도 토글이 사는 곳이 여기다.
11923
11951
  /* @__PURE__ */ jsxs(
11924
11952
  "div",
11925
11953
  {
@@ -11929,22 +11957,20 @@ var STable = /* @__PURE__ */ forwardRef(function STable2({
11929
11957
  bordered && "-mt-px border border-solid border-[color:var(--cmp-table-border-color)]"
11930
11958
  ),
11931
11959
  children: [
11932
- /* @__PURE__ */ jsx(SPagination, { currentPage: displayPage, lastPage, onPageChange: changePage }),
11933
- (useDensityToggle || useRowsPerPageSelect) && /* @__PURE__ */ jsxs("div", { className: "absolute right-[10px] top-1/2 flex -translate-y-1/2 items-center gap-[12px]", children: [
11934
- useDensityToggle && // 라벨·아이콘은 현재 밀도가 아니라 **누르면 되는 상태**를 가리킨다 (dense 면 "넓게 보기").
11935
- // row·rowDense 는 세로 막대라 90도 돌려 가로 행으로 쓴다.
11936
- /* @__PURE__ */ jsx(
11960
+ showPagination && /* @__PURE__ */ jsx(SPagination, { currentPage: displayPage, lastPage, onPageChange: changePage }),
11961
+ (dense || useRowsPerPageSelect) && /* @__PURE__ */ jsxs("div", { className: "absolute right-[10px] top-1/2 flex -translate-y-1/2 items-center gap-[12px]", children: [
11962
+ dense && /* @__PURE__ */ jsx(
11937
11963
  STextLink,
11938
11964
  {
11939
11965
  size: "sm",
11940
- icon: dense ? "row" : "rowDense",
11966
+ icon: innerDense ? "row" : "rowDense",
11941
11967
  iconRotate: 90,
11942
11968
  iconColor: "var(--sys-color-fg-quaternary)",
11943
- label: dense ? "\uB113\uAC8C \uBCF4\uAE30" : "\uC881\uAC8C \uBCF4\uAE30",
11944
- onClick: () => onDenseChange?.(!dense)
11969
+ label: innerDense ? "\uB113\uAC8C \uBCF4\uAE30" : "\uC881\uAC8C \uBCF4\uAE30",
11970
+ onClick: () => changeDense(!innerDense)
11945
11971
  }
11946
11972
  ),
11947
- useDensityToggle && useRowsPerPageSelect && /* @__PURE__ */ jsx(SDivider, { vertical: true, className: "my-[6px]" }),
11973
+ dense && useRowsPerPageSelect && /* @__PURE__ */ jsx(SDivider, { vertical: true, className: "my-[6px]" }),
11948
11974
  useRowsPerPageSelect && /* @__PURE__ */ jsx(
11949
11975
  SSelect2,
11950
11976
  {
@@ -12007,7 +12033,7 @@ var STableBar = /* @__PURE__ */ forwardRef(function STableBar2({ total, selected
12007
12033
  SDivider,
12008
12034
  {
12009
12035
  vertical: true,
12010
- className: "h-[var(--cmp-table-bar-divider-height)] self-center",
12036
+ height: "var(--cmp-table-bar-divider-height)",
12011
12037
  style: { backgroundColor: "var(--cmp-table-border-color)" }
12012
12038
  }
12013
12039
  ),
@@ -12932,13 +12958,7 @@ function SCalendar({
12932
12958
  }
12933
12959
  )
12934
12960
  ] }),
12935
- /* @__PURE__ */ jsx(
12936
- SDivider,
12937
- {
12938
- vertical: true,
12939
- className: "h-[var(--cmp-datepicker-calendar-header-divider-height)] self-center"
12940
- }
12941
- ),
12961
+ /* @__PURE__ */ jsx(SDivider, { vertical: true, height: "var(--cmp-datepicker-calendar-header-divider-height)" }),
12942
12962
  /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-[var(--cmp-datepicker-calendar-gap)]", children: [
12943
12963
  /* @__PURE__ */ jsx(
12944
12964
  SGhostButton,
@@ -15179,66 +15199,6 @@ var IconBlockquote = (p) => /* @__PURE__ */ jsxs(Frame, { ...p, children: [
15179
15199
  }
15180
15200
  )
15181
15201
  ] });
15182
- var IconHighlight = (p) => /* @__PURE__ */ jsx(Frame, { ...p, children: /* @__PURE__ */ jsx(
15183
- "path",
15184
- {
15185
- fillRule: "evenodd",
15186
- clipRule: "evenodd",
15187
- d: "M14.7072 4.70711C15.0977 4.31658 15.0977 3.68342 14.7072 3.29289C14.3167 2.90237 13.6835 2.90237 13.293 3.29289L8.69294 7.89286L8.68594 7.9C8.13626 8.46079 7.82837 9.21474 7.82837 10C7.82837 10.2306 7.85491 10.4584 7.90631 10.6795L2.29289 16.2929C2.10536 16.4804 2 16.7348 2 17V20C2 20.5523 2.44772 21 3 21H12C12.2652 21 12.5196 20.8946 12.7071 20.7071L15.3205 18.0937C15.5416 18.1452 15.7695 18.1717 16.0001 18.1717C16.7853 18.1717 17.5393 17.8639 18.1001 17.3142L22.7072 12.7071C23.0977 12.3166 23.0977 11.6834 22.7072 11.2929C22.3167 10.9024 21.6835 10.9024 21.293 11.2929L16.6971 15.8887C16.5105 16.0702 16.2605 16.1717 16.0001 16.1717C15.7397 16.1717 15.4897 16.0702 15.303 15.8887L10.1113 10.697C9.92992 10.5104 9.82837 10.2604 9.82837 10C9.82837 9.73963 9.92992 9.48958 10.1113 9.30297L14.7072 4.70711ZM13.5858 17L9.00004 12.4142L4 17.4142V19H11.5858L13.5858 17Z"
15188
- }
15189
- ) });
15190
- var IconSuperscript = (p) => /* @__PURE__ */ jsxs(Frame, { ...p, children: [
15191
- /* @__PURE__ */ jsx(
15192
- "path",
15193
- {
15194
- fillRule: "evenodd",
15195
- clipRule: "evenodd",
15196
- d: "M12.7071 7.29289C13.0976 7.68342 13.0976 8.31658 12.7071 8.70711L4.70711 16.7071C4.31658 17.0976 3.68342 17.0976 3.29289 16.7071C2.90237 16.3166 2.90237 15.6834 3.29289 15.2929L11.2929 7.29289C11.6834 6.90237 12.3166 6.90237 12.7071 7.29289Z"
15197
- }
15198
- ),
15199
- /* @__PURE__ */ jsx(
15200
- "path",
15201
- {
15202
- fillRule: "evenodd",
15203
- clipRule: "evenodd",
15204
- d: "M3.29289 7.29289C3.68342 6.90237 4.31658 6.90237 4.70711 7.29289L12.7071 15.2929C13.0976 15.6834 13.0976 16.3166 12.7071 16.7071C12.3166 17.0976 11.6834 17.0976 11.2929 16.7071L3.29289 8.70711C2.90237 8.31658 2.90237 7.68342 3.29289 7.29289Z"
15205
- }
15206
- ),
15207
- /* @__PURE__ */ jsx(
15208
- "path",
15209
- {
15210
- fillRule: "evenodd",
15211
- clipRule: "evenodd",
15212
- d: "M17.405 1.40657C18.0246 1.05456 18.7463 0.92634 19.4492 1.04344C20.1521 1.16054 20.7933 1.51583 21.2652 2.0497L21.2697 2.05469L21.2696 2.05471C21.7431 2.5975 22 3.28922 22 4.00203C22 5.08579 21.3952 5.84326 20.7727 6.34289C20.1966 6.80531 19.4941 7.13675 18.9941 7.37261C18.9714 7.38332 18.9491 7.39383 18.9273 7.40415C18.4487 7.63034 18.2814 7.78152 18.1927 7.91844C18.1778 7.94155 18.1625 7.96834 18.1473 8.00003H21C21.5523 8.00003 22 8.44774 22 9.00003C22 9.55231 21.5523 10 21 10H17C16.4477 10 16 9.55231 16 9.00003C16 8.17007 16.1183 7.44255 16.5138 6.83161C16.9107 6.21854 17.4934 5.86971 18.0728 5.59591C18.6281 5.33347 19.1376 5.09075 19.5208 4.78316C19.8838 4.49179 20 4.25026 20 4.00203C20 3.77192 19.9178 3.54865 19.7646 3.37182C19.5968 3.18324 19.3696 3.05774 19.1205 3.01625C18.8705 2.97459 18.6137 3.02017 18.3933 3.14533C18.1762 3.26898 18.0191 3.45826 17.9406 3.67557C17.7531 4.19504 17.18 4.46414 16.6605 4.27662C16.141 4.0891 15.8719 3.51596 16.0594 2.99649C16.303 2.3219 16.7817 1.76125 17.4045 1.40689L17.405 1.40657Z"
15213
- }
15214
- )
15215
- ] });
15216
- var IconSubscript = (p) => /* @__PURE__ */ jsxs(Frame, { ...p, children: [
15217
- /* @__PURE__ */ jsx(
15218
- "path",
15219
- {
15220
- fillRule: "evenodd",
15221
- clipRule: "evenodd",
15222
- d: "M3.29289 7.29289C3.68342 6.90237 4.31658 6.90237 4.70711 7.29289L12.7071 15.2929C13.0976 15.6834 13.0976 16.3166 12.7071 16.7071C12.3166 17.0976 11.6834 17.0976 11.2929 16.7071L3.29289 8.70711C2.90237 8.31658 2.90237 7.68342 3.29289 7.29289Z"
15223
- }
15224
- ),
15225
- /* @__PURE__ */ jsx(
15226
- "path",
15227
- {
15228
- fillRule: "evenodd",
15229
- clipRule: "evenodd",
15230
- d: "M12.7071 7.29289C13.0976 7.68342 13.0976 8.31658 12.7071 8.70711L4.70711 16.7071C4.31658 17.0976 3.68342 17.0976 3.29289 16.7071C2.90237 16.3166 2.90237 15.6834 3.29289 15.2929L11.2929 7.29289C11.6834 6.90237 12.3166 6.90237 12.7071 7.29289Z"
15231
- }
15232
- ),
15233
- /* @__PURE__ */ jsx(
15234
- "path",
15235
- {
15236
- fillRule: "evenodd",
15237
- clipRule: "evenodd",
15238
- d: "M17.4079 14.3995C18.0284 14.0487 18.7506 13.9217 19.4536 14.0397C20.1566 14.1578 20.7977 14.5138 21.2696 15.0481L21.2779 15.0574L21.2778 15.0575C21.7439 15.5988 22 16.2903 22 17C22 18.0823 21.3962 18.8401 20.7744 19.3404C20.194 19.8073 19.4858 20.141 18.9828 20.378C18.9638 20.387 18.9451 20.3958 18.9266 20.4045C18.4473 20.6306 18.2804 20.7817 18.1922 20.918C18.1773 20.9412 18.1619 20.9681 18.1467 21H21C21.5523 21 22 21.4477 22 22C22 22.5523 21.5523 23 21 23H17C16.4477 23 16 22.5523 16 22C16 21.1708 16.1176 20.4431 16.5128 19.832C16.9096 19.2184 17.4928 18.8695 18.0734 18.5956C18.6279 18.334 19.138 18.0901 19.5207 17.7821C19.8838 17.49 20 17.2477 20 17C20 16.7718 19.9176 16.5452 19.7663 16.3672C19.5983 16.1792 19.3712 16.0539 19.1224 16.0121C18.8722 15.9701 18.6152 16.015 18.3942 16.1394C18.1794 16.2628 18.0205 16.4549 17.9422 16.675C17.7572 17.1954 17.1854 17.4673 16.665 17.2822C16.1446 17.0972 15.8728 16.5254 16.0578 16.005C16.2993 15.3259 16.7797 14.7584 17.4039 14.4018L17.4079 14.3995L17.4079 14.3995Z"
15239
- }
15240
- )
15241
- ] });
15242
15202
  var IconAlignLeft = (p) => /* @__PURE__ */ jsxs(Frame, { ...p, children: [
15243
15203
  /* @__PURE__ */ jsx(
15244
15204
  "path",
@@ -15530,6 +15490,14 @@ var IconTextColor = (p) => /* @__PURE__ */ jsxs(Frame, { ...p, children: [
15530
15490
  }
15531
15491
  )
15532
15492
  ] });
15493
+ var IconTable = (p) => /* @__PURE__ */ jsx(Frame, { ...p, children: /* @__PURE__ */ jsx(
15494
+ "path",
15495
+ {
15496
+ fillRule: "evenodd",
15497
+ clipRule: "evenodd",
15498
+ d: "M3 5C3 4.44772 3.44772 4 4 4H20C20.5523 4 21 4.44772 21 5V19C21 19.5523 20.5523 20 20 20H4C3.44772 20 3 19.5523 3 19V5ZM5 6V9H19V6H5ZM19 11H13V13H19V11ZM19 15H13V18H19V15ZM11 18V15H5V18H11ZM5 13H11V11H5V13Z"
15499
+ }
15500
+ ) });
15533
15501
  var IconHorizontalRule = (p) => /* @__PURE__ */ jsxs(Frame, { ...p, children: [
15534
15502
  /* @__PURE__ */ jsx("rect", { x: 3, y: 5, width: 18, height: 2, rx: 1 }),
15535
15503
  /* @__PURE__ */ jsx("rect", { x: 2, y: 11, width: 20, height: 2, rx: 1 }),
@@ -15537,39 +15505,12 @@ var IconHorizontalRule = (p) => /* @__PURE__ */ jsxs(Frame, { ...p, children: [
15537
15505
  ] });
15538
15506
 
15539
15507
  // src/components/SEditor/editor.config.ts
15540
- var SEDITOR_TOOLBAR_ITEMS = [
15541
- "heading",
15542
- "fontSize",
15543
- "bold",
15544
- "italic",
15545
- "underline",
15546
- "strike",
15547
- "code",
15548
- "color",
15549
- "highlight",
15550
- "superscript",
15551
- "subscript",
15552
- "alignLeft",
15553
- "alignCenter",
15554
- "alignRight",
15555
- "alignJustify",
15556
- "bulletList",
15557
- "orderedList",
15558
- "taskList",
15559
- "list",
15560
- "blockquote",
15561
- "codeBlock",
15562
- "horizontalRule",
15563
- "link",
15564
- "image",
15565
- "undo",
15566
- "redo"
15567
- ];
15568
15508
  var SEDITOR_DEFAULT_TOOLBAR = [
15569
15509
  "undo",
15570
15510
  "redo",
15571
15511
  "|",
15572
15512
  "heading",
15513
+ "fontSize",
15573
15514
  "list",
15574
15515
  "blockquote",
15575
15516
  "codeBlock",
@@ -15580,18 +15521,29 @@ var SEDITOR_DEFAULT_TOOLBAR = [
15580
15521
  "code",
15581
15522
  "underline",
15582
15523
  "color",
15583
- "highlight",
15584
15524
  "link",
15585
15525
  "|",
15586
- "superscript",
15587
- "subscript",
15588
- "|",
15589
15526
  "alignLeft",
15590
15527
  "alignCenter",
15591
15528
  "alignRight",
15592
15529
  "alignJustify",
15593
15530
  "|",
15594
- "image"
15531
+ "table",
15532
+ "image",
15533
+ "horizontalRule"
15534
+ ];
15535
+ var SEDITOR_SIMPLE_TOOLBAR = [
15536
+ "undo",
15537
+ "redo",
15538
+ "|",
15539
+ "heading",
15540
+ "fontSize",
15541
+ "|",
15542
+ "bold",
15543
+ "italic",
15544
+ "underline",
15545
+ "strike",
15546
+ "color"
15595
15547
  ];
15596
15548
  var SEDITOR_DEFAULT_BUBBLE_MENU = [
15597
15549
  "bold",
@@ -15601,9 +15553,16 @@ var SEDITOR_DEFAULT_BUBBLE_MENU = [
15601
15553
  "underline",
15602
15554
  "|",
15603
15555
  "color",
15604
- "highlight",
15605
15556
  "link"
15606
15557
  ];
15558
+ var SEDITOR_SIMPLE_BUBBLE_MENU = [
15559
+ "bold",
15560
+ "italic",
15561
+ "strike",
15562
+ "underline",
15563
+ "|",
15564
+ "color"
15565
+ ];
15607
15566
  var SEDITOR_HEADING_LEVELS = [1, 2, 3];
15608
15567
  var SEDITOR_HEADING_LABELS = {
15609
15568
  0: "\uBCF8\uBB38",
@@ -15611,7 +15570,7 @@ var SEDITOR_HEADING_LABELS = {
15611
15570
  2: "\uC81C\uBAA9 2",
15612
15571
  3: "\uC81C\uBAA9 3"
15613
15572
  };
15614
- var SEDITOR_FONT_SIZES = [11, 12, 14, 16, 18];
15573
+ var SEDITOR_FONT_SIZES = [8, 9, 10, 11, 12, 14, 16, 18, 24, 30, 36, 48, 60, 72];
15615
15574
  var SEDITOR_DEFAULT_FONT_SIZE = 12;
15616
15575
  var SEDITOR_DEFAULT_COLORS = [
15617
15576
  { label: "\uAE30\uBCF8", color: "var(--color-fg-primary)" },
@@ -15623,17 +15582,13 @@ var SEDITOR_DEFAULT_COLORS = [
15623
15582
  { label: "\uC8FC\uC758", color: "var(--color-fg-warning)" },
15624
15583
  { label: "\uC704\uD5D8", color: "var(--color-fg-danger)" }
15625
15584
  ];
15626
- var SEDITOR_DEFAULT_HIGHLIGHTS = [
15627
- { label: "\uB178\uB791", color: "yellow_25" },
15628
- { label: "\uCD08\uB85D", color: "green_25" },
15629
- { label: "\uD30C\uB791", color: "brilliantblue_25" },
15630
- { label: "\uBE68\uAC15", color: "red_20" },
15631
- { label: "\uC8FC\uD669", color: "orange_20" },
15632
- { label: "\uD68C\uC0C9", color: "grey_20" }
15633
- ];
15634
15585
  var TASK_LIST_CLASS = "sd-editor-task-list";
15635
15586
  var TASK_ITEM_CLASS = "sd-editor-task-item";
15636
15587
  var IMAGE_CLASS = "sd-editor-image";
15588
+ var TABLE_CLASS = "sd-editor-table";
15589
+ var TABLE_ROW_CLASS = "sd-editor-table-row";
15590
+ var TABLE_HEADER_CLASS = "sd-editor-table-header";
15591
+ var TABLE_CELL_CLASS = "sd-editor-table-cell";
15637
15592
  var SEDITOR_CONTENT_CLASS = [
15638
15593
  "[&_.ProseMirror]:min-h-full [&_.ProseMirror]:outline-none [&_.ProseMirror]:whitespace-pre-wrap [&_.ProseMirror]:break-words",
15639
15594
  // placeholder — Placeholder 확장이 빈 첫 문단에 data-placeholder 와 클래스를 붙인다
@@ -15646,23 +15601,38 @@ var SEDITOR_CONTENT_CLASS = [
15646
15601
  "[&_ol]:my-[4px] [&_ol]:list-decimal [&_ol]:pl-[20px]",
15647
15602
  "[&_li]:my-0 [&_li>p]:my-0",
15648
15603
  // 체크목록 — 마커를 지우고 체크박스와 본문을 가로로 세운다
15649
- `[&_.${TASK_LIST_CLASS}]:my-[4px] [&_.${TASK_LIST_CLASS}]:list-none [&_.${TASK_LIST_CLASS}]:pl-0`,
15650
- `[&_.${TASK_ITEM_CLASS}]:flex [&_.${TASK_ITEM_CLASS}]:items-start [&_.${TASK_ITEM_CLASS}]:gap-[6px]`,
15651
- `[&_.${TASK_ITEM_CLASS}>label]:mt-[3px] [&_.${TASK_ITEM_CLASS}>label]:shrink-0 [&_.${TASK_ITEM_CLASS}>label]:leading-none`,
15652
- `[&_.${TASK_ITEM_CLASS}>div]:min-w-0 [&_.${TASK_ITEM_CLASS}>div]:flex-1`,
15653
- `[&_.${TASK_ITEM_CLASS}_input]:m-0 [&_.${TASK_ITEM_CLASS}_input]:h-[13px] [&_.${TASK_ITEM_CLASS}_input]:w-[13px] [&_.${TASK_ITEM_CLASS}_input]:cursor-pointer [&_.${TASK_ITEM_CLASS}_input]:accent-[var(--color-fg-accent)]`,
15654
- `[&_.${TASK_ITEM_CLASS}[data-checked=true]>div]:text-[color:var(--color-fg-tertiary)] [&_.${TASK_ITEM_CLASS}[data-checked=true]>div]:line-through`,
15604
+ "[&_.sd-editor-task-list]:my-[4px] [&_.sd-editor-task-list]:list-none [&_.sd-editor-task-list]:pl-0",
15605
+ "[&_.sd-editor-task-item]:flex [&_.sd-editor-task-item]:items-start [&_.sd-editor-task-item]:gap-[6px]",
15606
+ "[&_.sd-editor-task-item>label]:mt-[3px] [&_.sd-editor-task-item>label]:shrink-0 [&_.sd-editor-task-item>label]:leading-none",
15607
+ "[&_.sd-editor-task-item>div]:min-w-0 [&_.sd-editor-task-item>div]:flex-1",
15608
+ "[&_.sd-editor-task-item_input]:m-0 [&_.sd-editor-task-item_input]:h-[13px] [&_.sd-editor-task-item_input]:w-[13px] [&_.sd-editor-task-item_input]:cursor-pointer [&_.sd-editor-task-item_input]:accent-[var(--color-fg-accent)]",
15609
+ "[&_.sd-editor-task-item[data-checked=true]>div]:text-[color:var(--color-fg-tertiary)] [&_.sd-editor-task-item[data-checked=true]>div]:line-through",
15655
15610
  "[&_blockquote]:my-[8px] [&_blockquote]:border-l-[3px] [&_blockquote]:border-solid [&_blockquote]:border-l-[color:var(--color-border-default)] [&_blockquote]:pl-[12px] [&_blockquote]:text-[color:var(--color-fg-tertiary)]",
15656
15611
  "[&_a]:cursor-pointer [&_a]:text-[color:var(--color-fg-accent)] [&_a]:underline",
15657
15612
  "[&_hr]:my-[12px] [&_hr]:border-t [&_hr]:border-[color:var(--color-border-default)]",
15658
15613
  "[&_code]:rounded-[3px] [&_code]:bg-[var(--color-bg-neutralLight)] [&_code]:px-[4px] [&_code]:py-[1px]",
15659
15614
  "[&_pre]:my-[8px] [&_pre]:rounded-[4px] [&_pre]:bg-[var(--color-bg-neutralLight)] [&_pre]:p-[12px]",
15660
15615
  "[&_pre_code]:bg-transparent [&_pre_code]:p-0",
15661
- `[&_.${IMAGE_CLASS}]:my-[8px] [&_.${IMAGE_CLASS}]:h-auto [&_.${IMAGE_CLASS}]:max-w-full [&_.${IMAGE_CLASS}]:rounded-[4px]`,
15616
+ "[&_.sd-editor-image]:my-[8px] [&_.sd-editor-image]:h-auto [&_.sd-editor-image]:max-w-full [&_.sd-editor-image]:rounded-[4px]",
15617
+ /**
15618
+ * 표 — `table-layout: fixed` 로 열을 균등하게 나눈다.
15619
+ *
15620
+ * 열 너비를 저장하지 않기로 했으므로(tiptap-api.ts 의 Table 주석) 폭은 언제나 여기서
15621
+ * 정해진다. auto 로 두면 글자 많은 열이 넓어져 같은 표가 화면마다 다르게 보이고, 긴
15622
+ * 단어 하나가 상자 밖으로 표를 밀어낸다.
15623
+ */
15624
+ "[&_.sd-editor-table]:my-[8px] [&_.sd-editor-table]:w-full [&_.sd-editor-table]:table-fixed [&_.sd-editor-table]:border-collapse",
15625
+ "[&_.sd-editor-table-header]:border [&_.sd-editor-table-header]:border-solid [&_.sd-editor-table-header]:border-[color:var(--color-border-default)] [&_.sd-editor-table-header]:bg-[var(--color-bg-neutralLight)] [&_.sd-editor-table-header]:px-[8px] [&_.sd-editor-table-header]:py-[4px] [&_.sd-editor-table-header]:text-left [&_.sd-editor-table-header]:align-top [&_.sd-editor-table-header]:font-bold",
15626
+ "[&_.sd-editor-table-cell]:border [&_.sd-editor-table-cell]:border-solid [&_.sd-editor-table-cell]:border-[color:var(--color-border-default)] [&_.sd-editor-table-cell]:px-[8px] [&_.sd-editor-table-cell]:py-[4px] [&_.sd-editor-table-cell]:align-top",
15627
+ // 칸 안의 문단은 표 밖과 달리 위아래 여백을 갖지 않는다 — 한 줄짜리 칸이 대부분이다
15628
+ "[&_.sd-editor-table-header>p]:my-0 [&_.sd-editor-table-cell>p]:my-0",
15629
+ /*
15630
+ 고른 칸 표시 — ProseMirror 표 플러그인이 `.selectedCell` 을 붙인다. 배경을 직접 칠하면
15631
+ 칸이 자기 배경(헤더의 회색)을 잃으므로 덧대는 판을 하나 얹는다.
15632
+ */
15633
+ "[&_.selectedCell]:relative [&_.selectedCell]:after:pointer-events-none [&_.selectedCell]:after:absolute [&_.selectedCell]:after:inset-0 [&_.selectedCell]:after:bg-[var(--color-bg-accentFaint)]",
15662
15634
  "[&_.ProseMirror-selectednode]:outline [&_.ProseMirror-selectednode]:outline-2 [&_.ProseMirror-selectednode]:outline-[var(--color-border-accent)]",
15663
- "[&_strong]:font-bold [&_em]:italic [&_u]:underline [&_s]:line-through",
15664
- "[&_sup]:align-super [&_sup]:text-[0.75em] [&_sub]:align-sub [&_sub]:text-[0.75em]",
15665
- "[&_mark]:rounded-[2px] [&_mark]:bg-transparent [&_mark]:px-[1px]"
15635
+ "[&_strong]:font-bold [&_em]:italic [&_u]:underline [&_s]:line-through"
15666
15636
  ].join(" ");
15667
15637
  var BODY = { fontSize: 12, lineHeight: "20px", paddingX: 12, paddingY: 8 };
15668
15638
  var cssLen3 = (v) => typeof v === "number" ? `${v}px` : v;
@@ -15731,22 +15701,28 @@ var ToolbarButton = /* @__PURE__ */ forwardRef(function ToolbarButton2({ label,
15731
15701
  }
15732
15702
  );
15733
15703
  });
15734
- var Separator = () => /* @__PURE__ */ jsx(
15704
+ var Separator2 = () => /* @__PURE__ */ jsx(
15735
15705
  "span",
15736
15706
  {
15737
15707
  "aria-hidden": true,
15738
- className: "mx-[2px] h-[16px] w-[1px] shrink-0",
15739
- style: { background: "var(--sys-color-field-border-default)" }
15708
+ className: "mx-[4px] h-[16px] w-[1px] shrink-0",
15709
+ style: { background: "var(--sys-color-border-default)" }
15740
15710
  }
15741
15711
  );
15742
15712
  var ColorIndicator = ({ color, children }) => /* @__PURE__ */ jsxs("span", { className: "flex flex-col items-center gap-[1px]", children: [
15743
15713
  children,
15744
15714
  /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "h-[3px] w-[16px] rounded-[1px]", style: { background: color } })
15745
15715
  ] });
15746
- var menuClass = cn(
15747
- "z-50 overflow-hidden rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] p-[4px] shadow-normal-sm",
15748
- FLOATING_SLIDE_ANIM
15716
+ var MENU_BASE_CLASS = "z-50 rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] p-[4px] shadow-normal-sm";
15717
+ var menuClass = cn(MENU_BASE_CLASS, "overflow-hidden", FLOATING_SLIDE_ANIM);
15718
+ var scrollMenuClass = cn(
15719
+ MENU_BASE_CLASS,
15720
+ "overflow-x-hidden overflow-y-auto",
15721
+ FLOATING_SLIDE_ANIM,
15722
+ SCROLLBAR_CLASS
15749
15723
  );
15724
+ var FONT_SIZE_DEFAULT_LABEL = "\uAE30\uBCF8";
15725
+ var FONT_SIZE_MENU_MAX_HEIGHT = "min(280px, var(--radix-dropdown-menu-content-available-height))";
15750
15726
  var swatchClass = cn(
15751
15727
  "flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded-[4px] outline-none",
15752
15728
  "hover:bg-[var(--color-bg-neutralLight)] data-[highlighted]:bg-[var(--color-bg-neutralLight)]"
@@ -15761,6 +15737,9 @@ var menuItemClass = cn(
15761
15737
  "text-[color:var(--sys-color-fg-secondary)]",
15762
15738
  "data-[highlighted]:bg-[var(--sys-color-bg-accent)] data-[highlighted]:text-[color:var(--sys-color-fg-inverse)]"
15763
15739
  );
15740
+ var menuItemSelectedClass = "bg-[var(--cmp-listItem-bg-selected)] text-[color:var(--cmp-listItem-text-selected)]";
15741
+ var menuItemDisabledClass = "data-[disabled]:cursor-not-allowed data-[disabled]:bg-transparent data-[disabled]:text-[color:var(--cmp-ghostButton-icon-disabled)]";
15742
+ var menuSeparatorClass = "my-[4px] h-[1px] bg-[var(--sys-color-border-default)]";
15764
15743
  var PaletteItem = ({
15765
15744
  asMenu,
15766
15745
  label,
@@ -15802,6 +15781,111 @@ var ColorPalette = ({
15802
15781
  ),
15803
15782
  /* @__PURE__ */ jsx(PaletteItem, { asMenu, className: cn(menuItemClass, "w-full"), onSelect: onClear, children: clearLabel })
15804
15783
  ] });
15784
+ var TABLE_PICKER_ROWS = 8;
15785
+ var TABLE_PICKER_COLS = 8;
15786
+ var TABLE_PICKER_CELL = 16;
15787
+ var TABLE_PICKER_GAP = 4;
15788
+ var TableSizePicker = ({
15789
+ disabled,
15790
+ onPick
15791
+ }) => {
15792
+ const [size, setSize] = useState({ rows: 1, cols: 1 });
15793
+ const gridRef = useRef(null);
15794
+ useEffect(() => {
15795
+ if (disabled) return void 0;
15796
+ const id = setTimeout(() => gridRef.current?.focus(), 0);
15797
+ return () => clearTimeout(id);
15798
+ }, [disabled]);
15799
+ const clamp4 = (v, max) => Math.min(Math.max(v, 1), max);
15800
+ const move = (dRow, dCol) => setSize((p) => ({
15801
+ rows: clamp4(p.rows + dRow, TABLE_PICKER_ROWS),
15802
+ cols: clamp4(p.cols + dCol, TABLE_PICKER_COLS)
15803
+ }));
15804
+ return /* @__PURE__ */ jsxs("div", { className: "p-[4px]", children: [
15805
+ /* @__PURE__ */ jsx(
15806
+ "div",
15807
+ {
15808
+ ref: gridRef,
15809
+ role: "grid",
15810
+ "aria-label": "\uD45C \uD06C\uAE30",
15811
+ "aria-disabled": disabled || void 0,
15812
+ tabIndex: disabled ? -1 : 0,
15813
+ className: cn("flex flex-col outline-none", disabled && "pointer-events-none opacity-40"),
15814
+ style: { gap: TABLE_PICKER_GAP },
15815
+ onKeyDown: (e) => {
15816
+ const step = {
15817
+ ArrowUp: [-1, 0],
15818
+ ArrowDown: [1, 0],
15819
+ ArrowLeft: [0, -1],
15820
+ ArrowRight: [0, 1]
15821
+ };
15822
+ const d = step[e.key];
15823
+ if (d) {
15824
+ e.preventDefault();
15825
+ e.stopPropagation();
15826
+ move(d[0], d[1]);
15827
+ return;
15828
+ }
15829
+ if (e.key === "Enter" || e.key === " ") {
15830
+ e.preventDefault();
15831
+ e.stopPropagation();
15832
+ onPick(size.rows, size.cols);
15833
+ }
15834
+ },
15835
+ children: Array.from({ length: TABLE_PICKER_ROWS }, (_, r) => /* @__PURE__ */ jsx("div", { role: "row", className: "flex", style: { gap: TABLE_PICKER_GAP }, children: Array.from({ length: TABLE_PICKER_COLS }, (_2, c) => {
15836
+ const on = r < size.rows && c < size.cols;
15837
+ return /* @__PURE__ */ jsx(
15838
+ "button",
15839
+ {
15840
+ type: "button",
15841
+ role: "gridcell",
15842
+ "aria-label": `${r + 1}\uD589 ${c + 1}\uC5F4`,
15843
+ "aria-selected": on,
15844
+ tabIndex: -1,
15845
+ className: "box-border cursor-pointer rounded-[3px] border border-solid p-0 outline-none",
15846
+ style: {
15847
+ width: TABLE_PICKER_CELL,
15848
+ height: TABLE_PICKER_CELL,
15849
+ borderColor: on ? "var(--sys-color-bg-accent)" : "var(--sys-color-border-default)",
15850
+ background: on ? "var(--color-bg-accentFaint)" : "transparent"
15851
+ },
15852
+ onMouseEnter: () => setSize({ rows: r + 1, cols: c + 1 }),
15853
+ onFocus: () => setSize({ rows: r + 1, cols: c + 1 }),
15854
+ onClick: () => onPick(r + 1, c + 1)
15855
+ },
15856
+ c
15857
+ );
15858
+ }) }, r))
15859
+ }
15860
+ ),
15861
+ /* @__PURE__ */ jsxs(
15862
+ "div",
15863
+ {
15864
+ "aria-live": "polite",
15865
+ className: "mt-[6px] text-center text-[12px] leading-[20px] text-[color:var(--sys-color-fg-secondary)]",
15866
+ children: [
15867
+ size.rows,
15868
+ "\uD589 \xD7 ",
15869
+ size.cols,
15870
+ "\uC5F4"
15871
+ ]
15872
+ }
15873
+ )
15874
+ ] });
15875
+ };
15876
+ var TableMenuItem = ({
15877
+ label,
15878
+ disabled,
15879
+ onSelect
15880
+ }) => /* @__PURE__ */ jsx(
15881
+ RDropdown2.Item,
15882
+ {
15883
+ className: cn(menuItemClass, menuItemDisabledClass),
15884
+ disabled,
15885
+ onSelect,
15886
+ children: label
15887
+ }
15888
+ );
15805
15889
  var LinkEditor = ({
15806
15890
  href,
15807
15891
  onHrefChange,
@@ -15829,8 +15913,8 @@ var LinkEditor = ({
15829
15913
  /* @__PURE__ */ jsx(SButton, { size: "sm", label: "\uC801\uC6A9", onClick: onApply }),
15830
15914
  hasLink && /* @__PURE__ */ jsx(SButton, { size: "sm", color: "neutral", outline: true, label: "\uC81C\uAC70", onClick: onRemove })
15831
15915
  ] });
15832
- var TOOLBAR_BAR_CLASS = "flex flex-wrap items-center gap-[2px] border-b border-solid px-[8px] py-[4px]";
15833
- var TOOLBAR_BAR_STYLE = { borderBottomColor: "var(--sys-color-field-border-default)" };
15916
+ var TOOLBAR_BAR_CLASS = "sticky top-0 z-[1] flex flex-wrap items-center gap-[2px] border-b border-solid bg-inherit px-[8px] py-[4px]";
15917
+ var TOOLBAR_BAR_STYLE = { borderBottomColor: "var(--sys-color-border-default)" };
15834
15918
  var BUBBLE_BAR_CLASS = cn(
15835
15919
  "flex max-w-[calc(100vw-32px)] items-center gap-[2px] overflow-x-auto rounded-[var(--cmp-listBox-radius)]",
15836
15920
  "bg-[var(--cmp-listBox-bg)] px-[6px] py-[4px] shadow-normal-sm"
@@ -15842,8 +15926,6 @@ var readEditorState = (e) => ({
15842
15926
  underline: e.isActive("underline"),
15843
15927
  strike: e.isActive("strike"),
15844
15928
  code: e.isActive("code"),
15845
- superscript: e.isActive("superscript"),
15846
- subscript: e.isActive("subscript"),
15847
15929
  alignLeft: e.isActive({ textAlign: "left" }),
15848
15930
  alignCenter: e.isActive({ textAlign: "center" }),
15849
15931
  alignRight: e.isActive({ textAlign: "right" }),
@@ -15854,9 +15936,11 @@ var readEditorState = (e) => ({
15854
15936
  blockquote: e.isActive("blockquote"),
15855
15937
  codeBlock: e.isActive("codeBlock"),
15856
15938
  link: e.isActive("link"),
15939
+ inTable: e.isActive("table"),
15940
+ canMergeCells: e.can().mergeCells(),
15941
+ canSplitCell: e.can().splitCell(),
15857
15942
  linkHref: e.getAttributes("link").href ?? "",
15858
15943
  color: e.getAttributes("textStyle").color ?? "",
15859
- highlight: e.getAttributes("highlight").color ?? "",
15860
15944
  fontSize: e.getAttributes("textStyle").fontSize ?? "",
15861
15945
  canUndo: e.can().undo(),
15862
15946
  canRedo: e.can().redo()
@@ -15868,8 +15952,6 @@ var IDLE_TOOLBAR_STATE = {
15868
15952
  underline: false,
15869
15953
  strike: false,
15870
15954
  code: false,
15871
- superscript: false,
15872
- subscript: false,
15873
15955
  alignLeft: false,
15874
15956
  alignCenter: false,
15875
15957
  alignRight: false,
@@ -15881,8 +15963,10 @@ var IDLE_TOOLBAR_STATE = {
15881
15963
  codeBlock: false,
15882
15964
  link: false,
15883
15965
  linkHref: "",
15966
+ inTable: false,
15967
+ canMergeCells: false,
15968
+ canSplitCell: false,
15884
15969
  color: "",
15885
- highlight: "",
15886
15970
  fontSize: "",
15887
15971
  canUndo: false,
15888
15972
  canRedo: false
@@ -15891,9 +15975,6 @@ function EditorToolbarBar({
15891
15975
  state: state2,
15892
15976
  editor,
15893
15977
  items,
15894
- fontSizes,
15895
- colors,
15896
- highlights,
15897
15978
  onImageUpload,
15898
15979
  disabled,
15899
15980
  variant = "bar"
@@ -15902,6 +15983,7 @@ function EditorToolbarBar({
15902
15983
  const insideModal = useInsideModal();
15903
15984
  const isMobile = useIsMobile();
15904
15985
  const [linkOpen, setLinkOpen] = useState(false);
15986
+ const [tableOpen, setTableOpen] = useState(false);
15905
15987
  const [linkHref, setLinkHref] = useState("");
15906
15988
  const [uploading, setUploading] = useState(false);
15907
15989
  const [mobileView, setMobileView] = useState("main");
@@ -15916,9 +15998,8 @@ function EditorToolbarBar({
15916
15998
  const chain = () => editor?.chain()?.focus();
15917
15999
  const off = disabled;
15918
16000
  const currentFontSize = Number.parseInt(state2.fontSize, 10);
15919
- const activeFontSize = Number.isNaN(currentFontSize) ? SEDITOR_DEFAULT_FONT_SIZE : currentFontSize;
16001
+ const activeFontSize = Number.isNaN(currentFontSize) ? null : currentFontSize;
15920
16002
  const activeColor = resolveColor(state2.color) ?? "currentColor";
15921
- const activeHighlight = resolveColor(state2.highlight) ?? "currentColor";
15922
16003
  const pickImage = async (e) => {
15923
16004
  const file = e.target.files?.[0];
15924
16005
  e.target.value = "";
@@ -15935,8 +16016,6 @@ function EditorToolbarBar({
15935
16016
  };
15936
16017
  const applyColor = (color) => chain()?.setColor(resolveColor(color) ?? "inherit").run();
15937
16018
  const clearColor = () => chain()?.unsetColor().run();
15938
- const applyHighlight = (color) => chain()?.setHighlight({ color: resolveColor(color) ?? "transparent" }).run();
15939
- const clearHighlight = () => chain()?.unsetHighlight().run();
15940
16019
  const closeLinkEditor = () => {
15941
16020
  setLinkOpen(false);
15942
16021
  setMobileView("main");
@@ -16003,18 +16082,41 @@ function EditorToolbarBar({
16003
16082
  case "fontSize":
16004
16083
  return /* @__PURE__ */ jsxs(RDropdown2.Root, { modal: !insideModal, children: [
16005
16084
  /* @__PURE__ */ jsx(RDropdown2.Trigger, { asChild: true, disabled: off, children: /* @__PURE__ */ jsxs(ToolbarButton, { label: "\uAE00\uC790 \uD06C\uAE30", disabled: off, className: "px-[6px]", children: [
16006
- /* @__PURE__ */ jsx("span", { className: "text-[12px] leading-[20px]", children: activeFontSize }),
16085
+ /* @__PURE__ */ jsx("span", { className: "text-[12px] leading-[20px]", children: activeFontSize ?? FONT_SIZE_DEFAULT_LABEL }),
16007
16086
  /* @__PURE__ */ jsx(SIcon, { name: "caretDown", size: 12 })
16008
16087
  ] }) }),
16009
- /* @__PURE__ */ jsx(RDropdown2.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(RDropdown2.Content, { sideOffset: 4, align: "start", className: menuClass, children: fontSizes.map((size) => /* @__PURE__ */ jsx(
16010
- RDropdown2.Item,
16088
+ /* @__PURE__ */ jsx(RDropdown2.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxs(
16089
+ RDropdown2.Content,
16011
16090
  {
16012
- className: menuItemClass,
16013
- onSelect: () => size === SEDITOR_DEFAULT_FONT_SIZE ? chain()?.unsetFontSize().run() : chain()?.setFontSize(`${size}px`).run(),
16014
- children: /* @__PURE__ */ jsx("span", { style: { fontSize: size, lineHeight: "20px" }, children: size })
16015
- },
16016
- size
16017
- )) }) })
16091
+ sideOffset: 4,
16092
+ align: "start",
16093
+ className: cn(scrollMenuClass, "min-w-[72px]"),
16094
+ style: { maxHeight: FONT_SIZE_MENU_MAX_HEIGHT },
16095
+ children: [
16096
+ /* @__PURE__ */ jsx(
16097
+ RDropdown2.Item,
16098
+ {
16099
+ className: cn(menuItemClass, activeFontSize === null && menuItemSelectedClass),
16100
+ title: `${FONT_SIZE_DEFAULT_LABEL} (\uBCF8\uBB38 ${SEDITOR_DEFAULT_FONT_SIZE}px)`,
16101
+ onSelect: () => chain()?.unsetFontSize().run(),
16102
+ children: FONT_SIZE_DEFAULT_LABEL
16103
+ }
16104
+ ),
16105
+ SEDITOR_FONT_SIZES.map((size) => /* @__PURE__ */ jsx(
16106
+ RDropdown2.Item,
16107
+ {
16108
+ ref: activeFontSize === size ? (el) => {
16109
+ el?.scrollIntoView({ block: "nearest" });
16110
+ } : void 0,
16111
+ className: cn(menuItemClass, activeFontSize === size && menuItemSelectedClass),
16112
+ onSelect: () => chain()?.setFontSize(`${size}px`).run(),
16113
+ children: size
16114
+ },
16115
+ size
16116
+ ))
16117
+ ]
16118
+ }
16119
+ ) })
16018
16120
  ] }, item);
16019
16121
  case "bold":
16020
16122
  return /* @__PURE__ */ jsx(
@@ -16099,7 +16201,7 @@ function EditorToolbarBar({
16099
16201
  ColorPalette,
16100
16202
  {
16101
16203
  asMenu: true,
16102
- colors,
16204
+ colors: SEDITOR_DEFAULT_COLORS,
16103
16205
  columns: 4,
16104
16206
  clearLabel: "\uC0C9 \uC9C0\uC6B0\uAE30",
16105
16207
  onPick: applyColor,
@@ -16107,58 +16209,6 @@ function EditorToolbarBar({
16107
16209
  }
16108
16210
  ) }) })
16109
16211
  ] }, item);
16110
- case "highlight":
16111
- if (mobile)
16112
- return /* @__PURE__ */ jsx(
16113
- ToolbarButton,
16114
- {
16115
- label: "\uD615\uAD11\uD39C",
16116
- disabled: off,
16117
- onClick: () => setMobileView("highlight"),
16118
- children: /* @__PURE__ */ jsx(ColorIndicator, { color: off ? "currentColor" : activeHighlight, children: /* @__PURE__ */ jsx(IconHighlight, { size: ICON_SIZE }) })
16119
- },
16120
- item
16121
- );
16122
- return /* @__PURE__ */ jsxs(RDropdown2.Root, { modal: !insideModal, children: [
16123
- /* @__PURE__ */ jsx(RDropdown2.Trigger, { asChild: true, disabled: off, children: /* @__PURE__ */ jsx(ToolbarButton, { label: "\uD615\uAD11\uD39C", disabled: off, children: /* @__PURE__ */ jsx(ColorIndicator, { color: off ? "currentColor" : activeHighlight, children: /* @__PURE__ */ jsx(IconHighlight, { size: ICON_SIZE }) }) }) }),
16124
- /* @__PURE__ */ jsx(RDropdown2.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(RDropdown2.Content, { sideOffset: 4, align: "start", className: menuClass, children: /* @__PURE__ */ jsx(
16125
- ColorPalette,
16126
- {
16127
- asMenu: true,
16128
- colors: highlights,
16129
- columns: 3,
16130
- clearLabel: "\uD615\uAD11\uD39C \uC9C0\uC6B0\uAE30",
16131
- onPick: applyHighlight,
16132
- onClear: clearHighlight
16133
- }
16134
- ) }) })
16135
- ] }, item);
16136
- case "superscript":
16137
- return /* @__PURE__ */ jsx(
16138
- ToolbarButton,
16139
- {
16140
- label: "\uC704 \uCCA8\uC790",
16141
- active: state2.superscript,
16142
- "aria-pressed": state2.superscript,
16143
- disabled: off,
16144
- onClick: () => chain()?.toggleSuperscript().run(),
16145
- children: /* @__PURE__ */ jsx(IconSuperscript, { size: ICON_SIZE })
16146
- },
16147
- item
16148
- );
16149
- case "subscript":
16150
- return /* @__PURE__ */ jsx(
16151
- ToolbarButton,
16152
- {
16153
- label: "\uC544\uB798 \uCCA8\uC790",
16154
- active: state2.subscript,
16155
- "aria-pressed": state2.subscript,
16156
- disabled: off,
16157
- onClick: () => chain()?.toggleSubscript().run(),
16158
- children: /* @__PURE__ */ jsx(IconSubscript, { size: ICON_SIZE })
16159
- },
16160
- item
16161
- );
16162
16212
  case "alignLeft":
16163
16213
  return /* @__PURE__ */ jsx(
16164
16214
  ToolbarButton,
@@ -16384,6 +16434,127 @@ function EditorToolbarBar({
16384
16434
  },
16385
16435
  item
16386
16436
  );
16437
+ case "table":
16438
+ return /* @__PURE__ */ jsxs(
16439
+ RDropdown2.Root,
16440
+ {
16441
+ open: tableOpen,
16442
+ onOpenChange: setTableOpen,
16443
+ modal: !insideModal,
16444
+ children: [
16445
+ /* @__PURE__ */ jsx(RDropdown2.Trigger, { asChild: true, disabled: off, children: /* @__PURE__ */ jsxs(ToolbarButton, { label: "\uD45C", active: state2.inTable, disabled: off, className: "px-[6px]", children: [
16446
+ /* @__PURE__ */ jsx(IconTable, { size: ICON_SIZE }),
16447
+ /* @__PURE__ */ jsx(SIcon, { name: "caretDown", size: CARET_SIZE })
16448
+ ] }) }),
16449
+ /* @__PURE__ */ jsx(RDropdown2.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxs(RDropdown2.Content, { sideOffset: 4, align: "start", className: menuClass, children: [
16450
+ !state2.inTable && /* @__PURE__ */ jsxs(Fragment, { children: [
16451
+ /* @__PURE__ */ jsx(
16452
+ TableSizePicker,
16453
+ {
16454
+ disabled: state2.inTable,
16455
+ onPick: (rows, cols) => {
16456
+ chain()?.insertTable({ rows, cols, withHeaderRow: true }).run();
16457
+ setTableOpen(false);
16458
+ }
16459
+ }
16460
+ ),
16461
+ /* @__PURE__ */ jsx(RDropdown2.Separator, { className: menuSeparatorClass })
16462
+ ] }),
16463
+ /* @__PURE__ */ jsx(
16464
+ TableMenuItem,
16465
+ {
16466
+ label: "\uC704\uC5D0 \uD589 \uCD94\uAC00",
16467
+ disabled: !state2.inTable,
16468
+ onSelect: () => chain()?.addRowBefore().run()
16469
+ }
16470
+ ),
16471
+ /* @__PURE__ */ jsx(
16472
+ TableMenuItem,
16473
+ {
16474
+ label: "\uC544\uB798\uC5D0 \uD589 \uCD94\uAC00",
16475
+ disabled: !state2.inTable,
16476
+ onSelect: () => chain()?.addRowAfter().run()
16477
+ }
16478
+ ),
16479
+ /* @__PURE__ */ jsx(
16480
+ TableMenuItem,
16481
+ {
16482
+ label: "\uC67C\uCABD\uC5D0 \uC5F4 \uCD94\uAC00",
16483
+ disabled: !state2.inTable,
16484
+ onSelect: () => chain()?.addColumnBefore().run()
16485
+ }
16486
+ ),
16487
+ /* @__PURE__ */ jsx(
16488
+ TableMenuItem,
16489
+ {
16490
+ label: "\uC624\uB978\uCABD\uC5D0 \uC5F4 \uCD94\uAC00",
16491
+ disabled: !state2.inTable,
16492
+ onSelect: () => chain()?.addColumnAfter().run()
16493
+ }
16494
+ ),
16495
+ /* @__PURE__ */ jsx(RDropdown2.Separator, { className: menuSeparatorClass }),
16496
+ /* @__PURE__ */ jsx(
16497
+ TableMenuItem,
16498
+ {
16499
+ label: "\uC140 \uBCD1\uD569",
16500
+ disabled: !state2.canMergeCells,
16501
+ onSelect: () => chain()?.mergeCells().run()
16502
+ }
16503
+ ),
16504
+ /* @__PURE__ */ jsx(
16505
+ TableMenuItem,
16506
+ {
16507
+ label: "\uBCD1\uD569 \uD574\uC81C",
16508
+ disabled: !state2.canSplitCell,
16509
+ onSelect: () => chain()?.splitCell().run()
16510
+ }
16511
+ ),
16512
+ /* @__PURE__ */ jsx(
16513
+ TableMenuItem,
16514
+ {
16515
+ label: "\uD5E4\uB354 \uD589 \uD1A0\uAE00",
16516
+ disabled: !state2.inTable,
16517
+ onSelect: () => chain()?.toggleHeaderRow().run()
16518
+ }
16519
+ ),
16520
+ /* @__PURE__ */ jsx(
16521
+ TableMenuItem,
16522
+ {
16523
+ label: "\uD5E4\uB354 \uC5F4 \uD1A0\uAE00",
16524
+ disabled: !state2.inTable,
16525
+ onSelect: () => chain()?.toggleHeaderColumn().run()
16526
+ }
16527
+ ),
16528
+ /* @__PURE__ */ jsx(RDropdown2.Separator, { className: menuSeparatorClass }),
16529
+ /* @__PURE__ */ jsx(
16530
+ TableMenuItem,
16531
+ {
16532
+ label: "\uD589 \uC0AD\uC81C",
16533
+ disabled: !state2.inTable,
16534
+ onSelect: () => chain()?.deleteRow().run()
16535
+ }
16536
+ ),
16537
+ /* @__PURE__ */ jsx(
16538
+ TableMenuItem,
16539
+ {
16540
+ label: "\uC5F4 \uC0AD\uC81C",
16541
+ disabled: !state2.inTable,
16542
+ onSelect: () => chain()?.deleteColumn().run()
16543
+ }
16544
+ ),
16545
+ /* @__PURE__ */ jsx(
16546
+ TableMenuItem,
16547
+ {
16548
+ label: "\uD45C \uC0AD\uC81C",
16549
+ disabled: !state2.inTable,
16550
+ onSelect: () => chain()?.deleteTable().run()
16551
+ }
16552
+ )
16553
+ ] }) })
16554
+ ]
16555
+ },
16556
+ item
16557
+ );
16387
16558
  case "undo":
16388
16559
  return /* @__PURE__ */ jsx(
16389
16560
  ToolbarButton,
@@ -16420,7 +16591,6 @@ function EditorToolbarBar({
16420
16591
  if (mobileView !== "main") {
16421
16592
  const editing = {
16422
16593
  color: { icon: /* @__PURE__ */ jsx(IconTextColor, { size: ICON_SIZE }), label: "\uAE00\uC790\uC0C9" },
16423
- highlight: { icon: /* @__PURE__ */ jsx(IconHighlight, { size: ICON_SIZE }), label: "\uD615\uAD11\uD39C" },
16424
16594
  link: { icon: /* @__PURE__ */ jsx(IconLink, { size: ICON_SIZE }), label: "\uB9C1\uD06C" }
16425
16595
  }[mobileView];
16426
16596
  return /* @__PURE__ */ jsxs("div", { ...shell, children: [
@@ -16436,7 +16606,7 @@ function EditorToolbarBar({
16436
16606
  ]
16437
16607
  }
16438
16608
  ) }),
16439
- /* @__PURE__ */ jsx(Separator, {}),
16609
+ /* @__PURE__ */ jsx(Separator2, {}),
16440
16610
  mobileView === "link" ? /* @__PURE__ */ jsx(
16441
16611
  LinkEditor,
16442
16612
  {
@@ -16449,18 +16619,18 @@ function EditorToolbarBar({
16449
16619
  ) : /* @__PURE__ */ jsx(
16450
16620
  ColorPalette,
16451
16621
  {
16452
- colors: mobileView === "color" ? colors : highlights,
16453
- columns: mobileView === "color" ? 4 : 3,
16454
- clearLabel: mobileView === "color" ? "\uC0C9 \uC9C0\uC6B0\uAE30" : "\uD615\uAD11\uD39C \uC9C0\uC6B0\uAE30",
16455
- onPick: mobileView === "color" ? applyColor : applyHighlight,
16456
- onClear: mobileView === "color" ? clearColor : clearHighlight
16622
+ colors: SEDITOR_DEFAULT_COLORS,
16623
+ columns: 4,
16624
+ clearLabel: "\uC0C9 \uC9C0\uC6B0\uAE30",
16625
+ onPick: applyColor,
16626
+ onClear: clearColor
16457
16627
  }
16458
16628
  )
16459
16629
  ] });
16460
16630
  }
16461
16631
  return /* @__PURE__ */ jsxs("div", { ...shell, children: [
16462
16632
  groups.map((group, index) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
16463
- index > 0 && /* @__PURE__ */ jsx(Separator, {}),
16633
+ index > 0 && /* @__PURE__ */ jsx(Separator2, {}),
16464
16634
  /* @__PURE__ */ jsx(
16465
16635
  "div",
16466
16636
  {
@@ -16533,16 +16703,12 @@ var EditorBody = /* @__PURE__ */ forwardRef(function EditorBody2({
16533
16703
  onFocusChange,
16534
16704
  onReady,
16535
16705
  placeholder,
16536
- typography,
16537
16706
  editable,
16538
16707
  disabled,
16539
16708
  minHeight,
16540
16709
  maxHeight,
16541
16710
  toolbar,
16542
16711
  bubbleMenu,
16543
- fontSizes,
16544
- colors,
16545
- highlights,
16546
16712
  onImageUpload,
16547
16713
  editorClass,
16548
16714
  editorStyle
@@ -16551,12 +16717,8 @@ var EditorBody = /* @__PURE__ */ forwardRef(function EditorBody2({
16551
16717
  placeholderRef.current = placeholder;
16552
16718
  const handlers = useRef({ onInput, onFocusChange });
16553
16719
  handlers.current = { onInput, onFocusChange };
16554
- const typographyRef = useRef(typography);
16555
16720
  const extensions = useMemo(
16556
- () => api.createExtensions({
16557
- getPlaceholder: () => placeholderRef.current,
16558
- typography: typographyRef.current
16559
- }),
16721
+ () => api.createExtensions({ getPlaceholder: () => placeholderRef.current }),
16560
16722
  [api]
16561
16723
  );
16562
16724
  const editor = api.useEditor({
@@ -16604,28 +16766,22 @@ var EditorBody = /* @__PURE__ */ forwardRef(function EditorBody2({
16604
16766
  [editor, htmlRef]
16605
16767
  );
16606
16768
  return /* @__PURE__ */ jsxs(Fragment, { children: [
16607
- toolbar !== false && toolbar.length > 0 && /* @__PURE__ */ jsx(
16769
+ toolbar.length > 0 && /* @__PURE__ */ jsx(
16608
16770
  EditorToolbar,
16609
16771
  {
16610
16772
  api,
16611
16773
  editor,
16612
16774
  items: toolbar,
16613
- fontSizes,
16614
- colors,
16615
- highlights,
16616
16775
  onImageUpload,
16617
16776
  disabled: !editable
16618
16777
  }
16619
16778
  ),
16620
- bubbleMenu !== false && bubbleMenu.length > 0 && editable && /* @__PURE__ */ jsx(
16779
+ bubbleMenu.length > 0 && editable && /* @__PURE__ */ jsx(
16621
16780
  EditorBubbleMenu,
16622
16781
  {
16623
16782
  api,
16624
16783
  editor,
16625
16784
  items: bubbleMenu,
16626
- fontSizes,
16627
- colors,
16628
- highlights,
16629
16785
  onImageUpload,
16630
16786
  disabled: false
16631
16787
  }
@@ -16654,10 +16810,8 @@ var importTiptap = async () => {
16654
16810
  textAlign,
16655
16811
  textStyle,
16656
16812
  list,
16657
- highlight,
16658
16813
  image,
16659
- superscript,
16660
- subscript,
16814
+ table,
16661
16815
  typography,
16662
16816
  extensions
16663
16817
  ] = await Promise.all([
@@ -16667,17 +16821,12 @@ var importTiptap = async () => {
16667
16821
  import('@tiptap/extension-text-align'),
16668
16822
  import('@tiptap/extension-text-style'),
16669
16823
  import('@tiptap/extension-list'),
16670
- import('@tiptap/extension-highlight'),
16671
16824
  import('@tiptap/extension-image'),
16672
- import('@tiptap/extension-superscript'),
16673
- import('@tiptap/extension-subscript'),
16825
+ import('@tiptap/extension-table'),
16674
16826
  import('@tiptap/extension-typography'),
16675
16827
  import('@tiptap/extensions')
16676
16828
  ]);
16677
- const createExtensions = ({
16678
- getPlaceholder,
16679
- typography: withTypography
16680
- }) => [
16829
+ const createExtensions = ({ getPlaceholder }) => [
16681
16830
  starterKit.default.configure({
16682
16831
  heading: { levels: [...SEDITOR_HEADING_LEVELS] },
16683
16832
  link: {
@@ -16694,14 +16843,24 @@ var importTiptap = async () => {
16694
16843
  textAlign.default.configure({ types: ["heading", "paragraph"] }),
16695
16844
  list.TaskList.configure({ HTMLAttributes: { class: TASK_LIST_CLASS } }),
16696
16845
  list.TaskItem.configure({ nested: true, HTMLAttributes: { class: TASK_ITEM_CLASS } }),
16697
- highlight.default.configure({ multicolor: true }),
16698
16846
  // base64 를 막는다 — 본문 HTML 에 수 MB 짜리 data URI 가 박히면 그대로 DB·API 로 실려 간다.
16699
16847
  // 이미지는 onImageUpload 가 돌려준 URL 로만 들어온다.
16700
16848
  image.default.configure({ allowBase64: false, HTMLAttributes: { class: IMAGE_CLASS } }),
16701
- superscript.default,
16702
- subscript.default,
16849
+ /**
16850
+ * 표 — 열 너비는 **고정(균등)** 이다.
16851
+ *
16852
+ * `resizable` 을 켜면 열 경계를 끌어 폭을 정할 수 있지만 그 값이 저장 HTML 에
16853
+ * `colwidth` 로 px 단위로 박힌다. 작성한 화면보다 좁은 곳에서 다시 보여 줄 때 표가
16854
+ * 넘치고, 화면 폭이 제각각인 소비 앱에서는 되돌릴 방법이 없다. 대신 본문 스타일이
16855
+ * `table-layout: fixed` 로 열을 균등하게 나눠 어떤 폭에서도 표가 상자 안에 남는다.
16856
+ */
16857
+ table.Table.configure({ resizable: false, HTMLAttributes: { class: TABLE_CLASS } }),
16858
+ table.TableRow.configure({ HTMLAttributes: { class: TABLE_ROW_CLASS } }),
16859
+ table.TableHeader.configure({ HTMLAttributes: { class: TABLE_HEADER_CLASS } }),
16860
+ table.TableCell.configure({ HTMLAttributes: { class: TABLE_CELL_CLASS } }),
16703
16861
  extensions.Placeholder.configure({ placeholder: () => getPlaceholder() }),
16704
- ...withTypography ? [typography.default] : []
16862
+ // 따옴표·하이픈·화살표 자동 치환 (`"` → `“”`, `--` → `—`, `->` → `→`)
16863
+ typography.default
16705
16864
  ];
16706
16865
  return {
16707
16866
  useEditor: react.useEditor,
@@ -16754,13 +16913,8 @@ var SEditor = /* @__PURE__ */ forwardRef(function SEditor2({
16754
16913
  placeholder = "\uB0B4\uC6A9\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694.",
16755
16914
  minHeight = 200,
16756
16915
  maxHeight,
16757
- toolbar = SEDITOR_DEFAULT_TOOLBAR,
16758
- bubbleMenu = SEDITOR_DEFAULT_BUBBLE_MENU,
16759
- fontSizes = [...SEDITOR_FONT_SIZES],
16760
- colors = SEDITOR_DEFAULT_COLORS,
16761
- highlights = SEDITOR_DEFAULT_HIGHLIGHTS,
16916
+ simple = false,
16762
16917
  onImageUpload,
16763
- typography = false,
16764
16918
  rules,
16765
16919
  status,
16766
16920
  focused,
@@ -16852,7 +17006,8 @@ var SEditor = /* @__PURE__ */ forwardRef(function SEditor2({
16852
17006
  const resolvedError = error || ruleError !== "";
16853
17007
  const resolvedErrorMessage = ruleError !== "" ? ruleError : errorMessage;
16854
17008
  const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
16855
- const hasToolbar = toolbar !== false && toolbar.length > 0;
17009
+ const resolvedToolbar = simple ? SEDITOR_SIMPLE_TOOLBAR : SEDITOR_DEFAULT_TOOLBAR;
17010
+ const resolvedBubbleMenu = simple ? SEDITOR_SIMPLE_BUBBLE_MENU : SEDITOR_DEFAULT_BUBBLE_MENU;
16856
17011
  return /* @__PURE__ */ jsx(
16857
17012
  SField,
16858
17013
  {
@@ -16877,19 +17032,15 @@ var SEditor = /* @__PURE__ */ forwardRef(function SEditor2({
16877
17032
  multiline: true,
16878
17033
  className,
16879
17034
  style,
16880
- children: /* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1 flex-col", children: api === null ? (
17035
+ children: /* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1 flex-col bg-inherit", children: api === null ? (
16881
17036
  // 엔진을 불러오는 동안의 자리 — 툴바 높이와 본문 상자를 그대로 잡아 둔다
16882
17037
  /* @__PURE__ */ jsxs(Fragment, { children: [
16883
- hasToolbar && // 진짜 툴바를 잠긴 채로 그린다 — 버튼 개수·줄바꿈이 같아야 엔진이 붙어도 안 밀린다
16884
17038
  /* @__PURE__ */ jsx(
16885
17039
  EditorToolbarBar,
16886
17040
  {
16887
17041
  state: IDLE_TOOLBAR_STATE,
16888
17042
  editor: null,
16889
- items: toolbar,
16890
- fontSizes,
16891
- colors,
16892
- highlights,
17043
+ items: resolvedToolbar,
16893
17044
  onImageUpload,
16894
17045
  disabled: true
16895
17046
  }
@@ -16916,16 +17067,12 @@ var SEditor = /* @__PURE__ */ forwardRef(function SEditor2({
16916
17067
  onFocusChange: handleFocusChange,
16917
17068
  onReady: handleReady,
16918
17069
  placeholder,
16919
- typography,
16920
17070
  editable,
16921
17071
  disabled,
16922
17072
  minHeight,
16923
17073
  maxHeight,
16924
- toolbar,
16925
- bubbleMenu,
16926
- fontSizes,
16927
- colors,
16928
- highlights,
17074
+ toolbar: resolvedToolbar,
17075
+ bubbleMenu: resolvedBubbleMenu,
16929
17076
  onImageUpload,
16930
17077
  editorClass,
16931
17078
  editorStyle
@@ -17007,9 +17154,9 @@ var todayIso = () => {
17007
17154
  const pad = (n) => String(n).padStart(2, "0");
17008
17155
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
17009
17156
  };
17010
- var isInlineDateField = (field) => field.type === "date" && field.radioButton === true && (field.presets?.length ?? 0) > 0;
17157
+ var isInlineDateField = (field) => field.type === "datepicker-range" && field.radioButton === true && (field.presets?.length ?? 0) > 0;
17011
17158
  var getFieldPresets = (field) => {
17012
- if (field.type === "period") return field.presets ?? DEFAULT_PERIOD_PRESETS;
17159
+ if (field.type === "datepicker-statistics") return field.presets ?? DEFAULT_PERIOD_PRESETS;
17013
17160
  return field.presets ?? [];
17014
17161
  };
17015
17162
  var getDefaultPeriodInputValue = (unit) => {
@@ -17026,12 +17173,16 @@ var createPeriodValue = (unit) => ({
17026
17173
  value: getDefaultPeriodInputValue(unit)
17027
17174
  });
17028
17175
  var resolveFieldDefault = (field) => {
17029
- if (field.defaultValue !== void 0) return field.defaultValue;
17030
- if (field.type === "date")
17031
- return isInlineDateField(field) || field.required ? todayIso() : void 0;
17176
+ if (field.defaultValue !== void 0 && isFixedField(field)) return field.defaultValue;
17177
+ if (field.type === "datepicker-range") {
17178
+ if (!isInlineDateField(field) && !field.required) return void 0;
17179
+ const today = todayIso();
17180
+ return [today, today];
17181
+ }
17032
17182
  if (!field.required) return void 0;
17033
- if (field.type === "single") return field.options?.[0]?.value;
17034
- if (field.type === "period") {
17183
+ if (field.type === "datepicker-day") return todayIso();
17184
+ if (field.type === "select") return field.options?.[0]?.value;
17185
+ if (field.type === "datepicker-statistics") {
17035
17186
  const unit = getFieldPresets(field).find((preset) => !preset.custom)?.value;
17036
17187
  return unit ? createPeriodValue(unit) : void 0;
17037
17188
  }
@@ -17053,9 +17204,10 @@ var valuesMapEqual = (a, b) => {
17053
17204
  }
17054
17205
  return true;
17055
17206
  };
17207
+ var fieldValuesEqual = (field, a, b) => field.type === "datepicker-range" ? sameDateValue(a, b) : valuesEqual(a, b);
17056
17208
  var isAtDefaultValue = (field, value) => {
17057
17209
  const def = resolveFieldDefault(field);
17058
- return def !== void 0 && valuesEqual(value, def);
17210
+ return def !== void 0 && fieldValuesEqual(field, value, def);
17059
17211
  };
17060
17212
  var resetTargetValue = (field) => {
17061
17213
  const def = resolveFieldDefault(field);
@@ -17064,7 +17216,7 @@ var resetTargetValue = (field) => {
17064
17216
  var isAtResetTarget = (field, value) => {
17065
17217
  const target = resetTargetValue(field);
17066
17218
  if (isEmptyValue(value) && isEmptyValue(target)) return true;
17067
- return valuesEqual(value, target);
17219
+ return fieldValuesEqual(field, value, target);
17068
17220
  };
17069
17221
  var isInlineField = (field) => isInlineDateField(field) || field.type === "custom";
17070
17222
  var isFixedField = (field) => field.fixed === true || field.required === true;
@@ -17092,17 +17244,19 @@ var defaultGroupTooltipMessage = (rule, fields) => {
17092
17244
  const label = fields.find((f) => f.key === rule.key)?.label ?? "\uD56D\uBAA9";
17093
17245
  return `${label}${koreanParticle(label, "\uC744", "\uB97C")} \uC120\uD0DD\uD574 \uC8FC\uC138\uC694.`;
17094
17246
  };
17247
+ var toDateRange = (value) => Array.isArray(value) ? [value[0], value[1]] : [value, value];
17248
+ var sameDateValue = (a, b) => {
17249
+ const [aStart, aEnd] = toDateRange(a);
17250
+ const [bStart, bEnd] = toDateRange(b);
17251
+ return aStart === bStart && aEnd === bEnd;
17252
+ };
17095
17253
  var matchPresetId = (presets, value) => {
17096
17254
  if (isEmptyValue(value)) return null;
17097
17255
  if (isPeriodValue(value)) return value.unit;
17098
17256
  for (const preset of presets) {
17099
17257
  if (preset.custom) continue;
17100
17258
  const resolved = preset.resolve ? preset.resolve() : preset.value;
17101
- if (Array.isArray(resolved) && Array.isArray(value)) {
17102
- if (resolved[0] === value[0] && resolved[1] === value[1]) return preset.value;
17103
- } else if (!Array.isArray(resolved) && !Array.isArray(value) && resolved === value) {
17104
- return preset.value;
17105
- }
17259
+ if (sameDateValue(resolved, value)) return preset.value;
17106
17260
  }
17107
17261
  return presets.find((preset) => preset.custom)?.value ?? null;
17108
17262
  };
@@ -17113,7 +17267,7 @@ var formatValueList = (labels) => {
17113
17267
  };
17114
17268
  var displayValue = (field, value) => {
17115
17269
  if (isEmptyValue(value)) return "";
17116
- if (field.type === "multi") {
17270
+ if (field.type === "select-multi") {
17117
17271
  const values = toArrayValue(value);
17118
17272
  const selectableValues = (field.options ?? []).filter((option) => !option.disabled).map((option) => option.value);
17119
17273
  if (selectableValues.length > 0 && selectableValues.every((selectableValue) => values.includes(selectableValue))) {
@@ -17121,10 +17275,12 @@ var displayValue = (field, value) => {
17121
17275
  }
17122
17276
  return formatValueList(values.map((v) => optionLabel(field, v)));
17123
17277
  }
17124
- if (field.type === "single") return optionLabel(field, value);
17125
- if (field.type === "date")
17126
- return Array.isArray(value) ? `${value[0]} ~ ${value[1]}` : String(value);
17127
- if (field.type === "period") {
17278
+ if (field.type === "select") return optionLabel(field, value);
17279
+ if (field.type === "datepicker-day" || field.type === "datepicker-range") {
17280
+ if (!Array.isArray(value)) return String(value);
17281
+ return value[0] === value[1] ? String(value[0]) : `${value[0]} ~ ${value[1]}`;
17282
+ }
17283
+ if (field.type === "datepicker-statistics") {
17128
17284
  if (!isPeriodValue(value)) {
17129
17285
  const preset2 = getFieldPresets(field).find((p) => p.value === value);
17130
17286
  return preset2?.label ?? String(value);
@@ -17141,7 +17297,7 @@ var displayValue = (field, value) => {
17141
17297
  };
17142
17298
  var chipDisplayValue = (field, value) => {
17143
17299
  const text = displayValue(field, value);
17144
- if (field.type !== "date" || isEmptyValue(value)) return text;
17300
+ if (field.type !== "datepicker-range" || isEmptyValue(value)) return text;
17145
17301
  const presets = getFieldPresets(field);
17146
17302
  if (presets.length === 0) return text;
17147
17303
  const preset = presets.find((p) => p.value === matchPresetId(presets, value));
@@ -17232,6 +17388,14 @@ var SChipFilter = /* @__PURE__ */ forwardRef(function SChipFilter2({
17232
17388
  });
17233
17389
  if (changed) onValueChange?.({ ...values, ...patch });
17234
17390
  }, [fields, values, onValueChange]);
17391
+ if (typeof console !== "undefined") {
17392
+ const misused = fields.filter((f) => f.defaultValue !== void 0 && !isFixedField(f));
17393
+ if (misused.length > 0) {
17394
+ console.warn(
17395
+ `[SChipFilter] defaultValue \uB294 fixed\xB7required \uD544\uD130\uC5D0\uC11C\uB9CC \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uBB34\uC2DC\uD569\uB2C8\uB2E4. (${misused.map((f) => f.key).join(", ")})`
17396
+ );
17397
+ }
17398
+ }
17235
17399
  const fixedKeys = fields.filter(isFixedField).map((field) => field.key);
17236
17400
  const resolvedActiveKeys = Array.from(
17237
17401
  /* @__PURE__ */ new Set([...activeKeys ?? internalActiveKeys, ...fixedKeys])
@@ -17253,7 +17417,7 @@ var SChipFilter = /* @__PURE__ */ forwardRef(function SChipFilter2({
17253
17417
  if (currentOpenField?.type === "keyword") {
17254
17418
  return { width: CHIPFILTER_LISTBOX_WIDTH };
17255
17419
  }
17256
- if ((currentOpenField?.type === "date" || currentOpenField?.type === "period") && getFieldPresets(currentOpenField).length > 0) {
17420
+ if ((currentOpenField?.type === "datepicker-range" || currentOpenField?.type === "datepicker-statistics") && getFieldPresets(currentOpenField).length > 0) {
17257
17421
  return { width: CHIPFILTER_DATE_PRESET_LISTBOX_WIDTH };
17258
17422
  }
17259
17423
  return { width: CHIPFILTER_LISTBOX_WIDTH };
@@ -17389,7 +17553,7 @@ var SChipFilter = /* @__PURE__ */ forwardRef(function SChipFilter2({
17389
17553
  }
17390
17554
  clearValue(field.key);
17391
17555
  };
17392
- const node = field.type === "date" && isInlineDateField(field) ? /* @__PURE__ */ jsx(
17556
+ const node = field.type === "datepicker-range" && isInlineDateField(field) ? /* @__PURE__ */ jsx(
17393
17557
  InlineDatePresetFilter,
17394
17558
  {
17395
17559
  field,
@@ -17700,8 +17864,8 @@ function EditorPanel({
17700
17864
  onValueCommit,
17701
17865
  onClose
17702
17866
  }) {
17703
- const wrapsInPaddedTop = field.type === "date" || field.type === "period";
17704
- const isMulti = field.type === "multi";
17867
+ const wrapsInPaddedTop = field.type === "datepicker-day" || field.type === "datepicker-range" || field.type === "datepicker-statistics";
17868
+ const isMulti = field.type === "select-multi";
17705
17869
  const selectableValues = isMulti ? (field.options ?? []).filter((option) => !option.disabled).map((option) => option.value) : [];
17706
17870
  const selectedValues = isMulti ? toArrayValue(value) : [];
17707
17871
  const allSelected = isMulti && selectableValues.length > 0 && selectableValues.every((v) => selectedValues.includes(v));
@@ -17782,7 +17946,7 @@ function FilterEditor({
17782
17946
  onValueChange,
17783
17947
  onValueCommit
17784
17948
  }) {
17785
- if (field.type === "period") {
17949
+ if (field.type === "datepicker-statistics") {
17786
17950
  return /* @__PURE__ */ jsx(
17787
17951
  PeriodPresetEditor,
17788
17952
  {
@@ -17793,7 +17957,21 @@ function FilterEditor({
17793
17957
  }
17794
17958
  );
17795
17959
  }
17796
- if (field.type === "date") {
17960
+ if (field.type === "datepicker-day") {
17961
+ return /* @__PURE__ */ jsx(
17962
+ SDatePicker,
17963
+ {
17964
+ value: typeof value === "string" ? value : null,
17965
+ onValueChange,
17966
+ selectable: field.selectable,
17967
+ disabled,
17968
+ placeholder: field.placeholder,
17969
+ width: "100%",
17970
+ maxWidth: "100%"
17971
+ }
17972
+ );
17973
+ }
17974
+ if (field.type === "datepicker-range") {
17797
17975
  return /* @__PURE__ */ jsx(
17798
17976
  DatePresetEditor,
17799
17977
  {
@@ -17820,8 +17998,8 @@ function FilterEditor({
17820
17998
  OptionList,
17821
17999
  {
17822
18000
  field,
17823
- value: field.type === "multi" ? toArrayValue(value) : value,
17824
- multiple: field.type === "multi",
18001
+ value: field.type === "select-multi" ? toArrayValue(value) : value,
18002
+ multiple: field.type === "select-multi",
17825
18003
  disabled,
17826
18004
  onValueChange
17827
18005
  }
@@ -17846,17 +18024,16 @@ function DatePresetEditor({
17846
18024
  setSelectedId(preset.value);
17847
18025
  if (!preset.custom) onValueChange(preset.resolve ? preset.resolve() : preset.value);
17848
18026
  };
17849
- if (field.type === "date" && presets.length === 0) {
18027
+ if (presets.length === 0) {
17850
18028
  return /* @__PURE__ */ jsx(
17851
- SDatePicker,
18029
+ SDateRangePicker,
17852
18030
  {
17853
- value: typeof value === "string" ? value : null,
18031
+ value: Array.isArray(value) && value.length === 2 ? value : null,
17854
18032
  onValueChange,
17855
18033
  selectable: field.selectable,
18034
+ maxRange: field.maxRange,
17856
18035
  disabled,
17857
- placeholder: field.placeholder,
17858
- width: "100%",
17859
- maxWidth: "100%"
18036
+ width: "100%"
17860
18037
  }
17861
18038
  );
17862
18039
  }
@@ -19959,6 +20136,6 @@ function STimeRangePicker({
19959
20136
  );
19960
20137
  }
19961
20138
 
19962
- export { BADGE_COLORS, BUTTON_COLORS, BUTTON_SIZES, COLOR_KEYS, FIELD_WIDTH_GRADES, GNB_COLORS, GNB_COMMON, GNB_FOLD_MS, GNB_FULL_LOGO_WIDTH, GNB_HEADER, GNB_MENU, GNB_MENU_WIDTH, GNB_RAIL, GNB_RAIL_WIDTH, ICONS, IMAGE_FITS, PAGE_BACKGROUNDS, PAGE_CONTENT_HEIGHTS, RangeCalendar, SActionModal, SBadge, SBarcodeInput, SButton, SCROLL_AREA_AXES, SCalendar, SCallout, SCard, SCheckbox, SChip2 as SChip, SChipFilter, SChipInput, SCircleProgress, SConfirmModal, SDatePicker, SDatePickerMonthListbox, SDatePickerYearListbox, SDateRangePicker, SDivider, SDraggableGroup, SDraggableItem2 as SDraggableItem, SDraggableList, SDraggableProvider, SDrawer, SDropdownButton2 as SDropdownButton, SEDITOR_DEFAULT_BUBBLE_MENU, SEDITOR_DEFAULT_COLORS, SEDITOR_DEFAULT_FONT_SIZE, SEDITOR_DEFAULT_HIGHLIGHTS, SEDITOR_DEFAULT_TOOLBAR, SEDITOR_FONT_SIZES, SEDITOR_HEADING_LABELS, SEDITOR_HEADING_LEVELS, SEDITOR_TOOLBAR_ITEMS, SEditor, SExpansionItem, SExpansionList2 as SExpansionList, SField, SFilePicker, SForm, SGhostButton, SGnb, SGuide, SIcon, SImage, SInput, SKeyValueTable, SLAYOUT_MIN_WIDTH, SLayout, SLayoutContext, SLinearProgress, SList2 as SList, SListItem2 as SListItem, SLoadingContainer, SLoadingModal, SLoadingViewport, SModal, SModalOutlet, SNumberInput, SPage, SPagination, SPopover, SPopup, SPortal, SRadio, SRadioButton, SRadioGroup, SSPLITTER_UNITS, SScrollArea, SSearchInput, SSectionHeaderCard2 as SSectionHeaderCard, SSelect2 as SSelect, SSplitter2 as SSplitter, SStepper, SSwitch, STEPPER_SIZES, STable, STableBar, STabs, STag, STextLink, STextarea, STimePicker, STimeRangePicker, SToast, SToastContainer, SToggle, STooltip2 as STooltip, STree2 as STree, STreeItem2 as STreeItem, TAG_COLORS, TAG_SHAPES, TAG_SIZES, TIMEPICKER_SIZES, TIMEPICKER_SIZE_CONFIG, buttonPreset, cn, fieldWidthValue, findGnbAncestors, findGnbRailValue, isColorKey, isFieldWidthGrade, loading, resolveColor, useSLayout };
20139
+ export { BADGE_COLORS, BUTTON_COLORS, BUTTON_SIZES, COLOR_KEYS, FIELD_WIDTH_GRADES, GNB_COLORS, GNB_COMMON, GNB_FOLD_MS, GNB_FULL_LOGO_WIDTH, GNB_HEADER, GNB_MENU, GNB_MENU_WIDTH, GNB_RAIL, GNB_RAIL_WIDTH, ICONS, IMAGE_FITS, PAGE_BACKGROUNDS, PAGE_CONTENT_HEIGHTS, RangeCalendar, SActionModal, SBadge, SBarcodeInput, SButton, SCROLL_AREA_AXES, SCalendar, SCallout, SCard, SCheckbox, SChip2 as SChip, SChipFilter, SChipInput, SCircleProgress, SConfirmModal, SDatePicker, SDatePickerMonthListbox, SDatePickerYearListbox, SDateRangePicker, SDivider, SDraggableGroup, SDraggableItem2 as SDraggableItem, SDraggableList, SDraggableProvider, SDrawer, SDropdownButton2 as SDropdownButton, SEDITOR_DEFAULT_FONT_SIZE, SEDITOR_HEADING_LABELS, SEDITOR_HEADING_LEVELS, SEditor, SExpansionItem, SExpansionList2 as SExpansionList, SField, SFilePicker, SForm, SGhostButton, SGnb, SGuide, SIcon, SImage, SInput, SKeyValueTable, SLAYOUT_MIN_WIDTH, SLayout, SLayoutContext, SLinearProgress, SList2 as SList, SListItem2 as SListItem, SLoadingContainer, SLoadingModal, SLoadingViewport, SModal, SModalOutlet, SNumberInput, SPage, SPagination, SPopover, SPopup, SPortal, SRadio, SRadioButton, SRadioGroup, SSPLITTER_UNITS, SScrollArea, SSearchInput, SSectionHeaderCard2 as SSectionHeaderCard, SSelect2 as SSelect, SSplitter2 as SSplitter, SStepper, SSwitch, STEPPER_SIZES, STable, STableBar, STabs, STag, STextLink, STextarea, STimePicker, STimeRangePicker, SToast, SToastContainer, SToggle, STooltip2 as STooltip, STree2 as STree, STreeItem2 as STreeItem, TAG_COLORS, TAG_SHAPES, TAG_SIZES, TIMEPICKER_SIZES, TIMEPICKER_SIZE_CONFIG, buttonPreset, cn, fieldWidthValue, findGnbAncestors, findGnbRailValue, isColorKey, isFieldWidthGrade, loading, resolveColor, useSLayout };
19963
20140
  //# sourceMappingURL=index.js.map
19964
20141
  //# sourceMappingURL=index.js.map