sellmate-design-system-react 9.0.0-beta.47 → 9.0.0-beta.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/AGENTS.md +21 -5
  2. package/dist/components/SBarChart/README.md +104 -0
  3. package/dist/components/SBarChart/SBarChart.d.ts +75 -0
  4. package/dist/components/SBarChart/barChart.config.d.ts +65 -0
  5. package/dist/components/SBarChart/index.d.ts +2 -0
  6. package/dist/components/SChatAttachedFile/README.md +3 -4
  7. package/dist/components/SChatAttachedFile/SChatAttachedFile.d.ts +3 -44
  8. package/dist/components/SChatAttachedFile/chatAttachedFile.config.d.ts +19 -39
  9. package/dist/components/SChatAttachedFile/index.d.ts +1 -1
  10. package/dist/components/SChatFile/README.md +33 -0
  11. package/dist/components/SChatFile/SChatFile.d.ts +37 -0
  12. package/dist/components/SChatFile/chatFile.config.d.ts +56 -0
  13. package/dist/components/SChatFile/index.d.ts +2 -0
  14. package/dist/components/SChatMessage/README.md +9 -5
  15. package/dist/components/SChatMessage/SChatMessage.d.ts +22 -7
  16. package/dist/components/SGhostButton/README.md +2 -0
  17. package/dist/components/SIcon/README.md +2 -0
  18. package/dist/index.cjs +944 -132
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.ts +2 -0
  21. package/dist/index.js +939 -132
  22. package/dist/index.js.map +1 -1
  23. package/dist/lib/chart/cartesian.d.ts +46 -0
  24. package/dist/lib/chart/frame.d.ts +17 -0
  25. package/dist/lib/chart/legend.d.ts +15 -0
  26. package/dist/lib/chart/palette.d.ts +26 -0
  27. package/dist/lib/chart/scale.d.ts +26 -0
  28. package/dist/lib/chart/tooltip.d.ts +23 -0
  29. package/dist/lib/chart/types.d.ts +29 -0
  30. package/dist/lib/chart/use-element-size.d.ts +17 -0
  31. package/dist/llms-full.txt +171 -16
  32. package/dist/llms.txt +25 -10
  33. package/dist/styles.css +347 -40
  34. package/dist/theme.css +118 -7
  35. package/eslint/scale.gen.mjs +2 -2
  36. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -4681,10 +4681,9 @@ var STextarea = /* @__PURE__ */ react.forwardRef(function STextarea2({
4681
4681
  );
4682
4682
  });
4683
4683
  var DEFAULT_PLACEHOLDER = "\uBA54\uC2DC\uC9C0\uB97C \uC785\uB825\uD574 \uC8FC\uC138\uC694...";
4684
- var FIELD_MIN_HEIGHT = 48;
4685
4684
  var FIELD_BORDER = 1;
4686
- var TEXTAREA_MIN_HEIGHT = FIELD_MIN_HEIGHT - FIELD_BORDER * 2;
4687
- var BUTTON_BOTTOM_INSET = `calc((${FIELD_MIN_HEIGHT}px - var(--cmp-ghostButton-md-size)) / 2)`;
4685
+ var TEXTAREA_MIN_HEIGHT = `calc(var(--cmp-chatInput-buttonFrame-height) - ${FIELD_BORDER * 2}px)`;
4686
+ var BUTTON_BOTTOM_INSET = `calc((var(--cmp-chatInput-buttonFrame-height) - var(--cmp-ghostButton-md-size)) / 2)`;
4688
4687
  var DEFAULT_MAX_ROWS = 5;
4689
4688
  var SChatInputImpl = /* @__PURE__ */ react.forwardRef(function SChatInput({
4690
4689
  value = "",
@@ -4713,8 +4712,8 @@ var SChatInputImpl = /* @__PURE__ */ react.forwardRef(function SChatInput({
4713
4712
  e.preventDefault();
4714
4713
  send();
4715
4714
  };
4716
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col bg-(--sys-color-field-bg-default)", className), style, children: [
4717
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end gap-sd-8 p-sd-12", children: [
4715
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col bg-(--cmp-chatInput-bg)", className), style, children: [
4716
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end gap-(--cmp-chatInput-gap) p-(--cmp-chatInput-padding)", children: [
4718
4717
  onAttach != null && /* @__PURE__ */ jsxRuntime.jsx(
4719
4718
  SGhostButton,
4720
4719
  {
@@ -4776,81 +4775,67 @@ var SChatInputImpl = /* @__PURE__ */ react.forwardRef(function SChatInput({
4776
4775
  var SChatInput2 = /* @__PURE__ */ withDisplayName(SChatInputImpl, "SChatInput");
4777
4776
 
4778
4777
  // src/components/SChatAttachedFile/chatAttachedFile.config.ts
4779
- var CHAT_ATTACHED_FILE_VARIANTS = ["attached", "sent"];
4780
4778
  var CHAT_ATTACHED_FILE_CONFIG = {
4781
- attached: {
4782
- // 오른쪽 여백이 왼쪽보다 넓은 것은 제거 버튼이 자기 여백을 갖기 때문이다(시안 그대로).
4783
- box: "h-[30px] gap-sd-8 pl-sd-4 pr-sd-8 bg-(--sys-color-bg-neutralLight) border-(--sys-color-border-default)",
4784
- tile: "h-[20px] w-[20px] bg-(--sys-color-bg-frame)",
4785
- iconSize: 16,
4786
- nameTypo: "typo-body-sm-default"
4787
- },
4788
- sent: {
4789
- box: "h-[56px] gap-sd-12 px-sd-12 bg-(--sys-color-bg-frame) border-(--sys-color-border-strong)",
4790
- tile: "h-[28px] w-[28px] bg-(--sys-color-bg-accentFaint)",
4791
- iconSize: 20,
4792
- nameTypo: "typo-body-md-medium"
4793
- }
4779
+ /** 바깥 상자 — 좌우·상하 여백·면·선·라운드 */
4780
+ box: "px-(--cmp-chatAttachedFile-paddingX) py-(--cmp-chatAttachedFile-paddingY) rounded-(--cmp-chatAttachedFile-radius) border-(length:--cmp-chatAttachedFile-border-width) border-(--cmp-chatAttachedFile-border-color) bg-(--cmp-chatAttachedFile-bg)",
4781
+ /** 콘텐츠 묶음 ↔ 제거 버튼 간격 */
4782
+ outerGap: "gap-(--cmp-chatAttachedFile-gap)",
4783
+ /** 아이콘 칩 ↔ 파일명 간격 */
4784
+ contentGap: "gap-(--cmp-chatAttachedFile-content-gap)",
4785
+ /** 클립 아이콘이 앉는 칩 — 내부 패딩·면·라운드 (높이는 아이콘+패딩이 정한다) */
4786
+ tile: "p-(--cmp-chatAttachedFile-icon-wrapper-padding) rounded-(--cmp-chatAttachedFile-icon-wrapper-radius) bg-(--cmp-chatAttachedFile-icon-wrapper-bg)",
4787
+ /** 칩 안 클립 아이콘 크기(px). SVG width/height 는 속성값이라 CSS 변수를 못 받아 값으로 둔다 (토큰 값과 동일) */
4788
+ iconSize: 16,
4789
+ /** 파일명 타이포 프리셋 */
4790
+ nameTypo: "typo-body-sm-default",
4791
+ /** 파일명 텍스트색 */
4792
+ textColor: "text-(--cmp-chatAttachedFile-filename-color)"
4794
4793
  };
4795
- var SIZE_UNITS = ["B", "KB", "MB", "GB", "TB"];
4796
- function formatFileSize(bytes) {
4797
- if (!Number.isFinite(bytes) || bytes < 0) return "";
4798
- let value = bytes;
4799
- let unit = 0;
4800
- while (value >= 1024 && unit < SIZE_UNITS.length - 1) {
4801
- value /= 1024;
4802
- unit += 1;
4803
- }
4804
- return unit === 0 ? `${Math.round(value)}${SIZE_UNITS[0]}` : `${value.toFixed(1)}${SIZE_UNITS[unit]}`;
4805
- }
4806
- function normalizeExtension(extension) {
4807
- return extension.trim().replace(/^\.+/, "").toLowerCase();
4808
- }
4809
- function fileExtension(name) {
4810
- const dot = name.lastIndexOf(".");
4811
- return dot > 0 && dot < name.length - 1 ? name.slice(dot + 1).toLowerCase() : "";
4812
- }
4813
4794
  var SChatAttachedFileImpl = /* @__PURE__ */ react.forwardRef(
4814
- function SChatAttachedFile({ variant, name, extension, size, onRemove, className, ...rest }, ref) {
4815
- const preset = CHAT_ATTACHED_FILE_CONFIG[variant];
4816
- const ext = extension != null ? normalizeExtension(extension) : fileExtension(name);
4817
- const meta = [ext, size != null ? formatFileSize(size) : ""].filter(Boolean).join(" / ");
4818
- const showMeta = variant === "sent" && meta !== "";
4819
- const showRemove = variant === "attached" && onRemove != null;
4795
+ function SChatAttachedFile({ name, onRemove, className, ...rest }, ref) {
4820
4796
  return /* @__PURE__ */ jsxRuntime.jsxs(
4821
4797
  "div",
4822
4798
  {
4823
4799
  ref,
4824
4800
  className: cn(
4825
- "inline-flex max-w-full items-center rounded-8 border",
4826
- preset.box,
4801
+ "inline-flex max-w-full items-center border-solid",
4802
+ CHAT_ATTACHED_FILE_CONFIG.box,
4803
+ CHAT_ATTACHED_FILE_CONFIG.outerGap,
4827
4804
  className
4828
4805
  ),
4829
4806
  ...rest,
4830
4807
  children: [
4831
- /* @__PURE__ */ jsxRuntime.jsx(
4832
- "span",
4833
- {
4834
- className: cn(
4835
- "grid shrink-0 place-items-center rounded-4",
4836
- preset.tile,
4837
- "text-(--sys-color-fg-accentLight)"
4838
- ),
4839
- children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "attachFile", size: preset.iconSize })
4840
- }
4841
- ),
4842
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
4843
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("truncate text-(--sys-color-fg-secondary)", preset.nameTypo), children: name }),
4844
- showMeta && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-body-sm-default truncate text-(--sys-color-fg-secondary)", children: meta })
4808
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("flex min-w-0 items-center", CHAT_ATTACHED_FILE_CONFIG.contentGap), children: [
4809
+ /* @__PURE__ */ jsxRuntime.jsx(
4810
+ "span",
4811
+ {
4812
+ className: cn(
4813
+ "inline-grid shrink-0 place-items-center text-(--sys-color-fg-accentLight)",
4814
+ CHAT_ATTACHED_FILE_CONFIG.tile
4815
+ ),
4816
+ children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "attachFile", color: "grey_65", size: CHAT_ATTACHED_FILE_CONFIG.iconSize })
4817
+ }
4818
+ ),
4819
+ /* @__PURE__ */ jsxRuntime.jsx(
4820
+ "span",
4821
+ {
4822
+ className: cn(
4823
+ "truncate",
4824
+ CHAT_ATTACHED_FILE_CONFIG.nameTypo,
4825
+ CHAT_ATTACHED_FILE_CONFIG.textColor
4826
+ ),
4827
+ children: name
4828
+ }
4829
+ )
4845
4830
  ] }),
4846
- showRemove && /* @__PURE__ */ jsxRuntime.jsx(
4847
- "button",
4831
+ onRemove != null && /* @__PURE__ */ jsxRuntime.jsx(
4832
+ SGhostButton,
4848
4833
  {
4849
- type: "button",
4850
- "aria-label": `${name} \uC81C\uAC70`,
4834
+ icon: "close",
4835
+ size: "xs",
4836
+ ariaLabel: `${name} \uC81C\uAC70`,
4851
4837
  onClick: onRemove,
4852
- className: "ml-auto flex shrink-0 cursor-pointer items-center text-(--sys-color-fg-tertiary)",
4853
- children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "close", size: 16 })
4838
+ className: "shrink-0"
4854
4839
  }
4855
4840
  )
4856
4841
  ]
@@ -4859,12 +4844,120 @@ var SChatAttachedFileImpl = /* @__PURE__ */ react.forwardRef(
4859
4844
  }
4860
4845
  );
4861
4846
  var SChatAttachedFile2 = /* @__PURE__ */ withDisplayName(SChatAttachedFileImpl, "SChatAttachedFile");
4847
+
4848
+ // src/components/SChatFile/chatFile.config.ts
4849
+ var CHAT_FILE_CONFIG = {
4850
+ /** 바깥 상자 — 좌우 비대칭 여백·상하 여백·면·선·라운드 */
4851
+ box: "pl-(--cmp-chatFile-paddingLeft) pr-(--cmp-chatFile-paddingRight) py-(--cmp-chatFile-paddingY) rounded-(--cmp-chatFile-radius) border-(length:--cmp-chatFile-border-width) border-(--cmp-chatFile-border-color) bg-(--cmp-chatFile-bg-default)",
4852
+ /** 아이콘 칩 ↔ 파일명 간격 */
4853
+ contentGap: "gap-(--cmp-chatFile-gap)",
4854
+ /**
4855
+ * 클립 아이콘이 앉는 칩 — 내부 패딩·면·라운드 (높이는 아이콘+패딩이 정한다).
4856
+ *
4857
+ * hover 면은 상자가 아니라 여기에도 걸린다 — 카드가 어두워질 때 칩은 반대로 밝아져
4858
+ * 칩이 배경에 묻히지 않는다. 상자의 hover 를 따라가야 하므로 group-hover 로 받는다.
4859
+ *
4860
+ * **`--sys-color-bg-frame` 은 임시다.** 시안의 hover 칩 색(`#FFFFFF`)에 대응하는
4861
+ * 컴포넌트 토큰이 없다 — `component.chatMessage.chatFile.icon.wrapper.bg` 는 값이 하나뿐이라
4862
+ * hover 를 담지 못한다. 상자의 `bg.default` 가 참조하는 것과 같은 시스템 토큰으로 대신 걸어 둔다.
4863
+ * 디자인팀에 `icon.wrapper.bg.hover` 를 요청해 나오는 대로 갈아끼운다.
4864
+ */
4865
+ tile: "p-(--cmp-chatFile-icon-wrapper-padding) rounded-(--cmp-chatFile-icon-wrapper-radius) bg-(--cmp-chatFile-icon-wrapper-bg) group-hover/chat-file:bg-(--sys-color-bg-frame)",
4866
+ /** 칩 안 클립 아이콘 크기(px). SVG width/height 는 속성값이라 CSS 변수를 못 받아 값으로 둔다 (토큰 값과 동일) */
4867
+ iconSize: 20,
4868
+ /** 파일명 타이포 프리셋 */
4869
+ nameTypo: "typo-body-md-bold",
4870
+ /** 파일명·부가정보 텍스트색 */
4871
+ textColor: "text-(--cmp-chatFile-text-color)",
4872
+ /**
4873
+ * 눌리는 모양 — 커서·hover 면·포커스 링. 보낸 파일은 언제나 열 수 있으므로 늘 붙는다
4874
+ * (`onFileClick` 이 필수다).
4875
+ *
4876
+ * 상자의 여백·면·선과 따로 두는 이유: 이건 상호작용을 드러내는 값이라 성격이 다르다.
4877
+ * 링은 `SExpansionItem`·`SStepper` 와 같은 accent outline.
4878
+ */
4879
+ interactive: "cursor-pointer hover:bg-(--cmp-chatFile-bg-hover) focus-visible:outline focus-visible:outline-2 focus-visible:outline-(--sys-color-border-accent)"
4880
+ };
4881
+ var SIZE_UNITS = ["B", "KB", "MB", "GB", "TB"];
4882
+ function formatFileSize(bytes) {
4883
+ if (!Number.isFinite(bytes) || bytes < 0) return "";
4884
+ let value = bytes;
4885
+ let unit = 0;
4886
+ while (value >= 1024 && unit < SIZE_UNITS.length - 1) {
4887
+ value /= 1024;
4888
+ unit += 1;
4889
+ }
4890
+ return unit === 0 ? `${Math.round(value)}${SIZE_UNITS[0]}` : `${value.toFixed(1)}${SIZE_UNITS[unit]}`;
4891
+ }
4892
+ function normalizeExtension(extension) {
4893
+ return extension.trim().replace(/^\.+/, "").toLowerCase();
4894
+ }
4895
+ function fileExtension(name) {
4896
+ const dot = name.lastIndexOf(".");
4897
+ return dot > 0 && dot < name.length - 1 ? name.slice(dot + 1).toLowerCase() : "";
4898
+ }
4899
+ var SChatFileImpl = /* @__PURE__ */ react.forwardRef(function SChatFile({ name, extension, size, onFileClick, className, ...rest }, ref) {
4900
+ const ext = extension != null ? normalizeExtension(extension) : fileExtension(name);
4901
+ const meta = [ext, size != null ? formatFileSize(size) : ""].filter(Boolean).join(" / ");
4902
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4903
+ "div",
4904
+ {
4905
+ ref,
4906
+ className: cn(
4907
+ // group/chat-file: 아이콘 칩이 상자의 hover 를 따라가야 해서 이름을 붙인다 (config.tile 참고)
4908
+ "group/chat-file inline-flex max-w-full items-center border-solid",
4909
+ CHAT_FILE_CONFIG.box,
4910
+ CHAT_FILE_CONFIG.contentGap,
4911
+ CHAT_FILE_CONFIG.interactive,
4912
+ className
4913
+ ),
4914
+ ...rest,
4915
+ role: "button",
4916
+ tabIndex: 0,
4917
+ onClick: (event) => {
4918
+ rest.onClick?.(event);
4919
+ onFileClick?.();
4920
+ },
4921
+ onKeyDown: (event) => {
4922
+ rest.onKeyDown?.(event);
4923
+ if (event.key !== "Enter" && event.key !== " ") return;
4924
+ event.preventDefault();
4925
+ onFileClick?.();
4926
+ },
4927
+ children: [
4928
+ /* @__PURE__ */ jsxRuntime.jsx(
4929
+ "span",
4930
+ {
4931
+ className: cn(
4932
+ "inline-grid shrink-0 place-items-center text-(--sys-color-fg-accentLight)",
4933
+ CHAT_FILE_CONFIG.tile
4934
+ ),
4935
+ children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "attachFile", size: CHAT_FILE_CONFIG.iconSize })
4936
+ }
4937
+ ),
4938
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
4939
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("truncate", CHAT_FILE_CONFIG.nameTypo, CHAT_FILE_CONFIG.textColor), children: name }),
4940
+ meta !== "" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("typo-body-xs-default truncate", CHAT_FILE_CONFIG.textColor), children: meta })
4941
+ ] })
4942
+ ]
4943
+ }
4944
+ );
4945
+ });
4946
+ var SChatFile2 = /* @__PURE__ */ withDisplayName(SChatFileImpl, "SChatFile");
4862
4947
  var CHAT_MESSAGE_DIRECTIONS = ["incoming", "outgoing"];
4863
- var CHAT_MESSAGE_VARIANTS = ["default", "template"];
4948
+ var CHAT_MESSAGE_VARIANTS = ["default", "template", "admin"];
4864
4949
  var BUBBLE_SURFACE = {
4865
- incoming: "bg-(--sys-color-bg-screen) text-(--sys-color-fg-primary)",
4866
- outgoing: "bg-(--sys-color-bg-brand) text-(--sys-color-fg-inverse)",
4867
- template: "bg-(--sys-color-bg-accentFaint) text-(--sys-color-fg-deep)"
4950
+ incoming: "bg-(--cmp-chatBubble-incoming-bg) text-(--cmp-chatBubble-incoming-content)",
4951
+ outgoing: "bg-(--cmp-chatBubble-outgoing-general-bg) text-(--cmp-chatBubble-outgoing-general-content)",
4952
+ template: "bg-(--cmp-chatBubble-templete-bg) text-(--cmp-chatBubble-templete-content)",
4953
+ // TODO: `chatBubble.outgoing.admin` 토큰이 생기면 둘 다 그쪽으로 교체한다.
4954
+ // 지금은 admin 면을 가리키는 컴포넌트 토큰이 없어 글자색만 시맨틱 토큰을 직접 쓴다.
4955
+ admin: "bg-(--cmp-chatBubble-outgoing-default-bg) text-(--sys-color-fg-deep)"
4956
+ };
4957
+ var OUTGOING_SURFACE = {
4958
+ default: "outgoing",
4959
+ template: "template",
4960
+ admin: "admin"
4868
4961
  };
4869
4962
  var CHAT_MESSAGE_READ_STATUSES = ["read", "unread"];
4870
4963
  var READ_STATUS_LABEL = {
@@ -4872,8 +4965,8 @@ var READ_STATUS_LABEL = {
4872
4965
  unread: "\uC548 \uC77D\uC74C"
4873
4966
  };
4874
4967
  var READ_STATUS_COLOR = {
4875
- read: "text-(--sys-color-fg-tertiary)",
4876
- unread: "text-(--sys-color-fg-warning)"
4968
+ read: "text-(--cmp-chatTimeStamp-color)",
4969
+ unread: "text-(--cmp-chatReadMark-color)"
4877
4970
  };
4878
4971
  var AVATAR_SIZE = 32;
4879
4972
  var AVATAR_ROW_HEIGHT = 40;
@@ -4885,7 +4978,7 @@ function Avatar({ src, alt, placeholder }) {
4885
4978
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 items-center", style: { height: AVATAR_ROW_HEIGHT }, children: /* @__PURE__ */ jsxRuntime.jsx(
4886
4979
  "div",
4887
4980
  {
4888
- className: "relative overflow-hidden rounded-full bg-(--sys-color-bg-screen)",
4981
+ className: "relative overflow-hidden rounded-(--cmp-chatAvatar-radius) bg-(--cmp-chatAvatar-bg)",
4889
4982
  style: { width: AVATAR_SIZE, height: AVATAR_SIZE },
4890
4983
  children: src != null ? /* @__PURE__ */ jsxRuntime.jsx(SImage, { src, alt: alt ?? "", fit: "cover", className: "h-full w-full" }) : (
4891
4984
  // 원 밖으로 나가는 만큼을 좌우로 나눠 가운데를 맞추고, 아래는 원이 자른다.
@@ -4894,7 +4987,7 @@ function Avatar({ src, alt, placeholder }) {
4894
4987
  {
4895
4988
  name: "user",
4896
4989
  size: AVATAR_ICON_SIZE,
4897
- color: "var(--sys-color-fg-quaternary)",
4990
+ color: "var(--cmp-chatAvatar-icon)",
4898
4991
  className: "absolute top-0",
4899
4992
  style: { left: (AVATAR_SIZE - AVATAR_ICON_SIZE) / 2 }
4900
4993
  }
@@ -4914,12 +5007,14 @@ var SChatMessageImpl = /* @__PURE__ */ react.forwardRef(function SChatMessage({
4914
5007
  variant = "default",
4915
5008
  actions,
4916
5009
  messages,
5010
+ attachments,
4917
5011
  className,
4918
5012
  ...rest
4919
5013
  }, ref) {
4920
5014
  const outgoing = direction === "outgoing";
4921
- const surface = direction === "outgoing" && variant === "template" ? "template" : direction;
5015
+ const surface = outgoing ? OUTGOING_SURFACE[variant] : "incoming";
4922
5016
  const bubbles = messages ?? [];
5017
+ const files = attachments ?? [];
4923
5018
  return /* @__PURE__ */ jsxRuntime.jsxs(
4924
5019
  "div",
4925
5020
  {
@@ -4927,45 +5022,77 @@ var SChatMessageImpl = /* @__PURE__ */ react.forwardRef(function SChatMessage({
4927
5022
  className: cn(
4928
5023
  // 아바타와 본문 열이 같은 줄에 서고, 보낸 메시지는 좌우를 뒤집는다.
4929
5024
  // items-start 라 이름이 있든 없든 아바타는 언제나 첫 줄에 붙는다.
4930
- "flex items-start gap-sd-12",
5025
+ "flex items-start gap-(--cmp-chatMessage-avatarGap)",
4931
5026
  outgoing && "flex-row-reverse",
4932
5027
  className
4933
5028
  ),
4934
5029
  ...rest,
4935
5030
  children: [
4936
5031
  !outgoing && /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: avatarSrc, alt: avatarAlt, placeholder: continued }),
4937
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex min-w-0 flex-col gap-sd-4", outgoing ? "items-end" : "items-start"), children: [
4938
- !outgoing && !continued && sender != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-body-sm-default px-sd-8 text-(--sys-color-fg-secondary)", children: sender }),
4939
- bubbles.length > 0 && // 말풍선끼리는 이름·시각과의 간격(4px)보다 벌려 한 덩어리 안의 여러 발화로 읽히게 한다.
4940
- /* @__PURE__ */ jsxRuntime.jsx(
4941
- "div",
4942
- {
4943
- className: cn("flex min-w-0 flex-col gap-sd-8", outgoing ? "items-end" : "items-start"),
4944
- children: bubbles.map((message, index) => /* @__PURE__ */ jsxRuntime.jsx(
5032
+ /* @__PURE__ */ jsxRuntime.jsxs(
5033
+ "div",
5034
+ {
5035
+ className: cn(
5036
+ "flex min-w-0 flex-col gap-(--cmp-chatMessage-contents-gap)",
5037
+ outgoing ? "items-end" : "items-start"
5038
+ ),
5039
+ children: [
5040
+ !outgoing && !continued && sender != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-body-sm-bold px-(--cmp-chatMessage-name-paddingX) text-(--cmp-chatMessage-name-color)", children: sender }),
5041
+ bubbles.length > 0 && // 말풍선끼리는 이름·시각과의 간격(4px)보다 벌려 한 덩어리 안의 여러 발화로 읽히게 한다.
5042
+ /* @__PURE__ */ jsxRuntime.jsx(
4945
5043
  "div",
4946
5044
  {
4947
5045
  className: cn(
4948
- // 라운드 12px 은 대응 토큰이 없어 값으로 둔다 (디자인팀 토큰 추가 요청 대상).
4949
- "typo-body-md-default max-w-full rounded-[12px] px-sd-16 py-sd-8",
4950
- // 한글은 기본 규칙으로 두면 어절 한가운데서도 줄이 바뀐다 — 띄어쓰기에서만 끊고,
4951
- // 끊을 자리가 없는 긴 토큰(URL·주문번호)만 흘려보낸다.
4952
- "break-keep wrap-break-word",
4953
- BUBBLE_SURFACE[surface]
5046
+ "flex min-w-0 flex-col gap-(--cmp-chatMessage-group-bubble-gap)",
5047
+ outgoing ? "items-end" : "items-start"
4954
5048
  ),
4955
- children: message
4956
- },
4957
- index
4958
- ))
4959
- }
4960
- ),
4961
- (readStatus != null || time != null) && // 읽음 표시와 시각은 한 줄에 선다 — 읽음이 먼저, 시각이 뒤다.
4962
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "typo-body-sm-default flex items-center gap-sd-4 px-sd-8", children: [
4963
- readStatus != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: READ_STATUS_COLOR[readStatus], children: READ_STATUS_LABEL[readStatus] }),
4964
- time != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-(--sys-color-fg-tertiary)", children: time })
4965
- ] }),
4966
- actions != null && // 버튼이 많아 한 줄에 안 들어가면 감싼다 — 넘쳐서 잘리는 것보다 낫다.
4967
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-wrap gap-sd-8 px-sd-8", outgoing && "justify-end"), children: actions })
4968
- ] })
5049
+ children: bubbles.map((message, index) => /* @__PURE__ */ jsxRuntime.jsx(
5050
+ "div",
5051
+ {
5052
+ className: cn(
5053
+ "typo-body-md-medium max-w-full rounded-(--cmp-chatBubble-radius) px-(--cmp-chatBubble-paddingX) py-(--cmp-chatBubble-paddingY)",
5054
+ // 한글은 기본 규칙으로 두면 어절 한가운데서도 줄이 바뀐다 — 띄어쓰기에서만 끊고,
5055
+ // 끊을 자리가 없는 긴 토큰(URL·주문번호)만 흘려보낸다.
5056
+ "break-keep wrap-break-word",
5057
+ BUBBLE_SURFACE[surface]
5058
+ ),
5059
+ children: message
5060
+ },
5061
+ index
5062
+ ))
5063
+ }
5064
+ ),
5065
+ files.length > 0 && // 파일 칸끼리는 말풍선과 같은 간격으로 벌린다 — 한 덩어리 안의 여러 발화로 읽힌다.
5066
+ // 말풍선과 달리 면으로 감싸지 않는다 (`attachments` 주석 참고).
5067
+ /* @__PURE__ */ jsxRuntime.jsx(
5068
+ "div",
5069
+ {
5070
+ className: cn(
5071
+ "flex min-w-0 flex-col gap-(--cmp-chatMessage-group-bubble-gap)",
5072
+ outgoing ? "items-end" : "items-start"
5073
+ ),
5074
+ children: files.map((file, index) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-full", children: file }, index))
5075
+ }
5076
+ ),
5077
+ (readStatus != null || time != null) && // 읽음 표시와 시각은 한 줄에 선다 — 읽음이 먼저, 시각이 뒤다.
5078
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-(--cmp-chatMessage-subData-gap) px-(--cmp-chatMessage-subData-paddingX)", children: [
5079
+ readStatus != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("typo-body-sm-bold", READ_STATUS_COLOR[readStatus]), children: READ_STATUS_LABEL[readStatus] }),
5080
+ time != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-body-sm-medium text-(--cmp-chatTimeStamp-color)", children: time })
5081
+ ] }),
5082
+ actions != null && // 버튼이 많아 한 줄에 안 들어가면 감싼다 — 넘쳐서 잘리는 것보다 낫다.
5083
+ /* @__PURE__ */ jsxRuntime.jsx(
5084
+ "div",
5085
+ {
5086
+ className: cn(
5087
+ "flex flex-wrap gap-sd-8 px-(--cmp-chatMessage-bottomButtons-paddingX)",
5088
+ outgoing && "justify-end"
5089
+ ),
5090
+ children: actions
5091
+ }
5092
+ )
5093
+ ]
5094
+ }
5095
+ )
4969
5096
  ]
4970
5097
  }
4971
5098
  );
@@ -4981,14 +5108,13 @@ var SChatSystemMessageImpl = /* @__PURE__ */ react.forwardRef(
4981
5108
  "span",
4982
5109
  {
4983
5110
  className: cn(
4984
- // 라운드 15px 은 한 줄일 때 높이(20+4×2+1×2=30px)의 절반이다 — 한 줄에서는
4985
- // 완전한 알약으로 보이고, 여러 줄이 돼도 모서리가 상자 높이를 따라 부풀지 않는다.
4986
- // rounded-full 로 두면 두 줄부터 좌우가 커다란 반원이 되어 첫 글자가 안으로 밀린다.
4987
- // 대응 토큰이 없어 값으로 둔다 (디자인팀 토큰 추가 요청 대상).
4988
- "inline-flex max-w-full rounded-[15px] border",
4989
- "border-(--sys-color-border-default) bg-(--sys-color-bg-neutralBright)",
4990
- "typo-body-sm-default text-(--sys-color-fg-secondary)",
4991
- "px-sd-16 py-sd-4 text-center",
5111
+ // 라운드는 말풍선과 같은 토큰을 쓴다 — 여러 줄이 돼도 모서리가 상자 높이를 따라
5112
+ // 부풀지 않는다. 제 몫인 chatSystemMessage.radius 는 pill(9999px)이라 쓰지 않는다.
5113
+ // 두 줄부터 좌우가 커다란 반원이 되어 첫 글자가 안으로 밀리기 때문이다.
5114
+ "inline-flex max-w-full rounded-(--cmp-chatBubble-radius) border",
5115
+ "border-(--cmp-chatSystemMessage-border-color) bg-(--cmp-chatSystemMessage-bg)",
5116
+ "typo-body-sm-medium text-(--cmp-chatSystemMessage-color)",
5117
+ "px-(--cmp-chatSystemMessage-paddingX) py-(--cmp-chatSystemMessage-paddingY) text-center",
4992
5118
  // 한글은 기본 규칙으로 두면 어절 한가운데서도 줄이 바뀐다 — 띄어쓰기에서만 끊고,
4993
5119
  // 끊을 자리가 없는 긴 토큰(URL·주문번호)만 흘려보낸다 (SChatMessage 말풍선과 같은 규칙).
4994
5120
  // 가운데 정렬이라 마지막 줄에 한 단어만 남으면 특히 눈에 띄므로 text-pretty 로 줄을 고른다.
@@ -6313,10 +6439,21 @@ function SCheckbox({
6313
6439
  ) })
6314
6440
  }
6315
6441
  ),
6316
- label && // 고스트(500) 텍스트로 너비를 고정 → 두께 400↔500 전환 시 레이아웃이 밀리지 않음
6317
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "grid text-nowrap text-[12px] leading-[20px]", style: { color: labelColor }, children: [
6318
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "invisible font-medium", style: { gridArea: "1 / 1" }, children: label }),
6319
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { gridArea: "1 / 1", fontWeight: isChecked ? 500 : 400 }, children: label })
6442
+ label && // 고스트(500) 텍스트로 너비를 고정 → 두께 400↔500 전환 시 레이아웃이 밀리지 않음.
6443
+ // 한글은 기본 규칙으로 두면 어절 한가운데서도 줄이 바뀐다. 그러면 min-content 가 한 글자가
6444
+ // 되어, flex 아이템을 지켜 주는 min-width:auto 가 무력해지고 폭이 남는데도 라벨부터
6445
+ // 찌그러진다 — 띄어쓰기에서만 끊고, 끊을 자리가 없는 긴 토큰만 흘려보낸다
6446
+ // (SRadio·SSwitch 라벨과 같은 규칙). 두 사본에 함께 걸려야 하므로 바깥 grid 에 준다.
6447
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "grid break-keep wrap-break-word", style: { color: labelColor }, children: [
6448
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "typo-body-sm-medium invisible", style: { gridArea: "1 / 1" }, children: label }),
6449
+ /* @__PURE__ */ jsxRuntime.jsx(
6450
+ "span",
6451
+ {
6452
+ className: isChecked ? "typo-body-sm-medium" : "typo-body-sm-default",
6453
+ style: { gridArea: "1 / 1" },
6454
+ children: label
6455
+ }
6456
+ )
6320
6457
  ] })
6321
6458
  ]
6322
6459
  }
@@ -7770,7 +7907,7 @@ function SSwitch({
7770
7907
  style
7771
7908
  }) {
7772
7909
  const right = rightLabel;
7773
- const renderLabel = (text) => text ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[12px] font-medium leading-[20px]", children: text }) : null;
7910
+ const renderLabel = (text) => text ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-body-sm-medium break-keep wrap-break-word", children: text }) : null;
7774
7911
  const trackBg = disabled ? value ? "var(--cmp-switch-bg-disabled-on)" : "var(--cmp-switch-bg-disabled-off)" : value ? "var(--cmp-switch-bg-on)" : "var(--cmp-switch-bg-off)";
7775
7912
  return /* @__PURE__ */ jsxRuntime.jsxs(
7776
7913
  "label",
@@ -11777,7 +11914,7 @@ var SPageHeader = /* @__PURE__ */ withDisplayName(
11777
11914
  // plain 에는 전용 배경 토큰이 없어 시스템 흰 표면을 쓴다(토큰이 생기면 그것으로 갈아끼운다).
11778
11915
  bar ? "h-(--cmp-pageHeader-bar-height) border-b border-(--cmp-pageHeader-bar-border) bg-(--cmp-pageHeader-bar-bg) py-(--cmp-pageHeader-bar-paddingY)" : cn(
11779
11916
  // 스크롤되면 그림자를 더해 콘텐츠 위에 뜬 것처럼 보이게 한다.
11780
- "bg-(--sys-color-bg-frame) pt-(--cmp-pageHeader-plain-paddingTop) pb-(--cmp-pageHeader-plain-paddingBottom)",
11917
+ "bg-(--sys-color-bg-frame) py-(--cmp-pageHeader-plain-paddingY)",
11781
11918
  isScrolled && "shadow-floating"
11782
11919
  ),
11783
11920
  className
@@ -11787,7 +11924,10 @@ var SPageHeader = /* @__PURE__ */ withDisplayName(
11787
11924
  children: /* @__PURE__ */ jsxRuntime.jsxs(
11788
11925
  "div",
11789
11926
  {
11790
- className: "flex min-w-0 flex-1 items-center gap-(--cmp-pageHeader-gap)",
11927
+ className: cn(
11928
+ "flex min-w-0 flex-1 gap-(--cmp-pageHeader-gap)",
11929
+ bar ? "items-center" : "items-start"
11930
+ ),
11791
11931
  style: rowStyle,
11792
11932
  children: [
11793
11933
  hasBack && /* @__PURE__ */ jsxRuntime.jsx(
@@ -11797,7 +11937,7 @@ var SPageHeader = /* @__PURE__ */ withDisplayName(
11797
11937
  size: "xs",
11798
11938
  ariaLabel: "\uB4A4\uB85C\uAC00\uAE30",
11799
11939
  onClick: onBack,
11800
- className: "shrink-0"
11940
+ className: cn("shrink-0", bar ? "" : "mt-[3px]")
11801
11941
  }
11802
11942
  ),
11803
11943
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -15930,7 +16070,7 @@ function SRadio({
15930
16070
  label && /* @__PURE__ */ jsxRuntime.jsxs(
15931
16071
  "span",
15932
16072
  {
15933
- className: "grid",
16073
+ className: "grid break-keep wrap-break-word",
15934
16074
  style: {
15935
16075
  color: disabled ? "var(--cmp-radio-label-disabled)" : "var(--cmp-radio-label-default)"
15936
16076
  },
@@ -17745,6 +17885,673 @@ function SKeyValueTable({
17745
17885
  )
17746
17886
  ] });
17747
17887
  }
17888
+
17889
+ // src/lib/chart/scale.ts
17890
+ function niceNum(range, round) {
17891
+ if (range <= 0) return 1;
17892
+ const exponent = Math.floor(Math.log10(range));
17893
+ const fraction = range / 10 ** exponent;
17894
+ let nice;
17895
+ if (round) {
17896
+ nice = fraction < 1.5 ? 1 : fraction < 3 ? 2 : fraction < 7 ? 5 : 10;
17897
+ } else {
17898
+ nice = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10;
17899
+ }
17900
+ return nice * 10 ** exponent;
17901
+ }
17902
+ function trim(value, step) {
17903
+ const decimals = Math.max(0, -Math.floor(Math.log10(step)));
17904
+ return Number(value.toFixed(Math.min(decimals, 10)));
17905
+ }
17906
+ function niceScale(values, tickCount, fixedMax) {
17907
+ const finite = values.filter(Number.isFinite);
17908
+ const count = Math.max(2, Math.floor(tickCount));
17909
+ const rawMin = Math.min(0, ...finite);
17910
+ const rawMax = fixedMax ?? Math.max(0, ...finite);
17911
+ if (!Number.isFinite(rawMin) || !Number.isFinite(rawMax) || rawMax === rawMin) {
17912
+ const ticks2 = Array.from({ length: count }, (_, i) => i);
17913
+ return { min: 0, max: count - 1, ticks: ticks2 };
17914
+ }
17915
+ const range = niceNum(rawMax - rawMin, false);
17916
+ const step = niceNum(range / (count - 1), true);
17917
+ const min = trim(Math.floor(rawMin / step) * step, step);
17918
+ const max = trim(Math.ceil(rawMax / step) * step, step);
17919
+ const ticks = [];
17920
+ for (let v = min; v <= max + step / 2; v += step) ticks.push(trim(v, step));
17921
+ return { min, max, ticks };
17922
+ }
17923
+ function ratioOf(value, scale) {
17924
+ const span = scale.max - scale.min;
17925
+ if (span <= 0) return 0;
17926
+ return (value - scale.min) / span;
17927
+ }
17928
+ var AXIS_LABEL_GAP = 8;
17929
+ function ChartGrid({ scale, direction, width, height }) {
17930
+ const vertical = direction === "vertical";
17931
+ return /* @__PURE__ */ jsxRuntime.jsx("g", { "aria-hidden": true, children: scale.ticks.map((tick) => {
17932
+ const ratio = ratioOf(tick, scale);
17933
+ const isBaseline = tick === 0;
17934
+ const color = isBaseline ? "var(--cmp-chart-baseline-color)" : "var(--cmp-chart-grid-line-color)";
17935
+ const position = vertical ? height - ratio * height : ratio * width;
17936
+ const extent = vertical ? height : width;
17937
+ const snapped = Math.min(Math.max(Math.round(position), 0), Math.max(0, extent - 1)) + 0.5;
17938
+ return vertical ? /* @__PURE__ */ jsxRuntime.jsx(
17939
+ "line",
17940
+ {
17941
+ x1: 0,
17942
+ x2: width,
17943
+ y1: snapped,
17944
+ y2: snapped,
17945
+ stroke: color,
17946
+ strokeWidth: 1
17947
+ },
17948
+ tick
17949
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
17950
+ "line",
17951
+ {
17952
+ x1: snapped,
17953
+ x2: snapped,
17954
+ y1: 0,
17955
+ y2: height,
17956
+ stroke: color,
17957
+ strokeWidth: 1
17958
+ },
17959
+ tick
17960
+ );
17961
+ }) });
17962
+ }
17963
+ function ChartAxisLabels({
17964
+ scale,
17965
+ direction,
17966
+ format,
17967
+ className,
17968
+ style,
17969
+ sampleRef
17970
+ }) {
17971
+ const vertical = direction === "vertical";
17972
+ const widest = scale.ticks.reduce((longest, tick) => {
17973
+ const text = format(tick);
17974
+ return text.length > longest.length ? text : longest;
17975
+ }, "");
17976
+ return /* @__PURE__ */ jsxRuntime.jsxs(
17977
+ "div",
17978
+ {
17979
+ "aria-hidden": true,
17980
+ className: cn(
17981
+ "relative typo-body-sm-medium text-(--cmp-chart-axis-color)",
17982
+ vertical ? "h-full" : "w-full",
17983
+ className
17984
+ ),
17985
+ style,
17986
+ children: [
17987
+ scale.ticks.map((tick) => {
17988
+ const ratio = ratioOf(tick, scale);
17989
+ return vertical ? /* @__PURE__ */ jsxRuntime.jsx(
17990
+ "span",
17991
+ {
17992
+ className: "absolute right-0 -translate-y-1/2 whitespace-nowrap",
17993
+ style: { top: `${(1 - ratio) * 100}%` },
17994
+ children: format(tick)
17995
+ },
17996
+ tick
17997
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
17998
+ "span",
17999
+ {
18000
+ className: "absolute top-0 -translate-x-1/2 whitespace-nowrap",
18001
+ style: { left: `${ratio * 100}%` },
18002
+ children: format(tick)
18003
+ },
18004
+ tick
18005
+ );
18006
+ }),
18007
+ /* @__PURE__ */ jsxRuntime.jsx("span", { ref: sampleRef, "aria-hidden": true, className: "invisible inline-block whitespace-nowrap", children: vertical ? widest : "0" })
18008
+ ]
18009
+ }
18010
+ );
18011
+ }
18012
+ var ChartFrame = /* @__PURE__ */ react.forwardRef(function ChartFrame2({ legend, legendPosition = "top", children, className, style, ...props }, ref) {
18013
+ return /* @__PURE__ */ jsxRuntime.jsxs(
18014
+ "div",
18015
+ {
18016
+ ref,
18017
+ className: cn(
18018
+ "flex w-full flex-col gap-(--cmp-chart-gap)",
18019
+ "p-(--cmp-chart-paddingAll) bg-(--cmp-chart-bg)",
18020
+ className
18021
+ ),
18022
+ style,
18023
+ ...props,
18024
+ children: [
18025
+ legend && legendPosition === "top" && legend,
18026
+ children,
18027
+ legend && legendPosition === "bottom" && legend
18028
+ ]
18029
+ }
18030
+ );
18031
+ });
18032
+ var DOT_SIZE = 6;
18033
+ function ChartLegend({ items, align = "center", activeIndex, className }) {
18034
+ if (items.length === 0) return null;
18035
+ return /* @__PURE__ */ jsxRuntime.jsx(
18036
+ "ul",
18037
+ {
18038
+ className: cn(
18039
+ "flex list-none flex-wrap items-center gap-x-(--cmp-chart-legend-group-gap) p-0",
18040
+ align === "start" && "justify-start",
18041
+ align === "center" && "justify-center",
18042
+ align === "end" && "justify-end",
18043
+ className
18044
+ ),
18045
+ children: items.map((item4, index) => /* @__PURE__ */ jsxRuntime.jsxs(
18046
+ "li",
18047
+ {
18048
+ className: cn(
18049
+ "flex items-center gap-(--cmp-chart-legend-legendItem-gap)",
18050
+ "py-(--cmp-chart-legend-legendItem-paddingY)",
18051
+ "typo-body-sm-medium text-(--cmp-chart-legend-legendItem-color)",
18052
+ "transition-opacity",
18053
+ activeIndex != null && activeIndex !== index && "opacity-(--opacity-060)"
18054
+ ),
18055
+ children: [
18056
+ /* @__PURE__ */ jsxRuntime.jsx(
18057
+ "span",
18058
+ {
18059
+ "aria-hidden": true,
18060
+ className: "shrink-0 rounded-full",
18061
+ style: { width: DOT_SIZE, height: DOT_SIZE, background: item4.color }
18062
+ }
18063
+ ),
18064
+ item4.name
18065
+ ]
18066
+ },
18067
+ `${item4.name}-${index}`
18068
+ ))
18069
+ }
18070
+ );
18071
+ }
18072
+
18073
+ // src/lib/chart/palette.ts
18074
+ var V3 = (path) => `var(--cmp-chart-palette-${path})`;
18075
+ var CHART_COLORS = {
18076
+ positivePrimary: V3("variation-positivePrimary"),
18077
+ positiveSecondary: V3("variation-positiveSecondary"),
18078
+ negativePrimary: V3("variation-negativePrimary"),
18079
+ negativeSecondary: V3("variation-negativeSecondary"),
18080
+ neutralPrimary: V3("variation-neutralPrimary"),
18081
+ neutralSecondary: V3("variation-neutralSecondary")
18082
+ };
18083
+ var CHART_PALETTES = {
18084
+ default: [V3("single")],
18085
+ multi: [
18086
+ V3("multi-blue"),
18087
+ V3("multi-skyblue"),
18088
+ V3("multi-yellow"),
18089
+ V3("multi-olive"),
18090
+ V3("multi-lightRed"),
18091
+ V3("multi-warmBlue"),
18092
+ V3("multi-orange"),
18093
+ V3("multi-green"),
18094
+ V3("multi-navy"),
18095
+ V3("multi-grey"),
18096
+ V3("multi-red")
18097
+ ],
18098
+ gradation: [
18099
+ V3("gradation-1"),
18100
+ V3("gradation-2"),
18101
+ V3("gradation-3"),
18102
+ V3("gradation-4"),
18103
+ V3("gradation-5"),
18104
+ V3("gradation-6")
18105
+ ]
18106
+ };
18107
+ function paletteColor(palette, index, colors) {
18108
+ if (palette === "custom") {
18109
+ if (!colors?.length) return CHART_PALETTES.default[0];
18110
+ return CHART_COLORS[colors[index % colors.length]];
18111
+ }
18112
+ const list = CHART_PALETTES[palette] ?? CHART_PALETTES.default;
18113
+ return list[index % list.length];
18114
+ }
18115
+ function useElementSize() {
18116
+ const ref = react.useRef(null);
18117
+ const [size, setSize] = react.useState({ width: 0, height: 0 });
18118
+ react.useEffect(() => {
18119
+ const element = ref.current;
18120
+ if (!element) return;
18121
+ const update = () => {
18122
+ const { width, height } = element.getBoundingClientRect();
18123
+ setSize(
18124
+ (prev) => Math.abs(prev.width - width) < 0.5 && Math.abs(prev.height - height) < 0.5 ? prev : { width, height }
18125
+ );
18126
+ };
18127
+ update();
18128
+ if (typeof ResizeObserver === "undefined") return;
18129
+ const observer = new ResizeObserver(update);
18130
+ observer.observe(element);
18131
+ return () => observer.disconnect();
18132
+ }, []);
18133
+ return { ref, size };
18134
+ }
18135
+ var DOT_SIZE2 = 6;
18136
+ var CURSOR_OFFSET = 12;
18137
+ function place(cursor, size, extent) {
18138
+ if (!extent || !size) return cursor + CURSOR_OFFSET;
18139
+ const after = cursor + CURSOR_OFFSET;
18140
+ if (after + size <= extent) return after;
18141
+ const before = cursor - CURSOR_OFFSET - size;
18142
+ if (before >= 0) return before;
18143
+ return Math.max(0, Math.min(after, extent - size));
18144
+ }
18145
+ function ChartTooltip({ title, items, x, y, bounds, className }) {
18146
+ const { ref, size } = useElementSize();
18147
+ const measured = size.width > 0 && size.height > 0;
18148
+ return /* @__PURE__ */ jsxRuntime.jsxs(
18149
+ "div",
18150
+ {
18151
+ ref,
18152
+ role: "tooltip",
18153
+ className: cn(
18154
+ // left/top 대신 transform 으로 옮긴다. 좌표를 바꾸면 마우스가 움직일 때마다
18155
+ // 리플로우가 나 차트가 미세하게 흔들려 보인다. transform 은 레이아웃을
18156
+ // 건드리지 않으므로, 크기를 재기 전에 잠깐 밖으로 나가도 스크롤이 생기지 않는다.
18157
+ "pointer-events-none absolute top-0 left-0 z-10 w-max",
18158
+ "flex flex-col gap-(--cmp-chart-chartTooltip-gap)",
18159
+ "px-(--cmp-chart-chartTooltip-paddingX) py-(--cmp-chart-chartTooltip-paddingY)",
18160
+ "rounded-(--cmp-chart-chartTooltip-radius) bg-(--cmp-chart-chartTooltip-bg) shadow-floating",
18161
+ className
18162
+ ),
18163
+ style: {
18164
+ // 크기를 재기 전에는 원점에 숨겨 둔다. 커서 옆에 그려 두면 그림 밖으로
18165
+ // 넘쳐 스크롤 영역이 잠깐 늘어나고, 차트 전체가 한 번 흔들린다.
18166
+ // transform 도 스크롤 영역 계산에는 포함되므로 위치만 바꿔서는 못 막는다.
18167
+ transform: measured ? `translate(${place(x, size.width, bounds?.width ?? 0)}px, ${place(
18168
+ y,
18169
+ size.height,
18170
+ bounds?.height ?? 0
18171
+ )}px)` : void 0,
18172
+ visibility: measured ? void 0 : "hidden"
18173
+ },
18174
+ children: [
18175
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-body-md-bold text-(--cmp-chart-chartTooltip-title-color)", children: title }),
18176
+ items.map((item4, index) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-sd-8", children: [
18177
+ /* @__PURE__ */ jsxRuntime.jsx(
18178
+ "span",
18179
+ {
18180
+ "aria-hidden": true,
18181
+ className: "shrink-0 rounded-full",
18182
+ style: { width: DOT_SIZE2, height: DOT_SIZE2, background: item4.color }
18183
+ }
18184
+ ),
18185
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-body-sm-default text-(--sys-color-fg-primary)", children: item4.label }),
18186
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "typo-body-sm-bold ml-auto text-(--sys-color-fg-primary)", children: item4.value })
18187
+ ] }, `${item4.label}-${index}`))
18188
+ ]
18189
+ }
18190
+ );
18191
+ }
18192
+
18193
+ // src/components/SBarChart/barChart.config.ts
18194
+ var BAR_SIZE_MIN = 24;
18195
+ var BAR_SIZE_MAX = 80;
18196
+ var BAR_GAP = 6;
18197
+ var GROUP_PADDING_MIN = 8;
18198
+ var GROUP_PADDING_MAX = 24;
18199
+ var VALUE_LABEL_GAP = 6;
18200
+ var BAR_RADIUS = 8;
18201
+ var BAR_OPACITY_DEFAULT = "var(--opacity-080)";
18202
+ var BAR_OPACITY_DIMMED = "var(--opacity-060)";
18203
+ var BAR_VALUE_COLOR = "var(--sys-color-field-text-readOnly)";
18204
+ function bandLayout(size, categoryCount, seriesCount, barSizeMax = BAR_SIZE_MAX) {
18205
+ const categories = Math.max(1, categoryCount);
18206
+ const series = Math.max(1, seriesCount);
18207
+ const gaps = (series - 1) * BAR_GAP;
18208
+ const barRange = BAR_SIZE_MAX - BAR_SIZE_MIN;
18209
+ const padRange = GROUP_PADDING_MAX - GROUP_PADDING_MIN;
18210
+ const maxBar = Math.min(Math.max(BAR_SIZE_MIN, barSizeMax), BAR_SIZE_MAX);
18211
+ const tMax = (maxBar - BAR_SIZE_MIN) / barRange;
18212
+ const bandMin = BAR_SIZE_MIN * series + gaps + GROUP_PADDING_MIN * 2;
18213
+ const span = barRange * series + padRange * 2;
18214
+ const band = Math.min(size / categories, bandMin + span * tMax);
18215
+ const t = Math.min(Math.max((band - bandMin) / span, 0), tMax);
18216
+ const bar = BAR_SIZE_MIN + barRange * t;
18217
+ const padding = GROUP_PADDING_MIN + padRange * t;
18218
+ const group = bar * series + gaps;
18219
+ return {
18220
+ band,
18221
+ bar,
18222
+ group,
18223
+ padding,
18224
+ offset: Math.max(0, (size - band * categories) / 2)
18225
+ };
18226
+ }
18227
+ var defaultFormat = (value) => value.toLocaleString();
18228
+ function minBand(seriesCount) {
18229
+ const series = Math.max(1, seriesCount);
18230
+ return series * BAR_SIZE_MIN + (series - 1) * BAR_GAP + GROUP_PADDING_MIN * 2;
18231
+ }
18232
+ function barPath(x, y, width, height, direction, negative) {
18233
+ const r = Math.max(0, Math.min(BAR_RADIUS, width / 2, height / 2));
18234
+ if (r === 0) return `M${x} ${y}h${width}v${height}h${-width}Z`;
18235
+ if (direction === "vertical") {
18236
+ return negative ? (
18237
+ // 아래로 자란다 — 아래쪽 두 모서리가 둥글다
18238
+ `M${x} ${y}h${width}v${height - r}a${r} ${r} 0 0 1 ${-r} ${r}h${-(width - 2 * r)}a${r} ${r} 0 0 1 ${-r} ${-r}Z`
18239
+ ) : (
18240
+ // 위로 자란다 — 위쪽 두 모서리가 둥글다
18241
+ `M${x} ${y + height}v${-(height - r)}a${r} ${r} 0 0 1 ${r} ${-r}h${width - 2 * r}a${r} ${r} 0 0 1 ${r} ${r}v${height - r}Z`
18242
+ );
18243
+ }
18244
+ return negative ? (
18245
+ // 왼쪽으로 자란다
18246
+ `M${x + width} ${y}h${-(width - r)}a${r} ${r} 0 0 0 ${-r} ${r}v${height - 2 * r}a${r} ${r} 0 0 0 ${r} ${r}h${width - r}Z`
18247
+ ) : (
18248
+ // 오른쪽으로 자란다
18249
+ `M${x} ${y}h${width - r}a${r} ${r} 0 0 1 ${r} ${r}v${height - 2 * r}a${r} ${r} 0 0 1 ${-r} ${r}h${-(width - r)}Z`
18250
+ );
18251
+ }
18252
+ var SBarChart = /* @__PURE__ */ react.forwardRef(function SBarChart2({
18253
+ categories,
18254
+ series,
18255
+ direction = "vertical",
18256
+ palette = "default",
18257
+ colors: customColors,
18258
+ max,
18259
+ tickCount = 8,
18260
+ barSize = BAR_SIZE_MAX,
18261
+ showValueLabel = true,
18262
+ showLegend = true,
18263
+ legendPosition = "top",
18264
+ showTooltip = true,
18265
+ formatValue = defaultFormat,
18266
+ height,
18267
+ onBarClick,
18268
+ className,
18269
+ style
18270
+ }, ref) {
18271
+ const vertical = direction === "vertical";
18272
+ const { ref: plotRef, size } = useElementSize();
18273
+ const { ref: axisTextRef, size: axisText } = useElementSize();
18274
+ const { ref: axisSampleRef, size: axisSample } = useElementSize();
18275
+ const [hovered, setHovered] = react.useState(null);
18276
+ const hoveredCategory = hovered?.category ?? null;
18277
+ const perCategory = series.length === 1;
18278
+ const colorAt = react.useCallback(
18279
+ (seriesIndex, categoryIndex) => paletteColor(palette, perCategory ? categoryIndex : seriesIndex, customColors),
18280
+ [palette, customColors, perCategory]
18281
+ );
18282
+ const scale = react.useMemo(
18283
+ () => niceScale(
18284
+ series.flatMap((s) => s.data),
18285
+ tickCount,
18286
+ max
18287
+ ),
18288
+ [series, tickCount, max]
18289
+ );
18290
+ const axisLength = vertical ? size.width : size.height;
18291
+ const layout = react.useMemo(
18292
+ () => bandLayout(axisLength, categories.length, series.length, barSize),
18293
+ [axisLength, categories.length, series.length, barSize]
18294
+ );
18295
+ const zeroRatio = ratioOf(0, scale);
18296
+ const minPlotWidth = vertical ? categories.length * minBand(series.length) : 0;
18297
+ const totalHeight = height ?? (vertical ? 320 : void 0);
18298
+ const plotHeight = totalHeight == null ? Math.max(1, categories.length) * minBand(series.length) : typeof totalHeight === "number" ? Math.max(0, totalHeight - axisText.height) : `calc(${totalHeight} - ${axisText.height}px)`;
18299
+ const legend = showLegend ? /* @__PURE__ */ jsxRuntime.jsx(ChartLegend, { items: series.map((s, i) => ({ name: s.name, color: colorAt(i, 0) })) }) : null;
18300
+ const handleMove = (event) => {
18301
+ if (!showTooltip || categories.length === 0 || series.length === 0) return;
18302
+ const rect = event.currentTarget.getBoundingClientRect();
18303
+ const x = event.clientX - rect.left;
18304
+ const y = event.clientY - rect.top;
18305
+ const along = (vertical ? x : y) - layout.offset;
18306
+ const category = Math.floor(along / layout.band);
18307
+ if (category < 0 || category >= categories.length) {
18308
+ setHovered(null);
18309
+ return;
18310
+ }
18311
+ setHovered({ category, x, y });
18312
+ };
18313
+ const tooltipItems = hovered == null ? [] : series.flatMap((s, i) => {
18314
+ const value = s.data[hovered.category];
18315
+ if (value == null || !Number.isFinite(value)) return [];
18316
+ return [
18317
+ { color: colorAt(i, hovered.category), label: s.name, value: formatValue(value) }
18318
+ ];
18319
+ });
18320
+ const categoryLabels = /* @__PURE__ */ jsxRuntime.jsxs(
18321
+ "div",
18322
+ {
18323
+ "aria-hidden": true,
18324
+ className: cn(
18325
+ "relative typo-body-sm-medium text-(--cmp-chart-axis-color)",
18326
+ vertical ? "w-full" : "h-full"
18327
+ ),
18328
+ style: vertical ? { minWidth: minPlotWidth || void 0 } : { height: plotHeight },
18329
+ children: [
18330
+ categories.map((label, index) => {
18331
+ const center = layout.offset + (index + 0.5) * layout.band;
18332
+ return vertical ? /* @__PURE__ */ jsxRuntime.jsx(
18333
+ "span",
18334
+ {
18335
+ className: "absolute top-0 -translate-x-1/2 whitespace-nowrap",
18336
+ style: { left: center },
18337
+ children: label
18338
+ },
18339
+ `${label}-${index}`
18340
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
18341
+ "span",
18342
+ {
18343
+ className: "absolute right-0 -translate-y-1/2 whitespace-nowrap",
18344
+ style: { top: center },
18345
+ children: label
18346
+ },
18347
+ `${label}-${index}`
18348
+ );
18349
+ }),
18350
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "invisible block whitespace-nowrap", children: vertical ? "0" : categories.reduce((longest, c) => c.length > longest.length ? c : longest, "") })
18351
+ ]
18352
+ }
18353
+ );
18354
+ const bars = react.useMemo(
18355
+ () => size.width > 0 && size.height > 0 ? series.flatMap(
18356
+ (s, seriesIndex) => categories.map((_, categoryIndex) => {
18357
+ const value = s.data[categoryIndex];
18358
+ if (value == null || !Number.isFinite(value)) return null;
18359
+ const dimmed = hoveredCategory != null && hoveredCategory !== categoryIndex;
18360
+ const groupStart = layout.offset + categoryIndex * layout.band + (layout.band - layout.group) / 2;
18361
+ const offset = groupStart + seriesIndex * (layout.bar + BAR_GAP);
18362
+ const valueRatio = ratioOf(value, scale);
18363
+ const negative = value < 0;
18364
+ let x;
18365
+ let y;
18366
+ let width;
18367
+ let barHeight;
18368
+ let labelX;
18369
+ let labelY;
18370
+ if (vertical) {
18371
+ const zeroY = size.height - zeroRatio * size.height;
18372
+ const valueY = size.height - valueRatio * size.height;
18373
+ x = offset;
18374
+ width = layout.bar;
18375
+ y = Math.min(zeroY, valueY);
18376
+ barHeight = Math.abs(zeroY - valueY);
18377
+ labelX = offset + layout.bar / 2;
18378
+ labelY = negative ? y + barHeight + VALUE_LABEL_GAP + 10 : y - VALUE_LABEL_GAP;
18379
+ } else {
18380
+ const zeroX = zeroRatio * size.width;
18381
+ const valueX = valueRatio * size.width;
18382
+ x = Math.min(zeroX, valueX);
18383
+ width = Math.abs(zeroX - valueX);
18384
+ y = offset;
18385
+ barHeight = layout.bar;
18386
+ labelX = negative ? x - VALUE_LABEL_GAP : x + width + VALUE_LABEL_GAP;
18387
+ labelY = offset + layout.bar / 2;
18388
+ }
18389
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
18390
+ /* @__PURE__ */ jsxRuntime.jsx(
18391
+ "path",
18392
+ {
18393
+ d: barPath(x, y, width, barHeight, direction, negative),
18394
+ style: {
18395
+ fill: colorAt(seriesIndex, categoryIndex),
18396
+ opacity: dimmed ? BAR_OPACITY_DIMMED : BAR_OPACITY_DEFAULT,
18397
+ cursor: onBarClick ? "pointer" : void 0
18398
+ },
18399
+ onClick: onBarClick ? () => onBarClick({ seriesIndex, categoryIndex, value }) : void 0,
18400
+ children: /* @__PURE__ */ jsxRuntime.jsx("title", { children: `${categories[categoryIndex]} ${s.name} ${formatValue(value)}` })
18401
+ }
18402
+ ),
18403
+ showValueLabel && /* @__PURE__ */ jsxRuntime.jsx(
18404
+ "text",
18405
+ {
18406
+ x: labelX,
18407
+ y: labelY,
18408
+ className: "typo-body-sm-medium",
18409
+ style: { fill: BAR_VALUE_COLOR },
18410
+ textAnchor: vertical ? "middle" : negative ? "end" : "start",
18411
+ dominantBaseline: vertical ? "auto" : "central",
18412
+ children: formatValue(value)
18413
+ }
18414
+ )
18415
+ ] }, `${seriesIndex}-${categoryIndex}`);
18416
+ })
18417
+ ) : [],
18418
+ [
18419
+ size.width,
18420
+ size.height,
18421
+ series,
18422
+ categories,
18423
+ layout,
18424
+ scale,
18425
+ zeroRatio,
18426
+ vertical,
18427
+ direction,
18428
+ showValueLabel,
18429
+ formatValue,
18430
+ onBarClick,
18431
+ colorAt,
18432
+ hoveredCategory
18433
+ ]
18434
+ );
18435
+ const axisLabels = /* @__PURE__ */ jsxRuntime.jsx(
18436
+ ChartAxisLabels,
18437
+ {
18438
+ scale,
18439
+ direction,
18440
+ format: formatValue,
18441
+ sampleRef: axisSampleRef
18442
+ }
18443
+ );
18444
+ const inset = vertical ? { paddingTop: axisSample.height / 2, paddingBottom: axisSample.height / 2 } : { paddingLeft: axisSample.width / 2, paddingRight: axisSample.width / 2 };
18445
+ const plot = (
18446
+ // 바깥은 자리(높이·물러남)를, 안쪽은 그림을 맡는다. minWidth 는 바깥에 둬야
18447
+ // 스크롤 컨테이너가 넘치는 폭을 알아본다 — 안쪽에 두면 바깥이 부모 폭에 맞춰져
18448
+ // 스크롤이 생기지 않는다.
18449
+ /* @__PURE__ */ jsxRuntime.jsx(
18450
+ "div",
18451
+ {
18452
+ className: "relative min-w-0",
18453
+ style: { height: plotHeight, minWidth: minPlotWidth || void 0, ...inset },
18454
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
18455
+ "div",
18456
+ {
18457
+ ref: plotRef,
18458
+ className: "relative h-full w-full",
18459
+ onMouseMove: handleMove,
18460
+ onMouseLeave: () => setHovered(null),
18461
+ children: [
18462
+ size.width > 0 && size.height > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
18463
+ "svg",
18464
+ {
18465
+ width: size.width,
18466
+ height: size.height,
18467
+ role: "img",
18468
+ "aria-label": `${categories.length}\uAC1C \uD56D\uBAA9, ${series.length}\uAC1C \uACC4\uC5F4 \uB9C9\uB300 \uADF8\uB798\uD504`,
18469
+ children: [
18470
+ /* @__PURE__ */ jsxRuntime.jsx(
18471
+ ChartGrid,
18472
+ {
18473
+ scale,
18474
+ direction,
18475
+ width: size.width,
18476
+ height: size.height
18477
+ }
18478
+ ),
18479
+ hovered != null && /* @__PURE__ */ jsxRuntime.jsx(
18480
+ "rect",
18481
+ {
18482
+ "aria-hidden": true,
18483
+ x: vertical ? layout.offset + hovered.category * layout.band : 0,
18484
+ y: vertical ? 0 : layout.offset + hovered.category * layout.band,
18485
+ width: vertical ? layout.band : size.width,
18486
+ height: vertical ? size.height : layout.band,
18487
+ style: {
18488
+ fill: "var(--cmp-chart-barContainer-hover-bg)",
18489
+ fillOpacity: "var(--cmp-chart-barContainer-hover-opacity)"
18490
+ }
18491
+ }
18492
+ ),
18493
+ bars
18494
+ ]
18495
+ }
18496
+ ),
18497
+ showTooltip && hovered != null && series.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
18498
+ ChartTooltip,
18499
+ {
18500
+ title: categories[hovered.category] ?? "",
18501
+ items: tooltipItems,
18502
+ x: hovered.x,
18503
+ y: hovered.y,
18504
+ bounds: size
18505
+ }
18506
+ )
18507
+ ]
18508
+ }
18509
+ )
18510
+ }
18511
+ )
18512
+ );
18513
+ return /* @__PURE__ */ jsxRuntime.jsx(
18514
+ ChartFrame,
18515
+ {
18516
+ ref,
18517
+ legend,
18518
+ legendPosition,
18519
+ className,
18520
+ style,
18521
+ children: /* @__PURE__ */ jsxRuntime.jsx(
18522
+ "div",
18523
+ {
18524
+ className: "grid",
18525
+ style: {
18526
+ columnGap: AXIS_LABEL_GAP,
18527
+ // 눈금은 왼쪽 한 줄뿐이다 — 오른쪽에도 적으면 서로 다른 단위처럼 읽힌다.
18528
+ gridTemplateColumns: "max-content 1fr"
18529
+ },
18530
+ children: vertical ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
18531
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: plotHeight, ...inset }, children: /* @__PURE__ */ jsxRuntime.jsx(
18532
+ ChartAxisLabels,
18533
+ {
18534
+ scale,
18535
+ direction,
18536
+ format: formatValue,
18537
+ sampleRef: axisSampleRef
18538
+ }
18539
+ ) }),
18540
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 overflow-x-auto", children: [
18541
+ plot,
18542
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: axisTextRef, children: categoryLabels })
18543
+ ] })
18544
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
18545
+ categoryLabels,
18546
+ plot,
18547
+ /* @__PURE__ */ jsxRuntime.jsx("div", {}),
18548
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: axisTextRef, style: inset, children: axisLabels })
18549
+ ] })
18550
+ }
18551
+ )
18552
+ }
18553
+ );
18554
+ });
17748
18555
  var BUTTON_STYLE = {
17749
18556
  default: { color: "secondary" },
17750
18557
  danger: { color: "danger", outline: true },
@@ -22643,15 +23450,15 @@ var SBarcodeInput = /* @__PURE__ */ react.forwardRef(
22643
23450
  );
22644
23451
 
22645
23452
  // src/components/STimePicker/timepicker.config.ts
22646
- var V3 = (path) => `var(--cmp-timepicker-${path})`;
23453
+ var V4 = (path) => `var(--cmp-timepicker-${path})`;
22647
23454
  var TIMEPICKER_SIZES = ["sm", "md"];
22648
23455
  var TIMEPICKER_SIZE_CONFIG = {
22649
23456
  sm: {
22650
- height: V3("sm-height"),
22651
- paddingX: V3("sm-paddingX"),
22652
- gap: V3("sm-gap"),
22653
- icon: V3("sm-icon"),
22654
- radius: V3("sm-radius"),
23457
+ height: V4("sm-height"),
23458
+ paddingX: V4("sm-paddingX"),
23459
+ gap: V4("sm-gap"),
23460
+ icon: V4("sm-icon"),
23461
+ radius: V4("sm-radius"),
22655
23462
  // TODO: component.timepicker 토큰에 typography가 추가되면 CSS 변수로 교체한다.
22656
23463
  fontSize: 12,
22657
23464
  lineHeight: 20,
@@ -22660,11 +23467,11 @@ var TIMEPICKER_SIZE_CONFIG = {
22660
23467
  fieldMaxWidth: "md"
22661
23468
  },
22662
23469
  md: {
22663
- height: V3("md-height"),
22664
- paddingX: V3("md-paddingX"),
22665
- gap: V3("md-gap"),
22666
- icon: V3("md-icon"),
22667
- radius: V3("md-radius"),
23470
+ height: V4("md-height"),
23471
+ paddingX: V4("md-paddingX"),
23472
+ gap: V4("md-gap"),
23473
+ icon: V4("md-icon"),
23474
+ radius: V4("md-radius"),
22668
23475
  // TODO: component.timepicker 토큰에 typography가 추가되면 CSS 변수로 교체한다.
22669
23476
  fontSize: 14,
22670
23477
  lineHeight: 24,
@@ -23560,6 +24367,9 @@ exports.ACCOUNT_LIST_BOX_LABELS = ACCOUNT_LIST_BOX_LABELS;
23560
24367
  exports.ACCOUNT_LIST_BOX_LAYOUT = ACCOUNT_LIST_BOX_LAYOUT;
23561
24368
  exports.ACCOUNT_LIST_BOX_TONE_CONFIG = ACCOUNT_LIST_BOX_TONE_CONFIG;
23562
24369
  exports.BADGE_COLORS = BADGE_COLORS;
24370
+ exports.BAR_GAP = BAR_GAP;
24371
+ exports.BAR_SIZE_MAX = BAR_SIZE_MAX;
24372
+ exports.BAR_SIZE_MIN = BAR_SIZE_MIN;
23563
24373
  exports.BUTTON_COLORS = BUTTON_COLORS;
23564
24374
  exports.BUTTON_SIZES = BUTTON_SIZES;
23565
24375
  exports.CALENDAR_BOARD_DAY_BG = CALENDAR_BOARD_DAY_BG;
@@ -23568,7 +24378,7 @@ exports.CALENDAR_BOARD_EVENT_COLORS = CALENDAR_BOARD_EVENT_COLORS;
23568
24378
  exports.CALENDAR_BOARD_EVENT_PRESETS = CALENDAR_BOARD_EVENT_PRESETS;
23569
24379
  exports.CALENDAR_BOARD_MAX_VISIBLE_EVENTS = CALENDAR_BOARD_MAX_VISIBLE_EVENTS;
23570
24380
  exports.CHAT_ATTACHED_FILE_CONFIG = CHAT_ATTACHED_FILE_CONFIG;
23571
- exports.CHAT_ATTACHED_FILE_VARIANTS = CHAT_ATTACHED_FILE_VARIANTS;
24381
+ exports.CHAT_FILE_CONFIG = CHAT_FILE_CONFIG;
23572
24382
  exports.CHAT_MESSAGE_DIRECTIONS = CHAT_MESSAGE_DIRECTIONS;
23573
24383
  exports.CHAT_MESSAGE_READ_STATUSES = CHAT_MESSAGE_READ_STATUSES;
23574
24384
  exports.CHAT_MESSAGE_VARIANTS = CHAT_MESSAGE_VARIANTS;
@@ -23598,6 +24408,7 @@ exports.RangeCalendar = RangeCalendar;
23598
24408
  exports.SAccountListBox = SAccountListBox;
23599
24409
  exports.SActionModal = SActionModal;
23600
24410
  exports.SBadge = SBadge;
24411
+ exports.SBarChart = SBarChart;
23601
24412
  exports.SBarcodeInput = SBarcodeInput;
23602
24413
  exports.SButton = SButton;
23603
24414
  exports.SCROLL_AREA_AXES = SCROLL_AREA_AXES;
@@ -23606,6 +24417,7 @@ exports.SCalendarBoard = SCalendarBoard;
23606
24417
  exports.SCallout = SCallout;
23607
24418
  exports.SCard = SCard;
23608
24419
  exports.SChatAttachedFile = SChatAttachedFile2;
24420
+ exports.SChatFile = SChatFile2;
23609
24421
  exports.SChatInput = SChatInput2;
23610
24422
  exports.SChatMessage = SChatMessage2;
23611
24423
  exports.SChatSystemMessage = SChatSystemMessage2;