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.js CHANGED
@@ -4653,10 +4653,9 @@ var STextarea = /* @__PURE__ */ forwardRef(function STextarea2({
4653
4653
  );
4654
4654
  });
4655
4655
  var DEFAULT_PLACEHOLDER = "\uBA54\uC2DC\uC9C0\uB97C \uC785\uB825\uD574 \uC8FC\uC138\uC694...";
4656
- var FIELD_MIN_HEIGHT = 48;
4657
4656
  var FIELD_BORDER = 1;
4658
- var TEXTAREA_MIN_HEIGHT = FIELD_MIN_HEIGHT - FIELD_BORDER * 2;
4659
- var BUTTON_BOTTOM_INSET = `calc((${FIELD_MIN_HEIGHT}px - var(--cmp-ghostButton-md-size)) / 2)`;
4657
+ var TEXTAREA_MIN_HEIGHT = `calc(var(--cmp-chatInput-buttonFrame-height) - ${FIELD_BORDER * 2}px)`;
4658
+ var BUTTON_BOTTOM_INSET = `calc((var(--cmp-chatInput-buttonFrame-height) - var(--cmp-ghostButton-md-size)) / 2)`;
4660
4659
  var DEFAULT_MAX_ROWS = 5;
4661
4660
  var SChatInputImpl = /* @__PURE__ */ forwardRef(function SChatInput({
4662
4661
  value = "",
@@ -4685,8 +4684,8 @@ var SChatInputImpl = /* @__PURE__ */ forwardRef(function SChatInput({
4685
4684
  e.preventDefault();
4686
4685
  send();
4687
4686
  };
4688
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col bg-(--sys-color-field-bg-default)", className), style, children: [
4689
- /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-sd-8 p-sd-12", children: [
4687
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col bg-(--cmp-chatInput-bg)", className), style, children: [
4688
+ /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-(--cmp-chatInput-gap) p-(--cmp-chatInput-padding)", children: [
4690
4689
  onAttach != null && /* @__PURE__ */ jsx(
4691
4690
  SGhostButton,
4692
4691
  {
@@ -4748,81 +4747,67 @@ var SChatInputImpl = /* @__PURE__ */ forwardRef(function SChatInput({
4748
4747
  var SChatInput2 = /* @__PURE__ */ withDisplayName(SChatInputImpl, "SChatInput");
4749
4748
 
4750
4749
  // src/components/SChatAttachedFile/chatAttachedFile.config.ts
4751
- var CHAT_ATTACHED_FILE_VARIANTS = ["attached", "sent"];
4752
4750
  var CHAT_ATTACHED_FILE_CONFIG = {
4753
- attached: {
4754
- // 오른쪽 여백이 왼쪽보다 넓은 것은 제거 버튼이 자기 여백을 갖기 때문이다(시안 그대로).
4755
- box: "h-[30px] gap-sd-8 pl-sd-4 pr-sd-8 bg-(--sys-color-bg-neutralLight) border-(--sys-color-border-default)",
4756
- tile: "h-[20px] w-[20px] bg-(--sys-color-bg-frame)",
4757
- iconSize: 16,
4758
- nameTypo: "typo-body-sm-default"
4759
- },
4760
- sent: {
4761
- box: "h-[56px] gap-sd-12 px-sd-12 bg-(--sys-color-bg-frame) border-(--sys-color-border-strong)",
4762
- tile: "h-[28px] w-[28px] bg-(--sys-color-bg-accentFaint)",
4763
- iconSize: 20,
4764
- nameTypo: "typo-body-md-medium"
4765
- }
4751
+ /** 바깥 상자 — 좌우·상하 여백·면·선·라운드 */
4752
+ 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)",
4753
+ /** 콘텐츠 묶음 ↔ 제거 버튼 간격 */
4754
+ outerGap: "gap-(--cmp-chatAttachedFile-gap)",
4755
+ /** 아이콘 칩 ↔ 파일명 간격 */
4756
+ contentGap: "gap-(--cmp-chatAttachedFile-content-gap)",
4757
+ /** 클립 아이콘이 앉는 칩 — 내부 패딩·면·라운드 (높이는 아이콘+패딩이 정한다) */
4758
+ tile: "p-(--cmp-chatAttachedFile-icon-wrapper-padding) rounded-(--cmp-chatAttachedFile-icon-wrapper-radius) bg-(--cmp-chatAttachedFile-icon-wrapper-bg)",
4759
+ /** 칩 안 클립 아이콘 크기(px). SVG width/height 는 속성값이라 CSS 변수를 못 받아 값으로 둔다 (토큰 값과 동일) */
4760
+ iconSize: 16,
4761
+ /** 파일명 타이포 프리셋 */
4762
+ nameTypo: "typo-body-sm-default",
4763
+ /** 파일명 텍스트색 */
4764
+ textColor: "text-(--cmp-chatAttachedFile-filename-color)"
4766
4765
  };
4767
- var SIZE_UNITS = ["B", "KB", "MB", "GB", "TB"];
4768
- function formatFileSize(bytes) {
4769
- if (!Number.isFinite(bytes) || bytes < 0) return "";
4770
- let value = bytes;
4771
- let unit = 0;
4772
- while (value >= 1024 && unit < SIZE_UNITS.length - 1) {
4773
- value /= 1024;
4774
- unit += 1;
4775
- }
4776
- return unit === 0 ? `${Math.round(value)}${SIZE_UNITS[0]}` : `${value.toFixed(1)}${SIZE_UNITS[unit]}`;
4777
- }
4778
- function normalizeExtension(extension) {
4779
- return extension.trim().replace(/^\.+/, "").toLowerCase();
4780
- }
4781
- function fileExtension(name) {
4782
- const dot = name.lastIndexOf(".");
4783
- return dot > 0 && dot < name.length - 1 ? name.slice(dot + 1).toLowerCase() : "";
4784
- }
4785
4766
  var SChatAttachedFileImpl = /* @__PURE__ */ forwardRef(
4786
- function SChatAttachedFile({ variant, name, extension, size, onRemove, className, ...rest }, ref) {
4787
- const preset = CHAT_ATTACHED_FILE_CONFIG[variant];
4788
- const ext = extension != null ? normalizeExtension(extension) : fileExtension(name);
4789
- const meta = [ext, size != null ? formatFileSize(size) : ""].filter(Boolean).join(" / ");
4790
- const showMeta = variant === "sent" && meta !== "";
4791
- const showRemove = variant === "attached" && onRemove != null;
4767
+ function SChatAttachedFile({ name, onRemove, className, ...rest }, ref) {
4792
4768
  return /* @__PURE__ */ jsxs(
4793
4769
  "div",
4794
4770
  {
4795
4771
  ref,
4796
4772
  className: cn(
4797
- "inline-flex max-w-full items-center rounded-8 border",
4798
- preset.box,
4773
+ "inline-flex max-w-full items-center border-solid",
4774
+ CHAT_ATTACHED_FILE_CONFIG.box,
4775
+ CHAT_ATTACHED_FILE_CONFIG.outerGap,
4799
4776
  className
4800
4777
  ),
4801
4778
  ...rest,
4802
4779
  children: [
4803
- /* @__PURE__ */ jsx(
4804
- "span",
4805
- {
4806
- className: cn(
4807
- "grid shrink-0 place-items-center rounded-4",
4808
- preset.tile,
4809
- "text-(--sys-color-fg-accentLight)"
4810
- ),
4811
- children: /* @__PURE__ */ jsx(SIcon, { name: "attachFile", size: preset.iconSize })
4812
- }
4813
- ),
4814
- /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col", children: [
4815
- /* @__PURE__ */ jsx("span", { className: cn("truncate text-(--sys-color-fg-secondary)", preset.nameTypo), children: name }),
4816
- showMeta && /* @__PURE__ */ jsx("span", { className: "typo-body-sm-default truncate text-(--sys-color-fg-secondary)", children: meta })
4780
+ /* @__PURE__ */ jsxs("span", { className: cn("flex min-w-0 items-center", CHAT_ATTACHED_FILE_CONFIG.contentGap), children: [
4781
+ /* @__PURE__ */ jsx(
4782
+ "span",
4783
+ {
4784
+ className: cn(
4785
+ "inline-grid shrink-0 place-items-center text-(--sys-color-fg-accentLight)",
4786
+ CHAT_ATTACHED_FILE_CONFIG.tile
4787
+ ),
4788
+ children: /* @__PURE__ */ jsx(SIcon, { name: "attachFile", color: "grey_65", size: CHAT_ATTACHED_FILE_CONFIG.iconSize })
4789
+ }
4790
+ ),
4791
+ /* @__PURE__ */ jsx(
4792
+ "span",
4793
+ {
4794
+ className: cn(
4795
+ "truncate",
4796
+ CHAT_ATTACHED_FILE_CONFIG.nameTypo,
4797
+ CHAT_ATTACHED_FILE_CONFIG.textColor
4798
+ ),
4799
+ children: name
4800
+ }
4801
+ )
4817
4802
  ] }),
4818
- showRemove && /* @__PURE__ */ jsx(
4819
- "button",
4803
+ onRemove != null && /* @__PURE__ */ jsx(
4804
+ SGhostButton,
4820
4805
  {
4821
- type: "button",
4822
- "aria-label": `${name} \uC81C\uAC70`,
4806
+ icon: "close",
4807
+ size: "xs",
4808
+ ariaLabel: `${name} \uC81C\uAC70`,
4823
4809
  onClick: onRemove,
4824
- className: "ml-auto flex shrink-0 cursor-pointer items-center text-(--sys-color-fg-tertiary)",
4825
- children: /* @__PURE__ */ jsx(SIcon, { name: "close", size: 16 })
4810
+ className: "shrink-0"
4826
4811
  }
4827
4812
  )
4828
4813
  ]
@@ -4831,12 +4816,120 @@ var SChatAttachedFileImpl = /* @__PURE__ */ forwardRef(
4831
4816
  }
4832
4817
  );
4833
4818
  var SChatAttachedFile2 = /* @__PURE__ */ withDisplayName(SChatAttachedFileImpl, "SChatAttachedFile");
4819
+
4820
+ // src/components/SChatFile/chatFile.config.ts
4821
+ var CHAT_FILE_CONFIG = {
4822
+ /** 바깥 상자 — 좌우 비대칭 여백·상하 여백·면·선·라운드 */
4823
+ 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)",
4824
+ /** 아이콘 칩 ↔ 파일명 간격 */
4825
+ contentGap: "gap-(--cmp-chatFile-gap)",
4826
+ /**
4827
+ * 클립 아이콘이 앉는 칩 — 내부 패딩·면·라운드 (높이는 아이콘+패딩이 정한다).
4828
+ *
4829
+ * hover 면은 상자가 아니라 여기에도 걸린다 — 카드가 어두워질 때 칩은 반대로 밝아져
4830
+ * 칩이 배경에 묻히지 않는다. 상자의 hover 를 따라가야 하므로 group-hover 로 받는다.
4831
+ *
4832
+ * **`--sys-color-bg-frame` 은 임시다.** 시안의 hover 칩 색(`#FFFFFF`)에 대응하는
4833
+ * 컴포넌트 토큰이 없다 — `component.chatMessage.chatFile.icon.wrapper.bg` 는 값이 하나뿐이라
4834
+ * hover 를 담지 못한다. 상자의 `bg.default` 가 참조하는 것과 같은 시스템 토큰으로 대신 걸어 둔다.
4835
+ * 디자인팀에 `icon.wrapper.bg.hover` 를 요청해 나오는 대로 갈아끼운다.
4836
+ */
4837
+ 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)",
4838
+ /** 칩 안 클립 아이콘 크기(px). SVG width/height 는 속성값이라 CSS 변수를 못 받아 값으로 둔다 (토큰 값과 동일) */
4839
+ iconSize: 20,
4840
+ /** 파일명 타이포 프리셋 */
4841
+ nameTypo: "typo-body-md-bold",
4842
+ /** 파일명·부가정보 텍스트색 */
4843
+ textColor: "text-(--cmp-chatFile-text-color)",
4844
+ /**
4845
+ * 눌리는 모양 — 커서·hover 면·포커스 링. 보낸 파일은 언제나 열 수 있으므로 늘 붙는다
4846
+ * (`onFileClick` 이 필수다).
4847
+ *
4848
+ * 상자의 여백·면·선과 따로 두는 이유: 이건 상호작용을 드러내는 값이라 성격이 다르다.
4849
+ * 링은 `SExpansionItem`·`SStepper` 와 같은 accent outline.
4850
+ */
4851
+ interactive: "cursor-pointer hover:bg-(--cmp-chatFile-bg-hover) focus-visible:outline focus-visible:outline-2 focus-visible:outline-(--sys-color-border-accent)"
4852
+ };
4853
+ var SIZE_UNITS = ["B", "KB", "MB", "GB", "TB"];
4854
+ function formatFileSize(bytes) {
4855
+ if (!Number.isFinite(bytes) || bytes < 0) return "";
4856
+ let value = bytes;
4857
+ let unit = 0;
4858
+ while (value >= 1024 && unit < SIZE_UNITS.length - 1) {
4859
+ value /= 1024;
4860
+ unit += 1;
4861
+ }
4862
+ return unit === 0 ? `${Math.round(value)}${SIZE_UNITS[0]}` : `${value.toFixed(1)}${SIZE_UNITS[unit]}`;
4863
+ }
4864
+ function normalizeExtension(extension) {
4865
+ return extension.trim().replace(/^\.+/, "").toLowerCase();
4866
+ }
4867
+ function fileExtension(name) {
4868
+ const dot = name.lastIndexOf(".");
4869
+ return dot > 0 && dot < name.length - 1 ? name.slice(dot + 1).toLowerCase() : "";
4870
+ }
4871
+ var SChatFileImpl = /* @__PURE__ */ forwardRef(function SChatFile({ name, extension, size, onFileClick, className, ...rest }, ref) {
4872
+ const ext = extension != null ? normalizeExtension(extension) : fileExtension(name);
4873
+ const meta = [ext, size != null ? formatFileSize(size) : ""].filter(Boolean).join(" / ");
4874
+ return /* @__PURE__ */ jsxs(
4875
+ "div",
4876
+ {
4877
+ ref,
4878
+ className: cn(
4879
+ // group/chat-file: 아이콘 칩이 상자의 hover 를 따라가야 해서 이름을 붙인다 (config.tile 참고)
4880
+ "group/chat-file inline-flex max-w-full items-center border-solid",
4881
+ CHAT_FILE_CONFIG.box,
4882
+ CHAT_FILE_CONFIG.contentGap,
4883
+ CHAT_FILE_CONFIG.interactive,
4884
+ className
4885
+ ),
4886
+ ...rest,
4887
+ role: "button",
4888
+ tabIndex: 0,
4889
+ onClick: (event) => {
4890
+ rest.onClick?.(event);
4891
+ onFileClick?.();
4892
+ },
4893
+ onKeyDown: (event) => {
4894
+ rest.onKeyDown?.(event);
4895
+ if (event.key !== "Enter" && event.key !== " ") return;
4896
+ event.preventDefault();
4897
+ onFileClick?.();
4898
+ },
4899
+ children: [
4900
+ /* @__PURE__ */ jsx(
4901
+ "span",
4902
+ {
4903
+ className: cn(
4904
+ "inline-grid shrink-0 place-items-center text-(--sys-color-fg-accentLight)",
4905
+ CHAT_FILE_CONFIG.tile
4906
+ ),
4907
+ children: /* @__PURE__ */ jsx(SIcon, { name: "attachFile", size: CHAT_FILE_CONFIG.iconSize })
4908
+ }
4909
+ ),
4910
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col", children: [
4911
+ /* @__PURE__ */ jsx("span", { className: cn("truncate", CHAT_FILE_CONFIG.nameTypo, CHAT_FILE_CONFIG.textColor), children: name }),
4912
+ meta !== "" && /* @__PURE__ */ jsx("span", { className: cn("typo-body-xs-default truncate", CHAT_FILE_CONFIG.textColor), children: meta })
4913
+ ] })
4914
+ ]
4915
+ }
4916
+ );
4917
+ });
4918
+ var SChatFile2 = /* @__PURE__ */ withDisplayName(SChatFileImpl, "SChatFile");
4834
4919
  var CHAT_MESSAGE_DIRECTIONS = ["incoming", "outgoing"];
4835
- var CHAT_MESSAGE_VARIANTS = ["default", "template"];
4920
+ var CHAT_MESSAGE_VARIANTS = ["default", "template", "admin"];
4836
4921
  var BUBBLE_SURFACE = {
4837
- incoming: "bg-(--sys-color-bg-screen) text-(--sys-color-fg-primary)",
4838
- outgoing: "bg-(--sys-color-bg-brand) text-(--sys-color-fg-inverse)",
4839
- template: "bg-(--sys-color-bg-accentFaint) text-(--sys-color-fg-deep)"
4922
+ incoming: "bg-(--cmp-chatBubble-incoming-bg) text-(--cmp-chatBubble-incoming-content)",
4923
+ outgoing: "bg-(--cmp-chatBubble-outgoing-general-bg) text-(--cmp-chatBubble-outgoing-general-content)",
4924
+ template: "bg-(--cmp-chatBubble-templete-bg) text-(--cmp-chatBubble-templete-content)",
4925
+ // TODO: `chatBubble.outgoing.admin` 토큰이 생기면 둘 다 그쪽으로 교체한다.
4926
+ // 지금은 admin 면을 가리키는 컴포넌트 토큰이 없어 글자색만 시맨틱 토큰을 직접 쓴다.
4927
+ admin: "bg-(--cmp-chatBubble-outgoing-default-bg) text-(--sys-color-fg-deep)"
4928
+ };
4929
+ var OUTGOING_SURFACE = {
4930
+ default: "outgoing",
4931
+ template: "template",
4932
+ admin: "admin"
4840
4933
  };
4841
4934
  var CHAT_MESSAGE_READ_STATUSES = ["read", "unread"];
4842
4935
  var READ_STATUS_LABEL = {
@@ -4844,8 +4937,8 @@ var READ_STATUS_LABEL = {
4844
4937
  unread: "\uC548 \uC77D\uC74C"
4845
4938
  };
4846
4939
  var READ_STATUS_COLOR = {
4847
- read: "text-(--sys-color-fg-tertiary)",
4848
- unread: "text-(--sys-color-fg-warning)"
4940
+ read: "text-(--cmp-chatTimeStamp-color)",
4941
+ unread: "text-(--cmp-chatReadMark-color)"
4849
4942
  };
4850
4943
  var AVATAR_SIZE = 32;
4851
4944
  var AVATAR_ROW_HEIGHT = 40;
@@ -4857,7 +4950,7 @@ function Avatar({ src, alt, placeholder }) {
4857
4950
  return /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center", style: { height: AVATAR_ROW_HEIGHT }, children: /* @__PURE__ */ jsx(
4858
4951
  "div",
4859
4952
  {
4860
- className: "relative overflow-hidden rounded-full bg-(--sys-color-bg-screen)",
4953
+ className: "relative overflow-hidden rounded-(--cmp-chatAvatar-radius) bg-(--cmp-chatAvatar-bg)",
4861
4954
  style: { width: AVATAR_SIZE, height: AVATAR_SIZE },
4862
4955
  children: src != null ? /* @__PURE__ */ jsx(SImage, { src, alt: alt ?? "", fit: "cover", className: "h-full w-full" }) : (
4863
4956
  // 원 밖으로 나가는 만큼을 좌우로 나눠 가운데를 맞추고, 아래는 원이 자른다.
@@ -4866,7 +4959,7 @@ function Avatar({ src, alt, placeholder }) {
4866
4959
  {
4867
4960
  name: "user",
4868
4961
  size: AVATAR_ICON_SIZE,
4869
- color: "var(--sys-color-fg-quaternary)",
4962
+ color: "var(--cmp-chatAvatar-icon)",
4870
4963
  className: "absolute top-0",
4871
4964
  style: { left: (AVATAR_SIZE - AVATAR_ICON_SIZE) / 2 }
4872
4965
  }
@@ -4886,12 +4979,14 @@ var SChatMessageImpl = /* @__PURE__ */ forwardRef(function SChatMessage({
4886
4979
  variant = "default",
4887
4980
  actions,
4888
4981
  messages,
4982
+ attachments,
4889
4983
  className,
4890
4984
  ...rest
4891
4985
  }, ref) {
4892
4986
  const outgoing = direction === "outgoing";
4893
- const surface = direction === "outgoing" && variant === "template" ? "template" : direction;
4987
+ const surface = outgoing ? OUTGOING_SURFACE[variant] : "incoming";
4894
4988
  const bubbles = messages ?? [];
4989
+ const files = attachments ?? [];
4895
4990
  return /* @__PURE__ */ jsxs(
4896
4991
  "div",
4897
4992
  {
@@ -4899,45 +4994,77 @@ var SChatMessageImpl = /* @__PURE__ */ forwardRef(function SChatMessage({
4899
4994
  className: cn(
4900
4995
  // 아바타와 본문 열이 같은 줄에 서고, 보낸 메시지는 좌우를 뒤집는다.
4901
4996
  // items-start 라 이름이 있든 없든 아바타는 언제나 첫 줄에 붙는다.
4902
- "flex items-start gap-sd-12",
4997
+ "flex items-start gap-(--cmp-chatMessage-avatarGap)",
4903
4998
  outgoing && "flex-row-reverse",
4904
4999
  className
4905
5000
  ),
4906
5001
  ...rest,
4907
5002
  children: [
4908
5003
  !outgoing && /* @__PURE__ */ jsx(Avatar, { src: avatarSrc, alt: avatarAlt, placeholder: continued }),
4909
- /* @__PURE__ */ jsxs("div", { className: cn("flex min-w-0 flex-col gap-sd-4", outgoing ? "items-end" : "items-start"), children: [
4910
- !outgoing && !continued && sender != null && /* @__PURE__ */ jsx("span", { className: "typo-body-sm-default px-sd-8 text-(--sys-color-fg-secondary)", children: sender }),
4911
- bubbles.length > 0 && // 말풍선끼리는 이름·시각과의 간격(4px)보다 벌려 한 덩어리 안의 여러 발화로 읽히게 한다.
4912
- /* @__PURE__ */ jsx(
4913
- "div",
4914
- {
4915
- className: cn("flex min-w-0 flex-col gap-sd-8", outgoing ? "items-end" : "items-start"),
4916
- children: bubbles.map((message, index) => /* @__PURE__ */ jsx(
5004
+ /* @__PURE__ */ jsxs(
5005
+ "div",
5006
+ {
5007
+ className: cn(
5008
+ "flex min-w-0 flex-col gap-(--cmp-chatMessage-contents-gap)",
5009
+ outgoing ? "items-end" : "items-start"
5010
+ ),
5011
+ children: [
5012
+ !outgoing && !continued && sender != null && /* @__PURE__ */ jsx("span", { className: "typo-body-sm-bold px-(--cmp-chatMessage-name-paddingX) text-(--cmp-chatMessage-name-color)", children: sender }),
5013
+ bubbles.length > 0 && // 말풍선끼리는 이름·시각과의 간격(4px)보다 벌려 한 덩어리 안의 여러 발화로 읽히게 한다.
5014
+ /* @__PURE__ */ jsx(
4917
5015
  "div",
4918
5016
  {
4919
5017
  className: cn(
4920
- // 라운드 12px 은 대응 토큰이 없어 값으로 둔다 (디자인팀 토큰 추가 요청 대상).
4921
- "typo-body-md-default max-w-full rounded-[12px] px-sd-16 py-sd-8",
4922
- // 한글은 기본 규칙으로 두면 어절 한가운데서도 줄이 바뀐다 — 띄어쓰기에서만 끊고,
4923
- // 끊을 자리가 없는 긴 토큰(URL·주문번호)만 흘려보낸다.
4924
- "break-keep wrap-break-word",
4925
- BUBBLE_SURFACE[surface]
5018
+ "flex min-w-0 flex-col gap-(--cmp-chatMessage-group-bubble-gap)",
5019
+ outgoing ? "items-end" : "items-start"
4926
5020
  ),
4927
- children: message
4928
- },
4929
- index
4930
- ))
4931
- }
4932
- ),
4933
- (readStatus != null || time != null) && // 읽음 표시와 시각은 한 줄에 선다 — 읽음이 먼저, 시각이 뒤다.
4934
- /* @__PURE__ */ jsxs("div", { className: "typo-body-sm-default flex items-center gap-sd-4 px-sd-8", children: [
4935
- readStatus != null && /* @__PURE__ */ jsx("span", { className: READ_STATUS_COLOR[readStatus], children: READ_STATUS_LABEL[readStatus] }),
4936
- time != null && /* @__PURE__ */ jsx("span", { className: "text-(--sys-color-fg-tertiary)", children: time })
4937
- ] }),
4938
- actions != null && // 버튼이 많아 한 줄에 안 들어가면 감싼다 — 넘쳐서 잘리는 것보다 낫다.
4939
- /* @__PURE__ */ jsx("div", { className: cn("flex flex-wrap gap-sd-8 px-sd-8", outgoing && "justify-end"), children: actions })
4940
- ] })
5021
+ children: bubbles.map((message, index) => /* @__PURE__ */ jsx(
5022
+ "div",
5023
+ {
5024
+ className: cn(
5025
+ "typo-body-md-medium max-w-full rounded-(--cmp-chatBubble-radius) px-(--cmp-chatBubble-paddingX) py-(--cmp-chatBubble-paddingY)",
5026
+ // 한글은 기본 규칙으로 두면 어절 한가운데서도 줄이 바뀐다 — 띄어쓰기에서만 끊고,
5027
+ // 끊을 자리가 없는 긴 토큰(URL·주문번호)만 흘려보낸다.
5028
+ "break-keep wrap-break-word",
5029
+ BUBBLE_SURFACE[surface]
5030
+ ),
5031
+ children: message
5032
+ },
5033
+ index
5034
+ ))
5035
+ }
5036
+ ),
5037
+ files.length > 0 && // 파일 칸끼리는 말풍선과 같은 간격으로 벌린다 — 한 덩어리 안의 여러 발화로 읽힌다.
5038
+ // 말풍선과 달리 면으로 감싸지 않는다 (`attachments` 주석 참고).
5039
+ /* @__PURE__ */ jsx(
5040
+ "div",
5041
+ {
5042
+ className: cn(
5043
+ "flex min-w-0 flex-col gap-(--cmp-chatMessage-group-bubble-gap)",
5044
+ outgoing ? "items-end" : "items-start"
5045
+ ),
5046
+ children: files.map((file, index) => /* @__PURE__ */ jsx("div", { className: "max-w-full", children: file }, index))
5047
+ }
5048
+ ),
5049
+ (readStatus != null || time != null) && // 읽음 표시와 시각은 한 줄에 선다 — 읽음이 먼저, 시각이 뒤다.
5050
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-(--cmp-chatMessage-subData-gap) px-(--cmp-chatMessage-subData-paddingX)", children: [
5051
+ readStatus != null && /* @__PURE__ */ jsx("span", { className: cn("typo-body-sm-bold", READ_STATUS_COLOR[readStatus]), children: READ_STATUS_LABEL[readStatus] }),
5052
+ time != null && /* @__PURE__ */ jsx("span", { className: "typo-body-sm-medium text-(--cmp-chatTimeStamp-color)", children: time })
5053
+ ] }),
5054
+ actions != null && // 버튼이 많아 한 줄에 안 들어가면 감싼다 — 넘쳐서 잘리는 것보다 낫다.
5055
+ /* @__PURE__ */ jsx(
5056
+ "div",
5057
+ {
5058
+ className: cn(
5059
+ "flex flex-wrap gap-sd-8 px-(--cmp-chatMessage-bottomButtons-paddingX)",
5060
+ outgoing && "justify-end"
5061
+ ),
5062
+ children: actions
5063
+ }
5064
+ )
5065
+ ]
5066
+ }
5067
+ )
4941
5068
  ]
4942
5069
  }
4943
5070
  );
@@ -4953,14 +5080,13 @@ var SChatSystemMessageImpl = /* @__PURE__ */ forwardRef(
4953
5080
  "span",
4954
5081
  {
4955
5082
  className: cn(
4956
- // 라운드 15px 은 한 줄일 때 높이(20+4×2+1×2=30px)의 절반이다 — 한 줄에서는
4957
- // 완전한 알약으로 보이고, 여러 줄이 돼도 모서리가 상자 높이를 따라 부풀지 않는다.
4958
- // rounded-full 로 두면 두 줄부터 좌우가 커다란 반원이 되어 첫 글자가 안으로 밀린다.
4959
- // 대응 토큰이 없어 값으로 둔다 (디자인팀 토큰 추가 요청 대상).
4960
- "inline-flex max-w-full rounded-[15px] border",
4961
- "border-(--sys-color-border-default) bg-(--sys-color-bg-neutralBright)",
4962
- "typo-body-sm-default text-(--sys-color-fg-secondary)",
4963
- "px-sd-16 py-sd-4 text-center",
5083
+ // 라운드는 말풍선과 같은 토큰을 쓴다 — 여러 줄이 돼도 모서리가 상자 높이를 따라
5084
+ // 부풀지 않는다. 제 몫인 chatSystemMessage.radius 는 pill(9999px)이라 쓰지 않는다.
5085
+ // 두 줄부터 좌우가 커다란 반원이 되어 첫 글자가 안으로 밀리기 때문이다.
5086
+ "inline-flex max-w-full rounded-(--cmp-chatBubble-radius) border",
5087
+ "border-(--cmp-chatSystemMessage-border-color) bg-(--cmp-chatSystemMessage-bg)",
5088
+ "typo-body-sm-medium text-(--cmp-chatSystemMessage-color)",
5089
+ "px-(--cmp-chatSystemMessage-paddingX) py-(--cmp-chatSystemMessage-paddingY) text-center",
4964
5090
  // 한글은 기본 규칙으로 두면 어절 한가운데서도 줄이 바뀐다 — 띄어쓰기에서만 끊고,
4965
5091
  // 끊을 자리가 없는 긴 토큰(URL·주문번호)만 흘려보낸다 (SChatMessage 말풍선과 같은 규칙).
4966
5092
  // 가운데 정렬이라 마지막 줄에 한 단어만 남으면 특히 눈에 띄므로 text-pretty 로 줄을 고른다.
@@ -6285,10 +6411,21 @@ function SCheckbox({
6285
6411
  ) })
6286
6412
  }
6287
6413
  ),
6288
- label && // 고스트(500) 텍스트로 너비를 고정 → 두께 400↔500 전환 시 레이아웃이 밀리지 않음
6289
- /* @__PURE__ */ jsxs("span", { className: "grid text-nowrap text-[12px] leading-[20px]", style: { color: labelColor }, children: [
6290
- /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "invisible font-medium", style: { gridArea: "1 / 1" }, children: label }),
6291
- /* @__PURE__ */ jsx("span", { style: { gridArea: "1 / 1", fontWeight: isChecked ? 500 : 400 }, children: label })
6414
+ label && // 고스트(500) 텍스트로 너비를 고정 → 두께 400↔500 전환 시 레이아웃이 밀리지 않음.
6415
+ // 한글은 기본 규칙으로 두면 어절 한가운데서도 줄이 바뀐다. 그러면 min-content 가 한 글자가
6416
+ // 되어, flex 아이템을 지켜 주는 min-width:auto 가 무력해지고 폭이 남는데도 라벨부터
6417
+ // 찌그러진다 — 띄어쓰기에서만 끊고, 끊을 자리가 없는 긴 토큰만 흘려보낸다
6418
+ // (SRadio·SSwitch 라벨과 같은 규칙). 두 사본에 함께 걸려야 하므로 바깥 grid 에 준다.
6419
+ /* @__PURE__ */ jsxs("span", { className: "grid break-keep wrap-break-word", style: { color: labelColor }, children: [
6420
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "typo-body-sm-medium invisible", style: { gridArea: "1 / 1" }, children: label }),
6421
+ /* @__PURE__ */ jsx(
6422
+ "span",
6423
+ {
6424
+ className: isChecked ? "typo-body-sm-medium" : "typo-body-sm-default",
6425
+ style: { gridArea: "1 / 1" },
6426
+ children: label
6427
+ }
6428
+ )
6292
6429
  ] })
6293
6430
  ]
6294
6431
  }
@@ -7742,7 +7879,7 @@ function SSwitch({
7742
7879
  style
7743
7880
  }) {
7744
7881
  const right = rightLabel;
7745
- const renderLabel = (text) => text ? /* @__PURE__ */ jsx("span", { className: "text-[12px] font-medium leading-[20px]", children: text }) : null;
7882
+ const renderLabel = (text) => text ? /* @__PURE__ */ jsx("span", { className: "typo-body-sm-medium break-keep wrap-break-word", children: text }) : null;
7746
7883
  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)";
7747
7884
  return /* @__PURE__ */ jsxs(
7748
7885
  "label",
@@ -11749,7 +11886,7 @@ var SPageHeader = /* @__PURE__ */ withDisplayName(
11749
11886
  // plain 에는 전용 배경 토큰이 없어 시스템 흰 표면을 쓴다(토큰이 생기면 그것으로 갈아끼운다).
11750
11887
  bar ? "h-(--cmp-pageHeader-bar-height) border-b border-(--cmp-pageHeader-bar-border) bg-(--cmp-pageHeader-bar-bg) py-(--cmp-pageHeader-bar-paddingY)" : cn(
11751
11888
  // 스크롤되면 그림자를 더해 콘텐츠 위에 뜬 것처럼 보이게 한다.
11752
- "bg-(--sys-color-bg-frame) pt-(--cmp-pageHeader-plain-paddingTop) pb-(--cmp-pageHeader-plain-paddingBottom)",
11889
+ "bg-(--sys-color-bg-frame) py-(--cmp-pageHeader-plain-paddingY)",
11753
11890
  isScrolled && "shadow-floating"
11754
11891
  ),
11755
11892
  className
@@ -11759,7 +11896,10 @@ var SPageHeader = /* @__PURE__ */ withDisplayName(
11759
11896
  children: /* @__PURE__ */ jsxs(
11760
11897
  "div",
11761
11898
  {
11762
- className: "flex min-w-0 flex-1 items-center gap-(--cmp-pageHeader-gap)",
11899
+ className: cn(
11900
+ "flex min-w-0 flex-1 gap-(--cmp-pageHeader-gap)",
11901
+ bar ? "items-center" : "items-start"
11902
+ ),
11763
11903
  style: rowStyle,
11764
11904
  children: [
11765
11905
  hasBack && /* @__PURE__ */ jsx(
@@ -11769,7 +11909,7 @@ var SPageHeader = /* @__PURE__ */ withDisplayName(
11769
11909
  size: "xs",
11770
11910
  ariaLabel: "\uB4A4\uB85C\uAC00\uAE30",
11771
11911
  onClick: onBack,
11772
- className: "shrink-0"
11912
+ className: cn("shrink-0", bar ? "" : "mt-[3px]")
11773
11913
  }
11774
11914
  ),
11775
11915
  /* @__PURE__ */ jsxs(
@@ -15902,7 +16042,7 @@ function SRadio({
15902
16042
  label && /* @__PURE__ */ jsxs(
15903
16043
  "span",
15904
16044
  {
15905
- className: "grid",
16045
+ className: "grid break-keep wrap-break-word",
15906
16046
  style: {
15907
16047
  color: disabled ? "var(--cmp-radio-label-disabled)" : "var(--cmp-radio-label-default)"
15908
16048
  },
@@ -17717,6 +17857,673 @@ function SKeyValueTable({
17717
17857
  )
17718
17858
  ] });
17719
17859
  }
17860
+
17861
+ // src/lib/chart/scale.ts
17862
+ function niceNum(range, round) {
17863
+ if (range <= 0) return 1;
17864
+ const exponent = Math.floor(Math.log10(range));
17865
+ const fraction = range / 10 ** exponent;
17866
+ let nice;
17867
+ if (round) {
17868
+ nice = fraction < 1.5 ? 1 : fraction < 3 ? 2 : fraction < 7 ? 5 : 10;
17869
+ } else {
17870
+ nice = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10;
17871
+ }
17872
+ return nice * 10 ** exponent;
17873
+ }
17874
+ function trim(value, step) {
17875
+ const decimals = Math.max(0, -Math.floor(Math.log10(step)));
17876
+ return Number(value.toFixed(Math.min(decimals, 10)));
17877
+ }
17878
+ function niceScale(values, tickCount, fixedMax) {
17879
+ const finite = values.filter(Number.isFinite);
17880
+ const count = Math.max(2, Math.floor(tickCount));
17881
+ const rawMin = Math.min(0, ...finite);
17882
+ const rawMax = fixedMax ?? Math.max(0, ...finite);
17883
+ if (!Number.isFinite(rawMin) || !Number.isFinite(rawMax) || rawMax === rawMin) {
17884
+ const ticks2 = Array.from({ length: count }, (_, i) => i);
17885
+ return { min: 0, max: count - 1, ticks: ticks2 };
17886
+ }
17887
+ const range = niceNum(rawMax - rawMin, false);
17888
+ const step = niceNum(range / (count - 1), true);
17889
+ const min = trim(Math.floor(rawMin / step) * step, step);
17890
+ const max = trim(Math.ceil(rawMax / step) * step, step);
17891
+ const ticks = [];
17892
+ for (let v = min; v <= max + step / 2; v += step) ticks.push(trim(v, step));
17893
+ return { min, max, ticks };
17894
+ }
17895
+ function ratioOf(value, scale) {
17896
+ const span = scale.max - scale.min;
17897
+ if (span <= 0) return 0;
17898
+ return (value - scale.min) / span;
17899
+ }
17900
+ var AXIS_LABEL_GAP = 8;
17901
+ function ChartGrid({ scale, direction, width, height }) {
17902
+ const vertical = direction === "vertical";
17903
+ return /* @__PURE__ */ jsx("g", { "aria-hidden": true, children: scale.ticks.map((tick) => {
17904
+ const ratio = ratioOf(tick, scale);
17905
+ const isBaseline = tick === 0;
17906
+ const color = isBaseline ? "var(--cmp-chart-baseline-color)" : "var(--cmp-chart-grid-line-color)";
17907
+ const position = vertical ? height - ratio * height : ratio * width;
17908
+ const extent = vertical ? height : width;
17909
+ const snapped = Math.min(Math.max(Math.round(position), 0), Math.max(0, extent - 1)) + 0.5;
17910
+ return vertical ? /* @__PURE__ */ jsx(
17911
+ "line",
17912
+ {
17913
+ x1: 0,
17914
+ x2: width,
17915
+ y1: snapped,
17916
+ y2: snapped,
17917
+ stroke: color,
17918
+ strokeWidth: 1
17919
+ },
17920
+ tick
17921
+ ) : /* @__PURE__ */ jsx(
17922
+ "line",
17923
+ {
17924
+ x1: snapped,
17925
+ x2: snapped,
17926
+ y1: 0,
17927
+ y2: height,
17928
+ stroke: color,
17929
+ strokeWidth: 1
17930
+ },
17931
+ tick
17932
+ );
17933
+ }) });
17934
+ }
17935
+ function ChartAxisLabels({
17936
+ scale,
17937
+ direction,
17938
+ format,
17939
+ className,
17940
+ style,
17941
+ sampleRef
17942
+ }) {
17943
+ const vertical = direction === "vertical";
17944
+ const widest = scale.ticks.reduce((longest, tick) => {
17945
+ const text = format(tick);
17946
+ return text.length > longest.length ? text : longest;
17947
+ }, "");
17948
+ return /* @__PURE__ */ jsxs(
17949
+ "div",
17950
+ {
17951
+ "aria-hidden": true,
17952
+ className: cn(
17953
+ "relative typo-body-sm-medium text-(--cmp-chart-axis-color)",
17954
+ vertical ? "h-full" : "w-full",
17955
+ className
17956
+ ),
17957
+ style,
17958
+ children: [
17959
+ scale.ticks.map((tick) => {
17960
+ const ratio = ratioOf(tick, scale);
17961
+ return vertical ? /* @__PURE__ */ jsx(
17962
+ "span",
17963
+ {
17964
+ className: "absolute right-0 -translate-y-1/2 whitespace-nowrap",
17965
+ style: { top: `${(1 - ratio) * 100}%` },
17966
+ children: format(tick)
17967
+ },
17968
+ tick
17969
+ ) : /* @__PURE__ */ jsx(
17970
+ "span",
17971
+ {
17972
+ className: "absolute top-0 -translate-x-1/2 whitespace-nowrap",
17973
+ style: { left: `${ratio * 100}%` },
17974
+ children: format(tick)
17975
+ },
17976
+ tick
17977
+ );
17978
+ }),
17979
+ /* @__PURE__ */ jsx("span", { ref: sampleRef, "aria-hidden": true, className: "invisible inline-block whitespace-nowrap", children: vertical ? widest : "0" })
17980
+ ]
17981
+ }
17982
+ );
17983
+ }
17984
+ var ChartFrame = /* @__PURE__ */ forwardRef(function ChartFrame2({ legend, legendPosition = "top", children, className, style, ...props }, ref) {
17985
+ return /* @__PURE__ */ jsxs(
17986
+ "div",
17987
+ {
17988
+ ref,
17989
+ className: cn(
17990
+ "flex w-full flex-col gap-(--cmp-chart-gap)",
17991
+ "p-(--cmp-chart-paddingAll) bg-(--cmp-chart-bg)",
17992
+ className
17993
+ ),
17994
+ style,
17995
+ ...props,
17996
+ children: [
17997
+ legend && legendPosition === "top" && legend,
17998
+ children,
17999
+ legend && legendPosition === "bottom" && legend
18000
+ ]
18001
+ }
18002
+ );
18003
+ });
18004
+ var DOT_SIZE = 6;
18005
+ function ChartLegend({ items, align = "center", activeIndex, className }) {
18006
+ if (items.length === 0) return null;
18007
+ return /* @__PURE__ */ jsx(
18008
+ "ul",
18009
+ {
18010
+ className: cn(
18011
+ "flex list-none flex-wrap items-center gap-x-(--cmp-chart-legend-group-gap) p-0",
18012
+ align === "start" && "justify-start",
18013
+ align === "center" && "justify-center",
18014
+ align === "end" && "justify-end",
18015
+ className
18016
+ ),
18017
+ children: items.map((item4, index) => /* @__PURE__ */ jsxs(
18018
+ "li",
18019
+ {
18020
+ className: cn(
18021
+ "flex items-center gap-(--cmp-chart-legend-legendItem-gap)",
18022
+ "py-(--cmp-chart-legend-legendItem-paddingY)",
18023
+ "typo-body-sm-medium text-(--cmp-chart-legend-legendItem-color)",
18024
+ "transition-opacity",
18025
+ activeIndex != null && activeIndex !== index && "opacity-(--opacity-060)"
18026
+ ),
18027
+ children: [
18028
+ /* @__PURE__ */ jsx(
18029
+ "span",
18030
+ {
18031
+ "aria-hidden": true,
18032
+ className: "shrink-0 rounded-full",
18033
+ style: { width: DOT_SIZE, height: DOT_SIZE, background: item4.color }
18034
+ }
18035
+ ),
18036
+ item4.name
18037
+ ]
18038
+ },
18039
+ `${item4.name}-${index}`
18040
+ ))
18041
+ }
18042
+ );
18043
+ }
18044
+
18045
+ // src/lib/chart/palette.ts
18046
+ var V3 = (path) => `var(--cmp-chart-palette-${path})`;
18047
+ var CHART_COLORS = {
18048
+ positivePrimary: V3("variation-positivePrimary"),
18049
+ positiveSecondary: V3("variation-positiveSecondary"),
18050
+ negativePrimary: V3("variation-negativePrimary"),
18051
+ negativeSecondary: V3("variation-negativeSecondary"),
18052
+ neutralPrimary: V3("variation-neutralPrimary"),
18053
+ neutralSecondary: V3("variation-neutralSecondary")
18054
+ };
18055
+ var CHART_PALETTES = {
18056
+ default: [V3("single")],
18057
+ multi: [
18058
+ V3("multi-blue"),
18059
+ V3("multi-skyblue"),
18060
+ V3("multi-yellow"),
18061
+ V3("multi-olive"),
18062
+ V3("multi-lightRed"),
18063
+ V3("multi-warmBlue"),
18064
+ V3("multi-orange"),
18065
+ V3("multi-green"),
18066
+ V3("multi-navy"),
18067
+ V3("multi-grey"),
18068
+ V3("multi-red")
18069
+ ],
18070
+ gradation: [
18071
+ V3("gradation-1"),
18072
+ V3("gradation-2"),
18073
+ V3("gradation-3"),
18074
+ V3("gradation-4"),
18075
+ V3("gradation-5"),
18076
+ V3("gradation-6")
18077
+ ]
18078
+ };
18079
+ function paletteColor(palette, index, colors) {
18080
+ if (palette === "custom") {
18081
+ if (!colors?.length) return CHART_PALETTES.default[0];
18082
+ return CHART_COLORS[colors[index % colors.length]];
18083
+ }
18084
+ const list = CHART_PALETTES[palette] ?? CHART_PALETTES.default;
18085
+ return list[index % list.length];
18086
+ }
18087
+ function useElementSize() {
18088
+ const ref = useRef(null);
18089
+ const [size, setSize] = useState({ width: 0, height: 0 });
18090
+ useEffect(() => {
18091
+ const element = ref.current;
18092
+ if (!element) return;
18093
+ const update = () => {
18094
+ const { width, height } = element.getBoundingClientRect();
18095
+ setSize(
18096
+ (prev) => Math.abs(prev.width - width) < 0.5 && Math.abs(prev.height - height) < 0.5 ? prev : { width, height }
18097
+ );
18098
+ };
18099
+ update();
18100
+ if (typeof ResizeObserver === "undefined") return;
18101
+ const observer = new ResizeObserver(update);
18102
+ observer.observe(element);
18103
+ return () => observer.disconnect();
18104
+ }, []);
18105
+ return { ref, size };
18106
+ }
18107
+ var DOT_SIZE2 = 6;
18108
+ var CURSOR_OFFSET = 12;
18109
+ function place(cursor, size, extent) {
18110
+ if (!extent || !size) return cursor + CURSOR_OFFSET;
18111
+ const after = cursor + CURSOR_OFFSET;
18112
+ if (after + size <= extent) return after;
18113
+ const before = cursor - CURSOR_OFFSET - size;
18114
+ if (before >= 0) return before;
18115
+ return Math.max(0, Math.min(after, extent - size));
18116
+ }
18117
+ function ChartTooltip({ title, items, x, y, bounds, className }) {
18118
+ const { ref, size } = useElementSize();
18119
+ const measured = size.width > 0 && size.height > 0;
18120
+ return /* @__PURE__ */ jsxs(
18121
+ "div",
18122
+ {
18123
+ ref,
18124
+ role: "tooltip",
18125
+ className: cn(
18126
+ // left/top 대신 transform 으로 옮긴다. 좌표를 바꾸면 마우스가 움직일 때마다
18127
+ // 리플로우가 나 차트가 미세하게 흔들려 보인다. transform 은 레이아웃을
18128
+ // 건드리지 않으므로, 크기를 재기 전에 잠깐 밖으로 나가도 스크롤이 생기지 않는다.
18129
+ "pointer-events-none absolute top-0 left-0 z-10 w-max",
18130
+ "flex flex-col gap-(--cmp-chart-chartTooltip-gap)",
18131
+ "px-(--cmp-chart-chartTooltip-paddingX) py-(--cmp-chart-chartTooltip-paddingY)",
18132
+ "rounded-(--cmp-chart-chartTooltip-radius) bg-(--cmp-chart-chartTooltip-bg) shadow-floating",
18133
+ className
18134
+ ),
18135
+ style: {
18136
+ // 크기를 재기 전에는 원점에 숨겨 둔다. 커서 옆에 그려 두면 그림 밖으로
18137
+ // 넘쳐 스크롤 영역이 잠깐 늘어나고, 차트 전체가 한 번 흔들린다.
18138
+ // transform 도 스크롤 영역 계산에는 포함되므로 위치만 바꿔서는 못 막는다.
18139
+ transform: measured ? `translate(${place(x, size.width, bounds?.width ?? 0)}px, ${place(
18140
+ y,
18141
+ size.height,
18142
+ bounds?.height ?? 0
18143
+ )}px)` : void 0,
18144
+ visibility: measured ? void 0 : "hidden"
18145
+ },
18146
+ children: [
18147
+ /* @__PURE__ */ jsx("span", { className: "typo-body-md-bold text-(--cmp-chart-chartTooltip-title-color)", children: title }),
18148
+ items.map((item4, index) => /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-sd-8", children: [
18149
+ /* @__PURE__ */ jsx(
18150
+ "span",
18151
+ {
18152
+ "aria-hidden": true,
18153
+ className: "shrink-0 rounded-full",
18154
+ style: { width: DOT_SIZE2, height: DOT_SIZE2, background: item4.color }
18155
+ }
18156
+ ),
18157
+ /* @__PURE__ */ jsx("span", { className: "typo-body-sm-default text-(--sys-color-fg-primary)", children: item4.label }),
18158
+ /* @__PURE__ */ jsx("span", { className: "typo-body-sm-bold ml-auto text-(--sys-color-fg-primary)", children: item4.value })
18159
+ ] }, `${item4.label}-${index}`))
18160
+ ]
18161
+ }
18162
+ );
18163
+ }
18164
+
18165
+ // src/components/SBarChart/barChart.config.ts
18166
+ var BAR_SIZE_MIN = 24;
18167
+ var BAR_SIZE_MAX = 80;
18168
+ var BAR_GAP = 6;
18169
+ var GROUP_PADDING_MIN = 8;
18170
+ var GROUP_PADDING_MAX = 24;
18171
+ var VALUE_LABEL_GAP = 6;
18172
+ var BAR_RADIUS = 8;
18173
+ var BAR_OPACITY_DEFAULT = "var(--opacity-080)";
18174
+ var BAR_OPACITY_DIMMED = "var(--opacity-060)";
18175
+ var BAR_VALUE_COLOR = "var(--sys-color-field-text-readOnly)";
18176
+ function bandLayout(size, categoryCount, seriesCount, barSizeMax = BAR_SIZE_MAX) {
18177
+ const categories = Math.max(1, categoryCount);
18178
+ const series = Math.max(1, seriesCount);
18179
+ const gaps = (series - 1) * BAR_GAP;
18180
+ const barRange = BAR_SIZE_MAX - BAR_SIZE_MIN;
18181
+ const padRange = GROUP_PADDING_MAX - GROUP_PADDING_MIN;
18182
+ const maxBar = Math.min(Math.max(BAR_SIZE_MIN, barSizeMax), BAR_SIZE_MAX);
18183
+ const tMax = (maxBar - BAR_SIZE_MIN) / barRange;
18184
+ const bandMin = BAR_SIZE_MIN * series + gaps + GROUP_PADDING_MIN * 2;
18185
+ const span = barRange * series + padRange * 2;
18186
+ const band = Math.min(size / categories, bandMin + span * tMax);
18187
+ const t = Math.min(Math.max((band - bandMin) / span, 0), tMax);
18188
+ const bar = BAR_SIZE_MIN + barRange * t;
18189
+ const padding = GROUP_PADDING_MIN + padRange * t;
18190
+ const group = bar * series + gaps;
18191
+ return {
18192
+ band,
18193
+ bar,
18194
+ group,
18195
+ padding,
18196
+ offset: Math.max(0, (size - band * categories) / 2)
18197
+ };
18198
+ }
18199
+ var defaultFormat = (value) => value.toLocaleString();
18200
+ function minBand(seriesCount) {
18201
+ const series = Math.max(1, seriesCount);
18202
+ return series * BAR_SIZE_MIN + (series - 1) * BAR_GAP + GROUP_PADDING_MIN * 2;
18203
+ }
18204
+ function barPath(x, y, width, height, direction, negative) {
18205
+ const r = Math.max(0, Math.min(BAR_RADIUS, width / 2, height / 2));
18206
+ if (r === 0) return `M${x} ${y}h${width}v${height}h${-width}Z`;
18207
+ if (direction === "vertical") {
18208
+ return negative ? (
18209
+ // 아래로 자란다 — 아래쪽 두 모서리가 둥글다
18210
+ `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`
18211
+ ) : (
18212
+ // 위로 자란다 — 위쪽 두 모서리가 둥글다
18213
+ `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`
18214
+ );
18215
+ }
18216
+ return negative ? (
18217
+ // 왼쪽으로 자란다
18218
+ `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`
18219
+ ) : (
18220
+ // 오른쪽으로 자란다
18221
+ `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`
18222
+ );
18223
+ }
18224
+ var SBarChart = /* @__PURE__ */ forwardRef(function SBarChart2({
18225
+ categories,
18226
+ series,
18227
+ direction = "vertical",
18228
+ palette = "default",
18229
+ colors: customColors,
18230
+ max,
18231
+ tickCount = 8,
18232
+ barSize = BAR_SIZE_MAX,
18233
+ showValueLabel = true,
18234
+ showLegend = true,
18235
+ legendPosition = "top",
18236
+ showTooltip = true,
18237
+ formatValue = defaultFormat,
18238
+ height,
18239
+ onBarClick,
18240
+ className,
18241
+ style
18242
+ }, ref) {
18243
+ const vertical = direction === "vertical";
18244
+ const { ref: plotRef, size } = useElementSize();
18245
+ const { ref: axisTextRef, size: axisText } = useElementSize();
18246
+ const { ref: axisSampleRef, size: axisSample } = useElementSize();
18247
+ const [hovered, setHovered] = useState(null);
18248
+ const hoveredCategory = hovered?.category ?? null;
18249
+ const perCategory = series.length === 1;
18250
+ const colorAt = useCallback(
18251
+ (seriesIndex, categoryIndex) => paletteColor(palette, perCategory ? categoryIndex : seriesIndex, customColors),
18252
+ [palette, customColors, perCategory]
18253
+ );
18254
+ const scale = useMemo(
18255
+ () => niceScale(
18256
+ series.flatMap((s) => s.data),
18257
+ tickCount,
18258
+ max
18259
+ ),
18260
+ [series, tickCount, max]
18261
+ );
18262
+ const axisLength = vertical ? size.width : size.height;
18263
+ const layout = useMemo(
18264
+ () => bandLayout(axisLength, categories.length, series.length, barSize),
18265
+ [axisLength, categories.length, series.length, barSize]
18266
+ );
18267
+ const zeroRatio = ratioOf(0, scale);
18268
+ const minPlotWidth = vertical ? categories.length * minBand(series.length) : 0;
18269
+ const totalHeight = height ?? (vertical ? 320 : void 0);
18270
+ 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)`;
18271
+ const legend = showLegend ? /* @__PURE__ */ jsx(ChartLegend, { items: series.map((s, i) => ({ name: s.name, color: colorAt(i, 0) })) }) : null;
18272
+ const handleMove = (event) => {
18273
+ if (!showTooltip || categories.length === 0 || series.length === 0) return;
18274
+ const rect = event.currentTarget.getBoundingClientRect();
18275
+ const x = event.clientX - rect.left;
18276
+ const y = event.clientY - rect.top;
18277
+ const along = (vertical ? x : y) - layout.offset;
18278
+ const category = Math.floor(along / layout.band);
18279
+ if (category < 0 || category >= categories.length) {
18280
+ setHovered(null);
18281
+ return;
18282
+ }
18283
+ setHovered({ category, x, y });
18284
+ };
18285
+ const tooltipItems = hovered == null ? [] : series.flatMap((s, i) => {
18286
+ const value = s.data[hovered.category];
18287
+ if (value == null || !Number.isFinite(value)) return [];
18288
+ return [
18289
+ { color: colorAt(i, hovered.category), label: s.name, value: formatValue(value) }
18290
+ ];
18291
+ });
18292
+ const categoryLabels = /* @__PURE__ */ jsxs(
18293
+ "div",
18294
+ {
18295
+ "aria-hidden": true,
18296
+ className: cn(
18297
+ "relative typo-body-sm-medium text-(--cmp-chart-axis-color)",
18298
+ vertical ? "w-full" : "h-full"
18299
+ ),
18300
+ style: vertical ? { minWidth: minPlotWidth || void 0 } : { height: plotHeight },
18301
+ children: [
18302
+ categories.map((label, index) => {
18303
+ const center = layout.offset + (index + 0.5) * layout.band;
18304
+ return vertical ? /* @__PURE__ */ jsx(
18305
+ "span",
18306
+ {
18307
+ className: "absolute top-0 -translate-x-1/2 whitespace-nowrap",
18308
+ style: { left: center },
18309
+ children: label
18310
+ },
18311
+ `${label}-${index}`
18312
+ ) : /* @__PURE__ */ jsx(
18313
+ "span",
18314
+ {
18315
+ className: "absolute right-0 -translate-y-1/2 whitespace-nowrap",
18316
+ style: { top: center },
18317
+ children: label
18318
+ },
18319
+ `${label}-${index}`
18320
+ );
18321
+ }),
18322
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "invisible block whitespace-nowrap", children: vertical ? "0" : categories.reduce((longest, c) => c.length > longest.length ? c : longest, "") })
18323
+ ]
18324
+ }
18325
+ );
18326
+ const bars = useMemo(
18327
+ () => size.width > 0 && size.height > 0 ? series.flatMap(
18328
+ (s, seriesIndex) => categories.map((_, categoryIndex) => {
18329
+ const value = s.data[categoryIndex];
18330
+ if (value == null || !Number.isFinite(value)) return null;
18331
+ const dimmed = hoveredCategory != null && hoveredCategory !== categoryIndex;
18332
+ const groupStart = layout.offset + categoryIndex * layout.band + (layout.band - layout.group) / 2;
18333
+ const offset = groupStart + seriesIndex * (layout.bar + BAR_GAP);
18334
+ const valueRatio = ratioOf(value, scale);
18335
+ const negative = value < 0;
18336
+ let x;
18337
+ let y;
18338
+ let width;
18339
+ let barHeight;
18340
+ let labelX;
18341
+ let labelY;
18342
+ if (vertical) {
18343
+ const zeroY = size.height - zeroRatio * size.height;
18344
+ const valueY = size.height - valueRatio * size.height;
18345
+ x = offset;
18346
+ width = layout.bar;
18347
+ y = Math.min(zeroY, valueY);
18348
+ barHeight = Math.abs(zeroY - valueY);
18349
+ labelX = offset + layout.bar / 2;
18350
+ labelY = negative ? y + barHeight + VALUE_LABEL_GAP + 10 : y - VALUE_LABEL_GAP;
18351
+ } else {
18352
+ const zeroX = zeroRatio * size.width;
18353
+ const valueX = valueRatio * size.width;
18354
+ x = Math.min(zeroX, valueX);
18355
+ width = Math.abs(zeroX - valueX);
18356
+ y = offset;
18357
+ barHeight = layout.bar;
18358
+ labelX = negative ? x - VALUE_LABEL_GAP : x + width + VALUE_LABEL_GAP;
18359
+ labelY = offset + layout.bar / 2;
18360
+ }
18361
+ return /* @__PURE__ */ jsxs("g", { children: [
18362
+ /* @__PURE__ */ jsx(
18363
+ "path",
18364
+ {
18365
+ d: barPath(x, y, width, barHeight, direction, negative),
18366
+ style: {
18367
+ fill: colorAt(seriesIndex, categoryIndex),
18368
+ opacity: dimmed ? BAR_OPACITY_DIMMED : BAR_OPACITY_DEFAULT,
18369
+ cursor: onBarClick ? "pointer" : void 0
18370
+ },
18371
+ onClick: onBarClick ? () => onBarClick({ seriesIndex, categoryIndex, value }) : void 0,
18372
+ children: /* @__PURE__ */ jsx("title", { children: `${categories[categoryIndex]} ${s.name} ${formatValue(value)}` })
18373
+ }
18374
+ ),
18375
+ showValueLabel && /* @__PURE__ */ jsx(
18376
+ "text",
18377
+ {
18378
+ x: labelX,
18379
+ y: labelY,
18380
+ className: "typo-body-sm-medium",
18381
+ style: { fill: BAR_VALUE_COLOR },
18382
+ textAnchor: vertical ? "middle" : negative ? "end" : "start",
18383
+ dominantBaseline: vertical ? "auto" : "central",
18384
+ children: formatValue(value)
18385
+ }
18386
+ )
18387
+ ] }, `${seriesIndex}-${categoryIndex}`);
18388
+ })
18389
+ ) : [],
18390
+ [
18391
+ size.width,
18392
+ size.height,
18393
+ series,
18394
+ categories,
18395
+ layout,
18396
+ scale,
18397
+ zeroRatio,
18398
+ vertical,
18399
+ direction,
18400
+ showValueLabel,
18401
+ formatValue,
18402
+ onBarClick,
18403
+ colorAt,
18404
+ hoveredCategory
18405
+ ]
18406
+ );
18407
+ const axisLabels = /* @__PURE__ */ jsx(
18408
+ ChartAxisLabels,
18409
+ {
18410
+ scale,
18411
+ direction,
18412
+ format: formatValue,
18413
+ sampleRef: axisSampleRef
18414
+ }
18415
+ );
18416
+ const inset = vertical ? { paddingTop: axisSample.height / 2, paddingBottom: axisSample.height / 2 } : { paddingLeft: axisSample.width / 2, paddingRight: axisSample.width / 2 };
18417
+ const plot = (
18418
+ // 바깥은 자리(높이·물러남)를, 안쪽은 그림을 맡는다. minWidth 는 바깥에 둬야
18419
+ // 스크롤 컨테이너가 넘치는 폭을 알아본다 — 안쪽에 두면 바깥이 부모 폭에 맞춰져
18420
+ // 스크롤이 생기지 않는다.
18421
+ /* @__PURE__ */ jsx(
18422
+ "div",
18423
+ {
18424
+ className: "relative min-w-0",
18425
+ style: { height: plotHeight, minWidth: minPlotWidth || void 0, ...inset },
18426
+ children: /* @__PURE__ */ jsxs(
18427
+ "div",
18428
+ {
18429
+ ref: plotRef,
18430
+ className: "relative h-full w-full",
18431
+ onMouseMove: handleMove,
18432
+ onMouseLeave: () => setHovered(null),
18433
+ children: [
18434
+ size.width > 0 && size.height > 0 && /* @__PURE__ */ jsxs(
18435
+ "svg",
18436
+ {
18437
+ width: size.width,
18438
+ height: size.height,
18439
+ role: "img",
18440
+ "aria-label": `${categories.length}\uAC1C \uD56D\uBAA9, ${series.length}\uAC1C \uACC4\uC5F4 \uB9C9\uB300 \uADF8\uB798\uD504`,
18441
+ children: [
18442
+ /* @__PURE__ */ jsx(
18443
+ ChartGrid,
18444
+ {
18445
+ scale,
18446
+ direction,
18447
+ width: size.width,
18448
+ height: size.height
18449
+ }
18450
+ ),
18451
+ hovered != null && /* @__PURE__ */ jsx(
18452
+ "rect",
18453
+ {
18454
+ "aria-hidden": true,
18455
+ x: vertical ? layout.offset + hovered.category * layout.band : 0,
18456
+ y: vertical ? 0 : layout.offset + hovered.category * layout.band,
18457
+ width: vertical ? layout.band : size.width,
18458
+ height: vertical ? size.height : layout.band,
18459
+ style: {
18460
+ fill: "var(--cmp-chart-barContainer-hover-bg)",
18461
+ fillOpacity: "var(--cmp-chart-barContainer-hover-opacity)"
18462
+ }
18463
+ }
18464
+ ),
18465
+ bars
18466
+ ]
18467
+ }
18468
+ ),
18469
+ showTooltip && hovered != null && series.length > 0 && /* @__PURE__ */ jsx(
18470
+ ChartTooltip,
18471
+ {
18472
+ title: categories[hovered.category] ?? "",
18473
+ items: tooltipItems,
18474
+ x: hovered.x,
18475
+ y: hovered.y,
18476
+ bounds: size
18477
+ }
18478
+ )
18479
+ ]
18480
+ }
18481
+ )
18482
+ }
18483
+ )
18484
+ );
18485
+ return /* @__PURE__ */ jsx(
18486
+ ChartFrame,
18487
+ {
18488
+ ref,
18489
+ legend,
18490
+ legendPosition,
18491
+ className,
18492
+ style,
18493
+ children: /* @__PURE__ */ jsx(
18494
+ "div",
18495
+ {
18496
+ className: "grid",
18497
+ style: {
18498
+ columnGap: AXIS_LABEL_GAP,
18499
+ // 눈금은 왼쪽 한 줄뿐이다 — 오른쪽에도 적으면 서로 다른 단위처럼 읽힌다.
18500
+ gridTemplateColumns: "max-content 1fr"
18501
+ },
18502
+ children: vertical ? /* @__PURE__ */ jsxs(Fragment, { children: [
18503
+ /* @__PURE__ */ jsx("div", { style: { height: plotHeight, ...inset }, children: /* @__PURE__ */ jsx(
18504
+ ChartAxisLabels,
18505
+ {
18506
+ scale,
18507
+ direction,
18508
+ format: formatValue,
18509
+ sampleRef: axisSampleRef
18510
+ }
18511
+ ) }),
18512
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 overflow-x-auto", children: [
18513
+ plot,
18514
+ /* @__PURE__ */ jsx("div", { ref: axisTextRef, children: categoryLabels })
18515
+ ] })
18516
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
18517
+ categoryLabels,
18518
+ plot,
18519
+ /* @__PURE__ */ jsx("div", {}),
18520
+ /* @__PURE__ */ jsx("div", { ref: axisTextRef, style: inset, children: axisLabels })
18521
+ ] })
18522
+ }
18523
+ )
18524
+ }
18525
+ );
18526
+ });
17720
18527
  var BUTTON_STYLE = {
17721
18528
  default: { color: "secondary" },
17722
18529
  danger: { color: "danger", outline: true },
@@ -22615,15 +23422,15 @@ var SBarcodeInput = /* @__PURE__ */ forwardRef(
22615
23422
  );
22616
23423
 
22617
23424
  // src/components/STimePicker/timepicker.config.ts
22618
- var V3 = (path) => `var(--cmp-timepicker-${path})`;
23425
+ var V4 = (path) => `var(--cmp-timepicker-${path})`;
22619
23426
  var TIMEPICKER_SIZES = ["sm", "md"];
22620
23427
  var TIMEPICKER_SIZE_CONFIG = {
22621
23428
  sm: {
22622
- height: V3("sm-height"),
22623
- paddingX: V3("sm-paddingX"),
22624
- gap: V3("sm-gap"),
22625
- icon: V3("sm-icon"),
22626
- radius: V3("sm-radius"),
23429
+ height: V4("sm-height"),
23430
+ paddingX: V4("sm-paddingX"),
23431
+ gap: V4("sm-gap"),
23432
+ icon: V4("sm-icon"),
23433
+ radius: V4("sm-radius"),
22627
23434
  // TODO: component.timepicker 토큰에 typography가 추가되면 CSS 변수로 교체한다.
22628
23435
  fontSize: 12,
22629
23436
  lineHeight: 20,
@@ -22632,11 +23439,11 @@ var TIMEPICKER_SIZE_CONFIG = {
22632
23439
  fieldMaxWidth: "md"
22633
23440
  },
22634
23441
  md: {
22635
- height: V3("md-height"),
22636
- paddingX: V3("md-paddingX"),
22637
- gap: V3("md-gap"),
22638
- icon: V3("md-icon"),
22639
- radius: V3("md-radius"),
23442
+ height: V4("md-height"),
23443
+ paddingX: V4("md-paddingX"),
23444
+ gap: V4("md-gap"),
23445
+ icon: V4("md-icon"),
23446
+ radius: V4("md-radius"),
22640
23447
  // TODO: component.timepicker 토큰에 typography가 추가되면 CSS 변수로 교체한다.
22641
23448
  fontSize: 14,
22642
23449
  lineHeight: 24,
@@ -23526,6 +24333,6 @@ function STimeRangePicker({
23526
24333
  );
23527
24334
  }
23528
24335
 
23529
- export { ACCOUNT_LIST_BOX_ICONS, ACCOUNT_LIST_BOX_ITEM_TONES, ACCOUNT_LIST_BOX_LABELS, ACCOUNT_LIST_BOX_LAYOUT, ACCOUNT_LIST_BOX_TONE_CONFIG, BADGE_COLORS, BUTTON_COLORS, BUTTON_SIZES, CALENDAR_BOARD_DAY_BG, CALENDAR_BOARD_DAY_COLORS, CALENDAR_BOARD_EVENT_COLORS, CALENDAR_BOARD_EVENT_PRESETS, CALENDAR_BOARD_MAX_VISIBLE_EVENTS, CHAT_ATTACHED_FILE_CONFIG, CHAT_ATTACHED_FILE_VARIANTS, CHAT_MESSAGE_DIRECTIONS, CHAT_MESSAGE_READ_STATUSES, CHAT_MESSAGE_VARIANTS, COLOR_KEYS, FIELD_WIDTH_GRADES, GNB_COLORS, GNB_COMMON, GNB_FOLD_MS, GNB_FULL_LOGO_WIDTH, GNB_HEADER, GNB_MENU, GNB_MENU_WIDTH, GNB_RAIL, GNB_RAIL_WIDTH, GNB_SYSTEM_COLORS, GNB_SYSTEM_COLOR_CONFIG, GNB_SYSTEM_LAYOUT, GNB_SYSTEM_PLACEMENTS, GNB_SYSTEM_TOP_COLOR_CONFIG, ICONS, IMAGE_FITS, PAGE_BACKGROUNDS, PAGE_CONTENT_HEIGHTS, PAGE_CONTENT_WIDTHS, PAGE_HEADER_VARIANTS, RangeCalendar, SAccountListBox, SActionModal, SBadge, SBarcodeInput, SButton, SCROLL_AREA_AXES, SCalendar, SCalendarBoard, SCallout, SCard, SChatAttachedFile2 as SChatAttachedFile, SChatInput2 as SChatInput, SChatMessage2 as SChatMessage, SChatSystemMessage2 as SChatSystemMessage, SCheckbox, SChip2 as SChip, SChipFilter, SChipInput, SCircleProgress, SConfirmModal, SDatePicker, SDatePickerMonthListbox, SDatePickerYearListbox, SDateRangePicker, SDivider, SDraggableGroup, SDraggableItem2 as SDraggableItem, SDraggableList, SDraggableProvider, SDrawer, SDropdownButton2 as SDropdownButton, SEDITOR_DEFAULT_FONT_SIZE, SEDITOR_HEADING_LABELS, SEDITOR_HEADING_LEVELS, SEditor, SExpansionItem, SExpansionList2 as SExpansionList, SField, SFilePicker, SForm, SGhostButton, SGnb, SGnbSystem, SGnbSystemContext, SGuide, SIcon, SImage, SInput, SKeyValueTable, SLAYOUT_MIN_WIDTH, SLayout, SLayoutContext, SLinearProgress, SList2 as SList, SListItem2 as SListItem, SLoadingContainer, SLoadingModal, SLoadingViewport, SLoginCard2 as SLoginCard, SModal, SModalOutlet, SNumberInput, SPage, SPageHeader, SPagination, SPopover, SPopup, SPortal, SRadio, SRadioButton, SRadioCard, SRadioCardGroup, SRadioGroup, SSPLITTER_UNITS, SScrollArea, SSearchInput, SSectionHeaderCard2 as SSectionHeaderCard, SSelect2 as SSelect, SSplitter2 as SSplitter, SStepper, SSwitch, SSystemActionButton, STEPPER_SIZES, STable, STableBar, STabs, STag, STextLink, STextarea, STimePicker, STimeRangePicker, SToast, SToastContainer, SToggle, STooltip2 as STooltip, STree2 as STree, STreeItem2 as STreeItem, SYSTEM_ACTION_BUTTON_COLORS, SYSTEM_ACTION_BUTTON_COLOR_CONFIG, SYSTEM_ACTION_BUTTON_LAYOUT, SYSTEM_ACTION_BUTTON_TYPES, SYSTEM_ACTION_BUTTON_TYPE_CONFIG, TAG_COLORS, TAG_SHAPES, TAG_SIZES, TIMEPICKER_SIZES, TIMEPICKER_SIZE_CONFIG, buttonPreset, cn, fieldWidthValue, fileExtension, findGnbAncestors, findGnbRailValue, formatFileSize, isColorKey, isFieldWidthGrade, loading, normalizeExtension, resolveColor, useSLayout };
24336
+ export { ACCOUNT_LIST_BOX_ICONS, ACCOUNT_LIST_BOX_ITEM_TONES, ACCOUNT_LIST_BOX_LABELS, ACCOUNT_LIST_BOX_LAYOUT, ACCOUNT_LIST_BOX_TONE_CONFIG, BADGE_COLORS, BAR_GAP, BAR_SIZE_MAX, BAR_SIZE_MIN, BUTTON_COLORS, BUTTON_SIZES, CALENDAR_BOARD_DAY_BG, CALENDAR_BOARD_DAY_COLORS, CALENDAR_BOARD_EVENT_COLORS, CALENDAR_BOARD_EVENT_PRESETS, CALENDAR_BOARD_MAX_VISIBLE_EVENTS, CHAT_ATTACHED_FILE_CONFIG, CHAT_FILE_CONFIG, CHAT_MESSAGE_DIRECTIONS, CHAT_MESSAGE_READ_STATUSES, CHAT_MESSAGE_VARIANTS, COLOR_KEYS, FIELD_WIDTH_GRADES, GNB_COLORS, GNB_COMMON, GNB_FOLD_MS, GNB_FULL_LOGO_WIDTH, GNB_HEADER, GNB_MENU, GNB_MENU_WIDTH, GNB_RAIL, GNB_RAIL_WIDTH, GNB_SYSTEM_COLORS, GNB_SYSTEM_COLOR_CONFIG, GNB_SYSTEM_LAYOUT, GNB_SYSTEM_PLACEMENTS, GNB_SYSTEM_TOP_COLOR_CONFIG, ICONS, IMAGE_FITS, PAGE_BACKGROUNDS, PAGE_CONTENT_HEIGHTS, PAGE_CONTENT_WIDTHS, PAGE_HEADER_VARIANTS, RangeCalendar, SAccountListBox, SActionModal, SBadge, SBarChart, SBarcodeInput, SButton, SCROLL_AREA_AXES, SCalendar, SCalendarBoard, SCallout, SCard, SChatAttachedFile2 as SChatAttachedFile, SChatFile2 as SChatFile, SChatInput2 as SChatInput, SChatMessage2 as SChatMessage, SChatSystemMessage2 as SChatSystemMessage, SCheckbox, SChip2 as SChip, SChipFilter, SChipInput, SCircleProgress, SConfirmModal, SDatePicker, SDatePickerMonthListbox, SDatePickerYearListbox, SDateRangePicker, SDivider, SDraggableGroup, SDraggableItem2 as SDraggableItem, SDraggableList, SDraggableProvider, SDrawer, SDropdownButton2 as SDropdownButton, SEDITOR_DEFAULT_FONT_SIZE, SEDITOR_HEADING_LABELS, SEDITOR_HEADING_LEVELS, SEditor, SExpansionItem, SExpansionList2 as SExpansionList, SField, SFilePicker, SForm, SGhostButton, SGnb, SGnbSystem, SGnbSystemContext, SGuide, SIcon, SImage, SInput, SKeyValueTable, SLAYOUT_MIN_WIDTH, SLayout, SLayoutContext, SLinearProgress, SList2 as SList, SListItem2 as SListItem, SLoadingContainer, SLoadingModal, SLoadingViewport, SLoginCard2 as SLoginCard, SModal, SModalOutlet, SNumberInput, SPage, SPageHeader, SPagination, SPopover, SPopup, SPortal, SRadio, SRadioButton, SRadioCard, SRadioCardGroup, SRadioGroup, SSPLITTER_UNITS, SScrollArea, SSearchInput, SSectionHeaderCard2 as SSectionHeaderCard, SSelect2 as SSelect, SSplitter2 as SSplitter, SStepper, SSwitch, SSystemActionButton, STEPPER_SIZES, STable, STableBar, STabs, STag, STextLink, STextarea, STimePicker, STimeRangePicker, SToast, SToastContainer, SToggle, STooltip2 as STooltip, STree2 as STree, STreeItem2 as STreeItem, SYSTEM_ACTION_BUTTON_COLORS, SYSTEM_ACTION_BUTTON_COLOR_CONFIG, SYSTEM_ACTION_BUTTON_LAYOUT, SYSTEM_ACTION_BUTTON_TYPES, SYSTEM_ACTION_BUTTON_TYPE_CONFIG, TAG_COLORS, TAG_SHAPES, TAG_SIZES, TIMEPICKER_SIZES, TIMEPICKER_SIZE_CONFIG, buttonPreset, cn, fieldWidthValue, fileExtension, findGnbAncestors, findGnbRailValue, formatFileSize, isColorKey, isFieldWidthGrade, loading, normalizeExtension, resolveColor, useSLayout };
23530
24337
  //# sourceMappingURL=index.js.map
23531
24338
  //# sourceMappingURL=index.js.map