sellmate-design-system-react 9.0.0-beta.22 → 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.cjs CHANGED
@@ -3743,7 +3743,11 @@ var SDraggableItemView = /* @__PURE__ */ react.forwardRef(
3743
3743
  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)";
3744
3744
  const normalizedDepth = Math.max(1, Math.floor(depth));
3745
3745
  const depthOffset = (normalizedDepth - 1) * 20;
3746
- const depthStyle = depthOffset === 0 ? style : {
3746
+ const depthStyle = depthOffset === 0 ? style : bordered ? {
3747
+ ...style,
3748
+ marginLeft: depthOffset,
3749
+ width: `calc(100% - ${depthOffset}px)`
3750
+ } : {
3747
3751
  ...style,
3748
3752
  paddingLeft: `calc(var(--cmp-listDraggableItem-paddingX) + ${depthOffset}px)`
3749
3753
  };
@@ -4218,6 +4222,10 @@ function getSubtreeEnd(items, startIndex, getDepth) {
4218
4222
  }
4219
4223
  return endIndex;
4220
4224
  }
4225
+ function isDescendant(items, index, ancestorIndex, getDepth) {
4226
+ if (ancestorIndex == null || getDepth == null || index <= ancestorIndex) return false;
4227
+ return index < getSubtreeEnd(items, ancestorIndex, getDepth);
4228
+ }
4221
4229
  function getInsertionIndex(items, target, getDepth) {
4222
4230
  if (target.intent === "before") return target.index;
4223
4231
  if (target.intent === "inside") return target.index + 1;
@@ -4273,6 +4281,8 @@ function SDraggableListInner({
4273
4281
  const fromIndexRef = react.useRef(null);
4274
4282
  const currentSelectedKey = selectedKey ?? internalSelectedKey;
4275
4283
  const usesDepth = getDepth != null;
4284
+ const groupDragging = dragContext?.dragging;
4285
+ const draggedSubtreeStart = dragContext ? groupDragging?.listId === listId ? groupDragging?.index ?? null : null : draggingIndex;
4276
4286
  const startDrag = react.useCallback((event, index) => {
4277
4287
  event.preventDefault();
4278
4288
  fromIndexRef.current = index;
@@ -4404,7 +4414,7 @@ function SDraggableListInner({
4404
4414
  "data-draggable-list-id": dragContext ? listId : void 0,
4405
4415
  children: items.map((item, index) => {
4406
4416
  const itemKey = getKey(item, index);
4407
- const disabled = getDisabled?.(item, index) ?? false;
4417
+ const disabled = (getDisabled?.(item, index) ?? false) || isDescendant(items, index, draggedSubtreeStart, usesDepth ? readDepth : void 0);
4408
4418
  const depth = readDepth(item, index);
4409
4419
  const showBefore = isDropTarget && currentDropIndex === index && (dragContext || currentDropIntent === "before");
4410
4420
  const showInside = isDropTarget && currentDropIndex === index && !dragContext && usesDepth && currentDropIntent === "inside";
@@ -4437,6 +4447,7 @@ function SDraggableListInner({
4437
4447
  } else startDrag(event, index);
4438
4448
  },
4439
4449
  selected: currentSelectedKey === itemKey,
4450
+ disabled,
4440
4451
  depth
4441
4452
  })
4442
4453
  },
@@ -10432,7 +10443,11 @@ var SField = /* @__PURE__ */ react.forwardRef(function SField2({
10432
10443
  "div",
10433
10444
  {
10434
10445
  className: cn(
10435
- "relative box-border flex min-w-0 items-stretch overflow-hidden border border-solid border-(--field-bc)",
10446
+ "relative box-border flex min-w-0 items-stretch border border-solid border-(--field-bc)",
10447
+ // 둘 다 넘친 것을 잘라 내지만 clip 은 스크롤 상자를 만들지 않는다. hidden 이면
10448
+ // 이 상자가 스크롤포트가 되어 안쪽의 position:sticky 가 페이지 스크롤을 따라가지
10449
+ // 못한다 (SEditor 의 고정 툴바). 여러 줄 필드에서만 바꿔 파급을 좁힌다.
10450
+ multiline ? "overflow-clip" : "overflow-hidden",
10436
10451
  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]",
10437
10452
  disabled && "cursor-not-allowed"
10438
10453
  ),
@@ -10468,7 +10483,7 @@ var SField = /* @__PURE__ */ react.forwardRef(function SField2({
10468
10483
  ]
10469
10484
  }
10470
10485
  ),
10471
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 flex-1", children })
10486
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex min-w-0 flex-1", multiline && "bg-inherit"), children })
10472
10487
  ]
10473
10488
  }
10474
10489
  ),
@@ -15212,66 +15227,6 @@ var IconBlockquote = (p) => /* @__PURE__ */ jsxRuntime.jsxs(Frame, { ...p, child
15212
15227
  }
15213
15228
  )
15214
15229
  ] });
15215
- var IconHighlight = (p) => /* @__PURE__ */ jsxRuntime.jsx(Frame, { ...p, children: /* @__PURE__ */ jsxRuntime.jsx(
15216
- "path",
15217
- {
15218
- fillRule: "evenodd",
15219
- clipRule: "evenodd",
15220
- 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"
15221
- }
15222
- ) });
15223
- var IconSuperscript = (p) => /* @__PURE__ */ jsxRuntime.jsxs(Frame, { ...p, children: [
15224
- /* @__PURE__ */ jsxRuntime.jsx(
15225
- "path",
15226
- {
15227
- fillRule: "evenodd",
15228
- clipRule: "evenodd",
15229
- 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"
15230
- }
15231
- ),
15232
- /* @__PURE__ */ jsxRuntime.jsx(
15233
- "path",
15234
- {
15235
- fillRule: "evenodd",
15236
- clipRule: "evenodd",
15237
- 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"
15238
- }
15239
- ),
15240
- /* @__PURE__ */ jsxRuntime.jsx(
15241
- "path",
15242
- {
15243
- fillRule: "evenodd",
15244
- clipRule: "evenodd",
15245
- 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"
15246
- }
15247
- )
15248
- ] });
15249
- var IconSubscript = (p) => /* @__PURE__ */ jsxRuntime.jsxs(Frame, { ...p, children: [
15250
- /* @__PURE__ */ jsxRuntime.jsx(
15251
- "path",
15252
- {
15253
- fillRule: "evenodd",
15254
- clipRule: "evenodd",
15255
- 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"
15256
- }
15257
- ),
15258
- /* @__PURE__ */ jsxRuntime.jsx(
15259
- "path",
15260
- {
15261
- fillRule: "evenodd",
15262
- clipRule: "evenodd",
15263
- 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"
15264
- }
15265
- ),
15266
- /* @__PURE__ */ jsxRuntime.jsx(
15267
- "path",
15268
- {
15269
- fillRule: "evenodd",
15270
- clipRule: "evenodd",
15271
- 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"
15272
- }
15273
- )
15274
- ] });
15275
15230
  var IconAlignLeft = (p) => /* @__PURE__ */ jsxRuntime.jsxs(Frame, { ...p, children: [
15276
15231
  /* @__PURE__ */ jsxRuntime.jsx(
15277
15232
  "path",
@@ -15563,6 +15518,14 @@ var IconTextColor = (p) => /* @__PURE__ */ jsxRuntime.jsxs(Frame, { ...p, childr
15563
15518
  }
15564
15519
  )
15565
15520
  ] });
15521
+ var IconTable = (p) => /* @__PURE__ */ jsxRuntime.jsx(Frame, { ...p, children: /* @__PURE__ */ jsxRuntime.jsx(
15522
+ "path",
15523
+ {
15524
+ fillRule: "evenodd",
15525
+ clipRule: "evenodd",
15526
+ 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"
15527
+ }
15528
+ ) });
15566
15529
  var IconHorizontalRule = (p) => /* @__PURE__ */ jsxRuntime.jsxs(Frame, { ...p, children: [
15567
15530
  /* @__PURE__ */ jsxRuntime.jsx("rect", { x: 3, y: 5, width: 18, height: 2, rx: 1 }),
15568
15531
  /* @__PURE__ */ jsxRuntime.jsx("rect", { x: 2, y: 11, width: 20, height: 2, rx: 1 }),
@@ -15570,39 +15533,12 @@ var IconHorizontalRule = (p) => /* @__PURE__ */ jsxRuntime.jsxs(Frame, { ...p, c
15570
15533
  ] });
15571
15534
 
15572
15535
  // src/components/SEditor/editor.config.ts
15573
- var SEDITOR_TOOLBAR_ITEMS = [
15574
- "heading",
15575
- "fontSize",
15576
- "bold",
15577
- "italic",
15578
- "underline",
15579
- "strike",
15580
- "code",
15581
- "color",
15582
- "highlight",
15583
- "superscript",
15584
- "subscript",
15585
- "alignLeft",
15586
- "alignCenter",
15587
- "alignRight",
15588
- "alignJustify",
15589
- "bulletList",
15590
- "orderedList",
15591
- "taskList",
15592
- "list",
15593
- "blockquote",
15594
- "codeBlock",
15595
- "horizontalRule",
15596
- "link",
15597
- "image",
15598
- "undo",
15599
- "redo"
15600
- ];
15601
15536
  var SEDITOR_DEFAULT_TOOLBAR = [
15602
15537
  "undo",
15603
15538
  "redo",
15604
15539
  "|",
15605
15540
  "heading",
15541
+ "fontSize",
15606
15542
  "list",
15607
15543
  "blockquote",
15608
15544
  "codeBlock",
@@ -15613,18 +15549,29 @@ var SEDITOR_DEFAULT_TOOLBAR = [
15613
15549
  "code",
15614
15550
  "underline",
15615
15551
  "color",
15616
- "highlight",
15617
15552
  "link",
15618
15553
  "|",
15619
- "superscript",
15620
- "subscript",
15621
- "|",
15622
15554
  "alignLeft",
15623
15555
  "alignCenter",
15624
15556
  "alignRight",
15625
15557
  "alignJustify",
15626
15558
  "|",
15627
- "image"
15559
+ "table",
15560
+ "image",
15561
+ "horizontalRule"
15562
+ ];
15563
+ var SEDITOR_SIMPLE_TOOLBAR = [
15564
+ "undo",
15565
+ "redo",
15566
+ "|",
15567
+ "heading",
15568
+ "fontSize",
15569
+ "|",
15570
+ "bold",
15571
+ "italic",
15572
+ "underline",
15573
+ "strike",
15574
+ "color"
15628
15575
  ];
15629
15576
  var SEDITOR_DEFAULT_BUBBLE_MENU = [
15630
15577
  "bold",
@@ -15634,9 +15581,16 @@ var SEDITOR_DEFAULT_BUBBLE_MENU = [
15634
15581
  "underline",
15635
15582
  "|",
15636
15583
  "color",
15637
- "highlight",
15638
15584
  "link"
15639
15585
  ];
15586
+ var SEDITOR_SIMPLE_BUBBLE_MENU = [
15587
+ "bold",
15588
+ "italic",
15589
+ "strike",
15590
+ "underline",
15591
+ "|",
15592
+ "color"
15593
+ ];
15640
15594
  var SEDITOR_HEADING_LEVELS = [1, 2, 3];
15641
15595
  var SEDITOR_HEADING_LABELS = {
15642
15596
  0: "\uBCF8\uBB38",
@@ -15644,7 +15598,7 @@ var SEDITOR_HEADING_LABELS = {
15644
15598
  2: "\uC81C\uBAA9 2",
15645
15599
  3: "\uC81C\uBAA9 3"
15646
15600
  };
15647
- var SEDITOR_FONT_SIZES = [11, 12, 14, 16, 18];
15601
+ var SEDITOR_FONT_SIZES = [8, 9, 10, 11, 12, 14, 16, 18, 24, 30, 36, 48, 60, 72];
15648
15602
  var SEDITOR_DEFAULT_FONT_SIZE = 12;
15649
15603
  var SEDITOR_DEFAULT_COLORS = [
15650
15604
  { label: "\uAE30\uBCF8", color: "var(--color-fg-primary)" },
@@ -15656,17 +15610,13 @@ var SEDITOR_DEFAULT_COLORS = [
15656
15610
  { label: "\uC8FC\uC758", color: "var(--color-fg-warning)" },
15657
15611
  { label: "\uC704\uD5D8", color: "var(--color-fg-danger)" }
15658
15612
  ];
15659
- var SEDITOR_DEFAULT_HIGHLIGHTS = [
15660
- { label: "\uB178\uB791", color: "yellow_25" },
15661
- { label: "\uCD08\uB85D", color: "green_25" },
15662
- { label: "\uD30C\uB791", color: "brilliantblue_25" },
15663
- { label: "\uBE68\uAC15", color: "red_20" },
15664
- { label: "\uC8FC\uD669", color: "orange_20" },
15665
- { label: "\uD68C\uC0C9", color: "grey_20" }
15666
- ];
15667
15613
  var TASK_LIST_CLASS = "sd-editor-task-list";
15668
15614
  var TASK_ITEM_CLASS = "sd-editor-task-item";
15669
15615
  var IMAGE_CLASS = "sd-editor-image";
15616
+ var TABLE_CLASS = "sd-editor-table";
15617
+ var TABLE_ROW_CLASS = "sd-editor-table-row";
15618
+ var TABLE_HEADER_CLASS = "sd-editor-table-header";
15619
+ var TABLE_CELL_CLASS = "sd-editor-table-cell";
15670
15620
  var SEDITOR_CONTENT_CLASS = [
15671
15621
  "[&_.ProseMirror]:min-h-full [&_.ProseMirror]:outline-none [&_.ProseMirror]:whitespace-pre-wrap [&_.ProseMirror]:break-words",
15672
15622
  // placeholder — Placeholder 확장이 빈 첫 문단에 data-placeholder 와 클래스를 붙인다
@@ -15679,23 +15629,38 @@ var SEDITOR_CONTENT_CLASS = [
15679
15629
  "[&_ol]:my-[4px] [&_ol]:list-decimal [&_ol]:pl-[20px]",
15680
15630
  "[&_li]:my-0 [&_li>p]:my-0",
15681
15631
  // 체크목록 — 마커를 지우고 체크박스와 본문을 가로로 세운다
15682
- `[&_.${TASK_LIST_CLASS}]:my-[4px] [&_.${TASK_LIST_CLASS}]:list-none [&_.${TASK_LIST_CLASS}]:pl-0`,
15683
- `[&_.${TASK_ITEM_CLASS}]:flex [&_.${TASK_ITEM_CLASS}]:items-start [&_.${TASK_ITEM_CLASS}]:gap-[6px]`,
15684
- `[&_.${TASK_ITEM_CLASS}>label]:mt-[3px] [&_.${TASK_ITEM_CLASS}>label]:shrink-0 [&_.${TASK_ITEM_CLASS}>label]:leading-none`,
15685
- `[&_.${TASK_ITEM_CLASS}>div]:min-w-0 [&_.${TASK_ITEM_CLASS}>div]:flex-1`,
15686
- `[&_.${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)]`,
15687
- `[&_.${TASK_ITEM_CLASS}[data-checked=true]>div]:text-[color:var(--color-fg-tertiary)] [&_.${TASK_ITEM_CLASS}[data-checked=true]>div]:line-through`,
15632
+ "[&_.sd-editor-task-list]:my-[4px] [&_.sd-editor-task-list]:list-none [&_.sd-editor-task-list]:pl-0",
15633
+ "[&_.sd-editor-task-item]:flex [&_.sd-editor-task-item]:items-start [&_.sd-editor-task-item]:gap-[6px]",
15634
+ "[&_.sd-editor-task-item>label]:mt-[3px] [&_.sd-editor-task-item>label]:shrink-0 [&_.sd-editor-task-item>label]:leading-none",
15635
+ "[&_.sd-editor-task-item>div]:min-w-0 [&_.sd-editor-task-item>div]:flex-1",
15636
+ "[&_.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)]",
15637
+ "[&_.sd-editor-task-item[data-checked=true]>div]:text-[color:var(--color-fg-tertiary)] [&_.sd-editor-task-item[data-checked=true]>div]:line-through",
15688
15638
  "[&_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)]",
15689
15639
  "[&_a]:cursor-pointer [&_a]:text-[color:var(--color-fg-accent)] [&_a]:underline",
15690
15640
  "[&_hr]:my-[12px] [&_hr]:border-t [&_hr]:border-[color:var(--color-border-default)]",
15691
15641
  "[&_code]:rounded-[3px] [&_code]:bg-[var(--color-bg-neutralLight)] [&_code]:px-[4px] [&_code]:py-[1px]",
15692
15642
  "[&_pre]:my-[8px] [&_pre]:rounded-[4px] [&_pre]:bg-[var(--color-bg-neutralLight)] [&_pre]:p-[12px]",
15693
15643
  "[&_pre_code]:bg-transparent [&_pre_code]:p-0",
15694
- `[&_.${IMAGE_CLASS}]:my-[8px] [&_.${IMAGE_CLASS}]:h-auto [&_.${IMAGE_CLASS}]:max-w-full [&_.${IMAGE_CLASS}]:rounded-[4px]`,
15644
+ "[&_.sd-editor-image]:my-[8px] [&_.sd-editor-image]:h-auto [&_.sd-editor-image]:max-w-full [&_.sd-editor-image]:rounded-[4px]",
15645
+ /**
15646
+ * 표 — `table-layout: fixed` 로 열을 균등하게 나눈다.
15647
+ *
15648
+ * 열 너비를 저장하지 않기로 했으므로(tiptap-api.ts 의 Table 주석) 폭은 언제나 여기서
15649
+ * 정해진다. auto 로 두면 글자 많은 열이 넓어져 같은 표가 화면마다 다르게 보이고, 긴
15650
+ * 단어 하나가 상자 밖으로 표를 밀어낸다.
15651
+ */
15652
+ "[&_.sd-editor-table]:my-[8px] [&_.sd-editor-table]:w-full [&_.sd-editor-table]:table-fixed [&_.sd-editor-table]:border-collapse",
15653
+ "[&_.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",
15654
+ "[&_.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",
15655
+ // 칸 안의 문단은 표 밖과 달리 위아래 여백을 갖지 않는다 — 한 줄짜리 칸이 대부분이다
15656
+ "[&_.sd-editor-table-header>p]:my-0 [&_.sd-editor-table-cell>p]:my-0",
15657
+ /*
15658
+ 고른 칸 표시 — ProseMirror 표 플러그인이 `.selectedCell` 을 붙인다. 배경을 직접 칠하면
15659
+ 칸이 자기 배경(헤더의 회색)을 잃으므로 덧대는 판을 하나 얹는다.
15660
+ */
15661
+ "[&_.selectedCell]:relative [&_.selectedCell]:after:pointer-events-none [&_.selectedCell]:after:absolute [&_.selectedCell]:after:inset-0 [&_.selectedCell]:after:bg-[var(--color-bg-accentFaint)]",
15695
15662
  "[&_.ProseMirror-selectednode]:outline [&_.ProseMirror-selectednode]:outline-2 [&_.ProseMirror-selectednode]:outline-[var(--color-border-accent)]",
15696
- "[&_strong]:font-bold [&_em]:italic [&_u]:underline [&_s]:line-through",
15697
- "[&_sup]:align-super [&_sup]:text-[0.75em] [&_sub]:align-sub [&_sub]:text-[0.75em]",
15698
- "[&_mark]:rounded-[2px] [&_mark]:bg-transparent [&_mark]:px-[1px]"
15663
+ "[&_strong]:font-bold [&_em]:italic [&_u]:underline [&_s]:line-through"
15699
15664
  ].join(" ");
15700
15665
  var BODY = { fontSize: 12, lineHeight: "20px", paddingX: 12, paddingY: 8 };
15701
15666
  var cssLen3 = (v) => typeof v === "number" ? `${v}px` : v;
@@ -15764,22 +15729,28 @@ var ToolbarButton = /* @__PURE__ */ react.forwardRef(function ToolbarButton2({ l
15764
15729
  }
15765
15730
  );
15766
15731
  });
15767
- var Separator = () => /* @__PURE__ */ jsxRuntime.jsx(
15732
+ var Separator2 = () => /* @__PURE__ */ jsxRuntime.jsx(
15768
15733
  "span",
15769
15734
  {
15770
15735
  "aria-hidden": true,
15771
- className: "mx-[2px] h-[16px] w-[1px] shrink-0",
15772
- style: { background: "var(--sys-color-field-border-default)" }
15736
+ className: "mx-[4px] h-[16px] w-[1px] shrink-0",
15737
+ style: { background: "var(--sys-color-border-default)" }
15773
15738
  }
15774
15739
  );
15775
15740
  var ColorIndicator = ({ color, children }) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-col items-center gap-[1px]", children: [
15776
15741
  children,
15777
15742
  /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "h-[3px] w-[16px] rounded-[1px]", style: { background: color } })
15778
15743
  ] });
15779
- var menuClass = cn(
15780
- "z-50 overflow-hidden rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] p-[4px] shadow-normal-sm",
15781
- FLOATING_SLIDE_ANIM
15744
+ var MENU_BASE_CLASS = "z-50 rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] p-[4px] shadow-normal-sm";
15745
+ var menuClass = cn(MENU_BASE_CLASS, "overflow-hidden", FLOATING_SLIDE_ANIM);
15746
+ var scrollMenuClass = cn(
15747
+ MENU_BASE_CLASS,
15748
+ "overflow-x-hidden overflow-y-auto",
15749
+ FLOATING_SLIDE_ANIM,
15750
+ SCROLLBAR_CLASS
15782
15751
  );
15752
+ var FONT_SIZE_DEFAULT_LABEL = "\uAE30\uBCF8";
15753
+ var FONT_SIZE_MENU_MAX_HEIGHT = "min(280px, var(--radix-dropdown-menu-content-available-height))";
15783
15754
  var swatchClass = cn(
15784
15755
  "flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded-[4px] outline-none",
15785
15756
  "hover:bg-[var(--color-bg-neutralLight)] data-[highlighted]:bg-[var(--color-bg-neutralLight)]"
@@ -15794,6 +15765,9 @@ var menuItemClass = cn(
15794
15765
  "text-[color:var(--sys-color-fg-secondary)]",
15795
15766
  "data-[highlighted]:bg-[var(--sys-color-bg-accent)] data-[highlighted]:text-[color:var(--sys-color-fg-inverse)]"
15796
15767
  );
15768
+ var menuItemSelectedClass = "bg-[var(--cmp-listItem-bg-selected)] text-[color:var(--cmp-listItem-text-selected)]";
15769
+ var menuItemDisabledClass = "data-[disabled]:cursor-not-allowed data-[disabled]:bg-transparent data-[disabled]:text-[color:var(--cmp-ghostButton-icon-disabled)]";
15770
+ var menuSeparatorClass = "my-[4px] h-[1px] bg-[var(--sys-color-border-default)]";
15797
15771
  var PaletteItem = ({
15798
15772
  asMenu,
15799
15773
  label,
@@ -15835,6 +15809,111 @@ var ColorPalette = ({
15835
15809
  ),
15836
15810
  /* @__PURE__ */ jsxRuntime.jsx(PaletteItem, { asMenu, className: cn(menuItemClass, "w-full"), onSelect: onClear, children: clearLabel })
15837
15811
  ] });
15812
+ var TABLE_PICKER_ROWS = 8;
15813
+ var TABLE_PICKER_COLS = 8;
15814
+ var TABLE_PICKER_CELL = 16;
15815
+ var TABLE_PICKER_GAP = 4;
15816
+ var TableSizePicker = ({
15817
+ disabled,
15818
+ onPick
15819
+ }) => {
15820
+ const [size, setSize] = react.useState({ rows: 1, cols: 1 });
15821
+ const gridRef = react.useRef(null);
15822
+ react.useEffect(() => {
15823
+ if (disabled) return void 0;
15824
+ const id = setTimeout(() => gridRef.current?.focus(), 0);
15825
+ return () => clearTimeout(id);
15826
+ }, [disabled]);
15827
+ const clamp4 = (v, max) => Math.min(Math.max(v, 1), max);
15828
+ const move = (dRow, dCol) => setSize((p) => ({
15829
+ rows: clamp4(p.rows + dRow, TABLE_PICKER_ROWS),
15830
+ cols: clamp4(p.cols + dCol, TABLE_PICKER_COLS)
15831
+ }));
15832
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-[4px]", children: [
15833
+ /* @__PURE__ */ jsxRuntime.jsx(
15834
+ "div",
15835
+ {
15836
+ ref: gridRef,
15837
+ role: "grid",
15838
+ "aria-label": "\uD45C \uD06C\uAE30",
15839
+ "aria-disabled": disabled || void 0,
15840
+ tabIndex: disabled ? -1 : 0,
15841
+ className: cn("flex flex-col outline-none", disabled && "pointer-events-none opacity-40"),
15842
+ style: { gap: TABLE_PICKER_GAP },
15843
+ onKeyDown: (e) => {
15844
+ const step = {
15845
+ ArrowUp: [-1, 0],
15846
+ ArrowDown: [1, 0],
15847
+ ArrowLeft: [0, -1],
15848
+ ArrowRight: [0, 1]
15849
+ };
15850
+ const d = step[e.key];
15851
+ if (d) {
15852
+ e.preventDefault();
15853
+ e.stopPropagation();
15854
+ move(d[0], d[1]);
15855
+ return;
15856
+ }
15857
+ if (e.key === "Enter" || e.key === " ") {
15858
+ e.preventDefault();
15859
+ e.stopPropagation();
15860
+ onPick(size.rows, size.cols);
15861
+ }
15862
+ },
15863
+ children: Array.from({ length: TABLE_PICKER_ROWS }, (_, r) => /* @__PURE__ */ jsxRuntime.jsx("div", { role: "row", className: "flex", style: { gap: TABLE_PICKER_GAP }, children: Array.from({ length: TABLE_PICKER_COLS }, (_2, c) => {
15864
+ const on = r < size.rows && c < size.cols;
15865
+ return /* @__PURE__ */ jsxRuntime.jsx(
15866
+ "button",
15867
+ {
15868
+ type: "button",
15869
+ role: "gridcell",
15870
+ "aria-label": `${r + 1}\uD589 ${c + 1}\uC5F4`,
15871
+ "aria-selected": on,
15872
+ tabIndex: -1,
15873
+ className: "box-border cursor-pointer rounded-[3px] border border-solid p-0 outline-none",
15874
+ style: {
15875
+ width: TABLE_PICKER_CELL,
15876
+ height: TABLE_PICKER_CELL,
15877
+ borderColor: on ? "var(--sys-color-bg-accent)" : "var(--sys-color-border-default)",
15878
+ background: on ? "var(--color-bg-accentFaint)" : "transparent"
15879
+ },
15880
+ onMouseEnter: () => setSize({ rows: r + 1, cols: c + 1 }),
15881
+ onFocus: () => setSize({ rows: r + 1, cols: c + 1 }),
15882
+ onClick: () => onPick(r + 1, c + 1)
15883
+ },
15884
+ c
15885
+ );
15886
+ }) }, r))
15887
+ }
15888
+ ),
15889
+ /* @__PURE__ */ jsxRuntime.jsxs(
15890
+ "div",
15891
+ {
15892
+ "aria-live": "polite",
15893
+ className: "mt-[6px] text-center text-[12px] leading-[20px] text-[color:var(--sys-color-fg-secondary)]",
15894
+ children: [
15895
+ size.rows,
15896
+ "\uD589 \xD7 ",
15897
+ size.cols,
15898
+ "\uC5F4"
15899
+ ]
15900
+ }
15901
+ )
15902
+ ] });
15903
+ };
15904
+ var TableMenuItem = ({
15905
+ label,
15906
+ disabled,
15907
+ onSelect
15908
+ }) => /* @__PURE__ */ jsxRuntime.jsx(
15909
+ RDropdown2__namespace.Item,
15910
+ {
15911
+ className: cn(menuItemClass, menuItemDisabledClass),
15912
+ disabled,
15913
+ onSelect,
15914
+ children: label
15915
+ }
15916
+ );
15838
15917
  var LinkEditor = ({
15839
15918
  href,
15840
15919
  onHrefChange,
@@ -15862,8 +15941,8 @@ var LinkEditor = ({
15862
15941
  /* @__PURE__ */ jsxRuntime.jsx(SButton, { size: "sm", label: "\uC801\uC6A9", onClick: onApply }),
15863
15942
  hasLink && /* @__PURE__ */ jsxRuntime.jsx(SButton, { size: "sm", color: "neutral", outline: true, label: "\uC81C\uAC70", onClick: onRemove })
15864
15943
  ] });
15865
- var TOOLBAR_BAR_CLASS = "flex flex-wrap items-center gap-[2px] border-b border-solid px-[8px] py-[4px]";
15866
- var TOOLBAR_BAR_STYLE = { borderBottomColor: "var(--sys-color-field-border-default)" };
15944
+ 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]";
15945
+ var TOOLBAR_BAR_STYLE = { borderBottomColor: "var(--sys-color-border-default)" };
15867
15946
  var BUBBLE_BAR_CLASS = cn(
15868
15947
  "flex max-w-[calc(100vw-32px)] items-center gap-[2px] overflow-x-auto rounded-[var(--cmp-listBox-radius)]",
15869
15948
  "bg-[var(--cmp-listBox-bg)] px-[6px] py-[4px] shadow-normal-sm"
@@ -15875,8 +15954,6 @@ var readEditorState = (e) => ({
15875
15954
  underline: e.isActive("underline"),
15876
15955
  strike: e.isActive("strike"),
15877
15956
  code: e.isActive("code"),
15878
- superscript: e.isActive("superscript"),
15879
- subscript: e.isActive("subscript"),
15880
15957
  alignLeft: e.isActive({ textAlign: "left" }),
15881
15958
  alignCenter: e.isActive({ textAlign: "center" }),
15882
15959
  alignRight: e.isActive({ textAlign: "right" }),
@@ -15887,9 +15964,11 @@ var readEditorState = (e) => ({
15887
15964
  blockquote: e.isActive("blockquote"),
15888
15965
  codeBlock: e.isActive("codeBlock"),
15889
15966
  link: e.isActive("link"),
15967
+ inTable: e.isActive("table"),
15968
+ canMergeCells: e.can().mergeCells(),
15969
+ canSplitCell: e.can().splitCell(),
15890
15970
  linkHref: e.getAttributes("link").href ?? "",
15891
15971
  color: e.getAttributes("textStyle").color ?? "",
15892
- highlight: e.getAttributes("highlight").color ?? "",
15893
15972
  fontSize: e.getAttributes("textStyle").fontSize ?? "",
15894
15973
  canUndo: e.can().undo(),
15895
15974
  canRedo: e.can().redo()
@@ -15901,8 +15980,6 @@ var IDLE_TOOLBAR_STATE = {
15901
15980
  underline: false,
15902
15981
  strike: false,
15903
15982
  code: false,
15904
- superscript: false,
15905
- subscript: false,
15906
15983
  alignLeft: false,
15907
15984
  alignCenter: false,
15908
15985
  alignRight: false,
@@ -15914,8 +15991,10 @@ var IDLE_TOOLBAR_STATE = {
15914
15991
  codeBlock: false,
15915
15992
  link: false,
15916
15993
  linkHref: "",
15994
+ inTable: false,
15995
+ canMergeCells: false,
15996
+ canSplitCell: false,
15917
15997
  color: "",
15918
- highlight: "",
15919
15998
  fontSize: "",
15920
15999
  canUndo: false,
15921
16000
  canRedo: false
@@ -15924,9 +16003,6 @@ function EditorToolbarBar({
15924
16003
  state: state2,
15925
16004
  editor,
15926
16005
  items,
15927
- fontSizes,
15928
- colors,
15929
- highlights,
15930
16006
  onImageUpload,
15931
16007
  disabled,
15932
16008
  variant = "bar"
@@ -15935,6 +16011,7 @@ function EditorToolbarBar({
15935
16011
  const insideModal = useInsideModal();
15936
16012
  const isMobile = useIsMobile();
15937
16013
  const [linkOpen, setLinkOpen] = react.useState(false);
16014
+ const [tableOpen, setTableOpen] = react.useState(false);
15938
16015
  const [linkHref, setLinkHref] = react.useState("");
15939
16016
  const [uploading, setUploading] = react.useState(false);
15940
16017
  const [mobileView, setMobileView] = react.useState("main");
@@ -15949,9 +16026,8 @@ function EditorToolbarBar({
15949
16026
  const chain = () => editor?.chain()?.focus();
15950
16027
  const off = disabled;
15951
16028
  const currentFontSize = Number.parseInt(state2.fontSize, 10);
15952
- const activeFontSize = Number.isNaN(currentFontSize) ? SEDITOR_DEFAULT_FONT_SIZE : currentFontSize;
16029
+ const activeFontSize = Number.isNaN(currentFontSize) ? null : currentFontSize;
15953
16030
  const activeColor = resolveColor(state2.color) ?? "currentColor";
15954
- const activeHighlight = resolveColor(state2.highlight) ?? "currentColor";
15955
16031
  const pickImage = async (e) => {
15956
16032
  const file = e.target.files?.[0];
15957
16033
  e.target.value = "";
@@ -15968,8 +16044,6 @@ function EditorToolbarBar({
15968
16044
  };
15969
16045
  const applyColor = (color) => chain()?.setColor(resolveColor(color) ?? "inherit").run();
15970
16046
  const clearColor = () => chain()?.unsetColor().run();
15971
- const applyHighlight = (color) => chain()?.setHighlight({ color: resolveColor(color) ?? "transparent" }).run();
15972
- const clearHighlight = () => chain()?.unsetHighlight().run();
15973
16047
  const closeLinkEditor = () => {
15974
16048
  setLinkOpen(false);
15975
16049
  setMobileView("main");
@@ -16036,18 +16110,41 @@ function EditorToolbarBar({
16036
16110
  case "fontSize":
16037
16111
  return /* @__PURE__ */ jsxRuntime.jsxs(RDropdown2__namespace.Root, { modal: !insideModal, children: [
16038
16112
  /* @__PURE__ */ jsxRuntime.jsx(RDropdown2__namespace.Trigger, { asChild: true, disabled: off, children: /* @__PURE__ */ jsxRuntime.jsxs(ToolbarButton, { label: "\uAE00\uC790 \uD06C\uAE30", disabled: off, className: "px-[6px]", children: [
16039
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[12px] leading-[20px]", children: activeFontSize }),
16113
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[12px] leading-[20px]", children: activeFontSize ?? FONT_SIZE_DEFAULT_LABEL }),
16040
16114
  /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "caretDown", size: 12 })
16041
16115
  ] }) }),
16042
- /* @__PURE__ */ jsxRuntime.jsx(RDropdown2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(RDropdown2__namespace.Content, { sideOffset: 4, align: "start", className: menuClass, children: fontSizes.map((size) => /* @__PURE__ */ jsxRuntime.jsx(
16043
- RDropdown2__namespace.Item,
16116
+ /* @__PURE__ */ jsxRuntime.jsx(RDropdown2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(
16117
+ RDropdown2__namespace.Content,
16044
16118
  {
16045
- className: menuItemClass,
16046
- onSelect: () => size === SEDITOR_DEFAULT_FONT_SIZE ? chain()?.unsetFontSize().run() : chain()?.setFontSize(`${size}px`).run(),
16047
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: size, lineHeight: "20px" }, children: size })
16048
- },
16049
- size
16050
- )) }) })
16119
+ sideOffset: 4,
16120
+ align: "start",
16121
+ className: cn(scrollMenuClass, "min-w-[72px]"),
16122
+ style: { maxHeight: FONT_SIZE_MENU_MAX_HEIGHT },
16123
+ children: [
16124
+ /* @__PURE__ */ jsxRuntime.jsx(
16125
+ RDropdown2__namespace.Item,
16126
+ {
16127
+ className: cn(menuItemClass, activeFontSize === null && menuItemSelectedClass),
16128
+ title: `${FONT_SIZE_DEFAULT_LABEL} (\uBCF8\uBB38 ${SEDITOR_DEFAULT_FONT_SIZE}px)`,
16129
+ onSelect: () => chain()?.unsetFontSize().run(),
16130
+ children: FONT_SIZE_DEFAULT_LABEL
16131
+ }
16132
+ ),
16133
+ SEDITOR_FONT_SIZES.map((size) => /* @__PURE__ */ jsxRuntime.jsx(
16134
+ RDropdown2__namespace.Item,
16135
+ {
16136
+ ref: activeFontSize === size ? (el) => {
16137
+ el?.scrollIntoView({ block: "nearest" });
16138
+ } : void 0,
16139
+ className: cn(menuItemClass, activeFontSize === size && menuItemSelectedClass),
16140
+ onSelect: () => chain()?.setFontSize(`${size}px`).run(),
16141
+ children: size
16142
+ },
16143
+ size
16144
+ ))
16145
+ ]
16146
+ }
16147
+ ) })
16051
16148
  ] }, item);
16052
16149
  case "bold":
16053
16150
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -16132,7 +16229,7 @@ function EditorToolbarBar({
16132
16229
  ColorPalette,
16133
16230
  {
16134
16231
  asMenu: true,
16135
- colors,
16232
+ colors: SEDITOR_DEFAULT_COLORS,
16136
16233
  columns: 4,
16137
16234
  clearLabel: "\uC0C9 \uC9C0\uC6B0\uAE30",
16138
16235
  onPick: applyColor,
@@ -16140,58 +16237,6 @@ function EditorToolbarBar({
16140
16237
  }
16141
16238
  ) }) })
16142
16239
  ] }, item);
16143
- case "highlight":
16144
- if (mobile)
16145
- return /* @__PURE__ */ jsxRuntime.jsx(
16146
- ToolbarButton,
16147
- {
16148
- label: "\uD615\uAD11\uD39C",
16149
- disabled: off,
16150
- onClick: () => setMobileView("highlight"),
16151
- children: /* @__PURE__ */ jsxRuntime.jsx(ColorIndicator, { color: off ? "currentColor" : activeHighlight, children: /* @__PURE__ */ jsxRuntime.jsx(IconHighlight, { size: ICON_SIZE }) })
16152
- },
16153
- item
16154
- );
16155
- return /* @__PURE__ */ jsxRuntime.jsxs(RDropdown2__namespace.Root, { modal: !insideModal, children: [
16156
- /* @__PURE__ */ jsxRuntime.jsx(RDropdown2__namespace.Trigger, { asChild: true, disabled: off, children: /* @__PURE__ */ jsxRuntime.jsx(ToolbarButton, { label: "\uD615\uAD11\uD39C", disabled: off, children: /* @__PURE__ */ jsxRuntime.jsx(ColorIndicator, { color: off ? "currentColor" : activeHighlight, children: /* @__PURE__ */ jsxRuntime.jsx(IconHighlight, { size: ICON_SIZE }) }) }) }),
16157
- /* @__PURE__ */ jsxRuntime.jsx(RDropdown2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(RDropdown2__namespace.Content, { sideOffset: 4, align: "start", className: menuClass, children: /* @__PURE__ */ jsxRuntime.jsx(
16158
- ColorPalette,
16159
- {
16160
- asMenu: true,
16161
- colors: highlights,
16162
- columns: 3,
16163
- clearLabel: "\uD615\uAD11\uD39C \uC9C0\uC6B0\uAE30",
16164
- onPick: applyHighlight,
16165
- onClear: clearHighlight
16166
- }
16167
- ) }) })
16168
- ] }, item);
16169
- case "superscript":
16170
- return /* @__PURE__ */ jsxRuntime.jsx(
16171
- ToolbarButton,
16172
- {
16173
- label: "\uC704 \uCCA8\uC790",
16174
- active: state2.superscript,
16175
- "aria-pressed": state2.superscript,
16176
- disabled: off,
16177
- onClick: () => chain()?.toggleSuperscript().run(),
16178
- children: /* @__PURE__ */ jsxRuntime.jsx(IconSuperscript, { size: ICON_SIZE })
16179
- },
16180
- item
16181
- );
16182
- case "subscript":
16183
- return /* @__PURE__ */ jsxRuntime.jsx(
16184
- ToolbarButton,
16185
- {
16186
- label: "\uC544\uB798 \uCCA8\uC790",
16187
- active: state2.subscript,
16188
- "aria-pressed": state2.subscript,
16189
- disabled: off,
16190
- onClick: () => chain()?.toggleSubscript().run(),
16191
- children: /* @__PURE__ */ jsxRuntime.jsx(IconSubscript, { size: ICON_SIZE })
16192
- },
16193
- item
16194
- );
16195
16240
  case "alignLeft":
16196
16241
  return /* @__PURE__ */ jsxRuntime.jsx(
16197
16242
  ToolbarButton,
@@ -16417,6 +16462,127 @@ function EditorToolbarBar({
16417
16462
  },
16418
16463
  item
16419
16464
  );
16465
+ case "table":
16466
+ return /* @__PURE__ */ jsxRuntime.jsxs(
16467
+ RDropdown2__namespace.Root,
16468
+ {
16469
+ open: tableOpen,
16470
+ onOpenChange: setTableOpen,
16471
+ modal: !insideModal,
16472
+ children: [
16473
+ /* @__PURE__ */ jsxRuntime.jsx(RDropdown2__namespace.Trigger, { asChild: true, disabled: off, children: /* @__PURE__ */ jsxRuntime.jsxs(ToolbarButton, { label: "\uD45C", active: state2.inTable, disabled: off, className: "px-[6px]", children: [
16474
+ /* @__PURE__ */ jsxRuntime.jsx(IconTable, { size: ICON_SIZE }),
16475
+ /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "caretDown", size: CARET_SIZE })
16476
+ ] }) }),
16477
+ /* @__PURE__ */ jsxRuntime.jsx(RDropdown2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(RDropdown2__namespace.Content, { sideOffset: 4, align: "start", className: menuClass, children: [
16478
+ !state2.inTable && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16479
+ /* @__PURE__ */ jsxRuntime.jsx(
16480
+ TableSizePicker,
16481
+ {
16482
+ disabled: state2.inTable,
16483
+ onPick: (rows, cols) => {
16484
+ chain()?.insertTable({ rows, cols, withHeaderRow: true }).run();
16485
+ setTableOpen(false);
16486
+ }
16487
+ }
16488
+ ),
16489
+ /* @__PURE__ */ jsxRuntime.jsx(RDropdown2__namespace.Separator, { className: menuSeparatorClass })
16490
+ ] }),
16491
+ /* @__PURE__ */ jsxRuntime.jsx(
16492
+ TableMenuItem,
16493
+ {
16494
+ label: "\uC704\uC5D0 \uD589 \uCD94\uAC00",
16495
+ disabled: !state2.inTable,
16496
+ onSelect: () => chain()?.addRowBefore().run()
16497
+ }
16498
+ ),
16499
+ /* @__PURE__ */ jsxRuntime.jsx(
16500
+ TableMenuItem,
16501
+ {
16502
+ label: "\uC544\uB798\uC5D0 \uD589 \uCD94\uAC00",
16503
+ disabled: !state2.inTable,
16504
+ onSelect: () => chain()?.addRowAfter().run()
16505
+ }
16506
+ ),
16507
+ /* @__PURE__ */ jsxRuntime.jsx(
16508
+ TableMenuItem,
16509
+ {
16510
+ label: "\uC67C\uCABD\uC5D0 \uC5F4 \uCD94\uAC00",
16511
+ disabled: !state2.inTable,
16512
+ onSelect: () => chain()?.addColumnBefore().run()
16513
+ }
16514
+ ),
16515
+ /* @__PURE__ */ jsxRuntime.jsx(
16516
+ TableMenuItem,
16517
+ {
16518
+ label: "\uC624\uB978\uCABD\uC5D0 \uC5F4 \uCD94\uAC00",
16519
+ disabled: !state2.inTable,
16520
+ onSelect: () => chain()?.addColumnAfter().run()
16521
+ }
16522
+ ),
16523
+ /* @__PURE__ */ jsxRuntime.jsx(RDropdown2__namespace.Separator, { className: menuSeparatorClass }),
16524
+ /* @__PURE__ */ jsxRuntime.jsx(
16525
+ TableMenuItem,
16526
+ {
16527
+ label: "\uC140 \uBCD1\uD569",
16528
+ disabled: !state2.canMergeCells,
16529
+ onSelect: () => chain()?.mergeCells().run()
16530
+ }
16531
+ ),
16532
+ /* @__PURE__ */ jsxRuntime.jsx(
16533
+ TableMenuItem,
16534
+ {
16535
+ label: "\uBCD1\uD569 \uD574\uC81C",
16536
+ disabled: !state2.canSplitCell,
16537
+ onSelect: () => chain()?.splitCell().run()
16538
+ }
16539
+ ),
16540
+ /* @__PURE__ */ jsxRuntime.jsx(
16541
+ TableMenuItem,
16542
+ {
16543
+ label: "\uD5E4\uB354 \uD589 \uD1A0\uAE00",
16544
+ disabled: !state2.inTable,
16545
+ onSelect: () => chain()?.toggleHeaderRow().run()
16546
+ }
16547
+ ),
16548
+ /* @__PURE__ */ jsxRuntime.jsx(
16549
+ TableMenuItem,
16550
+ {
16551
+ label: "\uD5E4\uB354 \uC5F4 \uD1A0\uAE00",
16552
+ disabled: !state2.inTable,
16553
+ onSelect: () => chain()?.toggleHeaderColumn().run()
16554
+ }
16555
+ ),
16556
+ /* @__PURE__ */ jsxRuntime.jsx(RDropdown2__namespace.Separator, { className: menuSeparatorClass }),
16557
+ /* @__PURE__ */ jsxRuntime.jsx(
16558
+ TableMenuItem,
16559
+ {
16560
+ label: "\uD589 \uC0AD\uC81C",
16561
+ disabled: !state2.inTable,
16562
+ onSelect: () => chain()?.deleteRow().run()
16563
+ }
16564
+ ),
16565
+ /* @__PURE__ */ jsxRuntime.jsx(
16566
+ TableMenuItem,
16567
+ {
16568
+ label: "\uC5F4 \uC0AD\uC81C",
16569
+ disabled: !state2.inTable,
16570
+ onSelect: () => chain()?.deleteColumn().run()
16571
+ }
16572
+ ),
16573
+ /* @__PURE__ */ jsxRuntime.jsx(
16574
+ TableMenuItem,
16575
+ {
16576
+ label: "\uD45C \uC0AD\uC81C",
16577
+ disabled: !state2.inTable,
16578
+ onSelect: () => chain()?.deleteTable().run()
16579
+ }
16580
+ )
16581
+ ] }) })
16582
+ ]
16583
+ },
16584
+ item
16585
+ );
16420
16586
  case "undo":
16421
16587
  return /* @__PURE__ */ jsxRuntime.jsx(
16422
16588
  ToolbarButton,
@@ -16453,7 +16619,6 @@ function EditorToolbarBar({
16453
16619
  if (mobileView !== "main") {
16454
16620
  const editing = {
16455
16621
  color: { icon: /* @__PURE__ */ jsxRuntime.jsx(IconTextColor, { size: ICON_SIZE }), label: "\uAE00\uC790\uC0C9" },
16456
- highlight: { icon: /* @__PURE__ */ jsxRuntime.jsx(IconHighlight, { size: ICON_SIZE }), label: "\uD615\uAD11\uD39C" },
16457
16622
  link: { icon: /* @__PURE__ */ jsxRuntime.jsx(IconLink, { size: ICON_SIZE }), label: "\uB9C1\uD06C" }
16458
16623
  }[mobileView];
16459
16624
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ...shell, children: [
@@ -16469,7 +16634,7 @@ function EditorToolbarBar({
16469
16634
  ]
16470
16635
  }
16471
16636
  ) }),
16472
- /* @__PURE__ */ jsxRuntime.jsx(Separator, {}),
16637
+ /* @__PURE__ */ jsxRuntime.jsx(Separator2, {}),
16473
16638
  mobileView === "link" ? /* @__PURE__ */ jsxRuntime.jsx(
16474
16639
  LinkEditor,
16475
16640
  {
@@ -16482,18 +16647,18 @@ function EditorToolbarBar({
16482
16647
  ) : /* @__PURE__ */ jsxRuntime.jsx(
16483
16648
  ColorPalette,
16484
16649
  {
16485
- colors: mobileView === "color" ? colors : highlights,
16486
- columns: mobileView === "color" ? 4 : 3,
16487
- clearLabel: mobileView === "color" ? "\uC0C9 \uC9C0\uC6B0\uAE30" : "\uD615\uAD11\uD39C \uC9C0\uC6B0\uAE30",
16488
- onPick: mobileView === "color" ? applyColor : applyHighlight,
16489
- onClear: mobileView === "color" ? clearColor : clearHighlight
16650
+ colors: SEDITOR_DEFAULT_COLORS,
16651
+ columns: 4,
16652
+ clearLabel: "\uC0C9 \uC9C0\uC6B0\uAE30",
16653
+ onPick: applyColor,
16654
+ onClear: clearColor
16490
16655
  }
16491
16656
  )
16492
16657
  ] });
16493
16658
  }
16494
16659
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ...shell, children: [
16495
16660
  groups.map((group, index) => /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
16496
- index > 0 && /* @__PURE__ */ jsxRuntime.jsx(Separator, {}),
16661
+ index > 0 && /* @__PURE__ */ jsxRuntime.jsx(Separator2, {}),
16497
16662
  /* @__PURE__ */ jsxRuntime.jsx(
16498
16663
  "div",
16499
16664
  {
@@ -16566,16 +16731,12 @@ var EditorBody = /* @__PURE__ */ react.forwardRef(function EditorBody2({
16566
16731
  onFocusChange,
16567
16732
  onReady,
16568
16733
  placeholder,
16569
- typography,
16570
16734
  editable,
16571
16735
  disabled,
16572
16736
  minHeight,
16573
16737
  maxHeight,
16574
16738
  toolbar,
16575
16739
  bubbleMenu,
16576
- fontSizes,
16577
- colors,
16578
- highlights,
16579
16740
  onImageUpload,
16580
16741
  editorClass,
16581
16742
  editorStyle
@@ -16584,12 +16745,8 @@ var EditorBody = /* @__PURE__ */ react.forwardRef(function EditorBody2({
16584
16745
  placeholderRef.current = placeholder;
16585
16746
  const handlers = react.useRef({ onInput, onFocusChange });
16586
16747
  handlers.current = { onInput, onFocusChange };
16587
- const typographyRef = react.useRef(typography);
16588
16748
  const extensions = react.useMemo(
16589
- () => api.createExtensions({
16590
- getPlaceholder: () => placeholderRef.current,
16591
- typography: typographyRef.current
16592
- }),
16749
+ () => api.createExtensions({ getPlaceholder: () => placeholderRef.current }),
16593
16750
  [api]
16594
16751
  );
16595
16752
  const editor = api.useEditor({
@@ -16637,28 +16794,22 @@ var EditorBody = /* @__PURE__ */ react.forwardRef(function EditorBody2({
16637
16794
  [editor, htmlRef]
16638
16795
  );
16639
16796
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16640
- toolbar !== false && toolbar.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
16797
+ toolbar.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
16641
16798
  EditorToolbar,
16642
16799
  {
16643
16800
  api,
16644
16801
  editor,
16645
16802
  items: toolbar,
16646
- fontSizes,
16647
- colors,
16648
- highlights,
16649
16803
  onImageUpload,
16650
16804
  disabled: !editable
16651
16805
  }
16652
16806
  ),
16653
- bubbleMenu !== false && bubbleMenu.length > 0 && editable && /* @__PURE__ */ jsxRuntime.jsx(
16807
+ bubbleMenu.length > 0 && editable && /* @__PURE__ */ jsxRuntime.jsx(
16654
16808
  EditorBubbleMenu,
16655
16809
  {
16656
16810
  api,
16657
16811
  editor,
16658
16812
  items: bubbleMenu,
16659
- fontSizes,
16660
- colors,
16661
- highlights,
16662
16813
  onImageUpload,
16663
16814
  disabled: false
16664
16815
  }
@@ -16687,10 +16838,8 @@ var importTiptap = async () => {
16687
16838
  textAlign,
16688
16839
  textStyle,
16689
16840
  list,
16690
- highlight,
16691
16841
  image,
16692
- superscript,
16693
- subscript,
16842
+ table,
16694
16843
  typography,
16695
16844
  extensions
16696
16845
  ] = await Promise.all([
@@ -16700,17 +16849,12 @@ var importTiptap = async () => {
16700
16849
  import('@tiptap/extension-text-align'),
16701
16850
  import('@tiptap/extension-text-style'),
16702
16851
  import('@tiptap/extension-list'),
16703
- import('@tiptap/extension-highlight'),
16704
16852
  import('@tiptap/extension-image'),
16705
- import('@tiptap/extension-superscript'),
16706
- import('@tiptap/extension-subscript'),
16853
+ import('@tiptap/extension-table'),
16707
16854
  import('@tiptap/extension-typography'),
16708
16855
  import('@tiptap/extensions')
16709
16856
  ]);
16710
- const createExtensions = ({
16711
- getPlaceholder,
16712
- typography: withTypography
16713
- }) => [
16857
+ const createExtensions = ({ getPlaceholder }) => [
16714
16858
  starterKit.default.configure({
16715
16859
  heading: { levels: [...SEDITOR_HEADING_LEVELS] },
16716
16860
  link: {
@@ -16727,14 +16871,24 @@ var importTiptap = async () => {
16727
16871
  textAlign.default.configure({ types: ["heading", "paragraph"] }),
16728
16872
  list.TaskList.configure({ HTMLAttributes: { class: TASK_LIST_CLASS } }),
16729
16873
  list.TaskItem.configure({ nested: true, HTMLAttributes: { class: TASK_ITEM_CLASS } }),
16730
- highlight.default.configure({ multicolor: true }),
16731
16874
  // base64 를 막는다 — 본문 HTML 에 수 MB 짜리 data URI 가 박히면 그대로 DB·API 로 실려 간다.
16732
16875
  // 이미지는 onImageUpload 가 돌려준 URL 로만 들어온다.
16733
16876
  image.default.configure({ allowBase64: false, HTMLAttributes: { class: IMAGE_CLASS } }),
16734
- superscript.default,
16735
- subscript.default,
16877
+ /**
16878
+ * 표 — 열 너비는 **고정(균등)** 이다.
16879
+ *
16880
+ * `resizable` 을 켜면 열 경계를 끌어 폭을 정할 수 있지만 그 값이 저장 HTML 에
16881
+ * `colwidth` 로 px 단위로 박힌다. 작성한 화면보다 좁은 곳에서 다시 보여 줄 때 표가
16882
+ * 넘치고, 화면 폭이 제각각인 소비 앱에서는 되돌릴 방법이 없다. 대신 본문 스타일이
16883
+ * `table-layout: fixed` 로 열을 균등하게 나눠 어떤 폭에서도 표가 상자 안에 남는다.
16884
+ */
16885
+ table.Table.configure({ resizable: false, HTMLAttributes: { class: TABLE_CLASS } }),
16886
+ table.TableRow.configure({ HTMLAttributes: { class: TABLE_ROW_CLASS } }),
16887
+ table.TableHeader.configure({ HTMLAttributes: { class: TABLE_HEADER_CLASS } }),
16888
+ table.TableCell.configure({ HTMLAttributes: { class: TABLE_CELL_CLASS } }),
16736
16889
  extensions.Placeholder.configure({ placeholder: () => getPlaceholder() }),
16737
- ...withTypography ? [typography.default] : []
16890
+ // 따옴표·하이픈·화살표 자동 치환 (`"` → `“”`, `--` → `—`, `->` → `→`)
16891
+ typography.default
16738
16892
  ];
16739
16893
  return {
16740
16894
  useEditor: react.useEditor,
@@ -16787,13 +16941,8 @@ var SEditor = /* @__PURE__ */ react.forwardRef(function SEditor2({
16787
16941
  placeholder = "\uB0B4\uC6A9\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694.",
16788
16942
  minHeight = 200,
16789
16943
  maxHeight,
16790
- toolbar = SEDITOR_DEFAULT_TOOLBAR,
16791
- bubbleMenu = SEDITOR_DEFAULT_BUBBLE_MENU,
16792
- fontSizes = [...SEDITOR_FONT_SIZES],
16793
- colors = SEDITOR_DEFAULT_COLORS,
16794
- highlights = SEDITOR_DEFAULT_HIGHLIGHTS,
16944
+ simple = false,
16795
16945
  onImageUpload,
16796
- typography = false,
16797
16946
  rules,
16798
16947
  status,
16799
16948
  focused,
@@ -16885,7 +17034,8 @@ var SEditor = /* @__PURE__ */ react.forwardRef(function SEditor2({
16885
17034
  const resolvedError = error || ruleError !== "";
16886
17035
  const resolvedErrorMessage = ruleError !== "" ? ruleError : errorMessage;
16887
17036
  const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
16888
- const hasToolbar = toolbar !== false && toolbar.length > 0;
17037
+ const resolvedToolbar = simple ? SEDITOR_SIMPLE_TOOLBAR : SEDITOR_DEFAULT_TOOLBAR;
17038
+ const resolvedBubbleMenu = simple ? SEDITOR_SIMPLE_BUBBLE_MENU : SEDITOR_DEFAULT_BUBBLE_MENU;
16889
17039
  return /* @__PURE__ */ jsxRuntime.jsx(
16890
17040
  SField,
16891
17041
  {
@@ -16910,19 +17060,15 @@ var SEditor = /* @__PURE__ */ react.forwardRef(function SEditor2({
16910
17060
  multiline: true,
16911
17061
  className,
16912
17062
  style,
16913
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 flex-1 flex-col", children: api === null ? (
17063
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 flex-1 flex-col bg-inherit", children: api === null ? (
16914
17064
  // 엔진을 불러오는 동안의 자리 — 툴바 높이와 본문 상자를 그대로 잡아 둔다
16915
17065
  /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16916
- hasToolbar && // 진짜 툴바를 잠긴 채로 그린다 — 버튼 개수·줄바꿈이 같아야 엔진이 붙어도 안 밀린다
16917
17066
  /* @__PURE__ */ jsxRuntime.jsx(
16918
17067
  EditorToolbarBar,
16919
17068
  {
16920
17069
  state: IDLE_TOOLBAR_STATE,
16921
17070
  editor: null,
16922
- items: toolbar,
16923
- fontSizes,
16924
- colors,
16925
- highlights,
17071
+ items: resolvedToolbar,
16926
17072
  onImageUpload,
16927
17073
  disabled: true
16928
17074
  }
@@ -16949,16 +17095,12 @@ var SEditor = /* @__PURE__ */ react.forwardRef(function SEditor2({
16949
17095
  onFocusChange: handleFocusChange,
16950
17096
  onReady: handleReady,
16951
17097
  placeholder,
16952
- typography,
16953
17098
  editable,
16954
17099
  disabled,
16955
17100
  minHeight,
16956
17101
  maxHeight,
16957
- toolbar,
16958
- bubbleMenu,
16959
- fontSizes,
16960
- colors,
16961
- highlights,
17102
+ toolbar: resolvedToolbar,
17103
+ bubbleMenu: resolvedBubbleMenu,
16962
17104
  onImageUpload,
16963
17105
  editorClass,
16964
17106
  editorStyle
@@ -17040,9 +17182,9 @@ var todayIso = () => {
17040
17182
  const pad = (n) => String(n).padStart(2, "0");
17041
17183
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
17042
17184
  };
17043
- var isInlineDateField = (field) => field.type === "date" && field.radioButton === true && (field.presets?.length ?? 0) > 0;
17185
+ var isInlineDateField = (field) => field.type === "datepicker-range" && field.radioButton === true && (field.presets?.length ?? 0) > 0;
17044
17186
  var getFieldPresets = (field) => {
17045
- if (field.type === "period") return field.presets ?? DEFAULT_PERIOD_PRESETS;
17187
+ if (field.type === "datepicker-statistics") return field.presets ?? DEFAULT_PERIOD_PRESETS;
17046
17188
  return field.presets ?? [];
17047
17189
  };
17048
17190
  var getDefaultPeriodInputValue = (unit) => {
@@ -17059,12 +17201,16 @@ var createPeriodValue = (unit) => ({
17059
17201
  value: getDefaultPeriodInputValue(unit)
17060
17202
  });
17061
17203
  var resolveFieldDefault = (field) => {
17062
- if (field.defaultValue !== void 0) return field.defaultValue;
17063
- if (field.type === "date")
17064
- return isInlineDateField(field) || field.required ? todayIso() : void 0;
17204
+ if (field.defaultValue !== void 0 && isFixedField(field)) return field.defaultValue;
17205
+ if (field.type === "datepicker-range") {
17206
+ if (!isInlineDateField(field) && !field.required) return void 0;
17207
+ const today = todayIso();
17208
+ return [today, today];
17209
+ }
17065
17210
  if (!field.required) return void 0;
17066
- if (field.type === "single") return field.options?.[0]?.value;
17067
- if (field.type === "period") {
17211
+ if (field.type === "datepicker-day") return todayIso();
17212
+ if (field.type === "select") return field.options?.[0]?.value;
17213
+ if (field.type === "datepicker-statistics") {
17068
17214
  const unit = getFieldPresets(field).find((preset) => !preset.custom)?.value;
17069
17215
  return unit ? createPeriodValue(unit) : void 0;
17070
17216
  }
@@ -17086,9 +17232,10 @@ var valuesMapEqual = (a, b) => {
17086
17232
  }
17087
17233
  return true;
17088
17234
  };
17235
+ var fieldValuesEqual = (field, a, b) => field.type === "datepicker-range" ? sameDateValue(a, b) : valuesEqual(a, b);
17089
17236
  var isAtDefaultValue = (field, value) => {
17090
17237
  const def = resolveFieldDefault(field);
17091
- return def !== void 0 && valuesEqual(value, def);
17238
+ return def !== void 0 && fieldValuesEqual(field, value, def);
17092
17239
  };
17093
17240
  var resetTargetValue = (field) => {
17094
17241
  const def = resolveFieldDefault(field);
@@ -17097,7 +17244,7 @@ var resetTargetValue = (field) => {
17097
17244
  var isAtResetTarget = (field, value) => {
17098
17245
  const target = resetTargetValue(field);
17099
17246
  if (isEmptyValue(value) && isEmptyValue(target)) return true;
17100
- return valuesEqual(value, target);
17247
+ return fieldValuesEqual(field, value, target);
17101
17248
  };
17102
17249
  var isInlineField = (field) => isInlineDateField(field) || field.type === "custom";
17103
17250
  var isFixedField = (field) => field.fixed === true || field.required === true;
@@ -17125,17 +17272,19 @@ var defaultGroupTooltipMessage = (rule, fields) => {
17125
17272
  const label = fields.find((f) => f.key === rule.key)?.label ?? "\uD56D\uBAA9";
17126
17273
  return `${label}${koreanParticle(label, "\uC744", "\uB97C")} \uC120\uD0DD\uD574 \uC8FC\uC138\uC694.`;
17127
17274
  };
17275
+ var toDateRange = (value) => Array.isArray(value) ? [value[0], value[1]] : [value, value];
17276
+ var sameDateValue = (a, b) => {
17277
+ const [aStart, aEnd] = toDateRange(a);
17278
+ const [bStart, bEnd] = toDateRange(b);
17279
+ return aStart === bStart && aEnd === bEnd;
17280
+ };
17128
17281
  var matchPresetId = (presets, value) => {
17129
17282
  if (isEmptyValue(value)) return null;
17130
17283
  if (isPeriodValue(value)) return value.unit;
17131
17284
  for (const preset of presets) {
17132
17285
  if (preset.custom) continue;
17133
17286
  const resolved = preset.resolve ? preset.resolve() : preset.value;
17134
- if (Array.isArray(resolved) && Array.isArray(value)) {
17135
- if (resolved[0] === value[0] && resolved[1] === value[1]) return preset.value;
17136
- } else if (!Array.isArray(resolved) && !Array.isArray(value) && resolved === value) {
17137
- return preset.value;
17138
- }
17287
+ if (sameDateValue(resolved, value)) return preset.value;
17139
17288
  }
17140
17289
  return presets.find((preset) => preset.custom)?.value ?? null;
17141
17290
  };
@@ -17146,7 +17295,7 @@ var formatValueList = (labels) => {
17146
17295
  };
17147
17296
  var displayValue = (field, value) => {
17148
17297
  if (isEmptyValue(value)) return "";
17149
- if (field.type === "multi") {
17298
+ if (field.type === "select-multi") {
17150
17299
  const values = toArrayValue(value);
17151
17300
  const selectableValues = (field.options ?? []).filter((option) => !option.disabled).map((option) => option.value);
17152
17301
  if (selectableValues.length > 0 && selectableValues.every((selectableValue) => values.includes(selectableValue))) {
@@ -17154,10 +17303,12 @@ var displayValue = (field, value) => {
17154
17303
  }
17155
17304
  return formatValueList(values.map((v) => optionLabel(field, v)));
17156
17305
  }
17157
- if (field.type === "single") return optionLabel(field, value);
17158
- if (field.type === "date")
17159
- return Array.isArray(value) ? `${value[0]} ~ ${value[1]}` : String(value);
17160
- if (field.type === "period") {
17306
+ if (field.type === "select") return optionLabel(field, value);
17307
+ if (field.type === "datepicker-day" || field.type === "datepicker-range") {
17308
+ if (!Array.isArray(value)) return String(value);
17309
+ return value[0] === value[1] ? String(value[0]) : `${value[0]} ~ ${value[1]}`;
17310
+ }
17311
+ if (field.type === "datepicker-statistics") {
17161
17312
  if (!isPeriodValue(value)) {
17162
17313
  const preset2 = getFieldPresets(field).find((p) => p.value === value);
17163
17314
  return preset2?.label ?? String(value);
@@ -17174,7 +17325,7 @@ var displayValue = (field, value) => {
17174
17325
  };
17175
17326
  var chipDisplayValue = (field, value) => {
17176
17327
  const text = displayValue(field, value);
17177
- if (field.type !== "date" || isEmptyValue(value)) return text;
17328
+ if (field.type !== "datepicker-range" || isEmptyValue(value)) return text;
17178
17329
  const presets = getFieldPresets(field);
17179
17330
  if (presets.length === 0) return text;
17180
17331
  const preset = presets.find((p) => p.value === matchPresetId(presets, value));
@@ -17265,6 +17416,14 @@ var SChipFilter = /* @__PURE__ */ react.forwardRef(function SChipFilter2({
17265
17416
  });
17266
17417
  if (changed) onValueChange?.({ ...values, ...patch });
17267
17418
  }, [fields, values, onValueChange]);
17419
+ if (typeof console !== "undefined") {
17420
+ const misused = fields.filter((f) => f.defaultValue !== void 0 && !isFixedField(f));
17421
+ if (misused.length > 0) {
17422
+ console.warn(
17423
+ `[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(", ")})`
17424
+ );
17425
+ }
17426
+ }
17268
17427
  const fixedKeys = fields.filter(isFixedField).map((field) => field.key);
17269
17428
  const resolvedActiveKeys = Array.from(
17270
17429
  /* @__PURE__ */ new Set([...activeKeys ?? internalActiveKeys, ...fixedKeys])
@@ -17286,7 +17445,7 @@ var SChipFilter = /* @__PURE__ */ react.forwardRef(function SChipFilter2({
17286
17445
  if (currentOpenField?.type === "keyword") {
17287
17446
  return { width: CHIPFILTER_LISTBOX_WIDTH };
17288
17447
  }
17289
- if ((currentOpenField?.type === "date" || currentOpenField?.type === "period") && getFieldPresets(currentOpenField).length > 0) {
17448
+ if ((currentOpenField?.type === "datepicker-range" || currentOpenField?.type === "datepicker-statistics") && getFieldPresets(currentOpenField).length > 0) {
17290
17449
  return { width: CHIPFILTER_DATE_PRESET_LISTBOX_WIDTH };
17291
17450
  }
17292
17451
  return { width: CHIPFILTER_LISTBOX_WIDTH };
@@ -17422,7 +17581,7 @@ var SChipFilter = /* @__PURE__ */ react.forwardRef(function SChipFilter2({
17422
17581
  }
17423
17582
  clearValue(field.key);
17424
17583
  };
17425
- const node = field.type === "date" && isInlineDateField(field) ? /* @__PURE__ */ jsxRuntime.jsx(
17584
+ const node = field.type === "datepicker-range" && isInlineDateField(field) ? /* @__PURE__ */ jsxRuntime.jsx(
17426
17585
  InlineDatePresetFilter,
17427
17586
  {
17428
17587
  field,
@@ -17733,8 +17892,8 @@ function EditorPanel({
17733
17892
  onValueCommit,
17734
17893
  onClose
17735
17894
  }) {
17736
- const wrapsInPaddedTop = field.type === "date" || field.type === "period";
17737
- const isMulti = field.type === "multi";
17895
+ const wrapsInPaddedTop = field.type === "datepicker-day" || field.type === "datepicker-range" || field.type === "datepicker-statistics";
17896
+ const isMulti = field.type === "select-multi";
17738
17897
  const selectableValues = isMulti ? (field.options ?? []).filter((option) => !option.disabled).map((option) => option.value) : [];
17739
17898
  const selectedValues = isMulti ? toArrayValue(value) : [];
17740
17899
  const allSelected = isMulti && selectableValues.length > 0 && selectableValues.every((v) => selectedValues.includes(v));
@@ -17815,7 +17974,7 @@ function FilterEditor({
17815
17974
  onValueChange,
17816
17975
  onValueCommit
17817
17976
  }) {
17818
- if (field.type === "period") {
17977
+ if (field.type === "datepicker-statistics") {
17819
17978
  return /* @__PURE__ */ jsxRuntime.jsx(
17820
17979
  PeriodPresetEditor,
17821
17980
  {
@@ -17826,7 +17985,21 @@ function FilterEditor({
17826
17985
  }
17827
17986
  );
17828
17987
  }
17829
- if (field.type === "date") {
17988
+ if (field.type === "datepicker-day") {
17989
+ return /* @__PURE__ */ jsxRuntime.jsx(
17990
+ SDatePicker,
17991
+ {
17992
+ value: typeof value === "string" ? value : null,
17993
+ onValueChange,
17994
+ selectable: field.selectable,
17995
+ disabled,
17996
+ placeholder: field.placeholder,
17997
+ width: "100%",
17998
+ maxWidth: "100%"
17999
+ }
18000
+ );
18001
+ }
18002
+ if (field.type === "datepicker-range") {
17830
18003
  return /* @__PURE__ */ jsxRuntime.jsx(
17831
18004
  DatePresetEditor,
17832
18005
  {
@@ -17853,8 +18026,8 @@ function FilterEditor({
17853
18026
  OptionList,
17854
18027
  {
17855
18028
  field,
17856
- value: field.type === "multi" ? toArrayValue(value) : value,
17857
- multiple: field.type === "multi",
18029
+ value: field.type === "select-multi" ? toArrayValue(value) : value,
18030
+ multiple: field.type === "select-multi",
17858
18031
  disabled,
17859
18032
  onValueChange
17860
18033
  }
@@ -17879,17 +18052,16 @@ function DatePresetEditor({
17879
18052
  setSelectedId(preset.value);
17880
18053
  if (!preset.custom) onValueChange(preset.resolve ? preset.resolve() : preset.value);
17881
18054
  };
17882
- if (field.type === "date" && presets.length === 0) {
18055
+ if (presets.length === 0) {
17883
18056
  return /* @__PURE__ */ jsxRuntime.jsx(
17884
- SDatePicker,
18057
+ SDateRangePicker,
17885
18058
  {
17886
- value: typeof value === "string" ? value : null,
18059
+ value: Array.isArray(value) && value.length === 2 ? value : null,
17887
18060
  onValueChange,
17888
18061
  selectable: field.selectable,
18062
+ maxRange: field.maxRange,
17889
18063
  disabled,
17890
- placeholder: field.placeholder,
17891
- width: "100%",
17892
- maxWidth: "100%"
18064
+ width: "100%"
17893
18065
  }
17894
18066
  );
17895
18067
  }
@@ -20036,15 +20208,9 @@ exports.SDraggableList = SDraggableList;
20036
20208
  exports.SDraggableProvider = SDraggableProvider;
20037
20209
  exports.SDrawer = SDrawer;
20038
20210
  exports.SDropdownButton = SDropdownButton2;
20039
- exports.SEDITOR_DEFAULT_BUBBLE_MENU = SEDITOR_DEFAULT_BUBBLE_MENU;
20040
- exports.SEDITOR_DEFAULT_COLORS = SEDITOR_DEFAULT_COLORS;
20041
20211
  exports.SEDITOR_DEFAULT_FONT_SIZE = SEDITOR_DEFAULT_FONT_SIZE;
20042
- exports.SEDITOR_DEFAULT_HIGHLIGHTS = SEDITOR_DEFAULT_HIGHLIGHTS;
20043
- exports.SEDITOR_DEFAULT_TOOLBAR = SEDITOR_DEFAULT_TOOLBAR;
20044
- exports.SEDITOR_FONT_SIZES = SEDITOR_FONT_SIZES;
20045
20212
  exports.SEDITOR_HEADING_LABELS = SEDITOR_HEADING_LABELS;
20046
20213
  exports.SEDITOR_HEADING_LEVELS = SEDITOR_HEADING_LEVELS;
20047
- exports.SEDITOR_TOOLBAR_ITEMS = SEDITOR_TOOLBAR_ITEMS;
20048
20214
  exports.SEditor = SEditor;
20049
20215
  exports.SExpansionItem = SExpansionItem;
20050
20216
  exports.SExpansionList = SExpansionList2;