@x-plat/design-system 0.7.2 → 0.8.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.
- package/dist/components/AutoResizeTextArea/index.css +2 -0
- package/dist/components/Button/index.css +2 -1
- package/dist/components/Button/index.d.cts +6 -0
- package/dist/components/Button/index.d.ts +6 -0
- package/dist/components/Chart/index.cjs +8 -1
- package/dist/components/Chart/index.js +8 -1
- package/dist/components/ChatInput/index.css +4 -0
- package/dist/components/DatePicker/index.cjs +388 -400
- package/dist/components/DatePicker/index.css +7 -1
- package/dist/components/DatePicker/index.js +375 -387
- package/dist/components/Dropdown/index.cjs +21 -26
- package/dist/components/Dropdown/index.js +20 -25
- package/dist/components/Input/index.css +2 -0
- package/dist/components/Link/index.cjs +64 -0
- package/dist/components/Link/index.css +25 -0
- package/dist/components/Link/index.d.cts +27 -0
- package/dist/components/Link/index.d.ts +27 -0
- package/dist/components/Link/index.js +37 -0
- package/dist/components/LinkButton/index.cjs +64 -0
- package/dist/components/LinkButton/index.css +106 -0
- package/dist/components/LinkButton/index.d.cts +28 -0
- package/dist/components/LinkButton/index.d.ts +28 -0
- package/dist/components/LinkButton/index.js +37 -0
- package/dist/components/Modal/index.cjs +18 -28
- package/dist/components/Modal/index.css +3 -0
- package/dist/components/Modal/index.js +17 -27
- package/dist/components/PopOver/index.cjs +18 -23
- package/dist/components/PopOver/index.js +17 -22
- package/dist/components/Select/index.cjs +337 -342
- package/dist/components/Select/index.js +336 -341
- package/dist/components/TextArea/index.css +2 -0
- package/dist/components/Tooltip/index.cjs +92 -52
- package/dist/components/Tooltip/index.d.cts +10 -2
- package/dist/components/Tooltip/index.d.ts +10 -2
- package/dist/components/Tooltip/index.js +91 -51
- package/dist/components/index.cjs +578 -488
- package/dist/components/index.css +39 -1
- package/dist/components/index.d.cts +2 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +527 -439
- package/dist/index.cjs +602 -512
- package/dist/index.css +39 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +549 -461
- package/guidelines/AGENT_PROMPT.md +2 -2
- package/guidelines/Guidelines.md +2 -1
- package/guidelines/components/button.md +54 -0
- package/guidelines/components/card.md +15 -19
- package/guidelines/components/link.md +35 -0
- package/guidelines/components/overlay.md +30 -1
- package/package.json +1 -1
|
@@ -35,30 +35,25 @@ __export(Dropdown_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(Dropdown_exports);
|
|
36
36
|
|
|
37
37
|
// src/components/Dropdown/Dropdown.tsx
|
|
38
|
-
var
|
|
38
|
+
var import_react3 = __toESM(require("react"), 1);
|
|
39
39
|
|
|
40
40
|
// src/tokens/hooks/Portal.tsx
|
|
41
|
-
var import_react = __toESM(require("react"), 1);
|
|
42
41
|
var import_react_dom = __toESM(require("react-dom"), 1);
|
|
43
|
-
var import_jsx_runtime = require("react/jsx-runtime");
|
|
44
|
-
var PortalContainerContext = import_react.default.createContext(null);
|
|
45
42
|
var Portal = ({ children }) => {
|
|
46
|
-
const contextContainer = import_react.default.useContext(PortalContainerContext);
|
|
47
43
|
if (typeof document === "undefined") return null;
|
|
48
|
-
|
|
49
|
-
return import_react_dom.default.createPortal(children, container);
|
|
44
|
+
return import_react_dom.default.createPortal(children, document.body);
|
|
50
45
|
};
|
|
51
46
|
Portal.displayName = "Portal";
|
|
52
47
|
var Portal_default = Portal;
|
|
53
48
|
|
|
54
49
|
// src/tokens/hooks/useAutoPosition.ts
|
|
55
|
-
var
|
|
50
|
+
var import_react = __toESM(require("react"), 1);
|
|
56
51
|
var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
57
|
-
const [position, setPosition] =
|
|
52
|
+
const [position, setPosition] = import_react.default.useState({
|
|
58
53
|
position: {},
|
|
59
54
|
direction: "bottom"
|
|
60
55
|
});
|
|
61
|
-
const calculatePosition =
|
|
56
|
+
const calculatePosition = import_react.default.useCallback(() => {
|
|
62
57
|
if (!triggerRef.current || !popRef.current) return;
|
|
63
58
|
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
64
59
|
const popW = popRef.current.offsetWidth;
|
|
@@ -85,13 +80,13 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
85
80
|
direction
|
|
86
81
|
});
|
|
87
82
|
}, [triggerRef, popRef]);
|
|
88
|
-
|
|
83
|
+
import_react.default.useLayoutEffect(() => {
|
|
89
84
|
if (!enabled) return;
|
|
90
85
|
calculatePosition();
|
|
91
86
|
const raf = requestAnimationFrame(calculatePosition);
|
|
92
87
|
return () => cancelAnimationFrame(raf);
|
|
93
88
|
}, [calculatePosition, enabled]);
|
|
94
|
-
|
|
89
|
+
import_react.default.useEffect(() => {
|
|
95
90
|
if (!enabled || !popRef.current) return;
|
|
96
91
|
const observer = new ResizeObserver(() => {
|
|
97
92
|
calculatePosition();
|
|
@@ -99,7 +94,7 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
99
94
|
observer.observe(popRef.current);
|
|
100
95
|
return () => observer.disconnect();
|
|
101
96
|
}, [calculatePosition, enabled, popRef]);
|
|
102
|
-
|
|
97
|
+
import_react.default.useEffect(() => {
|
|
103
98
|
if (!enabled) return;
|
|
104
99
|
window.addEventListener("resize", calculatePosition);
|
|
105
100
|
window.addEventListener("scroll", calculatePosition, true);
|
|
@@ -113,9 +108,9 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
113
108
|
var useAutoPosition_default = useAutoPosition;
|
|
114
109
|
|
|
115
110
|
// src/tokens/hooks/useClickOutside.ts
|
|
116
|
-
var
|
|
111
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
117
112
|
var useClickOutside = (refs, handler, enabled = true) => {
|
|
118
|
-
|
|
113
|
+
import_react2.default.useEffect(() => {
|
|
119
114
|
if (!enabled) return;
|
|
120
115
|
const refArray = Array.isArray(refs) ? refs : [refs];
|
|
121
116
|
const listener = (event) => {
|
|
@@ -154,17 +149,17 @@ function clsx() {
|
|
|
154
149
|
var clsx_default = clsx;
|
|
155
150
|
|
|
156
151
|
// src/components/Dropdown/Dropdown.tsx
|
|
157
|
-
var
|
|
152
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
158
153
|
var Dropdown = (props) => {
|
|
159
154
|
const { items, children } = props;
|
|
160
|
-
const [isOpen, setIsOpen] =
|
|
161
|
-
const [mounted, setMounted] =
|
|
162
|
-
const [visible, setVisible] =
|
|
163
|
-
const triggerRef =
|
|
164
|
-
const menuRef =
|
|
155
|
+
const [isOpen, setIsOpen] = import_react3.default.useState(false);
|
|
156
|
+
const [mounted, setMounted] = import_react3.default.useState(false);
|
|
157
|
+
const [visible, setVisible] = import_react3.default.useState(false);
|
|
158
|
+
const triggerRef = import_react3.default.useRef(null);
|
|
159
|
+
const menuRef = import_react3.default.useRef(null);
|
|
165
160
|
const { position, direction } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
166
161
|
useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
|
|
167
|
-
|
|
162
|
+
import_react3.default.useEffect(() => {
|
|
168
163
|
if (isOpen) {
|
|
169
164
|
setMounted(true);
|
|
170
165
|
const t2 = setTimeout(() => setVisible(true), 1);
|
|
@@ -179,8 +174,8 @@ var Dropdown = (props) => {
|
|
|
179
174
|
item.onClick?.();
|
|
180
175
|
setIsOpen(false);
|
|
181
176
|
};
|
|
182
|
-
return /* @__PURE__ */ (0,
|
|
183
|
-
/* @__PURE__ */ (0,
|
|
177
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "lib-xplat-dropdown", children: [
|
|
178
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
184
179
|
"div",
|
|
185
180
|
{
|
|
186
181
|
ref: triggerRef,
|
|
@@ -189,14 +184,14 @@ var Dropdown = (props) => {
|
|
|
189
184
|
children
|
|
190
185
|
}
|
|
191
186
|
),
|
|
192
|
-
mounted && /* @__PURE__ */ (0,
|
|
187
|
+
mounted && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
193
188
|
"div",
|
|
194
189
|
{
|
|
195
190
|
ref: menuRef,
|
|
196
191
|
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }),
|
|
197
192
|
style: { top: position.top, left: position.left },
|
|
198
193
|
role: "menu",
|
|
199
|
-
children: items.map((item) => /* @__PURE__ */ (0,
|
|
194
|
+
children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
200
195
|
"button",
|
|
201
196
|
{
|
|
202
197
|
className: clsx_default("dropdown-item", {
|
|
@@ -1,28 +1,23 @@
|
|
|
1
1
|
// src/components/Dropdown/Dropdown.tsx
|
|
2
|
-
import
|
|
2
|
+
import React3 from "react";
|
|
3
3
|
|
|
4
4
|
// src/tokens/hooks/Portal.tsx
|
|
5
|
-
import React from "react";
|
|
6
5
|
import ReactDOM from "react-dom";
|
|
7
|
-
import { jsx } from "react/jsx-runtime";
|
|
8
|
-
var PortalContainerContext = React.createContext(null);
|
|
9
6
|
var Portal = ({ children }) => {
|
|
10
|
-
const contextContainer = React.useContext(PortalContainerContext);
|
|
11
7
|
if (typeof document === "undefined") return null;
|
|
12
|
-
|
|
13
|
-
return ReactDOM.createPortal(children, container);
|
|
8
|
+
return ReactDOM.createPortal(children, document.body);
|
|
14
9
|
};
|
|
15
10
|
Portal.displayName = "Portal";
|
|
16
11
|
var Portal_default = Portal;
|
|
17
12
|
|
|
18
13
|
// src/tokens/hooks/useAutoPosition.ts
|
|
19
|
-
import
|
|
14
|
+
import React from "react";
|
|
20
15
|
var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
21
|
-
const [position, setPosition] =
|
|
16
|
+
const [position, setPosition] = React.useState({
|
|
22
17
|
position: {},
|
|
23
18
|
direction: "bottom"
|
|
24
19
|
});
|
|
25
|
-
const calculatePosition =
|
|
20
|
+
const calculatePosition = React.useCallback(() => {
|
|
26
21
|
if (!triggerRef.current || !popRef.current) return;
|
|
27
22
|
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
28
23
|
const popW = popRef.current.offsetWidth;
|
|
@@ -49,13 +44,13 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
49
44
|
direction
|
|
50
45
|
});
|
|
51
46
|
}, [triggerRef, popRef]);
|
|
52
|
-
|
|
47
|
+
React.useLayoutEffect(() => {
|
|
53
48
|
if (!enabled) return;
|
|
54
49
|
calculatePosition();
|
|
55
50
|
const raf = requestAnimationFrame(calculatePosition);
|
|
56
51
|
return () => cancelAnimationFrame(raf);
|
|
57
52
|
}, [calculatePosition, enabled]);
|
|
58
|
-
|
|
53
|
+
React.useEffect(() => {
|
|
59
54
|
if (!enabled || !popRef.current) return;
|
|
60
55
|
const observer = new ResizeObserver(() => {
|
|
61
56
|
calculatePosition();
|
|
@@ -63,7 +58,7 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
63
58
|
observer.observe(popRef.current);
|
|
64
59
|
return () => observer.disconnect();
|
|
65
60
|
}, [calculatePosition, enabled, popRef]);
|
|
66
|
-
|
|
61
|
+
React.useEffect(() => {
|
|
67
62
|
if (!enabled) return;
|
|
68
63
|
window.addEventListener("resize", calculatePosition);
|
|
69
64
|
window.addEventListener("scroll", calculatePosition, true);
|
|
@@ -77,9 +72,9 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
|
77
72
|
var useAutoPosition_default = useAutoPosition;
|
|
78
73
|
|
|
79
74
|
// src/tokens/hooks/useClickOutside.ts
|
|
80
|
-
import
|
|
75
|
+
import React2 from "react";
|
|
81
76
|
var useClickOutside = (refs, handler, enabled = true) => {
|
|
82
|
-
|
|
77
|
+
React2.useEffect(() => {
|
|
83
78
|
if (!enabled) return;
|
|
84
79
|
const refArray = Array.isArray(refs) ? refs : [refs];
|
|
85
80
|
const listener = (event) => {
|
|
@@ -118,17 +113,17 @@ function clsx() {
|
|
|
118
113
|
var clsx_default = clsx;
|
|
119
114
|
|
|
120
115
|
// src/components/Dropdown/Dropdown.tsx
|
|
121
|
-
import { jsx
|
|
116
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
122
117
|
var Dropdown = (props) => {
|
|
123
118
|
const { items, children } = props;
|
|
124
|
-
const [isOpen, setIsOpen] =
|
|
125
|
-
const [mounted, setMounted] =
|
|
126
|
-
const [visible, setVisible] =
|
|
127
|
-
const triggerRef =
|
|
128
|
-
const menuRef =
|
|
119
|
+
const [isOpen, setIsOpen] = React3.useState(false);
|
|
120
|
+
const [mounted, setMounted] = React3.useState(false);
|
|
121
|
+
const [visible, setVisible] = React3.useState(false);
|
|
122
|
+
const triggerRef = React3.useRef(null);
|
|
123
|
+
const menuRef = React3.useRef(null);
|
|
129
124
|
const { position, direction } = useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
130
125
|
useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
|
|
131
|
-
|
|
126
|
+
React3.useEffect(() => {
|
|
132
127
|
if (isOpen) {
|
|
133
128
|
setMounted(true);
|
|
134
129
|
const t2 = setTimeout(() => setVisible(true), 1);
|
|
@@ -144,7 +139,7 @@ var Dropdown = (props) => {
|
|
|
144
139
|
setIsOpen(false);
|
|
145
140
|
};
|
|
146
141
|
return /* @__PURE__ */ jsxs("div", { className: "lib-xplat-dropdown", children: [
|
|
147
|
-
/* @__PURE__ */
|
|
142
|
+
/* @__PURE__ */ jsx(
|
|
148
143
|
"div",
|
|
149
144
|
{
|
|
150
145
|
ref: triggerRef,
|
|
@@ -153,14 +148,14 @@ var Dropdown = (props) => {
|
|
|
153
148
|
children
|
|
154
149
|
}
|
|
155
150
|
),
|
|
156
|
-
mounted && /* @__PURE__ */
|
|
151
|
+
mounted && /* @__PURE__ */ jsx(Portal_default, { children: /* @__PURE__ */ jsx(
|
|
157
152
|
"div",
|
|
158
153
|
{
|
|
159
154
|
ref: menuRef,
|
|
160
155
|
className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }),
|
|
161
156
|
style: { top: position.top, left: position.left },
|
|
162
157
|
role: "menu",
|
|
163
|
-
children: items.map((item) => /* @__PURE__ */
|
|
158
|
+
children: items.map((item) => /* @__PURE__ */ jsx(
|
|
164
159
|
"button",
|
|
165
160
|
{
|
|
166
161
|
className: clsx_default("dropdown-item", {
|
|
@@ -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 };
|