@x-plat/design-system 0.7.2 → 0.8.0

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 (41) hide show
  1. package/dist/components/AutoResizeTextArea/index.css +2 -0
  2. package/dist/components/Button/index.css +2 -1
  3. package/dist/components/Button/index.d.cts +6 -0
  4. package/dist/components/Button/index.d.ts +6 -0
  5. package/dist/components/Chart/index.cjs +8 -1
  6. package/dist/components/Chart/index.js +8 -1
  7. package/dist/components/ChatInput/index.css +4 -0
  8. package/dist/components/DatePicker/index.css +4 -1
  9. package/dist/components/Input/index.css +2 -0
  10. package/dist/components/Link/index.cjs +64 -0
  11. package/dist/components/Link/index.css +25 -0
  12. package/dist/components/Link/index.d.cts +27 -0
  13. package/dist/components/Link/index.d.ts +27 -0
  14. package/dist/components/Link/index.js +37 -0
  15. package/dist/components/LinkButton/index.cjs +64 -0
  16. package/dist/components/LinkButton/index.css +106 -0
  17. package/dist/components/LinkButton/index.d.cts +28 -0
  18. package/dist/components/LinkButton/index.d.ts +28 -0
  19. package/dist/components/LinkButton/index.js +37 -0
  20. package/dist/components/TextArea/index.css +2 -0
  21. package/dist/components/Tooltip/index.cjs +77 -32
  22. package/dist/components/Tooltip/index.d.cts +10 -2
  23. package/dist/components/Tooltip/index.d.ts +10 -2
  24. package/dist/components/Tooltip/index.js +77 -32
  25. package/dist/components/index.cjs +247 -153
  26. package/dist/components/index.css +36 -1
  27. package/dist/components/index.d.cts +2 -0
  28. package/dist/components/index.d.ts +2 -0
  29. package/dist/components/index.js +222 -130
  30. package/dist/index.cjs +266 -172
  31. package/dist/index.css +36 -1
  32. package/dist/index.d.cts +2 -0
  33. package/dist/index.d.ts +2 -0
  34. package/dist/index.js +239 -147
  35. package/guidelines/AGENT_PROMPT.md +2 -2
  36. package/guidelines/Guidelines.md +2 -1
  37. package/guidelines/components/button.md +54 -0
  38. package/guidelines/components/card.md +15 -19
  39. package/guidelines/components/link.md +35 -0
  40. package/guidelines/components/overlay.md +30 -1
  41. package/package.json +1 -1
@@ -21,6 +21,8 @@
21
21
  .lib-xplat-auto-resize-textarea-wrapper .lib-xplat-auto-resize-textarea:focus-within {
22
22
  border-color: var(--semantic-interaction-focus-ring);
23
23
  box-shadow: 0 0 0 2px var(--semantic-interaction-overlay-10);
24
+ outline: 2px solid transparent;
25
+ outline-offset: 2px;
24
26
  }
25
27
  .lib-xplat-auto-resize-textarea-wrapper .lib-xplat-auto-resize-textarea:has(> textarea:not(:placeholder-shown)):not(:focus-within) {
26
28
  border-color: var(--semantic-border-tertiary);
@@ -39,7 +39,8 @@
39
39
  font-weight: var(--semantic-typo-label-1-m-weight);
40
40
  letter-spacing: var(--semantic-typo-label-1-m-ls);
41
41
  }
42
- .lib-xplat-button:disabled {
42
+ .lib-xplat-button:disabled,
43
+ .lib-xplat-button.disabled {
43
44
  cursor: not-allowed;
44
45
  background-color: var(--semantic-surface-neutral-disabled) !important;
45
46
  border-color: var(--semantic-surface-neutral-disabled) !important;
@@ -9,6 +9,12 @@ interface ButtonProps extends Omit<ButtonAttributes, "className"> {
9
9
  type?: ButtonType;
10
10
  size?: ButtonSize;
11
11
  }
12
+ /**
13
+ * 버튼은 `<button>` 으로만 렌더된다. 누르면 **무언가 일어나는** 자리에 쓴다.
14
+ *
15
+ * 이동하는 자리는 버튼이 아니라 링크다. 버튼처럼 보여야 하면 `LinkButton`,
16
+ * 본문 속 텍스트 링크는 `Link` 를 쓴다.
17
+ */
12
18
  declare const Button: {
13
19
  (props: ButtonProps): react_jsx_runtime.JSX.Element;
14
20
  displayName: string;
@@ -9,6 +9,12 @@ interface ButtonProps extends Omit<ButtonAttributes, "className"> {
9
9
  type?: ButtonType;
10
10
  size?: ButtonSize;
11
11
  }
12
+ /**
13
+ * 버튼은 `<button>` 으로만 렌더된다. 누르면 **무언가 일어나는** 자리에 쓴다.
14
+ *
15
+ * 이동하는 자리는 버튼이 아니라 링크다. 버튼처럼 보여야 하면 `LinkButton`,
16
+ * 본문 속 텍스트 링크는 `Link` 를 쓴다.
17
+ */
12
18
  declare const Button: {
13
19
  (props: ButtonProps): react_jsx_runtime.JSX.Element;
14
20
  displayName: string;
@@ -172,9 +172,16 @@ var useChartTooltip = (enabled) => {
172
172
  }, []);
173
173
  return { tooltip, show, hide, move, containerRef };
174
174
  };
175
+ var formatTick = (value, maxVal) => {
176
+ const step = maxVal / 4;
177
+ if (!Number.isFinite(step) || step <= 0) return "0";
178
+ const decimals = step >= 1 ? 0 : Math.min(4, Math.ceil(-Math.log10(step)));
179
+ const fixed = value.toFixed(decimals);
180
+ return decimals === 0 ? Number(fixed).toLocaleString("en-US") : fixed;
181
+ };
175
182
  var GridLines = import_react.default.memo(({ width, height, chartH, maxVal }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: [0, 0.25, 0.5, 0.75, 1].map((ratio) => {
176
183
  const y = PADDING.top + (1 - ratio) * chartH;
177
- const val = Math.round(maxVal * ratio);
184
+ const val = formatTick(maxVal * ratio, maxVal);
178
185
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [
179
186
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: PADDING.left, y1: y, x2: width - PADDING.right, y2: y, className: "chart-grid" }),
180
187
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", { x: PADDING.left - 8, y: y + 4, className: "chart-axis-label", textAnchor: "end", children: val })
@@ -136,9 +136,16 @@ var useChartTooltip = (enabled) => {
136
136
  }, []);
137
137
  return { tooltip, show, hide, move, containerRef };
138
138
  };
139
+ var formatTick = (value, maxVal) => {
140
+ const step = maxVal / 4;
141
+ if (!Number.isFinite(step) || step <= 0) return "0";
142
+ const decimals = step >= 1 ? 0 : Math.min(4, Math.ceil(-Math.log10(step)));
143
+ const fixed = value.toFixed(decimals);
144
+ return decimals === 0 ? Number(fixed).toLocaleString("en-US") : fixed;
145
+ };
139
146
  var GridLines = React.memo(({ width, height, chartH, maxVal }) => /* @__PURE__ */ jsx(Fragment, { children: [0, 0.25, 0.5, 0.75, 1].map((ratio) => {
140
147
  const y = PADDING.top + (1 - ratio) * chartH;
141
- const val = Math.round(maxVal * ratio);
148
+ const val = formatTick(maxVal * ratio, maxVal);
142
149
  return /* @__PURE__ */ jsxs("g", { children: [
143
150
  /* @__PURE__ */ jsx("line", { x1: PADDING.left, y1: y, x2: width - PADDING.right, y2: y, className: "chart-grid" }),
144
151
  /* @__PURE__ */ jsx("text", { x: PADDING.left - 8, y: y + 4, className: "chart-axis-label", textAnchor: "end", children: val })
@@ -99,6 +99,8 @@
99
99
  .lib-xplat-auto-resize-textarea-wrapper .lib-xplat-auto-resize-textarea:focus-within {
100
100
  border-color: var(--semantic-interaction-focus-ring);
101
101
  box-shadow: 0 0 0 2px var(--semantic-interaction-overlay-10);
102
+ outline: 2px solid transparent;
103
+ outline-offset: 2px;
102
104
  }
103
105
  .lib-xplat-auto-resize-textarea-wrapper .lib-xplat-auto-resize-textarea:has(> textarea:not(:placeholder-shown)):not(:focus-within) {
104
106
  border-color: var(--semantic-border-tertiary);
@@ -144,6 +146,8 @@
144
146
  .lib-xplat-chat-input:focus-within {
145
147
  border-color: var(--semantic-interaction-focus-ring);
146
148
  box-shadow: 0 0 0 2px var(--semantic-interaction-overlay-10);
149
+ outline: 2px solid transparent;
150
+ outline-offset: 2px;
147
151
  }
148
152
  .lib-xplat-chat-input.disabled {
149
153
  background-color: var(--semantic-surface-neutral-secondary);
@@ -39,7 +39,8 @@
39
39
  font-weight: var(--semantic-typo-label-1-m-weight);
40
40
  letter-spacing: var(--semantic-typo-label-1-m-ls);
41
41
  }
42
- .lib-xplat-button:disabled {
42
+ .lib-xplat-button:disabled,
43
+ .lib-xplat-button.disabled {
43
44
  cursor: not-allowed;
44
45
  background-color: var(--semantic-surface-neutral-disabled) !important;
45
46
  border-color: var(--semantic-surface-neutral-disabled) !important;
@@ -127,6 +128,8 @@
127
128
  .lib-xplat-input-wrap .lib-xplat-input:focus-within {
128
129
  border-color: var(--semantic-interaction-focus-ring);
129
130
  box-shadow: 0 0 0 2px var(--semantic-interaction-overlay-10);
131
+ outline: 2px solid transparent;
132
+ outline-offset: 2px;
130
133
  }
131
134
  .lib-xplat-input-wrap .lib-xplat-input:has(> input:not(:placeholder-shown)):not(:focus-within) {
132
135
  border-color: var(--semantic-border-tertiary);
@@ -21,6 +21,8 @@
21
21
  .lib-xplat-input-wrap .lib-xplat-input:focus-within {
22
22
  border-color: var(--semantic-interaction-focus-ring);
23
23
  box-shadow: 0 0 0 2px var(--semantic-interaction-overlay-10);
24
+ outline: 2px solid transparent;
25
+ outline-offset: 2px;
24
26
  }
25
27
  .lib-xplat-input-wrap .lib-xplat-input:has(> input:not(:placeholder-shown)):not(:focus-within) {
26
28
  border-color: var(--semantic-border-tertiary);
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/components/Link/index.ts
21
+ var Link_exports = {};
22
+ __export(Link_exports, {
23
+ Link: () => Link_default
24
+ });
25
+ module.exports = __toCommonJS(Link_exports);
26
+
27
+ // ../../node_modules/clsx/dist/clsx.mjs
28
+ function r(e) {
29
+ var t, f, n = "";
30
+ if ("string" == typeof e || "number" == typeof e) n += e;
31
+ else if ("object" == typeof e) if (Array.isArray(e)) {
32
+ var o = e.length;
33
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
34
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
35
+ return n;
36
+ }
37
+ function clsx() {
38
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
39
+ return n;
40
+ }
41
+ var clsx_default = clsx;
42
+
43
+ // src/components/Link/Link.tsx
44
+ var import_jsx_runtime = require("react/jsx-runtime");
45
+ var Link = (props) => {
46
+ const { children, href, underline = "always", target, rel, ...rest } = props;
47
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
48
+ "a",
49
+ {
50
+ className: clsx_default("lib-xplat-link", `underline-${underline}`),
51
+ href,
52
+ target,
53
+ rel: target === "_blank" ? rel ?? "noopener noreferrer" : rel,
54
+ ...rest,
55
+ children
56
+ }
57
+ );
58
+ };
59
+ Link.displayName = "Link";
60
+ var Link_default = Link;
61
+ // Annotate the CommonJS export names for ESM import in node:
62
+ 0 && (module.exports = {
63
+ Link
64
+ });
@@ -0,0 +1,25 @@
1
+ /* src/components/Link/link.scss */
2
+ .lib-xplat-link {
3
+ color: var(--semantic-text-link);
4
+ cursor: pointer;
5
+ text-underline-offset: 2px;
6
+ text-decoration-thickness: 1px;
7
+ border-radius: var(--spacing-radius-sm);
8
+ transition: text-decoration-color 0.28s cubic-bezier(0.25, 0.46, 0.45, 0.94);
9
+ }
10
+ .lib-xplat-link.underline-always {
11
+ text-decoration: underline;
12
+ }
13
+ .lib-xplat-link.underline-hover {
14
+ text-decoration: none;
15
+ }
16
+ .lib-xplat-link.underline-hover:hover {
17
+ text-decoration: underline;
18
+ }
19
+ .lib-xplat-link.underline-none {
20
+ text-decoration: none;
21
+ }
22
+ .lib-xplat-link:focus-visible {
23
+ outline: 2px solid var(--semantic-interaction-focus-ring);
24
+ outline-offset: 2px;
25
+ }
@@ -0,0 +1,27 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ type Underline = "always" | "hover" | "none";
5
+ interface LinkProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "color" | "href"> {
6
+ children: React.ReactNode;
7
+ href: string;
8
+ /**
9
+ * 밑줄 표시 방식. 기본은 `"always"`.
10
+ *
11
+ * 본문 속 링크는 색만으로 구분하면 색각 이상이 있는 사용자가 놓친다.
12
+ * 주변 텍스트와 확실히 구분되는 자리(내비게이션·목록 등)에서만 `"hover"` 나
13
+ * `"none"` 으로 내린다.
14
+ */
15
+ underline?: Underline;
16
+ }
17
+ /**
18
+ * 본문 속 텍스트 링크. 크기·굵기는 주변 텍스트를 그대로 물려받는다.
19
+ *
20
+ * 버튼처럼 보여야 하는 링크는 `LinkButton` 을 쓴다.
21
+ */
22
+ declare const Link: {
23
+ (props: LinkProps): react_jsx_runtime.JSX.Element;
24
+ displayName: string;
25
+ };
26
+
27
+ export { Link };
@@ -0,0 +1,27 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ type Underline = "always" | "hover" | "none";
5
+ interface LinkProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "color" | "href"> {
6
+ children: React.ReactNode;
7
+ href: string;
8
+ /**
9
+ * 밑줄 표시 방식. 기본은 `"always"`.
10
+ *
11
+ * 본문 속 링크는 색만으로 구분하면 색각 이상이 있는 사용자가 놓친다.
12
+ * 주변 텍스트와 확실히 구분되는 자리(내비게이션·목록 등)에서만 `"hover"` 나
13
+ * `"none"` 으로 내린다.
14
+ */
15
+ underline?: Underline;
16
+ }
17
+ /**
18
+ * 본문 속 텍스트 링크. 크기·굵기는 주변 텍스트를 그대로 물려받는다.
19
+ *
20
+ * 버튼처럼 보여야 하는 링크는 `LinkButton` 을 쓴다.
21
+ */
22
+ declare const Link: {
23
+ (props: LinkProps): react_jsx_runtime.JSX.Element;
24
+ displayName: string;
25
+ };
26
+
27
+ export { Link };
@@ -0,0 +1,37 @@
1
+ // ../../node_modules/clsx/dist/clsx.mjs
2
+ function r(e) {
3
+ var t, f, n = "";
4
+ if ("string" == typeof e || "number" == typeof e) n += e;
5
+ else if ("object" == typeof e) if (Array.isArray(e)) {
6
+ var o = e.length;
7
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
8
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
9
+ return n;
10
+ }
11
+ function clsx() {
12
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
13
+ return n;
14
+ }
15
+ var clsx_default = clsx;
16
+
17
+ // src/components/Link/Link.tsx
18
+ import { jsx } from "react/jsx-runtime";
19
+ var Link = (props) => {
20
+ const { children, href, underline = "always", target, rel, ...rest } = props;
21
+ return /* @__PURE__ */ jsx(
22
+ "a",
23
+ {
24
+ className: clsx_default("lib-xplat-link", `underline-${underline}`),
25
+ href,
26
+ target,
27
+ rel: target === "_blank" ? rel ?? "noopener noreferrer" : rel,
28
+ ...rest,
29
+ children
30
+ }
31
+ );
32
+ };
33
+ Link.displayName = "Link";
34
+ var Link_default = Link;
35
+ export {
36
+ Link_default as Link
37
+ };
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/components/LinkButton/index.ts
21
+ var LinkButton_exports = {};
22
+ __export(LinkButton_exports, {
23
+ LinkButton: () => LinkButton_default
24
+ });
25
+ module.exports = __toCommonJS(LinkButton_exports);
26
+
27
+ // ../../node_modules/clsx/dist/clsx.mjs
28
+ function r(e) {
29
+ var t, f, n = "";
30
+ if ("string" == typeof e || "number" == typeof e) n += e;
31
+ else if ("object" == typeof e) if (Array.isArray(e)) {
32
+ var o = e.length;
33
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
34
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
35
+ return n;
36
+ }
37
+ function clsx() {
38
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
39
+ return n;
40
+ }
41
+ var clsx_default = clsx;
42
+
43
+ // src/components/LinkButton/LinkButton.tsx
44
+ var import_jsx_runtime = require("react/jsx-runtime");
45
+ var LinkButton = (props) => {
46
+ const { children, href, type = "primary", size = "md", target, rel, ...rest } = props;
47
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
48
+ "a",
49
+ {
50
+ className: clsx_default("lib-xplat-button", type, size),
51
+ href,
52
+ target,
53
+ rel: target === "_blank" ? rel ?? "noopener noreferrer" : rel,
54
+ ...rest,
55
+ children
56
+ }
57
+ );
58
+ };
59
+ LinkButton.displayName = "LinkButton";
60
+ var LinkButton_default = LinkButton;
61
+ // Annotate the CommonJS export names for ESM import in node:
62
+ 0 && (module.exports = {
63
+ LinkButton
64
+ });
@@ -0,0 +1,106 @@
1
+ /* src/components/Button/button.scss */
2
+ .lib-xplat-button {
3
+ width: 100%;
4
+ display: inline-flex;
5
+ align-items: center;
6
+ justify-content: center;
7
+ gap: var(--spacing-space-2);
8
+ white-space: nowrap;
9
+ border-radius: var(--spacing-radius-md);
10
+ font-weight: var(--semantic-typo-label-1-m-weight);
11
+ cursor: pointer;
12
+ border: 1px solid transparent;
13
+ transition: background-color 0.28s cubic-bezier(0.25, 0.46, 0.45, 0.94);
14
+ }
15
+ .lib-xplat-button.sm {
16
+ height: var(--spacing-control-height-sm);
17
+ padding: 0 var(--spacing-space-3);
18
+ font-family: var(--semantic-typo-caption-1-r-font);
19
+ font-size: var(--semantic-typo-caption-1-r-size);
20
+ line-height: var(--semantic-typo-caption-1-r-lh);
21
+ font-weight: var(--semantic-typo-caption-1-r-weight);
22
+ letter-spacing: var(--semantic-typo-caption-1-r-ls);
23
+ }
24
+ .lib-xplat-button.md {
25
+ height: var(--spacing-control-height-md);
26
+ padding: 0 var(--spacing-space-4);
27
+ font-family: var(--semantic-typo-label-2-m-font);
28
+ font-size: var(--semantic-typo-label-2-m-size);
29
+ line-height: var(--semantic-typo-label-2-m-lh);
30
+ font-weight: var(--semantic-typo-label-2-m-weight);
31
+ letter-spacing: var(--semantic-typo-label-2-m-ls);
32
+ }
33
+ .lib-xplat-button.lg {
34
+ height: var(--spacing-control-height-lg);
35
+ padding: 0 var(--spacing-space-6);
36
+ font-family: var(--semantic-typo-label-1-m-font);
37
+ font-size: var(--semantic-typo-label-1-m-size);
38
+ line-height: var(--semantic-typo-label-1-m-lh);
39
+ font-weight: var(--semantic-typo-label-1-m-weight);
40
+ letter-spacing: var(--semantic-typo-label-1-m-ls);
41
+ }
42
+ .lib-xplat-button:disabled,
43
+ .lib-xplat-button.disabled {
44
+ cursor: not-allowed;
45
+ background-color: var(--semantic-surface-neutral-disabled) !important;
46
+ border-color: var(--semantic-surface-neutral-disabled) !important;
47
+ color: var(--semantic-text-disabled) !important;
48
+ }
49
+ .lib-xplat-button.primary {
50
+ color: var(--semantic-text-inverse);
51
+ background-color: var(--semantic-surface-brand-default);
52
+ }
53
+ .lib-xplat-button.primary:hover:not(:disabled) {
54
+ background-color: var(--semantic-surface-brand-strong);
55
+ }
56
+ .lib-xplat-button.primary:active:not(:disabled) {
57
+ background-color: var(--semantic-surface-brand-strong);
58
+ }
59
+ .lib-xplat-button.primary:focus-visible {
60
+ outline: 2px solid var(--semantic-interaction-focus-ring);
61
+ outline-offset: 2px;
62
+ }
63
+ .lib-xplat-button.secondary {
64
+ color: var(--semantic-surface-brand-default);
65
+ background-color: var(--semantic-surface-neutral-primary);
66
+ border-color: var(--semantic-border-primary);
67
+ }
68
+ .lib-xplat-button.secondary:hover:not(:disabled) {
69
+ background-color: var(--semantic-surface-neutral-secondary);
70
+ }
71
+ .lib-xplat-button.secondary:active:not(:disabled) {
72
+ background-color: var(--semantic-surface-neutral-tertiary);
73
+ }
74
+ .lib-xplat-button.secondary:focus-visible {
75
+ outline: 2px solid var(--semantic-interaction-focus-ring);
76
+ outline-offset: 2px;
77
+ }
78
+ .lib-xplat-button.danger {
79
+ color: var(--semantic-text-inverse);
80
+ background-color: var(--semantic-surface-error-default);
81
+ }
82
+ .lib-xplat-button.danger:hover:not(:disabled) {
83
+ background-color: var(--semantic-surface-error-strong);
84
+ }
85
+ .lib-xplat-button.danger:active:not(:disabled) {
86
+ background-color: var(--semantic-surface-error-strong);
87
+ }
88
+ .lib-xplat-button.danger:focus-visible {
89
+ outline: 2px solid var(--semantic-interaction-focus-ring);
90
+ outline-offset: 2px;
91
+ }
92
+ .lib-xplat-button.ghost {
93
+ color: var(--semantic-text-secondary);
94
+ background-color: transparent;
95
+ border-color: transparent;
96
+ }
97
+ .lib-xplat-button.ghost:hover:not(:disabled) {
98
+ background-color: var(--semantic-surface-neutral-secondary);
99
+ }
100
+ .lib-xplat-button.ghost:active:not(:disabled) {
101
+ background-color: var(--semantic-surface-neutral-disabled);
102
+ }
103
+ .lib-xplat-button.ghost:focus-visible {
104
+ outline: 2px solid var(--semantic-interaction-focus-ring);
105
+ outline-offset: 2px;
106
+ }
@@ -0,0 +1,28 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ type LinkButtonType = "primary" | "secondary" | "danger" | "ghost";
5
+ type LinkButtonSize = "sm" | "md" | "lg";
6
+ interface LinkButtonProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "type" | "color" | "href"> {
7
+ children: React.ReactNode;
8
+ href: string;
9
+ type?: LinkButtonType;
10
+ size?: LinkButtonSize;
11
+ }
12
+ /**
13
+ * 버튼처럼 보이지만 **이동하는** 링크. `<a>` 로 렌더된다.
14
+ *
15
+ * 우클릭 메뉴·새 탭으로 열기·링크 미리보기가 동작해야 하는 자리에 쓴다.
16
+ * `<button>` 으로 만들면 그게 전부 막힌다.
17
+ *
18
+ * 누르면 무언가 **일어나는** 자리는 `Button`, 본문 속 텍스트 링크는 `Link` 다.
19
+ *
20
+ * `width: 100%` 가 들어 있어 부모를 꽉 채운다. 내용만큼만 차지해야 하면
21
+ * 감싸는 요소에 `width: fit-content` 를 준다.
22
+ */
23
+ declare const LinkButton: {
24
+ (props: LinkButtonProps): react_jsx_runtime.JSX.Element;
25
+ displayName: string;
26
+ };
27
+
28
+ export { LinkButton };
@@ -0,0 +1,28 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ type LinkButtonType = "primary" | "secondary" | "danger" | "ghost";
5
+ type LinkButtonSize = "sm" | "md" | "lg";
6
+ interface LinkButtonProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "type" | "color" | "href"> {
7
+ children: React.ReactNode;
8
+ href: string;
9
+ type?: LinkButtonType;
10
+ size?: LinkButtonSize;
11
+ }
12
+ /**
13
+ * 버튼처럼 보이지만 **이동하는** 링크. `<a>` 로 렌더된다.
14
+ *
15
+ * 우클릭 메뉴·새 탭으로 열기·링크 미리보기가 동작해야 하는 자리에 쓴다.
16
+ * `<button>` 으로 만들면 그게 전부 막힌다.
17
+ *
18
+ * 누르면 무언가 **일어나는** 자리는 `Button`, 본문 속 텍스트 링크는 `Link` 다.
19
+ *
20
+ * `width: 100%` 가 들어 있어 부모를 꽉 채운다. 내용만큼만 차지해야 하면
21
+ * 감싸는 요소에 `width: fit-content` 를 준다.
22
+ */
23
+ declare const LinkButton: {
24
+ (props: LinkButtonProps): react_jsx_runtime.JSX.Element;
25
+ displayName: string;
26
+ };
27
+
28
+ export { LinkButton };
@@ -0,0 +1,37 @@
1
+ // ../../node_modules/clsx/dist/clsx.mjs
2
+ function r(e) {
3
+ var t, f, n = "";
4
+ if ("string" == typeof e || "number" == typeof e) n += e;
5
+ else if ("object" == typeof e) if (Array.isArray(e)) {
6
+ var o = e.length;
7
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
8
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
9
+ return n;
10
+ }
11
+ function clsx() {
12
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
13
+ return n;
14
+ }
15
+ var clsx_default = clsx;
16
+
17
+ // src/components/LinkButton/LinkButton.tsx
18
+ import { jsx } from "react/jsx-runtime";
19
+ var LinkButton = (props) => {
20
+ const { children, href, type = "primary", size = "md", target, rel, ...rest } = props;
21
+ return /* @__PURE__ */ jsx(
22
+ "a",
23
+ {
24
+ className: clsx_default("lib-xplat-button", type, size),
25
+ href,
26
+ target,
27
+ rel: target === "_blank" ? rel ?? "noopener noreferrer" : rel,
28
+ ...rest,
29
+ children
30
+ }
31
+ );
32
+ };
33
+ LinkButton.displayName = "LinkButton";
34
+ var LinkButton_default = LinkButton;
35
+ export {
36
+ LinkButton_default as LinkButton
37
+ };
@@ -44,6 +44,8 @@
44
44
  .lib-xplat-textarea-wrap .lib-xplat-textarea:focus {
45
45
  border-color: var(--semantic-interaction-focus-ring);
46
46
  box-shadow: 0 0 0 2px var(--semantic-interaction-overlay-10);
47
+ outline: 2px solid transparent;
48
+ outline-offset: 2px;
47
49
  }
48
50
  .lib-xplat-textarea-wrap .lib-xplat-textarea:not(:placeholder-shown):not(:focus) {
49
51
  border-color: var(--semantic-border-tertiary);