@x-plat/design-system 0.13.0 → 0.14.1

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 (43) hide show
  1. package/dist/{breakpoints-DsXkJgdl.d.cts → breakpoints-CKkNxA-y.d.cts} +1 -1
  2. package/dist/{breakpoints-DsXkJgdl.d.ts → breakpoints-CKkNxA-y.d.ts} +1 -1
  3. package/dist/components/Badge/index.d.cts +1 -1
  4. package/dist/components/Badge/index.d.ts +1 -1
  5. package/dist/components/Dropdown/index.cjs +5 -15
  6. package/dist/components/Dropdown/index.css +0 -3
  7. package/dist/components/Dropdown/index.js +5 -15
  8. package/dist/components/PopOver/index.cjs +3 -14
  9. package/dist/components/PopOver/index.css +0 -3
  10. package/dist/components/PopOver/index.js +3 -14
  11. package/dist/components/Select/index.cjs +4 -14
  12. package/dist/components/Select/index.css +0 -3
  13. package/dist/components/Select/index.js +4 -14
  14. package/dist/components/TimePicker/index.cjs +4 -14
  15. package/dist/components/TimePicker/index.css +0 -3
  16. package/dist/components/TimePicker/index.js +4 -14
  17. package/dist/components/ToggleChip/index.cjs +69 -0
  18. package/dist/components/ToggleChip/index.css +102 -0
  19. package/dist/components/ToggleChip/index.d.cts +37 -0
  20. package/dist/components/ToggleChip/index.d.ts +37 -0
  21. package/dist/components/ToggleChip/index.js +42 -0
  22. package/dist/components/index.cjs +69 -54
  23. package/dist/components/index.css +37 -12
  24. package/dist/components/index.d.cts +2 -1
  25. package/dist/components/index.d.ts +2 -1
  26. package/dist/components/index.js +59 -45
  27. package/dist/index.cjs +88 -73
  28. package/dist/index.css +37 -12
  29. package/dist/index.d.cts +4 -3
  30. package/dist/index.d.ts +4 -3
  31. package/dist/index.js +76 -62
  32. package/dist/layout/Grid/Item/index.d.cts +1 -1
  33. package/dist/layout/Grid/Item/index.d.ts +1 -1
  34. package/dist/layout/Grid/index.d.cts +1 -1
  35. package/dist/layout/Grid/index.d.ts +1 -1
  36. package/dist/layout/index.d.cts +1 -1
  37. package/dist/layout/index.d.ts +1 -1
  38. package/dist/tokens/index.d.cts +1 -1
  39. package/dist/tokens/index.d.ts +1 -1
  40. package/guidelines/Guidelines.md +1 -1
  41. package/guidelines/MIGRATION.md +51 -0
  42. package/guidelines/components/chip-tag.md +80 -2
  43. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7979,10 +7979,8 @@ import React19 from "react";
7979
7979
  var useAutoPosition = (triggerRef, popRef, enabled = true) => {
7980
7980
  const [position, setPosition] = React19.useState({
7981
7981
  position: {},
7982
- direction: "bottom",
7983
- repositioning: false
7982
+ direction: "bottom"
7984
7983
  });
7985
- const placedRef = React19.useRef(false);
7986
7984
  const calculatePosition = React19.useCallback(() => {
7987
7985
  if (!triggerRef.current || !popRef.current) return;
7988
7986
  const triggerRect = triggerRef.current.getBoundingClientRect();
@@ -8005,18 +8003,10 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
8005
8003
  left = triggerRect.right - popW;
8006
8004
  }
8007
8005
  if (left < 8) left = 8;
8008
- setPosition({
8009
- position: { top, left },
8010
- direction,
8011
- repositioning: placedRef.current
8012
- });
8013
- placedRef.current = true;
8006
+ setPosition({ position: { top, left }, direction });
8014
8007
  }, [triggerRef, popRef]);
8015
8008
  React19.useLayoutEffect(() => {
8016
- if (!enabled) {
8017
- placedRef.current = false;
8018
- return;
8019
- }
8009
+ if (!enabled) return;
8020
8010
  calculatePosition();
8021
8011
  const raf = requestAnimationFrame(calculatePosition);
8022
8012
  return () => cancelAnimationFrame(raf);
@@ -8082,7 +8072,7 @@ var Dropdown = (props) => {
8082
8072
  const [visible, setVisible] = React21.useState(false);
8083
8073
  const triggerRef = React21.useRef(null);
8084
8074
  const menuRef = React21.useRef(null);
8085
- const { position, direction, repositioning } = useAutoPosition_default(triggerRef, menuRef, mounted);
8075
+ const { position, direction } = useAutoPosition_default(triggerRef, menuRef, mounted);
8086
8076
  useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
8087
8077
  useEscapeKey(isOpen, () => {
8088
8078
  setIsOpen(false);
@@ -8117,7 +8107,7 @@ var Dropdown = (props) => {
8117
8107
  "div",
8118
8108
  {
8119
8109
  ref: menuRef,
8120
- className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }, repositioning && "repositioning"),
8110
+ className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }),
8121
8111
  style: { top: position.top, left: position.left },
8122
8112
  role: "menu",
8123
8113
  children: items.map((item) => /* @__PURE__ */ jsx322(
@@ -10049,7 +10039,6 @@ var PopOver = (props) => {
10049
10039
  className: clsx_default(
10050
10040
  "lib-xplat-pop-over-content",
10051
10041
  position.direction,
10052
- position.repositioning && "repositioning",
10053
10042
  eventTrigger && "visible"
10054
10043
  ),
10055
10044
  ref: popRef,
@@ -10396,7 +10385,7 @@ var SelectRoot = (props) => {
10396
10385
  mounted && /* @__PURE__ */ jsx337(Portal_default, { children: /* @__PURE__ */ jsxs216(
10397
10386
  "div",
10398
10387
  {
10399
- className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass, position.repositioning && "repositioning"),
10388
+ className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass),
10400
10389
  ref: contentRef,
10401
10390
  style: { ...position.position, width: triggerRef.current?.offsetWidth },
10402
10391
  role: "listbox",
@@ -11289,7 +11278,7 @@ var TimePicker = (props) => {
11289
11278
  "div",
11290
11279
  {
11291
11280
  ref: contentRef,
11292
- className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit", position.repositioning && "repositioning"),
11281
+ className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit"),
11293
11282
  style: { ...position.position, width: triggerRef.current?.offsetWidth },
11294
11283
  role: "listbox",
11295
11284
  children: options.map((t) => /* @__PURE__ */ jsx351(
@@ -11409,9 +11398,33 @@ var ToastProvider = ({
11409
11398
  };
11410
11399
  ToastProvider.displayName = "ToastProvider";
11411
11400
 
11401
+ // src/components/ToggleChip/ToggleChip.tsx
11402
+ import { jsx as jsx353 } from "react/jsx-runtime";
11403
+ var ToggleChip = (props) => {
11404
+ const { children, selected = false, onClick, disabled = false, size = "md" } = props;
11405
+ return /* @__PURE__ */ jsx353(
11406
+ "button",
11407
+ {
11408
+ type: "button",
11409
+ className: clsx_default(
11410
+ "lib-xplat-chip",
11411
+ "lib-xplat-toggle-chip",
11412
+ size,
11413
+ selected ? "selected" : "unselected"
11414
+ ),
11415
+ "aria-pressed": selected,
11416
+ disabled,
11417
+ onClick,
11418
+ children
11419
+ }
11420
+ );
11421
+ };
11422
+ ToggleChip.displayName = "ToggleChip";
11423
+ var ToggleChip_default = ToggleChip;
11424
+
11412
11425
  // src/components/Tooltip/Tooltip.tsx
11413
11426
  import React42 from "react";
11414
- import { Fragment as Fragment6, jsx as jsx353, jsxs as jsxs224 } from "react/jsx-runtime";
11427
+ import { Fragment as Fragment6, jsx as jsx354, jsxs as jsxs224 } from "react/jsx-runtime";
11415
11428
  var OFFSET = 12;
11416
11429
  var GAP = 8;
11417
11430
  var SHOW_DELAY = 300;
@@ -11516,7 +11529,7 @@ var Tooltip = (props) => {
11516
11529
  window.clearTimeout(delayTimer.current);
11517
11530
  cancelAnimationFrame(rafRef.current);
11518
11531
  }, []);
11519
- if (!title && !description) return /* @__PURE__ */ jsx353(Fragment6, { children });
11532
+ if (!title && !description) return /* @__PURE__ */ jsx354(Fragment6, { children });
11520
11533
  return /* @__PURE__ */ jsxs224(
11521
11534
  "div",
11522
11535
  {
@@ -11530,7 +11543,7 @@ var Tooltip = (props) => {
11530
11543
  onBlur: close,
11531
11544
  children: [
11532
11545
  children,
11533
- visible && /* @__PURE__ */ jsx353(Portal_default, { children: /* @__PURE__ */ jsxs224(
11546
+ visible && /* @__PURE__ */ jsx354(Portal_default, { children: /* @__PURE__ */ jsxs224(
11534
11547
  "div",
11535
11548
  {
11536
11549
  ref: tooltipRef,
@@ -11538,8 +11551,8 @@ var Tooltip = (props) => {
11538
11551
  className: clsx_default("lib-xplat-tooltip", shape),
11539
11552
  style: { position: "fixed", left: pos.left, top: pos.top },
11540
11553
  children: [
11541
- title && /* @__PURE__ */ jsx353("div", { className: "tooltip-title", children: title }),
11542
- description && /* @__PURE__ */ jsx353("div", { className: "tooltip-desc", children: description })
11554
+ title && /* @__PURE__ */ jsx354("div", { className: "tooltip-title", children: title }),
11555
+ description && /* @__PURE__ */ jsx354("div", { className: "tooltip-desc", children: description })
11543
11556
  ]
11544
11557
  }
11545
11558
  ) })
@@ -11552,10 +11565,10 @@ var Tooltip_default = Tooltip;
11552
11565
 
11553
11566
  // src/components/Video/Video.tsx
11554
11567
  import React43 from "react";
11555
- import { jsx as jsx354, jsxs as jsxs225 } from "react/jsx-runtime";
11568
+ import { jsx as jsx355, jsxs as jsxs225 } from "react/jsx-runtime";
11556
11569
  var PipIcon = () => /* @__PURE__ */ jsxs225("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
11557
- /* @__PURE__ */ jsx354("rect", { x: "3", y: "5", width: "18", height: "14", rx: "2" }),
11558
- /* @__PURE__ */ jsx354("rect", { x: "12", y: "11", width: "7", height: "6", rx: "1", fill: "currentColor" })
11570
+ /* @__PURE__ */ jsx355("rect", { x: "3", y: "5", width: "18", height: "14", rx: "2" }),
11571
+ /* @__PURE__ */ jsx355("rect", { x: "12", y: "11", width: "7", height: "6", rx: "1", fill: "currentColor" })
11559
11572
  ] });
11560
11573
  var formatTime = (sec) => {
11561
11574
  if (!Number.isFinite(sec) || sec < 0) return "0:00";
@@ -11736,7 +11749,7 @@ var Video = React43.forwardRef((props, ref) => {
11736
11749
  ref: containerRef,
11737
11750
  className: clsx_default("lib-xplat-video", showControls && "has-controls"),
11738
11751
  children: [
11739
- /* @__PURE__ */ jsx354(
11752
+ /* @__PURE__ */ jsx355(
11740
11753
  "video",
11741
11754
  {
11742
11755
  ref: setRefs,
@@ -11757,7 +11770,7 @@ var Video = React43.forwardRef((props, ref) => {
11757
11770
  children
11758
11771
  }
11759
11772
  ),
11760
- showCenterPlay && /* @__PURE__ */ jsx354(
11773
+ showCenterPlay && /* @__PURE__ */ jsx355(
11761
11774
  "button",
11762
11775
  {
11763
11776
  type: "button",
@@ -11769,11 +11782,11 @@ var Video = React43.forwardRef((props, ref) => {
11769
11782
  onClick: togglePlay,
11770
11783
  "aria-label": isPlaying ? "\uC77C\uC2DC\uC815\uC9C0" : "\uC7AC\uC0DD",
11771
11784
  tabIndex: -1,
11772
- children: /* @__PURE__ */ jsx354("span", { className: "center-play-icon", children: /* @__PURE__ */ jsx354(PlayCircleIcon_default, {}) })
11785
+ children: /* @__PURE__ */ jsx355("span", { className: "center-play-icon", children: /* @__PURE__ */ jsx355(PlayCircleIcon_default, {}) })
11773
11786
  }
11774
11787
  ),
11775
11788
  showControls && /* @__PURE__ */ jsxs225("div", { className: "controls", onClick: (e) => e.stopPropagation(), children: [
11776
- /* @__PURE__ */ jsx354(
11789
+ /* @__PURE__ */ jsx355(
11777
11790
  "input",
11778
11791
  {
11779
11792
  type: "range",
@@ -11791,28 +11804,28 @@ var Video = React43.forwardRef((props, ref) => {
11791
11804
  }
11792
11805
  ),
11793
11806
  /* @__PURE__ */ jsxs225("div", { className: "controls-row", children: [
11794
- /* @__PURE__ */ jsx354(
11807
+ /* @__PURE__ */ jsx355(
11795
11808
  "button",
11796
11809
  {
11797
11810
  type: "button",
11798
11811
  className: "control-btn",
11799
11812
  onClick: togglePlay,
11800
11813
  "aria-label": isPlaying ? "\uC77C\uC2DC\uC815\uC9C0" : "\uC7AC\uC0DD",
11801
- children: isPlaying ? /* @__PURE__ */ jsx354(PauseIcon_default, {}) : /* @__PURE__ */ jsx354(PlayIcon_default, {})
11814
+ children: isPlaying ? /* @__PURE__ */ jsx355(PauseIcon_default, {}) : /* @__PURE__ */ jsx355(PlayIcon_default, {})
11802
11815
  }
11803
11816
  ),
11804
11817
  /* @__PURE__ */ jsxs225("div", { className: "volume-group", children: [
11805
- /* @__PURE__ */ jsx354(
11818
+ /* @__PURE__ */ jsx355(
11806
11819
  "button",
11807
11820
  {
11808
11821
  type: "button",
11809
11822
  className: "control-btn",
11810
11823
  onClick: toggleMute,
11811
11824
  "aria-label": isMuted ? "\uC74C\uC18C\uAC70 \uD574\uC81C" : "\uC74C\uC18C\uAC70",
11812
- children: /* @__PURE__ */ jsx354(VolumeGlyph, {})
11825
+ children: /* @__PURE__ */ jsx355(VolumeGlyph, {})
11813
11826
  }
11814
11827
  ),
11815
- /* @__PURE__ */ jsx354(
11828
+ /* @__PURE__ */ jsx355(
11816
11829
  "input",
11817
11830
  {
11818
11831
  type: "range",
@@ -11832,7 +11845,7 @@ var Video = React43.forwardRef((props, ref) => {
11832
11845
  " / ",
11833
11846
  formatTime(duration)
11834
11847
  ] }),
11835
- /* @__PURE__ */ jsx354("div", { className: "controls-spacer" }),
11848
+ /* @__PURE__ */ jsx355("div", { className: "controls-spacer" }),
11836
11849
  playbackRates && playbackRates.length > 0 && /* @__PURE__ */ jsxs225("div", { className: clsx_default("rate-group", rateMenuOpen && "is-open"), children: [
11837
11850
  /* @__PURE__ */ jsxs225(
11838
11851
  "button",
@@ -11848,7 +11861,7 @@ var Video = React43.forwardRef((props, ref) => {
11848
11861
  ]
11849
11862
  }
11850
11863
  ),
11851
- rateMenuOpen && /* @__PURE__ */ jsx354("ul", { className: "rate-menu", role: "menu", children: playbackRates.map((r2) => /* @__PURE__ */ jsx354("li", { children: /* @__PURE__ */ jsxs225(
11864
+ rateMenuOpen && /* @__PURE__ */ jsx355("ul", { className: "rate-menu", role: "menu", children: playbackRates.map((r2) => /* @__PURE__ */ jsx355("li", { children: /* @__PURE__ */ jsxs225(
11852
11865
  "button",
11853
11866
  {
11854
11867
  type: "button",
@@ -11862,7 +11875,7 @@ var Video = React43.forwardRef((props, ref) => {
11862
11875
  }
11863
11876
  ) }, r2)) })
11864
11877
  ] }),
11865
- showCaptions && /* @__PURE__ */ jsx354(
11878
+ showCaptions && /* @__PURE__ */ jsx355(
11866
11879
  "button",
11867
11880
  {
11868
11881
  type: "button",
@@ -11870,37 +11883,37 @@ var Video = React43.forwardRef((props, ref) => {
11870
11883
  onClick: toggleCaptions,
11871
11884
  "aria-label": captionsOn ? "\uC790\uB9C9 \uB044\uAE30" : "\uC790\uB9C9 \uCF1C\uAE30",
11872
11885
  "aria-pressed": captionsOn,
11873
- children: /* @__PURE__ */ jsx354(TypeIcon_default, {})
11886
+ children: /* @__PURE__ */ jsx355(TypeIcon_default, {})
11874
11887
  }
11875
11888
  ),
11876
- showPip && pipSupported && /* @__PURE__ */ jsx354(
11889
+ showPip && pipSupported && /* @__PURE__ */ jsx355(
11877
11890
  "button",
11878
11891
  {
11879
11892
  type: "button",
11880
11893
  className: clsx_default("control-btn", isPip && "is-active"),
11881
11894
  onClick: togglePip,
11882
11895
  "aria-label": isPip ? "PIP \uC885\uB8CC" : "PIP",
11883
- children: /* @__PURE__ */ jsx354(PipIcon, {})
11896
+ children: /* @__PURE__ */ jsx355(PipIcon, {})
11884
11897
  }
11885
11898
  ),
11886
- showDownload && /* @__PURE__ */ jsx354(
11899
+ showDownload && /* @__PURE__ */ jsx355(
11887
11900
  "a",
11888
11901
  {
11889
11902
  className: "control-btn",
11890
11903
  href: src,
11891
11904
  download: downloadFileName ?? true,
11892
11905
  "aria-label": "\uB2E4\uC6B4\uB85C\uB4DC",
11893
- children: /* @__PURE__ */ jsx354(DownloadIcon_default, {})
11906
+ children: /* @__PURE__ */ jsx355(DownloadIcon_default, {})
11894
11907
  }
11895
11908
  ),
11896
- /* @__PURE__ */ jsx354(
11909
+ /* @__PURE__ */ jsx355(
11897
11910
  "button",
11898
11911
  {
11899
11912
  type: "button",
11900
11913
  className: "control-btn",
11901
11914
  onClick: toggleFullscreen,
11902
11915
  "aria-label": isFullscreen ? "\uC804\uCCB4\uD654\uBA74 \uC885\uB8CC" : "\uC804\uCCB4\uD654\uBA74",
11903
- children: isFullscreen ? /* @__PURE__ */ jsx354(MinimizeIcon_default, {}) : /* @__PURE__ */ jsx354(MaximizeIcon_default, {})
11916
+ children: isFullscreen ? /* @__PURE__ */ jsx355(MinimizeIcon_default, {}) : /* @__PURE__ */ jsx355(MaximizeIcon_default, {})
11904
11917
  }
11905
11918
  )
11906
11919
  ] })
@@ -11913,7 +11926,7 @@ Video.displayName = "Video";
11913
11926
  var Video_default = Video;
11914
11927
 
11915
11928
  // src/layout/Grid/FullGrid/FullGrid.tsx
11916
- import { jsx as jsx355 } from "react/jsx-runtime";
11929
+ import { jsx as jsx356 } from "react/jsx-runtime";
11917
11930
  var GAP_MAP = {
11918
11931
  none: "var(--spacing-space-none)",
11919
11932
  xs: "var(--spacing-space-1)",
@@ -11926,13 +11939,13 @@ var GAP_MAP = {
11926
11939
  var FullGrid = (props) => {
11927
11940
  const { children, gap } = props;
11928
11941
  const style = gap != null ? { gap: GAP_MAP[gap] } : void 0;
11929
- return /* @__PURE__ */ jsx355("div", { className: "lib-xplat-full-grid", style, children });
11942
+ return /* @__PURE__ */ jsx356("div", { className: "lib-xplat-full-grid", style, children });
11930
11943
  };
11931
11944
  FullGrid.displayName = "FullGrid";
11932
11945
  var FullGrid_default = FullGrid;
11933
11946
 
11934
11947
  // src/layout/Grid/FullScreen/FullScreen.tsx
11935
- import { jsx as jsx356 } from "react/jsx-runtime";
11948
+ import { jsx as jsx357 } from "react/jsx-runtime";
11936
11949
  var GAP_MAP2 = {
11937
11950
  none: "var(--spacing-space-none)",
11938
11951
  xs: "var(--spacing-space-1)",
@@ -11945,13 +11958,13 @@ var GAP_MAP2 = {
11945
11958
  var FullScreen = (props) => {
11946
11959
  const { children, gap } = props;
11947
11960
  const style = gap != null ? { gap: GAP_MAP2[gap] } : void 0;
11948
- return /* @__PURE__ */ jsx356("div", { className: "lib-xplat-full-screen", style, children });
11961
+ return /* @__PURE__ */ jsx357("div", { className: "lib-xplat-full-screen", style, children });
11949
11962
  };
11950
11963
  FullScreen.displayName = "FullScreen";
11951
11964
  var FullScreen_default = FullScreen;
11952
11965
 
11953
11966
  // src/layout/Grid/Item/Item.tsx
11954
- import { jsx as jsx357 } from "react/jsx-runtime";
11967
+ import { jsx as jsx358 } from "react/jsx-runtime";
11955
11968
  var calculateSpans = (column) => {
11956
11969
  const spans = {};
11957
11970
  let inherited = column.default;
@@ -11968,35 +11981,35 @@ var GridItem = ({ column, children, className }) => {
11968
11981
  Object.entries(spans).forEach(([key, value]) => {
11969
11982
  style[`--column-${key}`] = value;
11970
11983
  });
11971
- return /* @__PURE__ */ jsx357("div", { className: clsx_default("lib-xplat-grid-item", className), style, children });
11984
+ return /* @__PURE__ */ jsx358("div", { className: clsx_default("lib-xplat-grid-item", className), style, children });
11972
11985
  };
11973
11986
  GridItem.displayName = "GridItem";
11974
11987
  var Item_default = GridItem;
11975
11988
 
11976
11989
  // src/layout/Header/Header.tsx
11977
- import { jsx as jsx358, jsxs as jsxs226 } from "react/jsx-runtime";
11990
+ import { jsx as jsx359, jsxs as jsxs226 } from "react/jsx-runtime";
11978
11991
  var Header = ({
11979
11992
  logo,
11980
11993
  centerContent,
11981
11994
  rightContent
11982
11995
  }) => {
11983
11996
  return /* @__PURE__ */ jsxs226("div", { className: "lib-xplat-layout-header", children: [
11984
- /* @__PURE__ */ jsx358("div", { children: logo }),
11985
- /* @__PURE__ */ jsx358("div", { children: centerContent }),
11986
- /* @__PURE__ */ jsx358("div", { children: rightContent })
11997
+ /* @__PURE__ */ jsx359("div", { children: logo }),
11998
+ /* @__PURE__ */ jsx359("div", { children: centerContent }),
11999
+ /* @__PURE__ */ jsx359("div", { children: rightContent })
11987
12000
  ] });
11988
12001
  };
11989
12002
  Header.displayName = "Header";
11990
12003
  var Header_default = Header;
11991
12004
 
11992
12005
  // src/layout/Layout/Layout.tsx
11993
- import { Fragment as Fragment7, jsx as jsx359, jsxs as jsxs227 } from "react/jsx-runtime";
12006
+ import { Fragment as Fragment7, jsx as jsx360, jsxs as jsxs227 } from "react/jsx-runtime";
11994
12007
  var Layout = (props) => {
11995
12008
  const { header, sideBar, children } = props;
11996
- return /* @__PURE__ */ jsx359("div", { className: "lib-xplat-layout", children: /* @__PURE__ */ jsxs227("div", { className: "lib-xplat-layout-content-wrapper", children: [
11997
- sideBar && /* @__PURE__ */ jsx359(Fragment7, { children: sideBar }),
12009
+ return /* @__PURE__ */ jsx360("div", { className: "lib-xplat-layout", children: /* @__PURE__ */ jsxs227("div", { className: "lib-xplat-layout-content-wrapper", children: [
12010
+ sideBar && /* @__PURE__ */ jsx360(Fragment7, { children: sideBar }),
11998
12011
  /* @__PURE__ */ jsxs227("div", { className: "lib-xplat-layout-content", children: [
11999
- header && /* @__PURE__ */ jsx359("div", { className: "lib-xplat-layout-conent-header", children: header }),
12012
+ header && /* @__PURE__ */ jsx360("div", { className: "lib-xplat-layout-conent-header", children: header }),
12000
12013
  children
12001
12014
  ] })
12002
12015
  ] }) });
@@ -12018,18 +12031,18 @@ var useSideBarContext = () => {
12018
12031
  var SideBarContext_default = SideBarContext;
12019
12032
 
12020
12033
  // src/layout/SideBar/SideBar.tsx
12021
- import { jsx as jsx360 } from "react/jsx-runtime";
12034
+ import { jsx as jsx361 } from "react/jsx-runtime";
12022
12035
  var SideBar = (props) => {
12023
12036
  const { children, className } = props;
12024
12037
  const [isOpen, setIsOpen] = React45.useState(true);
12025
12038
  const handleSwitchSideBar = () => {
12026
12039
  setIsOpen((prev) => !prev);
12027
12040
  };
12028
- return /* @__PURE__ */ jsx360(
12041
+ return /* @__PURE__ */ jsx361(
12029
12042
  SideBarContext_default.Provider,
12030
12043
  {
12031
12044
  value: { isSidebarOpen: isOpen, handleSwitchSideBar },
12032
- children: /* @__PURE__ */ jsx360(
12045
+ children: /* @__PURE__ */ jsx361(
12033
12046
  "div",
12034
12047
  {
12035
12048
  className: clsx_default(
@@ -12363,6 +12376,7 @@ export {
12363
12376
  ThumbsUpIcon_default as ThumbsUpIcon,
12364
12377
  TimePicker_default as TimePicker,
12365
12378
  ToastProvider,
12379
+ ToggleChip_default as ToggleChip,
12366
12380
  ToggleLeftIcon_default as ToggleLeftIcon,
12367
12381
  ToggleRightIcon_default as ToggleRightIcon,
12368
12382
  ToolIcon_default as ToolIcon,
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { b as GridColumnConfig } from '../../../breakpoints-DsXkJgdl.cjs';
2
+ import { G as GridColumnConfig } from '../../../breakpoints-CKkNxA-y.cjs';
3
3
 
4
4
  /**
5
5
  * Grid column span — 브레이크포인트별 컬럼 수.
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { b as GridColumnConfig } from '../../../breakpoints-DsXkJgdl.js';
2
+ import { G as GridColumnConfig } from '../../../breakpoints-CKkNxA-y.js';
3
3
 
4
4
  /**
5
5
  * Grid column span — 브레이크포인트별 컬럼 수.
@@ -1,5 +1,5 @@
1
1
  export { FullGrid } from './FullGrid/index.cjs';
2
2
  export { FullScreen } from './FullScreen/index.cjs';
3
3
  export { GridItem } from './Item/index.cjs';
4
- export { B as BREAKPOINT_KEYS_ORDERED, a as BreakpointKey, b as GridColumnConfig, G as GridSpanFor } from '../../breakpoints-DsXkJgdl.cjs';
4
+ export { B as BREAKPOINT_KEYS_ORDERED, a as BreakpointKey, G as GridColumnConfig, b as GridSpanFor } from '../../breakpoints-CKkNxA-y.cjs';
5
5
  import 'react';
@@ -1,5 +1,5 @@
1
1
  export { FullGrid } from './FullGrid/index.js';
2
2
  export { FullScreen } from './FullScreen/index.js';
3
3
  export { GridItem } from './Item/index.js';
4
- export { B as BREAKPOINT_KEYS_ORDERED, a as BreakpointKey, b as GridColumnConfig, G as GridSpanFor } from '../../breakpoints-DsXkJgdl.js';
4
+ export { B as BREAKPOINT_KEYS_ORDERED, a as BreakpointKey, G as GridColumnConfig, b as GridSpanFor } from '../../breakpoints-CKkNxA-y.js';
5
5
  import 'react';
@@ -1,7 +1,7 @@
1
1
  export { FullGrid } from './Grid/FullGrid/index.cjs';
2
2
  export { FullScreen } from './Grid/FullScreen/index.cjs';
3
3
  export { GridItem } from './Grid/Item/index.cjs';
4
- export { B as BREAKPOINT_KEYS_ORDERED, a as BreakpointKey, b as GridColumnConfig, G as GridSpanFor } from '../breakpoints-DsXkJgdl.cjs';
4
+ export { B as BREAKPOINT_KEYS_ORDERED, a as BreakpointKey, G as GridColumnConfig, b as GridSpanFor } from '../breakpoints-CKkNxA-y.cjs';
5
5
  export { Header } from './Header/index.cjs';
6
6
  export { Layout } from './Layout/index.cjs';
7
7
  export { SideBar, SideBarContext, useSideBarContext } from './SideBar/index.cjs';
@@ -1,7 +1,7 @@
1
1
  export { FullGrid } from './Grid/FullGrid/index.js';
2
2
  export { FullScreen } from './Grid/FullScreen/index.js';
3
3
  export { GridItem } from './Grid/Item/index.js';
4
- export { B as BREAKPOINT_KEYS_ORDERED, a as BreakpointKey, b as GridColumnConfig, G as GridSpanFor } from '../breakpoints-DsXkJgdl.js';
4
+ export { B as BREAKPOINT_KEYS_ORDERED, a as BreakpointKey, G as GridColumnConfig, b as GridSpanFor } from '../breakpoints-CKkNxA-y.js';
5
5
  export { Header } from './Header/index.js';
6
6
  export { Layout } from './Layout/index.js';
7
7
  export { SideBar, SideBarContext, useSideBarContext } from './SideBar/index.js';
@@ -1,4 +1,4 @@
1
- export { B as BREAKPOINT_KEYS_ORDERED, a as BreakpointKey, b as GridColumnConfig, G as GridSpanFor, c as breakpoints, g as gridColumns } from '../breakpoints-DsXkJgdl.cjs';
1
+ export { B as BREAKPOINT_KEYS_ORDERED, a as BreakpointKey, G as GridColumnConfig, b as GridSpanFor, c as breakpoints, g as gridColumns } from '../breakpoints-CKkNxA-y.cjs';
2
2
  export { TokenVar, cssVar, semantic } from '@x-plat/tokens-core';
3
3
  import React from 'react';
4
4
 
@@ -1,4 +1,4 @@
1
- export { B as BREAKPOINT_KEYS_ORDERED, a as BreakpointKey, b as GridColumnConfig, G as GridSpanFor, c as breakpoints, g as gridColumns } from '../breakpoints-DsXkJgdl.js';
1
+ export { B as BREAKPOINT_KEYS_ORDERED, a as BreakpointKey, G as GridColumnConfig, b as GridSpanFor, c as breakpoints, g as gridColumns } from '../breakpoints-CKkNxA-y.js';
2
2
  export { TokenVar, cssVar, semantic } from '@x-plat/tokens-core';
3
3
  import React from 'react';
4
4
 
@@ -55,7 +55,7 @@ React 기반 디자인 시스템 라이브러리이다. Figma Make Kit과 1:1
55
55
  - [피드백](./components/feedback.md) - Alert, Toast, NotificationBadge
56
56
  - [오버레이](./components/overlay.md) - Modal, Drawer, PopOver, Tooltip
57
57
  - [폼 컨트롤](./components/form.md) - CheckBox, Radio, Switch
58
- - [Chip & Tag](./components/chip-tag.md)
58
+ - [Chip & ToggleChip & Tag](./components/chip-tag.md)
59
59
  - [내비게이션](./components/navigation.md) - Tab, CardTab, Breadcrumb, Pagination, Steps
60
60
  - [DatePicker](./components/datepicker.md) - Calendar, DatePicker 4종
61
61
  - [Accordion](./components/accordion.md)
@@ -6,6 +6,33 @@
6
6
  - 최신본 URL: `https://unpkg.com/@x-plat/design-system/guidelines/MIGRATION.md`
7
7
  - 자기 버전부터 아래로 읽어 내려가면 된다.
8
8
 
9
+ ## 먼저: 지금 내가 위험한가
10
+
11
+ **`0.x` 에서 캐럿(`^`)은 마이너를 고정한다.** 메이저가 0 이면 npm 은 마이너 번호를
12
+ 메이저처럼 다룬다.
13
+
14
+ ```
15
+ ^0.12.0 ≡ >=0.12.0 <0.13.0 ← 0.13.0 은 안 온다
16
+ ^0.5.42 ≡ >=0.5.42 <0.6.0 ← 0.6.0 은 안 온다
17
+ ```
18
+
19
+ 그래서 **`install` 을 다시 돌려도 아래 변경들은 오지 않는다.** 전부
20
+ `package.json` 의 명시 버전을 직접 올리는 순간에 한꺼번에 온다.
21
+
22
+ 이 말은 두 가지를 뜻한다.
23
+
24
+ 1. **당장 안 올릴 거면 이 문서를 읽지 않아도 된다.** 지금 화면은 안 깨진다.
25
+ 2. **올릴 때는 건너뛴 구간의 절을 전부 읽어야 한다.** 한 마이너씩 올라가는 게
26
+ 아니라 여러 마이너를 한 번에 건너뛰게 되기 때문이다.
27
+
28
+ 특히 오래 머물러 있던 저장소는 **성격이 다른 변경 둘을 한꺼번에 맞는다.**
29
+ `0.5.x` 에서 최신으로 올리면 [0.6.0 CSS 변수 개명](#05x--060--css-변수-이름-전면-교체)과
30
+ [0.13.0 `label` 의미 변경](#0120--0130--fileupload--imageselector-의-label-뜻이-바뀜)을
31
+ 같이 겪는다. **둘 다 타입이나 빌드가 잡아 주지 않고 화면만 바뀐다.** 이관 후
32
+ 눈으로 확인할 것.
33
+
34
+ ---
35
+
9
36
  ## 이 문서를 믿어도 되는 범위
10
37
 
11
38
  각 항목은 **커밋 해시**를 달아 뒀다. 커밋 제목만 보고 판단하지 말 것 —
@@ -233,6 +260,30 @@ HTML 을 검색 색인에 넣는다면 **닫는 태그를 공백이나 줄바꿈
233
260
  직접 넘기는 구조라 라벨이 가리킬 대상이 없고, 후자는 `role="menu"` 인 액션
234
261
  메뉴라 검증할 값이 없다.
235
262
 
263
+ ## 0.12.0 ~ 0.14.0 — 오버레이 열림/닫힘 애니메이션이 죽어 있었다 (0.14.1 에서 고침)
264
+
265
+ **`e80f4df` 가 넣고 `0.14.1` 이 걷어냈다. 이 구간을 쓰고 있었다면 Select ·
266
+ Dropdown · PopOver · TimePicker 가 전부 애니메이션 없이 툭 튀어나왔다.**
267
+
268
+ 0.12.0 에서 "열린 오버레이가 스크롤 중 미끄러진다" 를 고치면서 원인을 둘로
269
+ 봤는데 하나가 틀렸다.
270
+
271
+ - **맞았던 것** — 스크롤 이벤트마다 `setState` 가 돌아 팝업이 한 프레임씩
272
+ 뒤따라왔다. rAF 로 묶어 고쳤고, 이쪽은 그대로 남아 있다.
273
+ - **틀렸던 것** — "방향이 뒤집히면 열림 애니메이션이 다시 발동한다" 고 보고
274
+ `.repositioning { transition: none }` 을 넣었다. 그런데 자리는 `top`/`left`
275
+ 로 옮기는데 전환은 `transform`/`opacity` 에만 걸려 있어 자리 이동은 애초에
276
+ 전환을 타지 않고, 방향이 뒤집혀도 `.top.visible` 과 `.bottom.visible` 이
277
+ 같은 `transform` 을 주므로 바뀌는 값이 없다.
278
+
279
+ 게다가 그 플래그는 첫 계산 직후 켜진 뒤 **닫힐 때까지 꺼지지 않았다.** 여는
280
+ 순간 `useLayoutEffect` → `rAF` → `ResizeObserver` 가 연달아 계산하므로 첫
281
+ 프레임 안에 `transition: none` 이 붙고, 그 뒤에 `.visible` 이 와도 전환이
282
+ 없다. 닫힘(`.exit`)도 같다.
283
+
284
+ **올리기만 하면 된다. 쓰는 쪽에서 고칠 것은 없다.** `.repositioning` 클래스를
285
+ 직접 잡는 CSS 를 쓰고 있었다면 그 규칙만 지우면 된다.
286
+
236
287
  ---
237
288
 
238
289
  ## 실제 이관에서 걸린 것 / 안 걸린 것
@@ -1,4 +1,4 @@
1
- # Chip & Tag
1
+ # Chip & ToggleChip & Tag
2
2
 
3
3
  ## Chip
4
4
 
@@ -41,9 +41,87 @@
41
41
 
42
42
  ---
43
43
 
44
+ ## ToggleChip
45
+
46
+ **눌러서 고르는** 칩이다. 켜짐/꺼짐을 다룬다 — `Tag` 의 클릭은 삭제이고, 이쪽은
47
+ 삭제가 아니다.
48
+
49
+ ```tsx
50
+ <ToggleChip selected={picked.has("ko")} onClick={() => toggle("ko")}>
51
+ 한국어
52
+ </ToggleChip>
53
+ ```
54
+
55
+ | Prop | 타입 | 기본값 | 설명 |
56
+ |------|------|--------|------|
57
+ | children | `ReactNode` | — | 내용 |
58
+ | selected | `boolean` | `false` | 켜진 상태. `aria-pressed` 도 함께 바뀐다 |
59
+ | onClick | `() => void` | — | 누를 때 |
60
+ | disabled | `boolean` | `false` | 흐리게 하고 못 누르게 한다 |
61
+ | size | `"sm" \| "md" \| "lg"` | `"md"` | `Chip` 과 같은 눈금 |
62
+
63
+ **여러 개 고르기와 한 개 고르기 양쪽에 쓴다.** 몇 개까지 켤 수 있는지, 마지막
64
+ 하나를 뗄 수 있는지 같은 규칙은 쓰는 쪽 사정이라 여기서 정하지 않는다. 묶어
65
+ 주는 껍데기도 없다 — 낱개로 늘어놓고 상태만 쥐고 있으면 된다.
66
+
67
+ ```tsx
68
+ // 여러 개 고르기
69
+ const [picked, setPicked] = useState<Set<string>>(new Set());
70
+ const toggle = (v: string) =>
71
+ setPicked((prev) => {
72
+ const next = new Set(prev);
73
+ next.has(v) ? next.delete(v) : next.add(v);
74
+ return next;
75
+ });
76
+
77
+ {OPTIONS.map((o) => (
78
+ <ToggleChip key={o.value} selected={picked.has(o.value)} onClick={() => toggle(o.value)}>
79
+ {o.label}
80
+ </ToggleChip>
81
+ ))}
82
+
83
+ // 한 개 고르기 (거르개)
84
+ {FILTERS.map((f) => (
85
+ <ToggleChip key={f} selected={filter === f} onClick={() => setFilter(f)}>
86
+ {f}
87
+ </ToggleChip>
88
+ ))}
89
+ ```
90
+
91
+ > **곁에 깔린 `Chip` 과 같은 `size` 를 쓸 것.** 고르는 칩은 거의 항상 표시용
92
+ > 칩 옆에 놓이는데, 양쪽 기본값이 `md` 라고 안심하고 두면 앱이 표시용 칩을
93
+ > `sm` 으로 통일해 쓰는 경우 고르는 칩만 한 눈금 커진다. 모양을 맞춰 놔도
94
+ > 크기가 어긋나면 똑같이 겉돈다.
95
+
96
+ `Chip` 과 **같은 알약 모양·같은 크기 눈금**을 쓴다. 두 CSS 가 따로 있는 게
97
+ 아니라 `ToggleChip` 이 `.lib-xplat-chip` 을 그대로 입고 상호작용분만 얹으므로
98
+ 둘이 따로 놀 수 없다. 거르개 칩 아래에 표시용 `Chip` 이 깔리는 화면에서
99
+ 겉돌지 않는다.
100
+
101
+ 색은 `Chip` 의 상태 색(primary·success…)을 받지 않는다. **고른 것과 안 고른 것**
102
+ 두 가지뿐이라 상태 색 어휘가 끼어들 자리가 없다. 고른 것은 옅은 브랜드 바탕에
103
+ 브랜드 테두리다 — 여러 개를 한꺼번에 켜는 쓰임이 더 많은데 진한 채움이 여럿이면
104
+ 화면이 시끄럽고 곁의 버튼과 구분이 안 된다.
105
+
106
+ ---
107
+
44
108
  ## 의사결정
45
109
 
46
110
  | 상황 | 사용할 것 |
47
111
  |------|----------|
48
- | 상태/분류 라벨 (삭제 불필요) | Chip |
112
+ | 상태/분류 라벨 (누를 일 없음) | Chip |
113
+ | 눌러서 고르기 (켜짐/꺼짐) | **ToggleChip** |
49
114
  | 사용자가 제거할 수 있는 태그 | Tag |
115
+ | 개수·점 표시 | NotificationBadge |
116
+
117
+ 셋이 비슷하게 생겼으므로 **무엇이 일어나는가**로 고른다.
118
+
119
+ | | 누르면 | 렌더 |
120
+ |---|---|---|
121
+ | `Chip` | 아무 일도 없다 | `<div>` |
122
+ | `ToggleChip` | 켜지거나 꺼진다 | `<button aria-pressed>` |
123
+ | `Tag` | (X 를 누르면) 사라진다 | `<span>` + 닫기 `<button>` |
124
+
125
+ > 고르는 칩을 `Chip` 을 `<button>` 으로 감싸서 만들지 말 것. 커서·초점 테두리·
126
+ > `aria-pressed` 가 빠지고, 실제로 그렇게 만든 화면들에서 **아무도 누를 수 있는
127
+ > 줄 몰랐다.** `ToggleChip` 이 그 셋을 기본으로 갖는다.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x-plat/design-system",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
4
4
  "description": "XPLAT UI Design System",
5
5
  "author": "XPLAT WOONG",
6
6
  "main": "dist/index.cjs",