moru-krds-react 0.1.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.
- package/LICENSE +21 -0
- package/README.md +61 -0
- package/dist/accordion/index.d.ts +63 -0
- package/dist/accordion/index.d.ts.map +1 -0
- package/dist/accordion/index.js +145 -0
- package/dist/accordion/index.js.map +1 -0
- package/dist/alert/index.d.ts +44 -0
- package/dist/alert/index.d.ts.map +1 -0
- package/dist/alert/index.js +66 -0
- package/dist/alert/index.js.map +1 -0
- package/dist/avatar/index.d.ts +102 -0
- package/dist/avatar/index.d.ts.map +1 -0
- package/dist/avatar/index.js +146 -0
- package/dist/avatar/index.js.map +1 -0
- package/dist/badge/index.d.ts +49 -0
- package/dist/badge/index.d.ts.map +1 -0
- package/dist/badge/index.js +41 -0
- package/dist/badge/index.js.map +1 -0
- package/dist/breadcrumb/index.d.ts +43 -0
- package/dist/breadcrumb/index.d.ts.map +1 -0
- package/dist/breadcrumb/index.js +43 -0
- package/dist/breadcrumb/index.js.map +1 -0
- package/dist/button/index.d.ts +78 -0
- package/dist/button/index.d.ts.map +1 -0
- package/dist/button/index.js +83 -0
- package/dist/button/index.js.map +1 -0
- package/dist/checkbox/index.d.ts +97 -0
- package/dist/checkbox/index.d.ts.map +1 -0
- package/dist/checkbox/index.js +110 -0
- package/dist/checkbox/index.js.map +1 -0
- package/dist/combobox/index.d.ts +135 -0
- package/dist/combobox/index.d.ts.map +1 -0
- package/dist/combobox/index.js +416 -0
- package/dist/combobox/index.js.map +1 -0
- package/dist/context-menu/index.d.ts +94 -0
- package/dist/context-menu/index.d.ts.map +1 -0
- package/dist/context-menu/index.js +399 -0
- package/dist/context-menu/index.js.map +1 -0
- package/dist/critical-alert/index.d.ts +39 -0
- package/dist/critical-alert/index.d.ts.map +1 -0
- package/dist/critical-alert/index.js +50 -0
- package/dist/critical-alert/index.js.map +1 -0
- package/dist/data-table/index.d.ts +94 -0
- package/dist/data-table/index.d.ts.map +1 -0
- package/dist/data-table/index.js +128 -0
- package/dist/data-table/index.js.map +1 -0
- package/dist/disclosure/index.d.ts +35 -0
- package/dist/disclosure/index.d.ts.map +1 -0
- package/dist/disclosure/index.js +54 -0
- package/dist/disclosure/index.js.map +1 -0
- package/dist/drawer/index.d.ts +106 -0
- package/dist/drawer/index.d.ts.map +1 -0
- package/dist/drawer/index.js +352 -0
- package/dist/drawer/index.js.map +1 -0
- package/dist/empty-state/index.d.ts +86 -0
- package/dist/empty-state/index.d.ts.map +1 -0
- package/dist/empty-state/index.js +138 -0
- package/dist/empty-state/index.js.map +1 -0
- package/dist/env.d.js +1 -0
- package/dist/env.d.js.map +1 -0
- package/dist/field/index.d.ts +149 -0
- package/dist/field/index.d.ts.map +1 -0
- package/dist/field/index.js +121 -0
- package/dist/field/index.js.map +1 -0
- package/dist/file-upload/index.d.ts +140 -0
- package/dist/file-upload/index.d.ts.map +1 -0
- package/dist/file-upload/index.js +249 -0
- package/dist/file-upload/index.js.map +1 -0
- package/dist/footer/index.d.ts +155 -0
- package/dist/footer/index.d.ts.map +1 -0
- package/dist/footer/index.js +186 -0
- package/dist/footer/index.js.map +1 -0
- package/dist/header/index.d.ts +170 -0
- package/dist/header/index.d.ts.map +1 -0
- package/dist/header/index.js +258 -0
- package/dist/header/index.js.map +1 -0
- package/dist/identifier/index.d.ts +38 -0
- package/dist/identifier/index.d.ts.map +1 -0
- package/dist/identifier/index.js +55 -0
- package/dist/identifier/index.js.map +1 -0
- package/dist/in-page-navigation/index.d.ts +71 -0
- package/dist/in-page-navigation/index.d.ts.map +1 -0
- package/dist/in-page-navigation/index.js +137 -0
- package/dist/in-page-navigation/index.js.map +1 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/input-group/index.d.ts +66 -0
- package/dist/input-group/index.d.ts.map +1 -0
- package/dist/input-group/index.js +85 -0
- package/dist/input-group/index.js.map +1 -0
- package/dist/lib/krds.d.ts +45 -0
- package/dist/lib/krds.d.ts.map +1 -0
- package/dist/lib/krds.js +11 -0
- package/dist/lib/krds.js.map +1 -0
- package/dist/lib/link.d.ts +34 -0
- package/dist/lib/link.d.ts.map +1 -0
- package/dist/lib/link.js +8 -0
- package/dist/lib/link.js.map +1 -0
- package/dist/main-menu/index.d.ts +123 -0
- package/dist/main-menu/index.d.ts.map +1 -0
- package/dist/main-menu/index.js +613 -0
- package/dist/main-menu/index.js.map +1 -0
- package/dist/masthead/index.d.ts +25 -0
- package/dist/masthead/index.d.ts.map +1 -0
- package/dist/masthead/index.js +21 -0
- package/dist/masthead/index.js.map +1 -0
- package/dist/modal/index.d.ts +105 -0
- package/dist/modal/index.d.ts.map +1 -0
- package/dist/modal/index.js +285 -0
- package/dist/modal/index.js.map +1 -0
- package/dist/pagination/index.d.ts +58 -0
- package/dist/pagination/index.d.ts.map +1 -0
- package/dist/pagination/index.js +82 -0
- package/dist/pagination/index.js.map +1 -0
- package/dist/progress/index.d.ts +58 -0
- package/dist/progress/index.d.ts.map +1 -0
- package/dist/progress/index.js +125 -0
- package/dist/progress/index.js.map +1 -0
- package/dist/radio/index.d.ts +111 -0
- package/dist/radio/index.d.ts.map +1 -0
- package/dist/radio/index.js +136 -0
- package/dist/radio/index.js.map +1 -0
- package/dist/resize/index.d.ts +118 -0
- package/dist/resize/index.d.ts.map +1 -0
- package/dist/resize/index.js +342 -0
- package/dist/resize/index.js.map +1 -0
- package/dist/scroll-area/index.d.ts +40 -0
- package/dist/scroll-area/index.d.ts.map +1 -0
- package/dist/scroll-area/index.js +52 -0
- package/dist/scroll-area/index.js.map +1 -0
- package/dist/select/index.d.ts +67 -0
- package/dist/select/index.d.ts.map +1 -0
- package/dist/select/index.js +61 -0
- package/dist/select/index.js.map +1 -0
- package/dist/separator/index.d.ts +47 -0
- package/dist/separator/index.d.ts.map +1 -0
- package/dist/separator/index.js +61 -0
- package/dist/separator/index.js.map +1 -0
- package/dist/side-navigation/index.d.ts +78 -0
- package/dist/side-navigation/index.d.ts.map +1 -0
- package/dist/side-navigation/index.js +188 -0
- package/dist/side-navigation/index.js.map +1 -0
- package/dist/skeleton/index.d.ts +76 -0
- package/dist/skeleton/index.d.ts.map +1 -0
- package/dist/skeleton/index.js +78 -0
- package/dist/skeleton/index.js.map +1 -0
- package/dist/skip-link/index.d.ts +46 -0
- package/dist/skip-link/index.d.ts.map +1 -0
- package/dist/skip-link/index.js +37 -0
- package/dist/skip-link/index.js.map +1 -0
- package/dist/spinner/index.d.ts +58 -0
- package/dist/spinner/index.d.ts.map +1 -0
- package/dist/spinner/index.js +36 -0
- package/dist/spinner/index.js.map +1 -0
- package/dist/step-indicator/index.d.ts +41 -0
- package/dist/step-indicator/index.d.ts.map +1 -0
- package/dist/step-indicator/index.js +63 -0
- package/dist/step-indicator/index.js.map +1 -0
- package/dist/structured-list/index.d.ts +150 -0
- package/dist/structured-list/index.d.ts.map +1 -0
- package/dist/structured-list/index.js +194 -0
- package/dist/structured-list/index.js.map +1 -0
- package/dist/tab/index.d.ts +108 -0
- package/dist/tab/index.d.ts.map +1 -0
- package/dist/tab/index.js +198 -0
- package/dist/tab/index.js.map +1 -0
- package/dist/table/index.d.ts +75 -0
- package/dist/table/index.d.ts.map +1 -0
- package/dist/table/index.js +91 -0
- package/dist/table/index.js.map +1 -0
- package/dist/tag/index.d.ts +71 -0
- package/dist/tag/index.d.ts.map +1 -0
- package/dist/tag/index.js +45 -0
- package/dist/tag/index.js.map +1 -0
- package/dist/text-input/index.d.ts +69 -0
- package/dist/text-input/index.d.ts.map +1 -0
- package/dist/text-input/index.js +70 -0
- package/dist/text-input/index.js.map +1 -0
- package/dist/text-list/index.d.ts +71 -0
- package/dist/text-list/index.d.ts.map +1 -0
- package/dist/text-list/index.js +79 -0
- package/dist/text-list/index.js.map +1 -0
- package/dist/textarea/index.d.ts +29 -0
- package/dist/textarea/index.d.ts.map +1 -0
- package/dist/textarea/index.js +69 -0
- package/dist/textarea/index.js.map +1 -0
- package/dist/toast/index.d.ts +76 -0
- package/dist/toast/index.d.ts.map +1 -0
- package/dist/toast/index.js +183 -0
- package/dist/toast/index.js.map +1 -0
- package/dist/tooltip/index.d.ts +84 -0
- package/dist/tooltip/index.d.ts.map +1 -0
- package/dist/tooltip/index.js +329 -0
- package/dist/tooltip/index.js.map +1 -0
- package/package.json +57 -0
- package/src/accordion/index.tsx +251 -0
- package/src/alert/index.tsx +111 -0
- package/src/avatar/index.tsx +272 -0
- package/src/badge/index.tsx +91 -0
- package/src/breadcrumb/index.tsx +125 -0
- package/src/button/index.tsx +190 -0
- package/src/checkbox/index.tsx +247 -0
- package/src/combobox/index.tsx +700 -0
- package/src/context-menu/index.tsx +623 -0
- package/src/critical-alert/index.tsx +102 -0
- package/src/data-table/index.tsx +289 -0
- package/src/disclosure/index.tsx +87 -0
- package/src/drawer/index.tsx +516 -0
- package/src/empty-state/index.tsx +256 -0
- package/src/env.d.ts +10 -0
- package/src/field/index.tsx +307 -0
- package/src/file-upload/index.tsx +492 -0
- package/src/footer/index.tsx +393 -0
- package/src/header/index.tsx +498 -0
- package/src/identifier/index.tsx +96 -0
- package/src/in-page-navigation/index.tsx +258 -0
- package/src/index.ts +72 -0
- package/src/input-group/index.tsx +197 -0
- package/src/lib/krds.ts +75 -0
- package/src/lib/link.tsx +35 -0
- package/src/main-menu/index.tsx +912 -0
- package/src/masthead/index.tsx +50 -0
- package/src/modal/index.tsx +457 -0
- package/src/pagination/index.tsx +198 -0
- package/src/progress/index.tsx +198 -0
- package/src/radio/index.tsx +283 -0
- package/src/resize/index.tsx +541 -0
- package/src/scroll-area/index.tsx +96 -0
- package/src/select/index.tsx +136 -0
- package/src/separator/index.tsx +107 -0
- package/src/side-navigation/index.tsx +336 -0
- package/src/skeleton/index.tsx +172 -0
- package/src/skip-link/index.tsx +89 -0
- package/src/spinner/index.tsx +98 -0
- package/src/step-indicator/index.tsx +122 -0
- package/src/structured-list/index.tsx +395 -0
- package/src/tab/index.tsx +348 -0
- package/src/table/index.tsx +186 -0
- package/src/tag/index.tsx +127 -0
- package/src/text-input/index.tsx +156 -0
- package/src/text-list/index.tsx +177 -0
- package/src/textarea/index.tsx +113 -0
- package/src/toast/index.tsx +311 -0
- package/src/tooltip/index.tsx +496 -0
- package/styles/krds-tailwind.css +335 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import {
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useId,
|
|
7
|
+
useRef,
|
|
8
|
+
useState
|
|
9
|
+
} from "react";
|
|
10
|
+
import { Button } from "../button/index.js";
|
|
11
|
+
import { cx } from "../lib/krds.js";
|
|
12
|
+
function alignClass(align) {
|
|
13
|
+
return align === "left" || align === "right" ? `drop-${align}` : void 0;
|
|
14
|
+
}
|
|
15
|
+
function itemText(item) {
|
|
16
|
+
return (item.text ?? (typeof item.label === "string" ? item.label : "")).trim().toLowerCase();
|
|
17
|
+
}
|
|
18
|
+
const TYPEAHEAD_RESET_MS = 500;
|
|
19
|
+
const VIEWPORT_GUTTER_PX = 8;
|
|
20
|
+
function useMenuController() {
|
|
21
|
+
const [open, setOpen] = useState(false);
|
|
22
|
+
const wrapRef = useRef(null);
|
|
23
|
+
const menuRef = useRef(null);
|
|
24
|
+
const returnFocusRef = useRef(null);
|
|
25
|
+
const initialFocusRef = useRef("first");
|
|
26
|
+
const items = useCallback(
|
|
27
|
+
() => Array.from(menuRef.current?.querySelectorAll('[role="menuitem"]') ?? []),
|
|
28
|
+
[]
|
|
29
|
+
);
|
|
30
|
+
const openMenu = useCallback((initial = "first", returnTo) => {
|
|
31
|
+
initialFocusRef.current = initial;
|
|
32
|
+
returnFocusRef.current = returnTo ?? document.activeElement ?? null;
|
|
33
|
+
setOpen(true);
|
|
34
|
+
}, []);
|
|
35
|
+
const close = useCallback((refocus = false) => {
|
|
36
|
+
setOpen(false);
|
|
37
|
+
if (refocus) returnFocusRef.current?.focus();
|
|
38
|
+
}, []);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (!open) return;
|
|
41
|
+
const list = items();
|
|
42
|
+
if (!list.length) return;
|
|
43
|
+
(initialFocusRef.current === "last" ? list[list.length - 1] : list[0]).focus();
|
|
44
|
+
}, [open, items]);
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (!open) return;
|
|
47
|
+
const onPointerDown = (e) => {
|
|
48
|
+
if (!wrapRef.current?.contains(e.target)) setOpen(false);
|
|
49
|
+
};
|
|
50
|
+
document.addEventListener("pointerdown", onPointerDown);
|
|
51
|
+
return () => document.removeEventListener("pointerdown", onPointerDown);
|
|
52
|
+
}, [open]);
|
|
53
|
+
return { open, openMenu, close, wrapRef, menuRef, items };
|
|
54
|
+
}
|
|
55
|
+
function mergeRef(inner, outer) {
|
|
56
|
+
return (node) => {
|
|
57
|
+
inner.current = node;
|
|
58
|
+
if (typeof outer === "function") outer(node);
|
|
59
|
+
else if (outer) outer.current = node;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function useOpenChange(open, onOpenChange) {
|
|
63
|
+
const latest = useRef(onOpenChange);
|
|
64
|
+
const mounted = useRef(false);
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
latest.current = onOpenChange;
|
|
67
|
+
});
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (!mounted.current) {
|
|
70
|
+
mounted.current = true;
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
latest.current?.(open);
|
|
74
|
+
}, [open]);
|
|
75
|
+
}
|
|
76
|
+
function MenuList({ id, items, label, labelledBy, menuRef, onKeyDown, onActivate }) {
|
|
77
|
+
return /* @__PURE__ */ jsx(
|
|
78
|
+
"ul",
|
|
79
|
+
{
|
|
80
|
+
ref: menuRef,
|
|
81
|
+
id,
|
|
82
|
+
role: "menu",
|
|
83
|
+
"aria-label": labelledBy ? void 0 : label,
|
|
84
|
+
"aria-labelledby": labelledBy,
|
|
85
|
+
className: "drop-list",
|
|
86
|
+
onKeyDown,
|
|
87
|
+
children: items.map((item, index) => {
|
|
88
|
+
if (item.separator) {
|
|
89
|
+
return /* @__PURE__ */ jsx(
|
|
90
|
+
"li",
|
|
91
|
+
{
|
|
92
|
+
role: "separator",
|
|
93
|
+
className: "my-1 h-px bg-divider"
|
|
94
|
+
},
|
|
95
|
+
item.id ?? `separator-${index}`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
const { id: itemId, label: itemLabel, icon, href, target, disabled, danger, active } = item;
|
|
99
|
+
const cls = cx(
|
|
100
|
+
"item-link",
|
|
101
|
+
active && "active",
|
|
102
|
+
// ํท์ ์ํยท๋นํ์ฑ ํญ๋ชฉ ๋ชจ์์ด ์๋ค โ ์ ํธ๋ฆฌํฐ๋ก ๋ณด์ถฉํ๋ค.
|
|
103
|
+
danger && !disabled && "text-danger",
|
|
104
|
+
disabled && "text-fg-disabled cursor-not-allowed hover:bg-transparent"
|
|
105
|
+
);
|
|
106
|
+
const iconNode = icon ? /* @__PURE__ */ jsx(
|
|
107
|
+
"i",
|
|
108
|
+
{
|
|
109
|
+
className: cx(
|
|
110
|
+
"svg-icon",
|
|
111
|
+
`ico-${icon}`,
|
|
112
|
+
danger && !disabled && "bg-danger",
|
|
113
|
+
disabled && "bg-fg-disabled"
|
|
114
|
+
),
|
|
115
|
+
"aria-hidden": "true"
|
|
116
|
+
}
|
|
117
|
+
) : null;
|
|
118
|
+
const shared = {
|
|
119
|
+
role: "menuitem",
|
|
120
|
+
// ๋ฉ๋ด ์์์๋ โโ ๋ก๋ง ์ค๊ฐ๋ค(roving tabindex). ์ด์ ์ ๋ถํ์ด ์ฎ๊ธด๋ค.
|
|
121
|
+
tabIndex: -1,
|
|
122
|
+
className: cls,
|
|
123
|
+
// ๋นํ์ฑ์ disabled ์์ฑ์ด ์๋๋ผ aria-disabled ๋ค โ ์ด์ ์ ๋ฐ์์ผ ํ๋ค(APG).
|
|
124
|
+
"aria-disabled": disabled || void 0,
|
|
125
|
+
"aria-current": active ? "true" : void 0
|
|
126
|
+
};
|
|
127
|
+
return /* @__PURE__ */ jsx("li", { role: "none", children: href !== void 0 ? /* @__PURE__ */ jsxs(
|
|
128
|
+
"a",
|
|
129
|
+
{
|
|
130
|
+
...shared,
|
|
131
|
+
href: disabled ? void 0 : href,
|
|
132
|
+
target,
|
|
133
|
+
title: target === "_blank" ? "\uC0C8 \uCC3D \uC5F4\uB9BC" : void 0,
|
|
134
|
+
onClick: (e) => {
|
|
135
|
+
if (disabled) {
|
|
136
|
+
e.preventDefault();
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
onActivate(item);
|
|
140
|
+
},
|
|
141
|
+
children: [
|
|
142
|
+
iconNode,
|
|
143
|
+
itemLabel
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
) : /* @__PURE__ */ jsxs(
|
|
147
|
+
"button",
|
|
148
|
+
{
|
|
149
|
+
...shared,
|
|
150
|
+
type: "button",
|
|
151
|
+
onClick: () => {
|
|
152
|
+
if (disabled) return;
|
|
153
|
+
onActivate(item);
|
|
154
|
+
},
|
|
155
|
+
children: [
|
|
156
|
+
iconNode,
|
|
157
|
+
itemLabel
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
) }, itemId);
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
function useMenuKeyDown({ items, close }, entries) {
|
|
166
|
+
const buffer = useRef("");
|
|
167
|
+
const timer = useRef(null);
|
|
168
|
+
useEffect(
|
|
169
|
+
() => () => {
|
|
170
|
+
if (timer.current) clearTimeout(timer.current);
|
|
171
|
+
},
|
|
172
|
+
[]
|
|
173
|
+
);
|
|
174
|
+
const focusAt = (list, index) => {
|
|
175
|
+
if (!list.length) return;
|
|
176
|
+
list[(index + list.length) % list.length].focus();
|
|
177
|
+
};
|
|
178
|
+
return (e) => {
|
|
179
|
+
const list = items();
|
|
180
|
+
const at = list.indexOf(document.activeElement);
|
|
181
|
+
switch (e.key) {
|
|
182
|
+
case "ArrowDown":
|
|
183
|
+
e.preventDefault();
|
|
184
|
+
focusAt(list, at + 1);
|
|
185
|
+
return;
|
|
186
|
+
case "ArrowUp":
|
|
187
|
+
e.preventDefault();
|
|
188
|
+
focusAt(list, at - 1);
|
|
189
|
+
return;
|
|
190
|
+
case "Home":
|
|
191
|
+
e.preventDefault();
|
|
192
|
+
focusAt(list, 0);
|
|
193
|
+
return;
|
|
194
|
+
case "End":
|
|
195
|
+
e.preventDefault();
|
|
196
|
+
focusAt(list, list.length - 1);
|
|
197
|
+
return;
|
|
198
|
+
case "Escape":
|
|
199
|
+
e.stopPropagation();
|
|
200
|
+
e.preventDefault();
|
|
201
|
+
close(true);
|
|
202
|
+
return;
|
|
203
|
+
case "Tab":
|
|
204
|
+
close();
|
|
205
|
+
return;
|
|
206
|
+
default:
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
if (e.key.length !== 1 || e.altKey || e.ctrlKey || e.metaKey) return;
|
|
210
|
+
const key = e.key.toLowerCase();
|
|
211
|
+
if (key === " " && !buffer.current) return;
|
|
212
|
+
e.preventDefault();
|
|
213
|
+
buffer.current += key;
|
|
214
|
+
if (timer.current) clearTimeout(timer.current);
|
|
215
|
+
timer.current = setTimeout(() => {
|
|
216
|
+
buffer.current = "";
|
|
217
|
+
}, TYPEAHEAD_RESET_MS);
|
|
218
|
+
const actions = entries.filter((i) => !i.separator);
|
|
219
|
+
const from = at < 0 ? 0 : at + (buffer.current.length > 1 ? 0 : 1);
|
|
220
|
+
for (let n = 0; n < actions.length; n += 1) {
|
|
221
|
+
const i = (from + n) % actions.length;
|
|
222
|
+
if (itemText(actions[i]).startsWith(buffer.current)) {
|
|
223
|
+
focusAt(list, i);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function ContextMenu({
|
|
230
|
+
items,
|
|
231
|
+
label,
|
|
232
|
+
triggerLabel,
|
|
233
|
+
icon = "more",
|
|
234
|
+
size = "small",
|
|
235
|
+
align = "right",
|
|
236
|
+
onSelect,
|
|
237
|
+
onOpenChange,
|
|
238
|
+
triggerClassName,
|
|
239
|
+
className,
|
|
240
|
+
ref,
|
|
241
|
+
...rest
|
|
242
|
+
}) {
|
|
243
|
+
const ctl = useMenuController();
|
|
244
|
+
const triggerRef = useRef(null);
|
|
245
|
+
const baseId = useId();
|
|
246
|
+
const menuId = `${baseId}-menu`;
|
|
247
|
+
const triggerId = `${baseId}-trigger`;
|
|
248
|
+
const onKeyDownMenu = useMenuKeyDown({ items: ctl.items, close: ctl.close }, items);
|
|
249
|
+
useOpenChange(ctl.open, onOpenChange);
|
|
250
|
+
const toggle = () => {
|
|
251
|
+
if (ctl.open) ctl.close(true);
|
|
252
|
+
else ctl.openMenu("first", triggerRef.current);
|
|
253
|
+
};
|
|
254
|
+
const onTriggerKeyDown = (e) => {
|
|
255
|
+
if (e.key !== "ArrowDown" && e.key !== "ArrowUp") return;
|
|
256
|
+
e.preventDefault();
|
|
257
|
+
ctl.openMenu(e.key === "ArrowDown" ? "first" : "last", triggerRef.current);
|
|
258
|
+
};
|
|
259
|
+
const triggerProps = {
|
|
260
|
+
id: triggerId,
|
|
261
|
+
ref: triggerRef,
|
|
262
|
+
size,
|
|
263
|
+
variant: "text",
|
|
264
|
+
// drop-btn ์ ํท CSS ์ ์๋ ์์ก์ด ํด๋์ค์ง๋ง ์ํ์ ์์ผ๋ฏ๋ก ๋จ๊ธด๋ค.
|
|
265
|
+
className: cx("drop-btn", triggerClassName),
|
|
266
|
+
"aria-haspopup": "true",
|
|
267
|
+
"aria-expanded": ctl.open,
|
|
268
|
+
"aria-controls": menuId,
|
|
269
|
+
onClick: toggle,
|
|
270
|
+
onKeyDown: onTriggerKeyDown
|
|
271
|
+
};
|
|
272
|
+
return /* @__PURE__ */ jsxs(
|
|
273
|
+
"div",
|
|
274
|
+
{
|
|
275
|
+
...rest,
|
|
276
|
+
ref: mergeRef(ctl.wrapRef, ref),
|
|
277
|
+
className: cx("krds-drop-wrap", alignClass(align), className),
|
|
278
|
+
onKeyDown: (e) => {
|
|
279
|
+
if (e.key === "Escape" && ctl.open) {
|
|
280
|
+
e.stopPropagation();
|
|
281
|
+
ctl.close(true);
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
children: [
|
|
285
|
+
triggerLabel === void 0 ? /* @__PURE__ */ jsx(Button, { iconOnly: true, icon, label, ...triggerProps }) : /* @__PURE__ */ jsx(Button, { icon: "toggle", ...triggerProps, children: triggerLabel }),
|
|
286
|
+
/* @__PURE__ */ jsx("div", { className: "drop-menu", style: ctl.open ? { display: "block" } : void 0, children: /* @__PURE__ */ jsx("div", { className: "drop-in", children: /* @__PURE__ */ jsx(
|
|
287
|
+
MenuList,
|
|
288
|
+
{
|
|
289
|
+
id: menuId,
|
|
290
|
+
items,
|
|
291
|
+
labelledBy: triggerId,
|
|
292
|
+
menuRef: ctl.menuRef,
|
|
293
|
+
onKeyDown: onKeyDownMenu,
|
|
294
|
+
onActivate: (item) => {
|
|
295
|
+
ctl.close(true);
|
|
296
|
+
item.onSelect?.(item.id);
|
|
297
|
+
onSelect?.(item.id);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
) }) })
|
|
301
|
+
]
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
function ContextMenuArea({
|
|
306
|
+
items,
|
|
307
|
+
label,
|
|
308
|
+
onSelect,
|
|
309
|
+
onOpenChange,
|
|
310
|
+
disabled,
|
|
311
|
+
className,
|
|
312
|
+
children,
|
|
313
|
+
ref,
|
|
314
|
+
...rest
|
|
315
|
+
}) {
|
|
316
|
+
const ctl = useMenuController();
|
|
317
|
+
const menuId = useId();
|
|
318
|
+
const [pos, setPos] = useState({ x: 0, y: 0 });
|
|
319
|
+
const [side, setSide] = useState("left");
|
|
320
|
+
const anchorRef = useRef(null);
|
|
321
|
+
const onKeyDownMenu = useMenuKeyDown({ items: ctl.items, close: ctl.close }, items);
|
|
322
|
+
useOpenChange(ctl.open, onOpenChange);
|
|
323
|
+
useEffect(() => {
|
|
324
|
+
if (!ctl.open) return;
|
|
325
|
+
const anchor = anchorRef.current;
|
|
326
|
+
const box = anchor?.firstElementChild?.getBoundingClientRect();
|
|
327
|
+
if (!anchor || !box) return;
|
|
328
|
+
const over = box.bottom - (window.innerHeight - VIEWPORT_GUTTER_PX);
|
|
329
|
+
if (over > 0) anchor.style.top = `${pos.y - over}px`;
|
|
330
|
+
}, [ctl.open, pos.x, pos.y]);
|
|
331
|
+
const openAt = (clientX, clientY) => {
|
|
332
|
+
const rect = ctl.wrapRef.current?.getBoundingClientRect();
|
|
333
|
+
if (!rect) return;
|
|
334
|
+
setPos({ x: clientX - rect.left, y: clientY - rect.top });
|
|
335
|
+
setSide(clientX > window.innerWidth / 2 ? "right" : "left");
|
|
336
|
+
ctl.openMenu("first");
|
|
337
|
+
};
|
|
338
|
+
const onContextMenu = (e) => {
|
|
339
|
+
if (disabled) return;
|
|
340
|
+
e.preventDefault();
|
|
341
|
+
openAt(e.clientX, e.clientY);
|
|
342
|
+
};
|
|
343
|
+
const onKeyDown = (e) => {
|
|
344
|
+
if (ctl.open) {
|
|
345
|
+
if (e.key === "Escape") {
|
|
346
|
+
e.stopPropagation();
|
|
347
|
+
ctl.close(true);
|
|
348
|
+
}
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
if (disabled) return;
|
|
352
|
+
if (e.key !== "ContextMenu" && !(e.key === "F10" && e.shiftKey)) return;
|
|
353
|
+
e.preventDefault();
|
|
354
|
+
const box = e.target.getBoundingClientRect?.();
|
|
355
|
+
if (box) openAt(box.left, box.bottom);
|
|
356
|
+
};
|
|
357
|
+
return /* @__PURE__ */ jsxs(
|
|
358
|
+
"div",
|
|
359
|
+
{
|
|
360
|
+
...rest,
|
|
361
|
+
ref: mergeRef(ctl.wrapRef, ref),
|
|
362
|
+
className: cx("krds-drop-wrap block", ctl.open && `drop-${side}`, className),
|
|
363
|
+
onContextMenu,
|
|
364
|
+
onKeyDown,
|
|
365
|
+
children: [
|
|
366
|
+
children,
|
|
367
|
+
ctl.open && // 0 ํฌ๊ธฐ ์ต์ปค. ๋ฉ๋ด์ ๊ธฐ์ค์ ์ผ ๋ฟ์ด๋ผ ํ๋ฉด์๋ ์คํฌ๋ฆฐ๋ฆฌ๋์๋ ์กํ์ง ์๋๋ค.
|
|
368
|
+
/* @__PURE__ */ jsx(
|
|
369
|
+
"div",
|
|
370
|
+
{
|
|
371
|
+
ref: anchorRef,
|
|
372
|
+
className: "absolute",
|
|
373
|
+
style: { left: pos.x, top: pos.y, width: 0, height: 0 },
|
|
374
|
+
children: /* @__PURE__ */ jsx("div", { className: "drop-menu", style: { display: "block" }, children: /* @__PURE__ */ jsx("div", { className: "drop-in", children: /* @__PURE__ */ jsx(
|
|
375
|
+
MenuList,
|
|
376
|
+
{
|
|
377
|
+
id: menuId,
|
|
378
|
+
items,
|
|
379
|
+
label,
|
|
380
|
+
menuRef: ctl.menuRef,
|
|
381
|
+
onKeyDown: onKeyDownMenu,
|
|
382
|
+
onActivate: (item) => {
|
|
383
|
+
ctl.close(true);
|
|
384
|
+
item.onSelect?.(item.id);
|
|
385
|
+
onSelect?.(item.id);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
) }) })
|
|
389
|
+
}
|
|
390
|
+
)
|
|
391
|
+
]
|
|
392
|
+
}
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
export {
|
|
396
|
+
ContextMenu,
|
|
397
|
+
ContextMenuArea
|
|
398
|
+
};
|
|
399
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/context-menu/index.tsx"],"sourcesContent":["'use client';\n\nimport {\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n type ComponentPropsWithRef,\n type KeyboardEvent as ReactKeyboardEvent,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n type Ref,\n} from 'react';\nimport { Button } from '../button';\nimport { cx, type KrdsIcon, type KrdsSize } from '../lib/krds';\n\n/**\n * ์ํฉ ๋ฉ๋ด(๋๋ณด๊ธฐ ยท ์ฐํด๋ฆญ) โ KRDS ์ ์๋ ๋ณด์ถฉ ๋ถํ์ด๋ค.\n *\n * ๋ชจ์์ ํท ๋๋กญ๋ค์ด(`krds-drop-wrap`), ๋์์ WAI-ARIA APG ์ Menu Button ํจํด์ด๋ค.\n * ํ ํ ์นธ์ ๋์ด์ ํ ๋์์ ํ๋๋ก ์ ์ ๋ ์ด๋ค โ ใ์ญ์ ใ๋ `danger` ๋ก ํ์ํ๊ณ \n * ๊ตฌ๋ถ์ (`{ separator: true }`)์ผ๋ก ๋๋จธ์ง์ ๋ผ์ด ๋๋๋ค.\n * **๋์ ๋ชฉ๋ก์๋ง ์ด๋ค.** ๋ฉ๋ด๋ Tab ์ ๊ฐ๋ก๋ง์ผ๋ฏ๋ก ์ธ์ด ์ ํยทํ๋ฉด ํฌ๊ธฐ์ฒ๋ผ Tab ์ผ๋ก ๋ฟ์์ผ\n * ํ๋ ๋ชฉ๋ก์๋ `ui/resize` ์ ๋๋กญ๋ค์ด์ ์ด๋ค. ํ์ ๋ฉ๋ด(2๋จ)๋ ์ง์ํ์ง ์๋๋ค.\n *\n * @example\n * <ContextMenu\n * label={`${row.name} ํ ๋๋ณด๊ธฐ`}\n * items={[\n * { id: 'edit', label: '์์ ', icon: 'setting', onSelect: () => edit(row) },\n * { separator: true },\n * { id: 'delete', label: '์ญ์ ', icon: 'delete', danger: true, onSelect: () => remove(row) },\n * ]}\n * />\n *\n * ์์ธํ: docs/krds/09-๋ถํ-๋
ธํธ.md#์ปจํ
์คํธ๋ฉ๋ด\n */\n\n/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * 1. ํญ๋ชฉ\n * โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\n/** ์คํ ํญ๋ชฉ. `href` ๊ฐ ์์ผ๋ฉด ๋งํฌ(`<a>`), ์์ผ๋ฉด ๋จ์ถ(`<button>`)๋ก ๊ทธ๋ฆฐ๋ค. */\nexport type ContextMenuAction = {\n id: string;\n label: ReactNode;\n /** ๊ธ์ ํ์์ ์ธ ๋ฌธ์์ด. `label` ์ด ๋ฌธ์์ด์ด๋ฉด ํ์ ์๋ค. */\n text?: string;\n /** ํท ์์ด์ฝ ์ด๋ฆ(`ico-` ๋บ ๊ฒ). ์: `delete` ยท `setting` ยท `download` */\n icon?: KrdsIcon;\n /** ์ด๋์ด๋ฉด ๋งํฌ๋ก ๊ทธ๋ฆฐ๋ค. ๋์์๋ ์ฃผ์ง ์๋๋ค. */\n href?: string;\n target?: string;\n /** ์ด์ ์ ๋ฐ๋ ์คํ๋์ง ์๋๋ค(`aria-disabled`). */\n disabled?: boolean;\n /** ๋๋๋ฆด ์ ์๋ ๋์(์ญ์ ๋ฑ). ๊ธ์๋ฅผ ์ํ์์ผ๋ก ๋ฌผ๋ค์ธ๋ค. */\n danger?: boolean;\n /** ํ์ฌ ์ํ ํ์(ํท `.active`). ์ ๋ ฌ ๊ธฐ์ค์ฒ๋ผ ใ์ง๊ธ ์ด๊ฒใ์ ๋ณด์ผ ๋. */\n active?: boolean;\n onSelect?: (id: string) => void;\n separator?: never;\n};\n\n/** ๊ตฌ๋ถ์ . ใ์ญ์ ใ์ฒ๋ผ ๋๋๋ฆด ์ ์๋ ํญ๋ชฉ์ ๋๋จธ์ง์ ๋ผ์ด ๋๋๋ค. */\nexport type ContextMenuSeparatorItem = {\n separator: true;\n /** ๋ชฉ๋ก key ์ฉ. ์์ผ๋ฉด ์๋ฒ์ผ๋ก ๋ง๋ ๋ค. */\n id?: string;\n};\n\nexport type ContextMenuItem = ContextMenuAction | ContextMenuSeparatorItem;\n\n/** ํท์ ๋๋กญ๋ค์ด ์ ๋ ฌ ํด๋์ค(`.drop-left` ยท `.drop-right`). ์๋ตํ๋ฉด ๊ฐ์ด๋ฐ(ํท ๊ธฐ๋ณธ). */\nexport type ContextMenuAlign = 'left' | 'center' | 'right';\n\n/** ์ ๋ ฌ โ ํท ํด๋์ค. `center` ๋ ํท ๊ธฐ๋ณธ๊ฐ์ด๋ผ ํด๋์ค๊ฐ ์๋ค. */\nfunction alignClass(align: ContextMenuAlign | undefined): string | undefined {\n return align === 'left' || align === 'right' ? `drop-${align}` : undefined;\n}\n\n/** ๊ธ์ ํ์์ ์ธ ๋ฌธ์์ด์ ๋ฝ๋๋ค. */\nfunction itemText(item: ContextMenuAction): string {\n return (item.text ?? (typeof item.label === 'string' ? item.label : '')).trim().toLowerCase();\n}\n\n/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * 2. ์ฌ๋ซ๊ธฐยท์ด์ โ ๋ ๋ถํ์ด ํจ๊ป ์ด๋ค\n * โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\n/** ์ด ๋ ์ด๋ ํญ๋ชฉ์ ์ด์ ์ ๋์ง. โ ๋ก ์ด๋ฉด ๋ง์ง๋ง ํญ๋ชฉ์ด๋ค(APG). */\ntype InitialFocus = 'first' | 'last';\n\n/** ๊ธ์ ํ์ ๋ฒํผ๊ฐ ์ด์ ์๋ ์๊ฐ(ms). APG ์์ ๊ฐ ์ฐ๋ ๊ฐ์ด๋ค. */\nconst TYPEAHEAD_RESET_MS = 500;\n\n/** ์ปค์ ๋ฉ๋ด๊ฐ ํ๋ฉด ์๋๋ก ๋์น ๋ ๋จ๊ธธ ์ฌ์ (px). KRDS ๋๊ธ์ ์์ด ๊ทธ๋ฆผ์๊ฐ ์๋ฆฌ์ง ์์ ๊ฐ์ผ๋ก ์ ํ๋ค. */\nconst VIEWPORT_GUTTER_PX = 8;\n\nfunction useMenuController() {\n const [open, setOpen] = useState(false);\n const wrapRef = useRef<HTMLDivElement>(null);\n const menuRef = useRef<HTMLUListElement>(null);\n /** ๋ซ์ ๋ ์ด์ ์ ๋๋ ค์ค ๊ณณ. ์ด๊ธฐ ์ง์ ์ ์ฑ์ด๋ค. */\n const returnFocusRef = useRef<HTMLElement | null>(null);\n /** ์ด๋ฆฐ ์งํ ์ด์ ์ ๋ ์๋ฆฌ. */\n const initialFocusRef = useRef<InitialFocus>('first');\n\n /** ์ง๊ธ ๋ฉ๋ด ์์ ์๋ ํญ๋ชฉ๋ค. ๊ตฌ๋ถ์ ์ ๊ฑธ๋ฆฌ์ง ์๋๋ค. */\n const items = useCallback(\n () => Array.from(menuRef.current?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]') ?? []),\n [],\n );\n\n /** ์ฐ๋ค. `returnTo` ๋ฅผ ์ฃผ์ง ์์ผ๋ฉด ์ด๊ธฐ ์ง์ ์ด์ ์ด ์๋ ๊ณณ์ผ๋ก ๋์๊ฐ๋ค. */\n const openMenu = useCallback((initial: InitialFocus = 'first', returnTo?: HTMLElement | null) => {\n initialFocusRef.current = initial;\n returnFocusRef.current = returnTo ?? (document.activeElement as HTMLElement | null) ?? null;\n setOpen(true);\n }, []);\n\n const close = useCallback((refocus = false) => {\n setOpen(false);\n if (refocus) returnFocusRef.current?.focus();\n }, []);\n\n // ์ด๋ฆฐ ์งํ ์ฒซ(๋๋ ๋ง์ง๋ง) ํญ๋ชฉ์ผ๋ก ์ด์ ์ ์ฎ๊ธด๋ค โ APG ์ Menu Button ๊ท์ ์ด๋ค.\n useEffect(() => {\n if (!open) return;\n const list = items();\n if (!list.length) return;\n (initialFocusRef.current === 'last' ? list[list.length - 1] : list[0]).focus();\n }, [open, items]);\n\n // ๋ฐ๊นฅ์ ๋๋ฅด๋ฉด ๋ซ๋๋ค. ์ด์ ์ ๋๋ ค์ฃผ์ง ์๋๋ค(๋๋ฅธ ๊ณณ์ผ๋ก ๊ฐ๋ ๊ฒ ์์ฐ์ค๋ฝ๋ค).\n useEffect(() => {\n if (!open) return;\n const onPointerDown = (e: PointerEvent) => {\n if (!wrapRef.current?.contains(e.target as Node)) setOpen(false);\n };\n document.addEventListener('pointerdown', onPointerDown);\n return () => document.removeEventListener('pointerdown', onPointerDown);\n }, [open]);\n\n return { open, openMenu, close, wrapRef, menuRef, items };\n}\n\n/** ๋ฐ์์ ์จ ref ์ ๋ถํ ๋ด๋ถ ref ๋ฅผ ํจ๊ป ์ฑ์ด๋ค. ๊ฐ์ธ๊ฐ ref ๋ฅผ ์ผํค์ง ์์ผ๋ ค๊ณ ๋๋ค. */\nfunction mergeRef<T>(inner: { current: T | null }, outer: Ref<T> | undefined) {\n return (node: T | null) => {\n inner.current = node;\n if (typeof outer === 'function') outer(node);\n else if (outer) outer.current = node;\n };\n}\n\n/** ์ด๋ฆผ์ด ๋ฐ๋ ๋๋ง ์๋ฆฐ๋ค. ์ธ๋ผ์ธ ์ฝ๋ฐฑ์ด ๋งค ๋ ๋ ์ ํจ์๋ผ ref ์ ๋ด์ ์์กด์ฑ์์ ๋บ๋ค. */\nfunction useOpenChange(open: boolean, onOpenChange?: (open: boolean) => void) {\n const latest = useRef(onOpenChange);\n const mounted = useRef(false);\n useEffect(() => {\n latest.current = onOpenChange;\n });\n useEffect(() => {\n // ๋ถ์๋ง์ `false` ๋ฅผ ์๋ฆฌ์ง ์๋๋ค โ ๋ฐ๋ ๊ฒ์ด ์๋ค.\n if (!mounted.current) {\n mounted.current = true;\n return;\n }\n latest.current?.(open);\n }, [open]);\n}\n\n/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * 3. ๋ชฉ๋ก ๊ทธ๋ฆฌ๊ธฐ\n * โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\ntype MenuListProps = {\n id: string;\n items: ReadonlyArray<ContextMenuItem>;\n /** ๋ฉ๋ด ์ด๋ฆ. ์ฌ๋ ๋จ์ถ๊ฐ ์์ผ๋ฉด ๊ทธ id ๋ฅผ `labelledBy` ๋ก ์ค๋ค. */\n label?: string;\n labelledBy?: string;\n menuRef: Ref<HTMLUListElement>;\n onKeyDown: (e: ReactKeyboardEvent<HTMLUListElement>) => void;\n onActivate: (item: ContextMenuAction) => void;\n};\n\nfunction MenuList({ id, items, label, labelledBy, menuRef, onKeyDown, onActivate }: MenuListProps) {\n return (\n <ul\n ref={menuRef}\n id={id}\n // โ
role=\"menu\" ๋ ์ด <ul> ์ ์ค๋ค. ๋ฐ๊นฅ .drop-menu ์ ์ฃผ๋ฉด ul/li ๊ฐ ํ์ฉ๋์ง ์๋ ์์์ด ๋๋ค.\n role=\"menu\"\n aria-label={labelledBy ? undefined : label}\n aria-labelledby={labelledBy}\n className=\"drop-list\"\n onKeyDown={onKeyDown}\n >\n {items.map((item, index) => {\n if (item.separator) {\n // ํท์ ๊ตฌ๋ถ์ ํด๋์ค๊ฐ ์๋ค โ ์ ํธ๋ฆฌํฐ๋ก ๊ทธ๋ฆฐ๋ค. ํท ๋ชฉ๋ก ๊ฐ๊ฒฉ(--krds-gap-3=8px)์ ๋ง์ถฐ my-1(4px)์ฉ.\n return (\n <li\n key={item.id ?? `separator-${index}`}\n role=\"separator\"\n className=\"my-1 h-px bg-divider\"\n />\n );\n }\n\n const { id: itemId, label: itemLabel, icon, href, target, disabled, danger, active } = item;\n const cls = cx(\n 'item-link',\n active && 'active',\n // ํท์ ์ํยท๋นํ์ฑ ํญ๋ชฉ ๋ชจ์์ด ์๋ค โ ์ ํธ๋ฆฌํฐ๋ก ๋ณด์ถฉํ๋ค.\n danger && !disabled && 'text-danger',\n disabled && 'text-fg-disabled cursor-not-allowed hover:bg-transparent',\n );\n const iconNode = icon ? (\n <i\n // .svg-icon ์ background-color ๋ฅผ mask ์์ผ๋ก ์ด๋ค โ ๊ธ์์๊ณผ ๋ง์ถ๋ ค๋ฉด bg-* ๋ฅผ ์น๋๋ค.\n className={cx(\n 'svg-icon',\n `ico-${icon}`,\n danger && !disabled && 'bg-danger',\n disabled && 'bg-fg-disabled',\n )}\n aria-hidden=\"true\"\n />\n ) : null;\n\n const shared = {\n role: 'menuitem' as const,\n // ๋ฉ๋ด ์์์๋ โโ ๋ก๋ง ์ค๊ฐ๋ค(roving tabindex). ์ด์ ์ ๋ถํ์ด ์ฎ๊ธด๋ค.\n tabIndex: -1,\n className: cls,\n // ๋นํ์ฑ์ disabled ์์ฑ์ด ์๋๋ผ aria-disabled ๋ค โ ์ด์ ์ ๋ฐ์์ผ ํ๋ค(APG).\n 'aria-disabled': disabled || undefined,\n 'aria-current': active ? ('true' as const) : undefined,\n };\n\n return (\n <li key={itemId} role=\"none\">\n {href !== undefined ? (\n <a\n {...shared}\n // ๋นํ์ฑ ๋งํฌ๋ href ๋ฅผ ๋ผ์ด ์ด๋์ ๋ง๋๋ค. tabIndex=-1 ์ด๋ผ ์ด์ ์ ๊ทธ๋๋ก ๋ฐ๋๋ค.\n href={disabled ? undefined : href}\n target={target}\n // ์ ์ฐฝ์ผ๋ก ์ด๋ฆฌ๋ฉด ๋ฏธ๋ฆฌ ์๋ฆฐ๋ค โ KRDS ์ ๊ทผ์ฑ ์๊ตฌ.\n title={target === '_blank' ? '์ ์ฐฝ ์ด๋ฆผ' : undefined}\n onClick={(e) => {\n if (disabled) {\n e.preventDefault();\n return;\n }\n onActivate(item);\n }}\n >\n {iconNode}\n {itemLabel}\n </a>\n ) : (\n <button\n {...shared}\n type=\"button\"\n onClick={() => {\n if (disabled) return;\n onActivate(item);\n }}\n >\n {iconNode}\n {itemLabel}\n </button>\n )}\n </li>\n );\n })}\n </ul>\n );\n}\n\n/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * 4. ํค๋ณด๋ โ APG Menu Button\n * โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\ntype Nav = {\n items: () => HTMLElement[];\n close: (refocus?: boolean) => void;\n};\n\n/**\n * ๋ฉ๋ด ์ ํค ์ฒ๋ฆฌ(APG) โ โโ ๋ ๋์์ ๋๊ณ , Home/End ๋ ์ ๋, Esc ๋ ๋ซ๊ณ ์ด์ ๋ณต๊ท,\n * Tab ์ ๋ซ๊ณ ํ๋ ค๋ณด๋ด๋ฉฐ, ๊ธ์๋ฅผ ์น๋ฉด ๊ทธ ๊ธ์๋ก ์์ํ๋ ๋ค์ ํญ๋ชฉ์ผ๋ก ๊ฐ๋ค.\n */\nfunction useMenuKeyDown({ items, close }: Nav, entries: ReadonlyArray<ContextMenuItem>) {\n const buffer = useRef('');\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // ๋ธ๋ฆฐ ํ์ด๋จธ๋ ๋ถํ์ด ์ฌ๋ผ์ง ๋ ๋ฐ๋์ ๋๋ค.\n useEffect(\n () => () => {\n if (timer.current) clearTimeout(timer.current);\n },\n [],\n );\n\n const focusAt = (list: HTMLElement[], index: number) => {\n if (!list.length) return;\n list[(index + list.length) % list.length].focus();\n };\n\n return (e: ReactKeyboardEvent<HTMLUListElement>) => {\n const list = items();\n const at = list.indexOf(document.activeElement as HTMLElement);\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n focusAt(list, at + 1);\n return;\n case 'ArrowUp':\n e.preventDefault();\n focusAt(list, at - 1);\n return;\n case 'Home':\n e.preventDefault();\n focusAt(list, 0);\n return;\n case 'End':\n e.preventDefault();\n focusAt(list, list.length - 1);\n return;\n case 'Escape':\n // ๋ฐ๊นฅ(๋ชจ๋ฌ ๋ฑ)์ด ๊ฐ์ Esc ๋ฅผ ๋ฐ์ง ์๋๋ก ์ฌ๊ธฐ์ ๋ฉ์ถ๋ค.\n e.stopPropagation();\n e.preventDefault();\n close(true);\n return;\n case 'Tab':\n // APG: Tab ์ ๋ฉ๋ด๋ฅผ ๋ซ๊ณ ์ด์ ์ ๋ค์ ์์๋ก ๋๊ธด๋ค. preventDefault ํ์ง ์๋๋ค.\n close();\n return;\n default:\n break;\n }\n\n // ๊ธ์ ํ์. ์กฐํฉํค๊ฐ ๊ฑธ๋ฆฐ ์
๋ ฅ์ ๋จ์ถํค์ด๋ฏ๋ก ๊ฑด๋๋ฆฌ์ง ์๋๋ค.\n if (e.key.length !== 1 || e.altKey || e.ctrlKey || e.metaKey) return;\n const key = e.key.toLowerCase();\n if (key === ' ' && !buffer.current) return; // Space ๋ ์คํ(๊ธฐ๋ณธ ๋์)์ด๋ค\n\n e.preventDefault();\n buffer.current += key;\n if (timer.current) clearTimeout(timer.current);\n timer.current = setTimeout(() => {\n buffer.current = '';\n }, TYPEAHEAD_RESET_MS);\n\n // ๊ตฌ๋ถ์ ์ ๋บ ์ค์ ํญ๋ชฉ ์์๋ก ๊ฒฌ์ค๋ค โ DOM ์์(list)์ ์ง์ด ๋ง๋๋ค.\n const actions = entries.filter((i): i is ContextMenuAction => !i.separator);\n const from = at < 0 ? 0 : at + (buffer.current.length > 1 ? 0 : 1);\n for (let n = 0; n < actions.length; n += 1) {\n const i = (from + n) % actions.length;\n if (itemText(actions[i]).startsWith(buffer.current)) {\n focusAt(list, i);\n return;\n }\n }\n };\n}\n\n/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * 5. ๋๋ณด๊ธฐ ๋จ์ถ โ ContextMenu\n * โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\nexport type ContextMenuProps = Omit<ComponentPropsWithRef<'div'>, 'onSelect'> & {\n items: ReadonlyArray<ContextMenuItem>;\n /** ๋จ์ถ์ ์ด๋ฆ(`sr-only`). ํ ์์์๋ ์ด๋ ํ์ธ์ง๊น์ง ๋ด๋๋ค โ ใํ๊ธธ๋ ํ ๋๋ณด๊ธฐใ. */\n label: string;\n /** ๊ธ์๊ฐ ์๋ ๋จ์ถ๋ก ๊ทธ๋ฆฐ๋ค. ์ฃผ๋ฉด ์์ด์ฝ ๋์ ใ๊ธ์ + ico-toggleใ์ด ๋๋ค. */\n triggerLabel?: ReactNode;\n /** ์์ด์ฝ๋ง์ธ ๋จ์ถ์ ์์ด์ฝ. ๊ธฐ๋ณธ `more`(ํท `ico_more.svg`). */\n icon?: KrdsIcon;\n /** ๋จ์ถ ํฌ๊ธฐ. ๊ธฐ๋ณธ small(40px) โ ํ ์ ํ ๋์ ์๋ฆฌ์ ๋ง์ถ ๊ฐ์ด๋ค. */\n size?: KrdsSize;\n /** ๋ฉ๋ด๊ฐ ํผ์ณ์ง๋ ์ชฝ. ๊ธฐ๋ณธ `right`(์ค๋ฅธ์ชฝ ๋ ์ด์ ๋์ด๋ ์๋ฆฌ๋ผ ์ผ์ชฝ์ผ๋ก ํธ๋ค). */\n align?: ContextMenuAlign;\n /** ํญ๋ชฉ๋ณ `onSelect` ์ ๋ณ๊ฐ๋ก, ๋ฌด์์ ๊ณจ๋๋ ํ ๋ฒ ๋ถ๋ฅธ๋ค. */\n onSelect?: (id: string) => void;\n onOpenChange?: (open: boolean) => void;\n /** ์ฌ๋ ๋จ์ถ์ ๋ถ์ผ ํด๋์ค. */\n triggerClassName?: string;\n};\n\n/** ๋๋ณด๊ธฐ ๋ฉ๋ด โ ํ ํ ๋์ยท์นด๋ ์ฐ์๋จ์ฒ๋ผ ใ์ด ๋์์ ๋ํ ๋์ ๋ฌถ์ใ์ ์ ๋๋ค. */\nexport function ContextMenu({\n items,\n label,\n triggerLabel,\n icon = 'more',\n size = 'small',\n align = 'right',\n onSelect,\n onOpenChange,\n triggerClassName,\n className,\n ref,\n ...rest\n}: ContextMenuProps) {\n const ctl = useMenuController();\n const triggerRef = useRef<HTMLButtonElement>(null);\n const baseId = useId();\n const menuId = `${baseId}-menu`;\n const triggerId = `${baseId}-trigger`;\n\n const onKeyDownMenu = useMenuKeyDown({ items: ctl.items, close: ctl.close }, items);\n useOpenChange(ctl.open, onOpenChange);\n\n const toggle = () => {\n // ๋ง์ฐ์ค๋ก ๋๋ ์ ๋ Safari ๋ ๋จ์ถ์ ์ด์ ์ ์ฃผ์ง ์๋๋ค โ ๋๋ ค์ค ์๋ฆฌ๋ฅผ ์ง์ ์ง์ ํ๋ค.\n if (ctl.open) ctl.close(true);\n else ctl.openMenu('first', triggerRef.current);\n };\n\n const onTriggerKeyDown = (e: ReactKeyboardEvent<HTMLButtonElement>) => {\n if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') return;\n e.preventDefault();\n // APG: โ ๋ก ์ด๋ฉด ์ฒซ ํญ๋ชฉ, โ ๋ก ์ด๋ฉด ๋ง์ง๋ง ํญ๋ชฉ์ ์ด์ .\n ctl.openMenu(e.key === 'ArrowDown' ? 'first' : 'last', triggerRef.current);\n };\n\n const triggerProps = {\n id: triggerId,\n ref: triggerRef,\n size,\n variant: 'text' as const,\n // drop-btn ์ ํท CSS ์ ์๋ ์์ก์ด ํด๋์ค์ง๋ง ์ํ์ ์์ผ๋ฏ๋ก ๋จ๊ธด๋ค.\n className: cx('drop-btn', triggerClassName),\n 'aria-haspopup': 'true' as const,\n 'aria-expanded': ctl.open,\n 'aria-controls': menuId,\n onClick: toggle,\n onKeyDown: onTriggerKeyDown,\n };\n\n return (\n <div\n {...rest}\n ref={mergeRef(ctl.wrapRef, ref)}\n className={cx('krds-drop-wrap', alignClass(align), className)}\n // ์ด์ ์ด ์ฌ๋ ๋จ์ถ์ ์์ ๋์ Esc. ๋ชฉ๋ก ์์์๋ <ul> ์ด ๋จผ์ ๋ฐ์ ์ฌ๊ธฐ๊น์ง ์ค์ง ์๋๋ค.\n onKeyDown={(e) => {\n if (e.key === 'Escape' && ctl.open) {\n e.stopPropagation();\n ctl.close(true);\n }\n }}\n >\n {triggerLabel === undefined ? (\n <Button iconOnly icon={icon} label={label} {...triggerProps} />\n ) : (\n <Button icon=\"toggle\" {...triggerProps}>\n {triggerLabel}\n </Button>\n )}\n\n {/*\n ํท์ `.drop-menu{display:none}` ๋ง ๋๊ณ ์ฌ๋ ํด๋์ค๋ฅผ ์ฃผ์ง ์๋๋ค โ ์ธ๋ผ์ธ์ผ๋ก ์ฐ๋ค.\n ์ ํ ๋์ display:none ์ด๋ผ ์คํฌ๋ฆฐ๋ฆฌ๋๋ ์ฝ์ง ์๋๋ค(๋ณ๋ hidden ์ฒ๋ฆฌ๊ฐ ํ์ ์๋ค).\n */}\n <div className=\"drop-menu\" style={ctl.open ? { display: 'block' } : undefined}>\n <div className=\"drop-in\">\n <MenuList\n id={menuId}\n items={items}\n labelledBy={triggerId}\n menuRef={ctl.menuRef}\n onKeyDown={onKeyDownMenu}\n onActivate={(item) => {\n ctl.close(true);\n item.onSelect?.(item.id);\n onSelect?.(item.id);\n }}\n />\n </div>\n </div>\n </div>\n );\n}\n\n/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * 6. ์ฐํด๋ฆญ ์์ญ โ ContextMenuArea\n * โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\nexport type ContextMenuAreaProps = Omit<ComponentPropsWithRef<'div'>, 'onSelect'> & {\n items: ReadonlyArray<ContextMenuItem>;\n /** ๋ฉ๋ด ์ด๋ฆ. ์ฌ๋ ๋จ์ถ๊ฐ ์์ผ๋ ์ฌ๊ธฐ์ ์ค๋ค โ ใ๋ชฉ๋ก ํญ๋ชฉ ๋์ใ์ฒ๋ผ. */\n label: string;\n onSelect?: (id: string) => void;\n onOpenChange?: (open: boolean) => void;\n /** ์ฐํด๋ฆญ์ ๊ฐ๋ก์ฑ์ง ์๋๋ค(๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ ๋ฉ๋ด๊ฐ ๋ฌ๋ค). */\n disabled?: boolean;\n};\n\n/**\n * ์ฐํด๋ฆญ ๋ฉ๋ด โ ์์ญ ์์์ ์ค๋ฅธ์ชฝ ๋จ์ถ(๋๋ Shift+F10 ยท ContextMenu ํค)๋ก ์ฐ๋ค.\n *\n * **๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ ๋ฉ๋ด๋ฅผ ๊ฐ๋ฆฐ๋ค.** ใ์ ํญ์์ ์ด๊ธฐใ๋ฅผ ๋นผ์์ผ๋ฏ๋ก ๊ผญ ํ์ํ ๊ณณ์๋ง ์ฐ๊ณ ,\n * ๊ฐ์ ๋์์ ์ฌ๋ ๋์ ๋ณด์ด๋ ๋จ์ถ(`ContextMenu`)๋ฅผ ํจ๊ป ๋๋ค.\n *\n * @example\n * <ContextMenuArea label=\"๋ชฉ๋ก ํญ๋ชฉ ๋์\" items={rowActions}>\n * <ul>โฆ</ul>\n * </ContextMenuArea>\n */\nexport function ContextMenuArea({\n items,\n label,\n onSelect,\n onOpenChange,\n disabled,\n className,\n children,\n ref,\n ...rest\n}: ContextMenuAreaProps) {\n const ctl = useMenuController();\n const menuId = useId();\n /** ๊ฐ์ธ๊ฐ ์ผ์ชฝ ์๋ฅผ ์์ ์ผ๋ก ํ ์ต์ปค ์ขํ(px). */\n const [pos, setPos] = useState({ x: 0, y: 0 });\n const [side, setSide] = useState<'left' | 'right'>('left');\n const anchorRef = useRef<HTMLDivElement>(null);\n\n const onKeyDownMenu = useMenuKeyDown({ items: ctl.items, close: ctl.close }, items);\n useOpenChange(ctl.open, onOpenChange);\n\n // ํ๋ฉด ์๋๋ก ๋์น๋ฉด ๊ทธ๋งํผ ๋์ด์ฌ๋ฆฐ๋ค. ์ํ๊ฐ ์๋๋ผ ์ต์ปค์ style.top ์ ์ง์ ์ด๋ค โ\n // ์ฌ๊ณ ๋์ ์ํ๋ฅผ ๋ฐ๊พธ๋ฉด ํ ํ๋ ์์ด ์๋ชป๋ ์๋ฆฌ์ ๊ทธ๋ ค์ง๋ค. ์๋ก ๋ค์ง์ง๋ ์๋๋ค(๊ผญ์ง๊ฐ ๊ฑฐ๊พธ๋ก ์ ๋ค).\n useEffect(() => {\n if (!ctl.open) return;\n const anchor = anchorRef.current;\n const box = anchor?.firstElementChild?.getBoundingClientRect();\n if (!anchor || !box) return;\n const over = box.bottom - (window.innerHeight - VIEWPORT_GUTTER_PX);\n if (over > 0) anchor.style.top = `${pos.y - over}px`;\n }, [ctl.open, pos.x, pos.y]);\n\n /** ๊ฐ์ธ๊ฐ ๊ธฐ์ค ์ขํ๋ก ์ฎ๊ฒจ ๋ด๊ณ ์ฐ๋ค. */\n const openAt = (clientX: number, clientY: number) => {\n const rect = ctl.wrapRef.current?.getBoundingClientRect();\n if (!rect) return;\n setPos({ x: clientX - rect.left, y: clientY - rect.top });\n // ์ค๋ฅธ์ชฝ ์ ๋ฐ์์ ์ด๋ฉด ๋ฉ๋ด๋ฅผ ์ผ์ชฝ์ผ๋ก ํธ๋ค.\n setSide(clientX > window.innerWidth / 2 ? 'right' : 'left');\n ctl.openMenu('first');\n };\n\n const onContextMenu = (e: ReactMouseEvent<HTMLDivElement>) => {\n if (disabled) return;\n e.preventDefault();\n openAt(e.clientX, e.clientY);\n };\n\n const onKeyDown = (e: ReactKeyboardEvent<HTMLDivElement>) => {\n // ๋ฉ๋ด๊ฐ ์ด๋ ค ์์ผ๋ฉด ๋ชฉ๋ก ์ชฝ ์ฒ๋ฆฌ์ ๋งก๊ธด๋ค.\n if (ctl.open) {\n if (e.key === 'Escape') {\n e.stopPropagation();\n ctl.close(true);\n }\n return;\n }\n if (disabled) return;\n // ํค๋ณด๋๋ก ์ํฉ ๋ฉ๋ด๋ฅผ ์ฌ๋ ํ์ค ๋ ๊ฐ์ง.\n if (e.key !== 'ContextMenu' && !(e.key === 'F10' && e.shiftKey)) return;\n e.preventDefault();\n // ์ด์ ์ด ์๋ ์์์ ์ผ์ชฝ ์๋์ ๋์ด๋ค โ ์ปค์๊ฐ ์์ผ๋ ๊ทธ ์๋ฆฌ๊ฐ ๊ธฐ์ค์ด๋ค.\n const box = (e.target as HTMLElement).getBoundingClientRect?.();\n if (box) openAt(box.left, box.bottom);\n };\n\n return (\n <div\n {...rest}\n ref={mergeRef(ctl.wrapRef, ref)}\n // ํท ๊ฐ์ธ๊ฐ๋ inline-flex ๋ค โ ์์ญ์ ๊ฐ์ธ๋ ์ฐ์์ด๋ผ block ์ผ๋ก ๋๋๋ฆฐ๋ค.\n className={cx('krds-drop-wrap block', ctl.open && `drop-${side}`, className)}\n onContextMenu={onContextMenu}\n onKeyDown={onKeyDown}\n >\n {children}\n\n {ctl.open && (\n // 0 ํฌ๊ธฐ ์ต์ปค. ๋ฉ๋ด์ ๊ธฐ์ค์ ์ผ ๋ฟ์ด๋ผ ํ๋ฉด์๋ ์คํฌ๋ฆฐ๋ฆฌ๋์๋ ์กํ์ง ์๋๋ค.\n <div\n ref={anchorRef}\n className=\"absolute\"\n style={{ left: pos.x, top: pos.y, width: 0, height: 0 }}\n >\n <div className=\"drop-menu\" style={{ display: 'block' }}>\n <div className=\"drop-in\">\n <MenuList\n id={menuId}\n items={items}\n label={label}\n menuRef={ctl.menuRef}\n onKeyDown={onKeyDownMenu}\n onActivate={(item) => {\n ctl.close(true);\n item.onSelect?.(item.id);\n onSelect?.(item.id);\n }}\n />\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* ๊ธด๊ธ ๊ณต์ง โ KRDS `krds-critical-alerts`.
|
|
4
|
+
*
|
|
5
|
+
* **์ฌ๋ยท์ฌํด, ์๊ณ ์๋ ์ฅ์ , ์ ๊ฒ ์ฌ์ ์๊ณ ์๋ง ์ด๋ค.** ๊ท๊ฒฉ์ด ํผ๋๋ฐฑ ๋ฉ์์งยท์ผ๋ฐ ๊ณต์งยทํ๋ณด์
|
|
6
|
+
* ์ฐ๋ ๊ฒ์ ๊ธ์งํ๋ค โ ๋ณธ๋ฌธ ์๋ด๋ `Alert`, ํผ ์ค๋ฅ๋ `Field` ์ `error` ๋ค.
|
|
7
|
+
* ํ ํ๋ฉด์ ํ๋, ๋งํฌ๋ ํ๋, ๋ณธ๋ฌธ์ ํ ์ค์ด๋ค(ํท์ด ๋ ์ค์์ ์๋ผ๋ธ๋ค).
|
|
8
|
+
* ๋ซ๊ธฐ ๋จ์ถ๋ ๊ท๊ฒฉ์ด ๊ธ์งํด prop ์์ฒด๊ฐ ์๋ค. ์๋ฆฌ๋ ์ฃผ๋ฉ๋ด์ ํ์ด๋ก ์ฌ์ด, ๋ณธ๋ฌธ์ ์ฒซ ์์๋ค.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* <CriticalAlert level="danger" href="/notice/1024" linkTitle="์ง์คํธ์ฐ ๋์ ์๋ด">
|
|
12
|
+
* ์ง์คํธ์ฐ๋ก ์ผ๋ถ ๋ฏผ์ ์ฒ๋ฆฌ๊ฐ ์ง์ฐ๋๊ณ ์์ต๋๋ค.
|
|
13
|
+
* </CriticalAlert>
|
|
14
|
+
*
|
|
15
|
+
* ์์ธํ: docs/krds/09-๋ถํ-๋
ธํธ.md#๊ธด๊ธ๊ณต์ง
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* ๊ธด๊ธ๋. `danger` ์ฌ๋ยท๊ธ์์ค๋ฌ์ด ์ฅ์ (ใ๊ธด๊ธใ) ยท `ok` ์๋น์ค ์ค๋จ ์ฌ์ ์๊ณ (ใ์์ ใ) ยท
|
|
19
|
+
* `info` ๋๋ถ๋ถ์ ์ฌ์ฉ์๊ฐ ์์์ผ ํ๋ ์ํฉ(ใ์๋ดใ).
|
|
20
|
+
*/
|
|
21
|
+
export type CriticalAlertLevel = 'danger' | 'ok' | 'info';
|
|
22
|
+
export type CriticalAlertProps = Omit<ComponentPropsWithRef<'div'>, 'children'> & {
|
|
23
|
+
/** ๊ธด๊ธ๋. ๊ธฐ๋ณธ๊ฐ `danger` โ ์ด ๋ถํ์ ์ธ ์ํฉ ์์ฒด๊ฐ ๊ธด๊ธ ์ํฉ์ด๋ค. */
|
|
24
|
+
level?: CriticalAlertLevel;
|
|
25
|
+
/** ๋ฐฐ์ง ๊ธ์. ์๋ตํ๋ฉด ๊ธด๊ธ๋๋ณ ๊ธฐ๋ณธ๊ฐ(๊ธด๊ธ/์์ /์๋ด). ๊ฐ์ถ์ง ๋ง๋ผ โ ์์ด์ฝ๋ง์ผ๋ก๋ ์ ์ฝํ๋ค. */
|
|
26
|
+
label?: string;
|
|
27
|
+
/** ๊ณต์ง ๋ด์ฉ. ํ ์ค๋ก ์ด๋ค โ ํท์ด ๋ ์ค์์ ์๋ผ๋ธ๋ค. */
|
|
28
|
+
children: ReactNode;
|
|
29
|
+
/** ์์ธ ํ๋ฉด ๋งํฌ. ๊ท๊ฒฉ์ ํ๋๋ง ๋ ์ ์๋ค. */
|
|
30
|
+
href?: string;
|
|
31
|
+
/** ๋งํฌ ๊ธ์. ๊ธฐ๋ณธ ใ์์ธํ ๋ณด๊ธฐใ. ์์ ํ๋ฉด(<768px)์์๋ ๊ฐ์ถฐ์ง๊ณ ํ์ดํ๋ง ๋จ๋๋ค. */
|
|
32
|
+
linkLabel?: ReactNode;
|
|
33
|
+
/** ๋งํฌ์ ๋ชฉ์ ์ง ์ค๋ช
(`title`). ใ์์ธํ ๋ณด๊ธฐใ๋ง์ผ๋ก๋ ๋ชฉ์ ์ง๋ฅผ ์ ์ ์์ผ๋ ๋ฌธ์ ์ ๋ชฉ์ ๋ฃ๋๋ค. */
|
|
34
|
+
linkTitle?: string;
|
|
35
|
+
/** ๋งํฌ target. `_blank` ๋ฉด `title` ์ ใ์ ์ฐฝ ์ด๋ฆผใ์ ๋ง๋ถ์ธ๋ค. */
|
|
36
|
+
linkTarget?: ComponentPropsWithRef<'a'>['target'];
|
|
37
|
+
};
|
|
38
|
+
export declare function CriticalAlert({ level, label, children, href, linkLabel, linkTitle, linkTarget, className, role, 'aria-label': ariaLabel, ...rest }: CriticalAlertProps): import("react").JSX.Element;
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/critical-alert/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAG9D;;;;;;;;;;;;;;GAcG;AAEH;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,IAAI,GAAG,MAAM,CAAC;AAS1D,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,GAAG;IAChF,kDAAkD;IAClD,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,QAAQ,EAAE,SAAS,CAAC;IACpB,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,UAAU,CAAC,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;CACnD,CAAC;AAEF,wBAAgB,aAAa,CAAC,EAC5B,KAAgB,EAChB,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,SAAoB,EACpB,SAAS,EACT,UAAU,EACV,SAAS,EAIT,IAAe,EACf,YAAY,EAAE,SAAmB,EACjC,GAAG,IAAI,EACR,EAAE,kBAAkB,+BAqCpB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from "../lib/krds.js";
|
|
3
|
+
const DEFAULT_LABEL = {
|
|
4
|
+
danger: "\uAE34\uAE09",
|
|
5
|
+
ok: "\uC548\uC804",
|
|
6
|
+
info: "\uC548\uB0B4"
|
|
7
|
+
};
|
|
8
|
+
function CriticalAlert({
|
|
9
|
+
level = "danger",
|
|
10
|
+
label,
|
|
11
|
+
children,
|
|
12
|
+
href,
|
|
13
|
+
linkLabel = "\uC790\uC138\uD788 \uBCF4\uAE30",
|
|
14
|
+
linkTitle,
|
|
15
|
+
linkTarget,
|
|
16
|
+
className,
|
|
17
|
+
// ์ ๊ทผ์ฑ ๊ฐ์ด๋: ใ๊ธด๊ธ ๊ณต์ง ์น์
์ role="banner" ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐฐ๋ ์ญํ ์ ๋ถ์ฌใ.
|
|
18
|
+
// ํท ์ํ์๋ ์๊ณ ๊ฐ์ด๋๊ฐ ์๊ตฌํ ๊ฒ์ด๋ค. ํ์ด์ง์ <header> ๊ฐ ์ด๋ฏธ ์์ผ๋ฉด banner
|
|
19
|
+
// ๋๋๋งํฌ๊ฐ ๋์ด ๋๋ฏ๋ก ์ด๋ฆ์ ๋ถ์ฌ ๊ตฌ๋ถํ๋ค(aria-label ์ ์ฐ๋ฆฌ๊ฐ ๋ง๋ ๊ฒ).
|
|
20
|
+
role = "banner",
|
|
21
|
+
"aria-label": ariaLabel = "\uAE34\uAE09 \uACF5\uC9C0",
|
|
22
|
+
...rest
|
|
23
|
+
}) {
|
|
24
|
+
const newWindow = linkTarget === "_blank";
|
|
25
|
+
const title = linkTitle ? newWindow ? `${linkTitle} (\uC0C8 \uCC3D \uC5F4\uB9BC)` : linkTitle : newWindow ? "\uC0C8 \uCC3D \uC5F4\uB9BC" : void 0;
|
|
26
|
+
return (
|
|
27
|
+
// `.main-urgent-wrap` ์ ํท CSS ์ ์๋ค(์ ์ฃผ์ ์ฐธ๊ณ ) โ ์ ํญ๋ง Tailwind ๋ก ์ค๋ค.
|
|
28
|
+
/* @__PURE__ */ jsx("div", { className: cx("w-full", className), role, "aria-label": ariaLabel, ...rest, children: /* @__PURE__ */ jsx("ul", { className: "krds-critical-alerts", children: /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("div", { className: "critical-ban", children: [
|
|
29
|
+
/* @__PURE__ */ jsx("span", { className: cx("critical-badge", level), children: label ?? DEFAULT_LABEL[level] }),
|
|
30
|
+
/* @__PURE__ */ jsx("p", { className: "critical-txt", children }),
|
|
31
|
+
href && /* @__PURE__ */ jsxs(
|
|
32
|
+
"a",
|
|
33
|
+
{
|
|
34
|
+
href,
|
|
35
|
+
className: "krds-btn medium link basic",
|
|
36
|
+
target: linkTarget,
|
|
37
|
+
title,
|
|
38
|
+
children: [
|
|
39
|
+
/* @__PURE__ */ jsx("span", { className: "hidden md:inline", children: linkLabel }),
|
|
40
|
+
/* @__PURE__ */ jsx("i", { className: "svg-icon ico-angle right", "aria-hidden": "true" })
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
] }) }) }) })
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
CriticalAlert
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/critical-alert/index.tsx"],"sourcesContent":["import type { ComponentPropsWithRef, ReactNode } from 'react';\nimport { cx } from '../lib/krds';\n\n/**\n * ๊ธด๊ธ ๊ณต์ง โ KRDS `krds-critical-alerts`.\n *\n * **์ฌ๋ยท์ฌํด, ์๊ณ ์๋ ์ฅ์ , ์ ๊ฒ ์ฌ์ ์๊ณ ์๋ง ์ด๋ค.** ๊ท๊ฒฉ์ด ํผ๋๋ฐฑ ๋ฉ์์งยท์ผ๋ฐ ๊ณต์งยทํ๋ณด์\n * ์ฐ๋ ๊ฒ์ ๊ธ์งํ๋ค โ ๋ณธ๋ฌธ ์๋ด๋ `Alert`, ํผ ์ค๋ฅ๋ `Field` ์ `error` ๋ค.\n * ํ ํ๋ฉด์ ํ๋, ๋งํฌ๋ ํ๋, ๋ณธ๋ฌธ์ ํ ์ค์ด๋ค(ํท์ด ๋ ์ค์์ ์๋ผ๋ธ๋ค).\n * ๋ซ๊ธฐ ๋จ์ถ๋ ๊ท๊ฒฉ์ด ๊ธ์งํด prop ์์ฒด๊ฐ ์๋ค. ์๋ฆฌ๋ ์ฃผ๋ฉ๋ด์ ํ์ด๋ก ์ฌ์ด, ๋ณธ๋ฌธ์ ์ฒซ ์์๋ค.\n *\n * @example\n * <CriticalAlert level=\"danger\" href=\"/notice/1024\" linkTitle=\"์ง์คํธ์ฐ ๋์ ์๋ด\">\n * ์ง์คํธ์ฐ๋ก ์ผ๋ถ ๋ฏผ์ ์ฒ๋ฆฌ๊ฐ ์ง์ฐ๋๊ณ ์์ต๋๋ค.\n * </CriticalAlert>\n *\n * ์์ธํ: docs/krds/09-๋ถํ-๋
ธํธ.md#๊ธด๊ธ๊ณต์ง\n */\n\n/**\n * ๊ธด๊ธ๋. `danger` ์ฌ๋ยท๊ธ์์ค๋ฌ์ด ์ฅ์ (ใ๊ธด๊ธใ) ยท `ok` ์๋น์ค ์ค๋จ ์ฌ์ ์๊ณ (ใ์์ ใ) ยท\n * `info` ๋๋ถ๋ถ์ ์ฌ์ฉ์๊ฐ ์์์ผ ํ๋ ์ํฉ(ใ์๋ดใ).\n */\nexport type CriticalAlertLevel = 'danger' | 'ok' | 'info';\n\n/** ๊ธด๊ธ๋๋ณ ๊ธฐ๋ณธ ๋ ์ด๋ธ. ํท ์ํ์ ์ ํ ๊ธ์ ๊ทธ๋๋ก๋ค. */\nconst DEFAULT_LABEL: Record<CriticalAlertLevel, string> = {\n danger: '๊ธด๊ธ',\n ok: '์์ ',\n info: '์๋ด',\n};\n\nexport type CriticalAlertProps = Omit<ComponentPropsWithRef<'div'>, 'children'> & {\n /** ๊ธด๊ธ๋. ๊ธฐ๋ณธ๊ฐ `danger` โ ์ด ๋ถํ์ ์ธ ์ํฉ ์์ฒด๊ฐ ๊ธด๊ธ ์ํฉ์ด๋ค. */\n level?: CriticalAlertLevel;\n /** ๋ฐฐ์ง ๊ธ์. ์๋ตํ๋ฉด ๊ธด๊ธ๋๋ณ ๊ธฐ๋ณธ๊ฐ(๊ธด๊ธ/์์ /์๋ด). ๊ฐ์ถ์ง ๋ง๋ผ โ ์์ด์ฝ๋ง์ผ๋ก๋ ์ ์ฝํ๋ค. */\n label?: string;\n /** ๊ณต์ง ๋ด์ฉ. ํ ์ค๋ก ์ด๋ค โ ํท์ด ๋ ์ค์์ ์๋ผ๋ธ๋ค. */\n children: ReactNode;\n /** ์์ธ ํ๋ฉด ๋งํฌ. ๊ท๊ฒฉ์ ํ๋๋ง ๋ ์ ์๋ค. */\n href?: string;\n /** ๋งํฌ ๊ธ์. ๊ธฐ๋ณธ ใ์์ธํ ๋ณด๊ธฐใ. ์์ ํ๋ฉด(<768px)์์๋ ๊ฐ์ถฐ์ง๊ณ ํ์ดํ๋ง ๋จ๋๋ค. */\n linkLabel?: ReactNode;\n /** ๋งํฌ์ ๋ชฉ์ ์ง ์ค๋ช
(`title`). ใ์์ธํ ๋ณด๊ธฐใ๋ง์ผ๋ก๋ ๋ชฉ์ ์ง๋ฅผ ์ ์ ์์ผ๋ ๋ฌธ์ ์ ๋ชฉ์ ๋ฃ๋๋ค. */\n linkTitle?: string;\n /** ๋งํฌ target. `_blank` ๋ฉด `title` ์ ใ์ ์ฐฝ ์ด๋ฆผใ์ ๋ง๋ถ์ธ๋ค. */\n linkTarget?: ComponentPropsWithRef<'a'>['target'];\n};\n\nexport function CriticalAlert({\n level = 'danger',\n label,\n children,\n href,\n linkLabel = '์์ธํ ๋ณด๊ธฐ',\n linkTitle,\n linkTarget,\n className,\n // ์ ๊ทผ์ฑ ๊ฐ์ด๋: ใ๊ธด๊ธ ๊ณต์ง ์น์
์ role=\"banner\" ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐฐ๋ ์ญํ ์ ๋ถ์ฌใ.\n // ํท ์ํ์๋ ์๊ณ ๊ฐ์ด๋๊ฐ ์๊ตฌํ ๊ฒ์ด๋ค. ํ์ด์ง์ <header> ๊ฐ ์ด๋ฏธ ์์ผ๋ฉด banner\n // ๋๋๋งํฌ๊ฐ ๋์ด ๋๋ฏ๋ก ์ด๋ฆ์ ๋ถ์ฌ ๊ตฌ๋ถํ๋ค(aria-label ์ ์ฐ๋ฆฌ๊ฐ ๋ง๋ ๊ฒ).\n role = 'banner',\n 'aria-label': ariaLabel = '๊ธด๊ธ ๊ณต์ง',\n ...rest\n}: CriticalAlertProps) {\n const newWindow = linkTarget === '_blank';\n const title = linkTitle\n ? newWindow\n ? `${linkTitle} (์ ์ฐฝ ์ด๋ฆผ)`\n : linkTitle\n : newWindow\n ? '์ ์ฐฝ ์ด๋ฆผ'\n : undefined;\n\n return (\n // `.main-urgent-wrap` ์ ํท CSS ์ ์๋ค(์ ์ฃผ์ ์ฐธ๊ณ ) โ ์ ํญ๋ง Tailwind ๋ก ์ค๋ค.\n <div className={cx('w-full', className)} role={role} aria-label={ariaLabel} {...rest}>\n <ul className=\"krds-critical-alerts\">\n {/* ๊ท๊ฒฉ์ ํญ๋ชฉ์ ํ๋๋ฟ์ด๋ค. ๋๋ฆฌ์ง ๋ง๋ผ. */}\n <li>\n <div className=\"critical-ban\">\n {/* ์์ด์ฝ์ ์ด ๋ฐฐ์ง์ ::before ๋ค. ์์ <i> ๋ sr-only ๋ฅผ ๋ฃ์ง ๋ง๋ผ. */}\n <span className={cx('critical-badge', level)}>{label ?? DEFAULT_LABEL[level]}</span>\n <p className=\"critical-txt\">{children}</p>\n {href && (\n <a\n href={href}\n className=\"krds-btn medium link basic\"\n target={linkTarget}\n title={title}\n >\n {/* ํท์ `m-hide`(๋ชจ๋ฐ์ผ ์จ๊น)๊ฐ CSS ์ ์์ด Tailwind ๋ก ๋์ ํ๋ค. */}\n <span className=\"hidden md:inline\">{linkLabel}</span>\n <i className=\"svg-icon ico-angle right\" aria-hidden=\"true\" />\n </a>\n )}\n </div>\n </li>\n </ul>\n </div>\n );\n}\n"],"mappings":"AAkFY,cAGE,YAHF;AAjFZ,SAAS,UAAU;AAyBnB,MAAM,gBAAoD;AAAA,EACxD,QAAQ;AAAA,EACR,IAAI;AAAA,EACJ,MAAM;AACR;AAmBO,SAAS,cAAc;AAAA,EAC5B,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAIA,OAAO;AAAA,EACP,cAAc,YAAY;AAAA,EAC1B,GAAG;AACL,GAAuB;AACrB,QAAM,YAAY,eAAe;AACjC,QAAM,QAAQ,YACV,YACE,GAAG,SAAS,kCACZ,YACF,YACE,+BACA;AAEN;AAAA;AAAA,IAEE,oBAAC,SAAI,WAAW,GAAG,UAAU,SAAS,GAAG,MAAY,cAAY,WAAY,GAAG,MAC9E,8BAAC,QAAG,WAAU,wBAEZ,8BAAC,QACC,+BAAC,SAAI,WAAU,gBAEb;AAAA,0BAAC,UAAK,WAAW,GAAG,kBAAkB,KAAK,GAAI,mBAAS,cAAc,KAAK,GAAE;AAAA,MAC7E,oBAAC,OAAE,WAAU,gBAAgB,UAAS;AAAA,MACrC,QACC;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,WAAU;AAAA,UACV,QAAQ;AAAA,UACR;AAAA,UAGA;AAAA,gCAAC,UAAK,WAAU,oBAAoB,qBAAU;AAAA,YAC9C,oBAAC,OAAE,WAAU,4BAA2B,eAAY,QAAO;AAAA;AAAA;AAAA,MAC7D;AAAA,OAEJ,GACF,GACF,GACF;AAAA;AAEJ;","names":[]}
|