sellmate-design-system-react 9.0.0-beta.5 → 9.0.0-beta.7

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
@@ -5,7 +5,7 @@ import { forwardRef, useState, useRef, useEffect, createContext, useContext, use
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
6
  import { createPortal } from 'react-dom';
7
7
  import * as RCheckbox from '@radix-ui/react-checkbox';
8
- import * as RPopover9 from '@radix-ui/react-popover';
8
+ import * as RPopover10 from '@radix-ui/react-popover';
9
9
  import { createRoot } from 'react-dom/client';
10
10
  import * as RTooltip from '@radix-ui/react-tooltip';
11
11
  import * as RDropdown from '@radix-ui/react-dropdown-menu';
@@ -3417,7 +3417,7 @@ var SDraggableItemView = /* @__PURE__ */ forwardRef(
3417
3417
  !disabled && !selected && !dragging && "hover:bg-(--cmp-listDraggableItem-bg-hover)",
3418
3418
  hasSupportingText && supportingTextPosition === "bottom" ? dense ? "min-h-[52px]" : "min-h-[60px]" : dense ? "h-[32px]" : "h-[40px]",
3419
3419
  paddingYClass,
3420
- // 항목 사이 구분선은 리스트가 그린다 — SDraggableList 의 separator (SList.tsx)
3420
+ // 항목 사이 구분선은 리스트가 그린다.
3421
3421
  bordered && cn(
3422
3422
  "rounded-(--cmp-listDraggableItem-radius-bordered) border border-(--cmp-listDraggableItem-border-default)",
3423
3423
  !disabled && !selected && !dragging && "hover:border-(--cmp-listDraggableItem-bordered-border-hover)",
@@ -3625,7 +3625,7 @@ var SDraggableItemImpl = /* @__PURE__ */ forwardRef(function SDraggableItem({
3625
3625
  ] });
3626
3626
  });
3627
3627
  var SDraggableItem2 = /* @__PURE__ */ withDisplayName(SDraggableItemImpl, "SDraggableItem");
3628
- var SListImpl = /* @__PURE__ */ forwardRef(function SList({ className, children, useGap = false, usePadding = false, separator = false, ...rest }, ref) {
3628
+ var SListImpl = /* @__PURE__ */ forwardRef(function SList({ className, children, useGap = false, usePadding = false, ...rest }, ref) {
3629
3629
  return /* @__PURE__ */ jsx(
3630
3630
  "div",
3631
3631
  {
@@ -3633,7 +3633,7 @@ var SListImpl = /* @__PURE__ */ forwardRef(function SList({ className, children,
3633
3633
  className: cn(
3634
3634
  useGap && "flex flex-col gap-(--cmp-list-group-gap)",
3635
3635
  usePadding && "p-(--cmp-list-group-padding)",
3636
- separator && "[&>*]:border-b [&>*]:border-(--cmp-listItem-border-default)",
3636
+ "[&>*]:border-b [&>*]:border-(--cmp-listItem-border-default)",
3637
3637
  className
3638
3638
  ),
3639
3639
  ...rest,
@@ -4005,7 +4005,7 @@ var SExpansionItem = /* @__PURE__ */ forwardRef(
4005
4005
  ref,
4006
4006
  className: cn(
4007
4007
  "group/expansion-item relative overflow-hidden bg-(--cmp-listExpansionItem-title-bg-default)",
4008
- // 항목 사이 구분선은 리스트가 그린다 — SList/SExpansionList 의 separator (SList.tsx)
4008
+ // 항목 사이 구분선은 리스트가 그린다.
4009
4009
  // 보더 색은 시맨틱 토큰(border-default → hover strong → 펼침 accentLight)을 쓴다.
4010
4010
  // TODO: expansionItem/bordered/radius 토큰 생성 후 rounded 고정값도 토큰으로 교체한다.
4011
4011
  bordered && "rounded-[8px] border border-border-default hover:border-border-strong [&:has(>button:hover)]:border-border-strong",
@@ -4557,8 +4557,8 @@ function SGhostButton({
4557
4557
  }
4558
4558
  );
4559
4559
  if (!hasTooltip) return btn;
4560
- return /* @__PURE__ */ jsxs(RPopover9.Root, { open, onOpenChange: setOpen, children: [
4561
- /* @__PURE__ */ jsx(RPopover9.Anchor, { asChild: true, children: /* @__PURE__ */ jsx(
4560
+ return /* @__PURE__ */ jsxs(RPopover10.Root, { open, onOpenChange: setOpen, children: [
4561
+ /* @__PURE__ */ jsx(RPopover10.Anchor, { asChild: true, children: /* @__PURE__ */ jsx(
4562
4562
  "span",
4563
4563
  {
4564
4564
  className: cn("inline-flex", anchorClassName),
@@ -4570,8 +4570,8 @@ function SGhostButton({
4570
4570
  children: btn
4571
4571
  }
4572
4572
  ) }),
4573
- /* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
4574
- RPopover9.Content,
4573
+ /* @__PURE__ */ jsx(RPopover10.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
4574
+ RPopover10.Content,
4575
4575
  {
4576
4576
  side: "top",
4577
4577
  sideOffset: 4,
@@ -4585,6 +4585,18 @@ function SGhostButton({
4585
4585
  ) })
4586
4586
  ] });
4587
4587
  }
4588
+ var TREE_LABEL_TYPOGRAPHY = {
4589
+ sm: {
4590
+ default: "typo-body-sm-medium",
4591
+ selected: "typo-body-sm-bold",
4592
+ rowHeight: "h-[28px]"
4593
+ },
4594
+ md: {
4595
+ default: "typo-body-md-medium",
4596
+ selected: "typo-body-md-bold",
4597
+ rowHeight: "h-[32px]"
4598
+ }
4599
+ };
4588
4600
  function collectIds(nodes) {
4589
4601
  return nodes.flatMap((node) => [node.id, ...collectIds(node.children ?? [])]);
4590
4602
  }
@@ -4595,18 +4607,19 @@ function collectSelectableIds(node) {
4595
4607
  function toSelectedSet(value) {
4596
4608
  return new Set(value ?? []);
4597
4609
  }
4598
- function getSelectionState(node, selectedSet) {
4599
- if (selectedSet.has(node.id)) {
4600
- return { selected: true, indeterminate: false };
4610
+ var TREE_ALL_NODE = { id: "__all__", label: "\uC804\uCCB4" };
4611
+ function getSelectionState(node, selectedSet, cascadeSelection) {
4612
+ if (!cascadeSelection) {
4613
+ return { selected: selectedSet.has(node.id), indeterminate: false };
4601
4614
  }
4602
4615
  const selectableChildren = (node.children ?? []).filter(
4603
4616
  (child) => collectSelectableIds(child).length > 0
4604
4617
  );
4605
4618
  if (selectableChildren.length === 0) {
4606
- return { selected: false, indeterminate: false };
4619
+ return { selected: selectedSet.has(node.id), indeterminate: false };
4607
4620
  }
4608
4621
  const childStates = selectableChildren.map(
4609
- (child) => getSelectionState(child, selectedSet)
4622
+ (child) => getSelectionState(child, selectedSet, cascadeSelection)
4610
4623
  );
4611
4624
  const selectedCount = childStates.filter((state2) => state2.selected).length;
4612
4625
  return {
@@ -4616,6 +4629,7 @@ function getSelectionState(node, selectedSet) {
4616
4629
  }
4617
4630
  function TreeConnector({
4618
4631
  guideline,
4632
+ size,
4619
4633
  depth,
4620
4634
  hasChildren,
4621
4635
  isLast,
@@ -4623,6 +4637,8 @@ function TreeConnector({
4623
4637
  }) {
4624
4638
  if (depth <= 1) return null;
4625
4639
  const ancestorConnectors = ancestorLast.slice(0, -1);
4640
+ const branchTop = size === "sm" ? "top-[13px]" : "top-[15px]";
4641
+ const nodeHeight = size === "sm" ? "h-[15px]" : "h-[17px]";
4626
4642
  return /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "flex self-stretch", children: [
4627
4643
  ancestorConnectors.map((last, index) => /* @__PURE__ */ jsx(
4628
4644
  "span",
@@ -4636,13 +4652,22 @@ function TreeConnector({
4636
4652
  /* @__PURE__ */ jsxs("span", { className: "relative block w-[20px] shrink-0", children: [
4637
4653
  guideline && !isLast && /* @__PURE__ */ jsx("span", { className: "absolute bottom-0 left-[6px] top-[-1px] w-px bg-(--cmp-tree-connector-line-color)" }),
4638
4654
  guideline && /* @__PURE__ */ jsxs(Fragment, { children: [
4639
- /* @__PURE__ */ jsx("span", { className: "absolute left-[6px] top-[-1px] h-[17px] w-px bg-(--cmp-tree-connector-line-color)" }),
4655
+ /* @__PURE__ */ jsx(
4656
+ "span",
4657
+ {
4658
+ className: cn(
4659
+ "absolute left-[6px] top-[-1px] w-px bg-(--cmp-tree-connector-line-color)",
4660
+ nodeHeight
4661
+ )
4662
+ }
4663
+ ),
4640
4664
  /* @__PURE__ */ jsx(
4641
4665
  "span",
4642
4666
  {
4643
4667
  "data-tree-connector-branch": hasChildren ? "parent" : "leaf",
4644
4668
  className: cn(
4645
- "absolute left-[6px] top-[15px] h-px bg-(--cmp-tree-connector-line-color)",
4669
+ "absolute left-[6px] h-px bg-(--cmp-tree-connector-line-color)",
4670
+ branchTop,
4646
4671
  hasChildren ? "w-[14px]" : "w-[calc(14px+var(--cmp-tree-item-arrow-icon))]"
4647
4672
  )
4648
4673
  }
@@ -4651,6 +4676,44 @@ function TreeConnector({
4651
4676
  ] })
4652
4677
  ] });
4653
4678
  }
4679
+ function STreeAllItem({
4680
+ selected,
4681
+ indeterminate,
4682
+ border,
4683
+ size,
4684
+ onSelect
4685
+ }) {
4686
+ const checkboxValue = indeterminate ? null : selected;
4687
+ const typography = TREE_LABEL_TYPOGRAPHY[size];
4688
+ const labelTypo = selected || indeterminate ? typography.selected : typography.default;
4689
+ return /* @__PURE__ */ jsx(
4690
+ "div",
4691
+ {
4692
+ role: "treeitem",
4693
+ "aria-level": 1,
4694
+ "aria-selected": selected,
4695
+ onClick: onSelect,
4696
+ className: cn(
4697
+ "group/tree-item box-border flex w-full cursor-pointer items-center overflow-hidden bg-(--cmp-tree-item-bg-default) px-(--cmp-tree-item-paddingX) text-left hover:bg-(--cmp-tree-item-bg-hover)",
4698
+ typography.rowHeight,
4699
+ border && "border-b border-(--cmp-tree-item-border-default)"
4700
+ ),
4701
+ children: /* @__PURE__ */ jsxs("div", { className: "box-border flex min-w-0 flex-1 items-center gap-(--cmp-tree-item-contentGap)", children: [
4702
+ /* @__PURE__ */ jsx("span", { onClick: (event) => event.stopPropagation(), className: "flex shrink-0", children: /* @__PURE__ */ jsx(SCheckbox, { value: checkboxValue, onValueChange: () => onSelect() }) }),
4703
+ /* @__PURE__ */ jsx(
4704
+ "span",
4705
+ {
4706
+ className: cn(
4707
+ "block min-w-0 flex-1 truncate py-(--cmp-tree-item-paddingY) text-(--cmp-tree-item-text-default)",
4708
+ labelTypo
4709
+ ),
4710
+ children: "\uC804\uCCB4"
4711
+ }
4712
+ )
4713
+ ] })
4714
+ }
4715
+ );
4716
+ }
4654
4717
  var STreeItemImpl = /* @__PURE__ */ forwardRef(function STreeItem({
4655
4718
  node,
4656
4719
  depth = 1,
@@ -4662,6 +4725,7 @@ var STreeItemImpl = /* @__PURE__ */ forwardRef(function STreeItem({
4662
4725
  border = true,
4663
4726
  indeterminate = false,
4664
4727
  selectable = true,
4728
+ size = "sm",
4665
4729
  leading,
4666
4730
  trailing,
4667
4731
  onToggle,
@@ -4673,6 +4737,7 @@ var STreeItemImpl = /* @__PURE__ */ forwardRef(function STreeItem({
4673
4737
  const renderState = {
4674
4738
  node,
4675
4739
  depth,
4740
+ size,
4676
4741
  expanded,
4677
4742
  selected,
4678
4743
  indeterminate,
@@ -4682,6 +4747,8 @@ var STreeItemImpl = /* @__PURE__ */ forwardRef(function STreeItem({
4682
4747
  const leadingNode = typeof leading === "function" ? leading(renderState) : leading;
4683
4748
  const trailingNode = typeof trailing === "function" ? trailing(renderState) : trailing;
4684
4749
  const checkboxValue = indeterminate ? null : selected;
4750
+ const typography = TREE_LABEL_TYPOGRAPHY[size];
4751
+ const labelTypo = selected || indeterminate ? typography.selected : typography.default;
4685
4752
  const handleSelect = (event) => {
4686
4753
  if (node.disabled) return;
4687
4754
  onTreeSelect?.(node, event);
@@ -4701,7 +4768,8 @@ var STreeItemImpl = /* @__PURE__ */ forwardRef(function STreeItem({
4701
4768
  "aria-disabled": node.disabled || void 0,
4702
4769
  onClick: handleRowClick,
4703
4770
  className: cn(
4704
- "group/tree-item box-border flex h-[32px] w-full items-center gap-(--cmp-tree-item-rowGap) overflow-hidden bg-(--cmp-tree-item-bg-default) px-(--cmp-tree-item-paddingX) text-left",
4771
+ "group/tree-item box-border flex w-full items-center gap-(--cmp-tree-item-rowGap) overflow-hidden bg-(--cmp-tree-item-bg-default) px-(--cmp-tree-item-paddingX) text-left",
4772
+ typography.rowHeight,
4705
4773
  border && "border-b border-(--cmp-tree-item-border-default)",
4706
4774
  !node.disabled && "hover:bg-(--cmp-tree-item-bg-hover)",
4707
4775
  node.disabled && "cursor-not-allowed opacity-60",
@@ -4714,13 +4782,14 @@ var STreeItemImpl = /* @__PURE__ */ forwardRef(function STreeItem({
4714
4782
  TreeConnector,
4715
4783
  {
4716
4784
  guideline,
4785
+ size,
4717
4786
  depth,
4718
4787
  hasChildren,
4719
4788
  isLast,
4720
4789
  ancestorLast
4721
4790
  }
4722
4791
  ),
4723
- /* @__PURE__ */ jsxs("div", { className: "box-border flex h-full min-w-0 flex-1 items-center gap-(--cmp-tree-item-contentGap) py-(--cmp-tree-item-paddingY)", children: [
4792
+ /* @__PURE__ */ jsxs("div", { className: "box-border flex min-w-0 flex-1 items-center gap-(--cmp-tree-item-contentGap)", children: [
4724
4793
  hasChildren ? /* @__PURE__ */ jsx(
4725
4794
  SGhostButton,
4726
4795
  {
@@ -4762,8 +4831,8 @@ var STreeItemImpl = /* @__PURE__ */ forwardRef(function STreeItem({
4762
4831
  if (!node.disabled && selectable) onTreeSelect?.(node, event);
4763
4832
  },
4764
4833
  className: cn(
4765
- "block min-w-0 flex-1 truncate text-[14px] leading-[24px]",
4766
- selected || indeterminate ? "font-bold text-(--cmp-tree-item-text-selected)" : "font-medium text-(--cmp-tree-item-text-default)",
4834
+ "block min-w-0 flex-1 truncate py-(--cmp-tree-item-paddingY) text-(--cmp-tree-item-text-default)",
4835
+ labelTypo,
4767
4836
  node.disabled ? "cursor-not-allowed" : selectable ? "cursor-pointer" : void 0
4768
4837
  ),
4769
4838
  children: node.label
@@ -4783,6 +4852,8 @@ var STreeImpl = /* @__PURE__ */ forwardRef(function STree({
4783
4852
  expandedIds,
4784
4853
  defaultExpandedIds,
4785
4854
  selectable = true,
4855
+ size = "sm",
4856
+ useAll = false,
4786
4857
  cascadeSelection = true,
4787
4858
  guideline = true,
4788
4859
  border = true,
@@ -4801,6 +4872,11 @@ var STreeImpl = /* @__PURE__ */ forwardRef(function STree({
4801
4872
  const currentExpandedIds = expandedIds ?? internalExpandedIds;
4802
4873
  const selectedSet = useMemo(() => toSelectedSet(currentValue), [currentValue]);
4803
4874
  const expandedSet = useMemo(() => new Set(currentExpandedIds), [currentExpandedIds]);
4875
+ const selectableIds = useMemo(() => items.flatMap(collectSelectableIds), [items]);
4876
+ const allSelected = selectableIds.length > 0 && selectableIds.every((id) => selectedSet.has(id));
4877
+ const someSelected = selectableIds.some((id) => selectedSet.has(id));
4878
+ const allIndeterminate = someSelected && !allSelected;
4879
+ const showAllItem = selectable && useAll;
4804
4880
  const updateExpanded = (node) => {
4805
4881
  const next = new Set(currentExpandedIds);
4806
4882
  if (next.has(node.id)) next.delete(node.id);
@@ -4812,7 +4888,7 @@ var STreeImpl = /* @__PURE__ */ forwardRef(function STree({
4812
4888
  const updateSelected = (node) => {
4813
4889
  if (node.disabled) return;
4814
4890
  const targetIds = cascadeSelection ? collectSelectableIds(node) : [node.id];
4815
- const everySelected = getSelectionState(node, selectedSet).selected;
4891
+ const everySelected = getSelectionState(node, selectedSet, cascadeSelection).selected;
4816
4892
  const next = new Set(selectedSet);
4817
4893
  targetIds.forEach((id) => {
4818
4894
  if (everySelected) next.delete(id);
@@ -4822,10 +4898,22 @@ var STreeImpl = /* @__PURE__ */ forwardRef(function STree({
4822
4898
  if (value === void 0) setInternalValue(orderedIds);
4823
4899
  onValueChange?.(orderedIds, node);
4824
4900
  };
4901
+ const updateAllSelected = (event) => {
4902
+ event?.stopPropagation();
4903
+ if (selectableIds.length === 0) return;
4904
+ const next = new Set(selectedSet);
4905
+ selectableIds.forEach((id) => {
4906
+ if (allSelected) next.delete(id);
4907
+ else next.add(id);
4908
+ });
4909
+ const orderedIds = collectIds(items).filter((id) => next.has(id));
4910
+ if (value === void 0) setInternalValue(orderedIds);
4911
+ onValueChange?.(orderedIds, TREE_ALL_NODE);
4912
+ };
4825
4913
  const renderNodes = (nodes, depth = 1, ancestorLast = []) => nodes.map((node, index) => {
4826
4914
  const isLast = index === nodes.length - 1;
4827
4915
  const isExpanded = expandedSet.has(node.id);
4828
- const { selected, indeterminate } = getSelectionState(node, selectedSet);
4916
+ const { selected, indeterminate } = getSelectionState(node, selectedSet, cascadeSelection);
4829
4917
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [
4830
4918
  /* @__PURE__ */ jsx(
4831
4919
  STreeItem2,
@@ -4838,6 +4926,7 @@ var STreeImpl = /* @__PURE__ */ forwardRef(function STree({
4838
4926
  selected,
4839
4927
  indeterminate,
4840
4928
  selectable,
4929
+ size,
4841
4930
  guideline,
4842
4931
  border,
4843
4932
  leading,
@@ -4859,14 +4948,26 @@ var STreeImpl = /* @__PURE__ */ forwardRef(function STree({
4859
4948
  ) : null
4860
4949
  ] }, node.id);
4861
4950
  });
4862
- return /* @__PURE__ */ jsx(
4951
+ return /* @__PURE__ */ jsxs(
4863
4952
  "div",
4864
4953
  {
4865
4954
  ref,
4866
4955
  role: "tree",
4867
4956
  className: cn("flex w-full flex-col items-start bg-(--cmp-tree-item-bg-default)", className),
4868
4957
  ...rest,
4869
- children: renderNodes(items)
4958
+ children: [
4959
+ showAllItem && /* @__PURE__ */ jsx(
4960
+ STreeAllItem,
4961
+ {
4962
+ selected: allSelected,
4963
+ indeterminate: allIndeterminate,
4964
+ border,
4965
+ size,
4966
+ onSelect: updateAllSelected
4967
+ }
4968
+ ),
4969
+ renderNodes(items)
4970
+ ]
4870
4971
  }
4871
4972
  );
4872
4973
  });
@@ -5046,14 +5147,14 @@ var STooltipImpl = /* @__PURE__ */ forwardRef(function STooltip({
5046
5147
  ...style,
5047
5148
  ...contentPropsStyle
5048
5149
  };
5049
- return /* @__PURE__ */ jsxs(RPopover9.Root, { open, onOpenChange: setOpenState, children: [
5150
+ return /* @__PURE__ */ jsxs(RPopover10.Root, { open, onOpenChange: setOpenState, children: [
5050
5151
  isNone ? (
5051
5152
  // 트리거 없음: children 을 래퍼 없이 그대로 앵커로 쓴다 (소비자 레이아웃 보존).
5052
5153
  // mouse/focus 핸들러가 없으므로 useClose 없이도 자동 닫힘이 발생하지 않는다.
5053
- /* @__PURE__ */ jsx(RPopover9.Anchor, { asChild: true, children: triggerNode })
5154
+ /* @__PURE__ */ jsx(RPopover10.Anchor, { asChild: true, children: triggerNode })
5054
5155
  ) : isHover ? (
5055
5156
  // hover: Anchor(위치 기준) + 직접 mouse 핸들러 — 클릭으로 토글되지 않도록 Trigger 미사용
5056
- /* @__PURE__ */ jsx(RPopover9.Anchor, { asChild: true, children: /* @__PURE__ */ jsx(
5157
+ /* @__PURE__ */ jsx(RPopover10.Anchor, { asChild: true, children: /* @__PURE__ */ jsx(
5057
5158
  "span",
5058
5159
  {
5059
5160
  className: "inline-flex",
@@ -5064,9 +5165,9 @@ var STooltipImpl = /* @__PURE__ */ forwardRef(function STooltip({
5064
5165
  children: triggerNode
5065
5166
  }
5066
5167
  ) })
5067
- ) : /* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: triggerNode }),
5068
- /* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxs(
5069
- RPopover9.Content,
5168
+ ) : /* @__PURE__ */ jsx(RPopover10.Trigger, { asChild: true, children: triggerNode }),
5169
+ /* @__PURE__ */ jsx(RPopover10.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxs(
5170
+ RPopover10.Content,
5070
5171
  {
5071
5172
  side: placement,
5072
5173
  sideOffset,
@@ -5100,7 +5201,7 @@ var STooltipImpl = /* @__PURE__ */ forwardRef(function STooltip({
5100
5201
  }
5101
5202
  )
5102
5203
  ] }),
5103
- /* @__PURE__ */ jsx(RPopover9.Arrow, { width: 16, height: 12, style: { fill: bg } })
5204
+ /* @__PURE__ */ jsx(RPopover10.Arrow, { width: 16, height: 12, style: { fill: bg } })
5104
5205
  ]
5105
5206
  }
5106
5207
  ) })
@@ -6387,10 +6488,10 @@ function SPopover({
6387
6488
  const descColor = type === "default" ? "var(--cmp-popover-default-description)" : "var(--cmp-popover-light-description)";
6388
6489
  const leftLinkLabelClass = type === "default" ? "text-[color:var(--cmp-popover-default-subAction)]" : "text-[color:var(--cmp-popover-light-subAction)]";
6389
6490
  const triggerNode = trigger ?? /* @__PURE__ */ jsx("span", { className: "inline-flex cursor-pointer", "aria-label": ariaLabel, children: /* @__PURE__ */ jsx(SIcon, { name: icon, size: iconSize, color }) });
6390
- return /* @__PURE__ */ jsxs(RPopover9.Root, { open: actualOpen, onOpenChange: setOpen, children: [
6391
- /* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: triggerNode }),
6392
- /* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxs(
6393
- RPopover9.Content,
6491
+ return /* @__PURE__ */ jsxs(RPopover10.Root, { open: actualOpen, onOpenChange: setOpen, children: [
6492
+ /* @__PURE__ */ jsx(RPopover10.Trigger, { asChild: true, children: triggerNode }),
6493
+ /* @__PURE__ */ jsx(RPopover10.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxs(
6494
+ RPopover10.Content,
6394
6495
  {
6395
6496
  side: placement,
6396
6497
  sideOffset: 8,
@@ -6456,7 +6557,7 @@ function SPopover({
6456
6557
  ]
6457
6558
  }
6458
6559
  ),
6459
- /* @__PURE__ */ jsx(RPopover9.Arrow, { width: 16, height: 12, style: { fill: bg } })
6560
+ /* @__PURE__ */ jsx(RPopover10.Arrow, { width: 16, height: 12, style: { fill: bg } })
6460
6561
  ]
6461
6562
  }
6462
6563
  ) })
@@ -6487,7 +6588,7 @@ function SPortal({
6487
6588
  const portalContainer = usePortalContainer();
6488
6589
  const { minWidth: styleMinWidth, maxWidth: styleMaxWidth, ...restStyle } = style ?? {};
6489
6590
  return /* @__PURE__ */ jsxs(
6490
- RPopover9.Root,
6591
+ RPopover10.Root,
6491
6592
  {
6492
6593
  open,
6493
6594
  onOpenChange: (next) => {
@@ -6495,9 +6596,9 @@ function SPortal({
6495
6596
  if (!next) onClose?.();
6496
6597
  },
6497
6598
  children: [
6498
- /* @__PURE__ */ jsx(RPopover9.Anchor, { virtualRef: anchorRef }),
6499
- /* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
6500
- RPopover9.Content,
6599
+ /* @__PURE__ */ jsx(RPopover10.Anchor, { virtualRef: anchorRef }),
6600
+ /* @__PURE__ */ jsx(RPopover10.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
6601
+ RPopover10.Content,
6501
6602
  {
6502
6603
  side: placement,
6503
6604
  align,
@@ -6695,10 +6796,10 @@ function SGuide({
6695
6796
  );
6696
6797
  if (isNotion)
6697
6798
  return /* @__PURE__ */ jsx("span", { className, style, children: trigger });
6698
- return /* @__PURE__ */ jsxs(RPopover9.Root, { open, onOpenChange: setOpen, children: [
6699
- /* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: trigger }),
6700
- /* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxs(
6701
- RPopover9.Content,
6799
+ return /* @__PURE__ */ jsxs(RPopover10.Root, { open, onOpenChange: setOpen, children: [
6800
+ /* @__PURE__ */ jsx(RPopover10.Trigger, { asChild: true, children: trigger }),
6801
+ /* @__PURE__ */ jsx(RPopover10.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxs(
6802
+ RPopover10.Content,
6702
6803
  {
6703
6804
  side: "bottom",
6704
6805
  align: "start",
@@ -8779,10 +8880,10 @@ var SGnb = /* @__PURE__ */ forwardRef(function SGnb2({
8779
8880
  }
8780
8881
  ),
8781
8882
  header === "fix" && menuResizeHandle,
8782
- /* @__PURE__ */ jsxs(RPopover9.Root, { open: labelTip !== null, onOpenChange: (open) => !open && setLabelTip(null), children: [
8783
- /* @__PURE__ */ jsx(RPopover9.Anchor, { virtualRef: labelTipAnchorRef }),
8784
- /* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
8785
- RPopover9.Content,
8883
+ /* @__PURE__ */ jsxs(RPopover10.Root, { open: labelTip !== null, onOpenChange: (open) => !open && setLabelTip(null), children: [
8884
+ /* @__PURE__ */ jsx(RPopover10.Anchor, { virtualRef: labelTipAnchorRef }),
8885
+ /* @__PURE__ */ jsx(RPopover10.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
8886
+ RPopover10.Content,
8786
8887
  {
8787
8888
  side: "right",
8788
8889
  sideOffset: 4,
@@ -8853,13 +8954,155 @@ var SPageHeader = /* @__PURE__ */ withDisplayName(
8853
8954
  );
8854
8955
  var MIN_CONTENT_WIDTH = `calc(var(${SLAYOUT_MIN_WIDTH_VAR}, 0px) - 100cqw + 100%)`;
8855
8956
  var BACKGROUND_CLASS = {
8856
- frame: `bg-[var(--sys-color-bg-frame)] ${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_CLASS}`,
8857
- neutral: `bg-[var(--sys-color-bg-neutralLight)] ${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_WHITE_CLASS}`,
8858
- screen: `bg-[var(--sys-color-bg-screen)] ${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_CLASS}`
8957
+ frame: "bg-[var(--sys-color-bg-frame)]",
8958
+ neutral: "bg-[var(--sys-color-bg-neutralLight)]",
8959
+ screen: "bg-[var(--sys-color-bg-screen)]"
8960
+ };
8961
+ var NATIVE_SCROLLBAR_BACKGROUND_CLASS = {
8962
+ frame: `${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_CLASS}`,
8963
+ neutral: `${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_WHITE_CLASS}`,
8964
+ screen: `${SCROLLBAR_TRACK_BORDER_CLASS} ${SCROLLBAR_TRACK_BG_CLASS}`
8965
+ };
8966
+ var SCROLLBAR_SIZE = 12;
8967
+ var SCROLLBAR_MIN_THUMB_SIZE = 32;
8968
+ var getMetrics = (viewportSize, contentSize, scrollOffset) => {
8969
+ if (contentSize <= viewportSize) {
8970
+ return { visible: false, thumbSize: 0, thumbOffset: 0 };
8971
+ }
8972
+ const trackSize = viewportSize;
8973
+ const maxScrollOffset = contentSize - viewportSize;
8974
+ const thumbSize = Math.min(
8975
+ trackSize,
8976
+ Math.max(SCROLLBAR_MIN_THUMB_SIZE, viewportSize / contentSize * trackSize)
8977
+ );
8978
+ const maxThumbOffset = trackSize - thumbSize;
8979
+ const thumbOffset = maxScrollOffset > 0 ? scrollOffset / maxScrollOffset * maxThumbOffset : 0;
8980
+ return { visible: true, thumbSize, thumbOffset };
8981
+ };
8982
+ var setForwardedRef = (ref, node) => {
8983
+ if (typeof ref === "function") {
8984
+ ref(node);
8985
+ return;
8986
+ }
8987
+ if (ref) ref.current = node;
8859
8988
  };
8989
+ function SPageOverlayScrollbars({ scrollRef }) {
8990
+ const [vertical, setVertical] = useState({
8991
+ visible: false,
8992
+ thumbSize: 0,
8993
+ thumbOffset: 0
8994
+ });
8995
+ const [horizontal, setHorizontal] = useState({
8996
+ visible: false,
8997
+ thumbSize: 0,
8998
+ thumbOffset: 0
8999
+ });
9000
+ const update = useCallback(() => {
9001
+ const el = scrollRef.current;
9002
+ if (!el) return;
9003
+ setVertical(getMetrics(el.clientHeight, el.scrollHeight, el.scrollTop));
9004
+ setHorizontal(getMetrics(el.clientWidth, el.scrollWidth, el.scrollLeft));
9005
+ }, [scrollRef]);
9006
+ useEffect(() => {
9007
+ const el = scrollRef.current;
9008
+ if (!el) return;
9009
+ update();
9010
+ el.addEventListener("scroll", update, { passive: true });
9011
+ const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(update);
9012
+ observer?.observe(el);
9013
+ if (el.firstElementChild) observer?.observe(el.firstElementChild);
9014
+ return () => {
9015
+ el.removeEventListener("scroll", update);
9016
+ observer?.disconnect();
9017
+ };
9018
+ }, [scrollRef, update]);
9019
+ const dragVertical = (startEvent) => {
9020
+ const el = scrollRef.current;
9021
+ if (!el || !vertical.visible) return;
9022
+ startEvent.preventDefault();
9023
+ startEvent.currentTarget.setPointerCapture(startEvent.pointerId);
9024
+ const startPointer = startEvent.clientY;
9025
+ const startScrollTop = el.scrollTop;
9026
+ const maxThumbOffset = el.clientHeight - vertical.thumbSize;
9027
+ const maxScrollTop = el.scrollHeight - el.clientHeight;
9028
+ if (maxThumbOffset <= 0 || maxScrollTop <= 0) return;
9029
+ const onPointerMove = (moveEvent) => {
9030
+ const delta = moveEvent.clientY - startPointer;
9031
+ el.scrollTop = startScrollTop + delta / maxThumbOffset * maxScrollTop;
9032
+ };
9033
+ const onPointerUp = () => {
9034
+ window.removeEventListener("pointermove", onPointerMove);
9035
+ window.removeEventListener("pointerup", onPointerUp);
9036
+ };
9037
+ window.addEventListener("pointermove", onPointerMove);
9038
+ window.addEventListener("pointerup", onPointerUp, { once: true });
9039
+ };
9040
+ const dragHorizontal = (startEvent) => {
9041
+ const el = scrollRef.current;
9042
+ if (!el || !horizontal.visible) return;
9043
+ startEvent.preventDefault();
9044
+ startEvent.currentTarget.setPointerCapture(startEvent.pointerId);
9045
+ const startPointer = startEvent.clientX;
9046
+ const startScrollLeft = el.scrollLeft;
9047
+ const maxThumbOffset = el.clientWidth - horizontal.thumbSize;
9048
+ const maxScrollLeft = el.scrollWidth - el.clientWidth;
9049
+ if (maxThumbOffset <= 0 || maxScrollLeft <= 0) return;
9050
+ const onPointerMove = (moveEvent) => {
9051
+ const delta = moveEvent.clientX - startPointer;
9052
+ el.scrollLeft = startScrollLeft + delta / maxThumbOffset * maxScrollLeft;
9053
+ };
9054
+ const onPointerUp = () => {
9055
+ window.removeEventListener("pointermove", onPointerMove);
9056
+ window.removeEventListener("pointerup", onPointerUp);
9057
+ };
9058
+ window.addEventListener("pointermove", onPointerMove);
9059
+ window.addEventListener("pointerup", onPointerUp, { once: true });
9060
+ };
9061
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
9062
+ vertical.visible && /* @__PURE__ */ jsx(
9063
+ "div",
9064
+ {
9065
+ "aria-hidden": "true",
9066
+ className: "pointer-events-none absolute bottom-0 right-0 top-0 z-[1] w-[12px]",
9067
+ style: { bottom: horizontal.visible ? SCROLLBAR_SIZE : 0 },
9068
+ children: /* @__PURE__ */ jsx(
9069
+ "div",
9070
+ {
9071
+ className: "pointer-events-auto absolute right-[2px] w-[8px] cursor-default touch-none rounded-full bg-[var(--color-grey-45)]",
9072
+ style: {
9073
+ height: vertical.thumbSize,
9074
+ transform: `translateY(${vertical.thumbOffset}px)`
9075
+ },
9076
+ onPointerDown: dragVertical
9077
+ }
9078
+ )
9079
+ }
9080
+ ),
9081
+ horizontal.visible && /* @__PURE__ */ jsx(
9082
+ "div",
9083
+ {
9084
+ "aria-hidden": "true",
9085
+ className: "pointer-events-none absolute bottom-0 left-0 right-0 z-[1] h-[12px]",
9086
+ style: { right: vertical.visible ? SCROLLBAR_SIZE : 0 },
9087
+ children: /* @__PURE__ */ jsx(
9088
+ "div",
9089
+ {
9090
+ className: "pointer-events-auto absolute bottom-[2px] h-[8px] cursor-default touch-none rounded-full bg-[var(--color-grey-45)]",
9091
+ style: {
9092
+ width: horizontal.thumbSize,
9093
+ transform: `translateX(${horizontal.thumbOffset}px)`
9094
+ },
9095
+ onPointerDown: dragHorizontal
9096
+ }
9097
+ )
9098
+ }
9099
+ )
9100
+ ] });
9101
+ }
8860
9102
  var SPage = /* @__PURE__ */ forwardRef(function SPage2({
8861
9103
  background = "frame",
8862
9104
  scrollEndSpacing = true,
9105
+ overlayScrollbar = false,
8863
9106
  contentHeight = "auto",
8864
9107
  header,
8865
9108
  className,
@@ -8870,6 +9113,14 @@ var SPage = /* @__PURE__ */ forwardRef(function SPage2({
8870
9113
  }, ref) {
8871
9114
  const layout = useContext(SLayoutContext);
8872
9115
  const gridStyle = layout?.header === "full" ? { gridArea: "page" } : void 0;
9116
+ const scrollRef = useRef(null);
9117
+ const setMainRef = useCallback(
9118
+ (node) => {
9119
+ scrollRef.current = node;
9120
+ setForwardedRef(ref, node);
9121
+ },
9122
+ [ref]
9123
+ );
8873
9124
  const [scrolled, setScrolled] = useState(false);
8874
9125
  const handleScroll = (e) => {
8875
9126
  onScroll?.(e);
@@ -8879,21 +9130,54 @@ var SPage = /* @__PURE__ */ forwardRef(function SPage2({
8879
9130
  const main = /* @__PURE__ */ jsx(
8880
9131
  "main",
8881
9132
  {
8882
- ref,
9133
+ ref: setMainRef,
8883
9134
  className: cn(
8884
9135
  "box-border min-h-0 min-w-0 flex-1 overflow-auto p-[var(--cmp-pageBody-padding-default)]",
9136
+ overlayScrollbar && "h-full",
8885
9137
  !fill && scrollEndSpacing && "pb-[var(--cmp-pageBody-padding-scrollEnd)]",
8886
- SCROLLBAR_CLASS,
9138
+ overlayScrollbar ? SCROLLBAR_HIDDEN_CLASS : `${SCROLLBAR_CLASS} ${NATIVE_SCROLLBAR_BACKGROUND_CLASS[background]}`,
8887
9139
  BACKGROUND_CLASS[background],
8888
9140
  className
8889
9141
  ),
8890
- style: header == null ? { ...gridStyle, ...style } : style,
9142
+ style: header == null && !overlayScrollbar ? { ...gridStyle, ...style } : style,
8891
9143
  onScroll: handleScroll,
8892
9144
  ...rest,
8893
9145
  children: /* @__PURE__ */ jsx("div", { className: cn(fill && "h-full"), style: { minWidth: MIN_CONTENT_WIDTH }, children })
8894
9146
  }
8895
9147
  );
8896
- if (header == null) return main;
9148
+ if (!overlayScrollbar) {
9149
+ if (header == null) return main;
9150
+ return (
9151
+ // fix 가 아닌 헤더는 자기 배경이 투명이라(SPageHeader.tsx) 이 배경이 그대로 비친다.
9152
+ /* @__PURE__ */ jsxs(
9153
+ "div",
9154
+ {
9155
+ className: cn("flex min-h-0 min-w-0 flex-1 flex-col", BACKGROUND_CLASS[background]),
9156
+ style: gridStyle,
9157
+ children: [
9158
+ /* @__PURE__ */ jsx(SPageHeader, { ...header, scrolled }),
9159
+ main
9160
+ ]
9161
+ }
9162
+ )
9163
+ );
9164
+ }
9165
+ if (header == null) {
9166
+ return /* @__PURE__ */ jsxs(
9167
+ "div",
9168
+ {
9169
+ className: cn(
9170
+ "relative min-h-0 min-w-0 flex-1 overflow-hidden",
9171
+ BACKGROUND_CLASS[background]
9172
+ ),
9173
+ style: gridStyle,
9174
+ children: [
9175
+ main,
9176
+ /* @__PURE__ */ jsx(SPageOverlayScrollbars, { scrollRef })
9177
+ ]
9178
+ }
9179
+ );
9180
+ }
8897
9181
  return (
8898
9182
  // fix 가 아닌 헤더는 자기 배경이 투명이라(SPageHeader.tsx) 이 배경이 그대로 비친다 —
8899
9183
  // 그래서 SPage 의 background 를 main 뿐 아니라 여기에도 칠한다(스크롤바 관련 클래스는
@@ -8905,7 +9189,10 @@ var SPage = /* @__PURE__ */ forwardRef(function SPage2({
8905
9189
  style: gridStyle,
8906
9190
  children: [
8907
9191
  /* @__PURE__ */ jsx(SPageHeader, { ...header, scrolled }),
8908
- main
9192
+ /* @__PURE__ */ jsxs("div", { className: "relative min-h-0 min-w-0 flex-1 overflow-hidden", children: [
9193
+ main,
9194
+ /* @__PURE__ */ jsx(SPageOverlayScrollbars, { scrollRef })
9195
+ ] })
8909
9196
  ]
8910
9197
  }
8911
9198
  )
@@ -11212,6 +11499,67 @@ var STableBar = /* @__PURE__ */ forwardRef(function STableBar2({ total, selected
11212
11499
 
11213
11500
  // src/lib/autofill.ts
11214
11501
  var AUTOFILL_RESET_CLASS = "autofill:[-webkit-text-fill-color:currentColor] autofill:[box-shadow:0_0_0_1000px_var(--sys-color-field-bg-default)_inset] autofill:[transition:background-color_5000s_ease-in-out_0s] [&:-webkit-autofill]:[-webkit-text-fill-color:currentColor] [&:-webkit-autofill]:[box-shadow:0_0_0_1000px_var(--sys-color-field-bg-default)_inset] [&:-webkit-autofill]:[transition:background-color_5000s_ease-in-out_0s]";
11502
+ var HIDE_DELAY_MS2 = 100;
11503
+ function mergeRefs(...refs) {
11504
+ return (node) => {
11505
+ for (const ref of refs) {
11506
+ if (!ref) continue;
11507
+ if (typeof ref === "function") ref(node);
11508
+ else ref.current = node;
11509
+ }
11510
+ };
11511
+ }
11512
+ function useTruncatedValueTooltip({
11513
+ enabled,
11514
+ text
11515
+ }) {
11516
+ const portalContainer = usePortalContainer();
11517
+ const elRef = useRef(null);
11518
+ const [open, setOpen] = useState(false);
11519
+ const hideTimer = useRef(void 0);
11520
+ const cancelHide = useCallback(() => {
11521
+ if (hideTimer.current) {
11522
+ clearTimeout(hideTimer.current);
11523
+ hideTimer.current = void 0;
11524
+ }
11525
+ }, []);
11526
+ const startHide = useCallback(() => {
11527
+ cancelHide();
11528
+ hideTimer.current = setTimeout(() => setOpen(false), HIDE_DELAY_MS2);
11529
+ }, [cancelHide]);
11530
+ const onMouseEnter = useCallback(() => {
11531
+ cancelHide();
11532
+ const el = elRef.current;
11533
+ if (!el) return;
11534
+ if (el.scrollWidth - el.clientWidth > 1) setOpen(true);
11535
+ }, [cancelHide]);
11536
+ useEffect(() => {
11537
+ if (!enabled || text === "") setOpen(false);
11538
+ }, [enabled, text]);
11539
+ useEffect(() => cancelHide, [cancelHide]);
11540
+ const active = enabled && text !== "";
11541
+ return {
11542
+ valueRef: elRef,
11543
+ onMouseEnter: active ? onMouseEnter : cancelHide,
11544
+ onMouseLeave: active ? startHide : cancelHide,
11545
+ tooltip: active ? /* @__PURE__ */ jsxs(RPopover10.Root, { open, onOpenChange: setOpen, children: [
11546
+ /* @__PURE__ */ jsx(RPopover10.Anchor, { virtualRef: elRef }),
11547
+ /* @__PURE__ */ jsx(RPopover10.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
11548
+ RPopover10.Content,
11549
+ {
11550
+ side: "top",
11551
+ sideOffset: 4,
11552
+ "aria-hidden": true,
11553
+ className: cn("z-50", FLOATING_SLIDE_ANIM),
11554
+ onOpenAutoFocus: (e) => e.preventDefault(),
11555
+ onMouseEnter: cancelHide,
11556
+ onMouseLeave: startHide,
11557
+ children: /* @__PURE__ */ jsx(STag, { shape: "square", size: "xs", color: "grey", label: text })
11558
+ }
11559
+ ) })
11560
+ ] }) : null
11561
+ };
11562
+ }
11215
11563
  var FONT = {
11216
11564
  sm: { fontSize: 12, lineHeight: 20, paddingX: "var(--cmp-textinput-sm-paddingX)" },
11217
11565
  md: { fontSize: 14, lineHeight: 24, paddingX: "var(--cmp-textinput-md-paddingX)" }
@@ -11269,6 +11617,10 @@ var SInput = /* @__PURE__ */ forwardRef(function SInput2({
11269
11617
  const resolvedError = error || ruleError !== "";
11270
11618
  const resolvedErrorMessage = ruleError !== "" ? ruleError : errorMessage;
11271
11619
  const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
11620
+ const valueTooltip = useTruncatedValueTooltip({
11621
+ enabled: readOnly && !disabled,
11622
+ text: String(value ?? "")
11623
+ });
11272
11624
  return /* @__PURE__ */ jsx(
11273
11625
  SField,
11274
11626
  {
@@ -11309,7 +11661,7 @@ var SInput = /* @__PURE__ */ forwardRef(function SInput2({
11309
11661
  /* @__PURE__ */ jsx(
11310
11662
  "input",
11311
11663
  {
11312
- ref,
11664
+ ref: mergeRefs(ref, valueTooltip.valueRef),
11313
11665
  type: inputType,
11314
11666
  value: value ?? "",
11315
11667
  disabled,
@@ -11334,9 +11686,18 @@ var SInput = /* @__PURE__ */ forwardRef(function SInput2({
11334
11686
  color: disabled ? "var(--cmp-textinput-text-disabled)" : "var(--sys-color-field-text-default)",
11335
11687
  ...inputStyle
11336
11688
  },
11337
- ...rest
11689
+ ...rest,
11690
+ onMouseEnter: (e) => {
11691
+ rest.onMouseEnter?.(e);
11692
+ valueTooltip.onMouseEnter();
11693
+ },
11694
+ onMouseLeave: (e) => {
11695
+ rest.onMouseLeave?.(e);
11696
+ valueTooltip.onMouseLeave();
11697
+ }
11338
11698
  }
11339
11699
  ),
11700
+ valueTooltip.tooltip,
11340
11701
  suffix != null && /* @__PURE__ */ jsx("span", { className: "flex flex-shrink-0 items-center", children: suffix }),
11341
11702
  clearable && hasValue && !disabled && !readOnly && /* @__PURE__ */ jsx(
11342
11703
  SGhostButton,
@@ -11570,8 +11931,10 @@ var SNumberInput = /* @__PURE__ */ forwardRef(function SNumberInput2({
11570
11931
  const [display, setDisplay] = useState(() => formatWithCommas(numValue));
11571
11932
  const [ruleError, setRuleError] = useState("");
11572
11933
  const innerRef = useRef(null);
11934
+ const valueTooltip = useTruncatedValueTooltip({ enabled: readOnly && !disabled, text: display });
11573
11935
  const setRefs2 = (el) => {
11574
11936
  innerRef.current = el;
11937
+ valueTooltip.valueRef.current = el;
11575
11938
  if (typeof ref === "function") ref(el);
11576
11939
  else if (ref) ref.current = el;
11577
11940
  };
@@ -11785,9 +12148,12 @@ var SNumberInput = /* @__PURE__ */ forwardRef(function SNumberInput2({
11785
12148
  textAlign: useButton ? "center" : "right",
11786
12149
  color: disabled ? "var(--cmp-numberInput-text-disabled)" : "var(--cmp-numberInput-text-default)",
11787
12150
  ...inputStyle
11788
- }
12151
+ },
12152
+ onMouseEnter: valueTooltip.onMouseEnter,
12153
+ onMouseLeave: valueTooltip.onMouseLeave
11789
12154
  }
11790
12155
  ),
12156
+ valueTooltip.tooltip,
11791
12157
  inputSuffix !== "" && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", style: { color: affixColor }, children: inputSuffix }),
11792
12158
  useButton && stepper("inc")
11793
12159
  ]
@@ -12528,8 +12894,8 @@ function SDatePicker({
12528
12894
  disabled,
12529
12895
  className,
12530
12896
  style,
12531
- children: /* @__PURE__ */ jsxs(RPopover9.Root, { open, onOpenChange: (o) => !disabled && setOpen(o), children: [
12532
- /* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
12897
+ children: /* @__PURE__ */ jsxs(RPopover10.Root, { open, onOpenChange: (o) => !disabled && setOpen(o), children: [
12898
+ /* @__PURE__ */ jsx(RPopover10.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
12533
12899
  "button",
12534
12900
  {
12535
12901
  type: "button",
@@ -12565,8 +12931,8 @@ function SDatePicker({
12565
12931
  ]
12566
12932
  }
12567
12933
  ) }),
12568
- /* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
12569
- RPopover9.Content,
12934
+ /* @__PURE__ */ jsx(RPopover10.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
12935
+ RPopover10.Content,
12570
12936
  {
12571
12937
  side: "bottom",
12572
12938
  align: mode === "date" ? "start" : "center",
@@ -13032,7 +13398,7 @@ function SDateRangePicker({
13032
13398
  className,
13033
13399
  style,
13034
13400
  children: /* @__PURE__ */ jsxs(
13035
- RPopover9.Root,
13401
+ RPopover10.Root,
13036
13402
  {
13037
13403
  open,
13038
13404
  onOpenChange: (o) => {
@@ -13041,7 +13407,7 @@ function SDateRangePicker({
13041
13407
  if (!o) setPendingStart(null);
13042
13408
  },
13043
13409
  children: [
13044
- /* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
13410
+ /* @__PURE__ */ jsx(RPopover10.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
13045
13411
  "button",
13046
13412
  {
13047
13413
  type: "button",
@@ -13082,8 +13448,8 @@ function SDateRangePicker({
13082
13448
  ]
13083
13449
  }
13084
13450
  ) }),
13085
- /* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
13086
- RPopover9.Content,
13451
+ /* @__PURE__ */ jsx(RPopover10.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
13452
+ RPopover10.Content,
13087
13453
  {
13088
13454
  side: "bottom",
13089
13455
  align: "start",
@@ -14609,8 +14975,8 @@ var SChipFilter = /* @__PURE__ */ forwardRef(function SChipFilter2({
14609
14975
  })(),
14610
14976
  hasRightActions && /* @__PURE__ */ jsxs(Fragment, { children: [
14611
14977
  /* @__PURE__ */ jsx(Divider, { inset: true }),
14612
- hasAddButton && /* @__PURE__ */ jsxs(RPopover9.Root, { open: addOpen, onOpenChange: setAddOpen, children: [
14613
- /* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
14978
+ hasAddButton && /* @__PURE__ */ jsxs(RPopover10.Root, { open: addOpen, onOpenChange: setAddOpen, children: [
14979
+ /* @__PURE__ */ jsx(RPopover10.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
14614
14980
  "button",
14615
14981
  {
14616
14982
  type: "button",
@@ -14635,8 +15001,8 @@ var SChipFilter = /* @__PURE__ */ forwardRef(function SChipFilter2({
14635
15001
  ]
14636
15002
  }
14637
15003
  ) }),
14638
- /* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
14639
- RPopover9.Content,
15004
+ /* @__PURE__ */ jsx(RPopover10.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
15005
+ RPopover10.Content,
14640
15006
  {
14641
15007
  side: "bottom",
14642
15008
  align: "start",
@@ -14676,17 +15042,17 @@ var SChipFilter = /* @__PURE__ */ forwardRef(function SChipFilter2({
14676
15042
  )
14677
15043
  ] })
14678
15044
  ] }),
14679
- /* @__PURE__ */ jsxs(RPopover9.Root, { open: openKey != null, onOpenChange: (next) => !next && setOpenKey(null), children: [
15045
+ /* @__PURE__ */ jsxs(RPopover10.Root, { open: openKey != null, onOpenChange: (next) => !next && setOpenKey(null), children: [
14680
15046
  /* @__PURE__ */ jsx(
14681
- RPopover9.Anchor,
15047
+ RPopover10.Anchor,
14682
15048
  {
14683
15049
  virtualRef: {
14684
15050
  current: openKey ? triggerRefs.current.get(openKey) : null
14685
15051
  }
14686
15052
  }
14687
15053
  ),
14688
- /* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
14689
- RPopover9.Content,
15054
+ /* @__PURE__ */ jsx(RPopover10.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
15055
+ RPopover10.Content,
14690
15056
  {
14691
15057
  side: "bottom",
14692
15058
  align: "start",
@@ -15226,8 +15592,8 @@ function InlineDatePresetFilter({
15226
15592
  applied && (rangeValue ? (
15227
15593
  // 뱃지 모양은 그대로 두고, 눌렀을 때 캘린더가 열려 기간을 직접 다시 고를 수 있게 한다.
15228
15594
  // 직접 고르면 프리셋 선택은 해제된다.
15229
- /* @__PURE__ */ jsxs(RPopover9.Root, { open: pickerOpen, onOpenChange: setPickerOpen, children: [
15230
- /* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
15595
+ /* @__PURE__ */ jsxs(RPopover10.Root, { open: pickerOpen, onOpenChange: setPickerOpen, children: [
15596
+ /* @__PURE__ */ jsx(RPopover10.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
15231
15597
  "button",
15232
15598
  {
15233
15599
  type: "button",
@@ -15236,8 +15602,8 @@ function InlineDatePresetFilter({
15236
15602
  children: badge
15237
15603
  }
15238
15604
  ) }),
15239
- /* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
15240
- RPopover9.Content,
15605
+ /* @__PURE__ */ jsx(RPopover10.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
15606
+ RPopover10.Content,
15241
15607
  {
15242
15608
  side: "bottom",
15243
15609
  align: "start",
@@ -16048,6 +16414,10 @@ var SBarcodeInput = /* @__PURE__ */ forwardRef(
16048
16414
  });
16049
16415
  const resolvedError = error || ruleError !== "";
16050
16416
  const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
16417
+ const valueTooltip = useTruncatedValueTooltip({
16418
+ enabled: readOnly && !disabled,
16419
+ text: String(value ?? "")
16420
+ });
16051
16421
  return /* @__PURE__ */ jsx(
16052
16422
  SField,
16053
16423
  {
@@ -16084,7 +16454,7 @@ var SBarcodeInput = /* @__PURE__ */ forwardRef(
16084
16454
  /* @__PURE__ */ jsx(
16085
16455
  "input",
16086
16456
  {
16087
- ref,
16457
+ ref: mergeRefs(ref, valueTooltip.valueRef),
16088
16458
  name,
16089
16459
  type: "text",
16090
16460
  value: value ?? "",
@@ -16110,9 +16480,12 @@ var SBarcodeInput = /* @__PURE__ */ forwardRef(
16110
16480
  fontSize: f.fontSize,
16111
16481
  color: disabled ? "var(--cmp-textinput-text-disabled)" : "var(--cmp-textinput-text-default)",
16112
16482
  ...inputStyle
16113
- }
16483
+ },
16484
+ onMouseEnter: valueTooltip.onMouseEnter,
16485
+ onMouseLeave: valueTooltip.onMouseLeave
16114
16486
  }
16115
16487
  ),
16488
+ valueTooltip.tooltip,
16116
16489
  suffix,
16117
16490
  clearable && hasValue && !disabled && /* @__PURE__ */ jsx(
16118
16491
  SGhostButton,
@@ -16492,8 +16865,8 @@ function STimePicker({
16492
16865
  disabled,
16493
16866
  className,
16494
16867
  style,
16495
- children: /* @__PURE__ */ jsxs(RPopover9.Root, { open, onOpenChange: commitOpen, children: [
16496
- /* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
16868
+ children: /* @__PURE__ */ jsxs(RPopover10.Root, { open, onOpenChange: commitOpen, children: [
16869
+ /* @__PURE__ */ jsx(RPopover10.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
16497
16870
  "div",
16498
16871
  {
16499
16872
  ref: triggerRef,
@@ -16553,8 +16926,8 @@ function STimePicker({
16553
16926
  ]
16554
16927
  }
16555
16928
  ) }),
16556
- /* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
16557
- RPopover9.Content,
16929
+ /* @__PURE__ */ jsx(RPopover10.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
16930
+ RPopover10.Content,
16558
16931
  {
16559
16932
  side: "bottom",
16560
16933
  align: "start",
@@ -16959,8 +17332,8 @@ function STimeRangePicker({
16959
17332
  disabled,
16960
17333
  className,
16961
17334
  style,
16962
- children: /* @__PURE__ */ jsxs(RPopover9.Root, { open, onOpenChange: commitOpen, children: [
16963
- /* @__PURE__ */ jsx(RPopover9.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
17335
+ children: /* @__PURE__ */ jsxs(RPopover10.Root, { open, onOpenChange: commitOpen, children: [
17336
+ /* @__PURE__ */ jsx(RPopover10.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
16964
17337
  "div",
16965
17338
  {
16966
17339
  ref: triggerRef,
@@ -17020,8 +17393,8 @@ function STimeRangePicker({
17020
17393
  ]
17021
17394
  }
17022
17395
  ) }),
17023
- /* @__PURE__ */ jsx(RPopover9.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
17024
- RPopover9.Content,
17396
+ /* @__PURE__ */ jsx(RPopover10.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx(
17397
+ RPopover10.Content,
17025
17398
  {
17026
17399
  side: "bottom",
17027
17400
  align: "start",