@brycks/core-front 0.3.2 → 0.3.4
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/feedback/Alert/Alert.cjs +1 -1
- package/dist/components/feedback/Alert/Alert.cjs.map +1 -1
- package/dist/components/feedback/Alert/Alert.js +52 -177
- package/dist/components/feedback/Alert/Alert.js.map +1 -1
- package/dist/components/feedback/Modal/Modal.cjs +1 -1
- package/dist/components/feedback/Modal/Modal.cjs.map +1 -1
- package/dist/components/feedback/Modal/Modal.js +7 -6
- package/dist/components/feedback/Modal/Modal.js.map +1 -1
- package/dist/components/form/Checkbox/Checkbox.cjs +1 -1
- package/dist/components/form/Checkbox/Checkbox.js +12 -12
- package/dist/components/form/Input/Input.cjs +1 -1
- package/dist/components/form/Input/Input.js +13 -13
- package/dist/components/form/Slider/Slider.cjs +1 -1
- package/dist/components/form/Slider/Slider.js +1 -1
- package/dist/components/form/Switch/Switch.cjs +1 -1
- package/dist/components/form/Switch/Switch.cjs.map +1 -1
- package/dist/components/form/Switch/Switch.js +70 -105
- package/dist/components/form/Switch/Switch.js.map +1 -1
- package/dist/components/layout/Card/Card.cjs +1 -1
- package/dist/components/layout/Card/Card.cjs.map +1 -1
- package/dist/components/layout/Card/Card.js +59 -121
- package/dist/components/layout/Card/Card.js.map +1 -1
- package/dist/components/navigation/Dropdown/Dropdown.cjs +1 -6
- package/dist/components/navigation/Dropdown/Dropdown.cjs.map +1 -1
- package/dist/components/navigation/Dropdown/Dropdown.js +118 -183
- package/dist/components/navigation/Dropdown/Dropdown.js.map +1 -1
- package/dist/components/navigation/Menu/Menu.cjs +1 -1
- package/dist/components/navigation/Menu/Menu.js +5 -5
- package/dist/components/navigation/Tabs/Tabs.cjs +1 -6
- package/dist/components/navigation/Tabs/Tabs.cjs.map +1 -1
- package/dist/components/navigation/Tabs/Tabs.js +92 -162
- package/dist/components/navigation/Tabs/Tabs.js.map +1 -1
- package/dist/components/primitives/Button/Button.cjs +1 -1
- package/dist/components/primitives/Button/Button.cjs.map +1 -1
- package/dist/components/primitives/Button/Button.js +72 -96
- package/dist/components/primitives/Button/Button.js.map +1 -1
- package/dist/components/primitives/Button/Button.styles.cjs +1 -1
- package/dist/components/primitives/Button/Button.styles.cjs.map +1 -1
- package/dist/components/primitives/Button/Button.styles.js +8 -317
- package/dist/components/primitives/Button/Button.styles.js.map +1 -1
- package/dist/components/utility/Badge/Badge.cjs +1 -1
- package/dist/components/utility/Badge/Badge.cjs.map +1 -1
- package/dist/components/utility/Badge/Badge.js +23 -80
- package/dist/components/utility/Badge/Badge.js.map +1 -1
- package/dist/feedback.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -1,263 +1,198 @@
|
|
|
1
|
-
import { jsx as u, jsxs as
|
|
2
|
-
import { forwardRef as
|
|
3
|
-
import { createPortal as
|
|
4
|
-
import { cx as
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const J = te(null);
|
|
10
|
-
function ae() {
|
|
11
|
-
const f = oe(J);
|
|
12
|
-
if (!f)
|
|
1
|
+
import { jsx as u, jsxs as O } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as k, useState as b, useRef as z, useEffect as v, useCallback as P, cloneElement as G, createContext as J, useContext as Q } from "react";
|
|
3
|
+
import { createPortal as T } from "react-dom";
|
|
4
|
+
import { cx as y } from "../../../utils/styles.js";
|
|
5
|
+
const X = J(null);
|
|
6
|
+
function V() {
|
|
7
|
+
const p = Q(X);
|
|
8
|
+
if (!p)
|
|
13
9
|
throw new Error("Dropdown components must be used within a Dropdown");
|
|
14
|
-
return
|
|
10
|
+
return p;
|
|
15
11
|
}
|
|
16
|
-
const
|
|
12
|
+
const Z = k(function({
|
|
17
13
|
trigger: r,
|
|
18
|
-
isOpen:
|
|
19
|
-
defaultOpen:
|
|
20
|
-
onOpenChange:
|
|
14
|
+
isOpen: o,
|
|
15
|
+
defaultOpen: i = !1,
|
|
16
|
+
onOpenChange: c,
|
|
21
17
|
placement: s = "bottom-start",
|
|
22
|
-
offset:
|
|
23
|
-
closeOnSelect:
|
|
24
|
-
className:
|
|
25
|
-
style:
|
|
26
|
-
children:
|
|
27
|
-
testId:
|
|
28
|
-
...
|
|
29
|
-
},
|
|
30
|
-
const [
|
|
31
|
-
|
|
32
|
-
const
|
|
18
|
+
offset: f = 4,
|
|
19
|
+
closeOnSelect: h = !0,
|
|
20
|
+
className: g,
|
|
21
|
+
style: x,
|
|
22
|
+
children: E,
|
|
23
|
+
testId: N,
|
|
24
|
+
...C
|
|
25
|
+
}, I) {
|
|
26
|
+
const [Y, B] = b(i), [L, H] = b({ top: 0, left: 0 }), [l, m] = b(-1), [_, R] = b(!1), w = z(null), D = z(null), t = o ?? Y;
|
|
27
|
+
v(() => (R(!0), () => R(!1)), []);
|
|
28
|
+
const a = P(
|
|
33
29
|
(e) => {
|
|
34
|
-
|
|
30
|
+
o === void 0 && B(e), c?.(e), e || m(-1);
|
|
35
31
|
},
|
|
36
|
-
[
|
|
37
|
-
),
|
|
38
|
-
|
|
39
|
-
if (!
|
|
32
|
+
[o, c]
|
|
33
|
+
), M = P(() => a(!1), [a]);
|
|
34
|
+
v(() => {
|
|
35
|
+
if (!t || !w.current || !_) return;
|
|
40
36
|
const e = () => {
|
|
41
|
-
const n =
|
|
37
|
+
const n = w.current;
|
|
42
38
|
if (!n) return;
|
|
43
|
-
const
|
|
44
|
-
let W = 0,
|
|
45
|
-
s.startsWith("bottom") ? W =
|
|
39
|
+
const d = n.getBoundingClientRect(), j = window.scrollX, q = window.scrollY;
|
|
40
|
+
let W = 0, A = 0;
|
|
41
|
+
s.startsWith("bottom") ? W = d.bottom + q + f : W = d.top + q - f, s.endsWith("start") ? A = d.left + j : A = d.right + j, H({ top: W, left: A });
|
|
46
42
|
};
|
|
47
43
|
return e(), window.addEventListener("resize", e), window.addEventListener("scroll", e, !0), () => {
|
|
48
44
|
window.removeEventListener("resize", e), window.removeEventListener("scroll", e, !0);
|
|
49
45
|
};
|
|
50
|
-
}, [
|
|
51
|
-
if (!
|
|
46
|
+
}, [t, s, f, _]), v(() => {
|
|
47
|
+
if (!t) return;
|
|
52
48
|
const e = (n) => {
|
|
53
|
-
|
|
49
|
+
w.current?.contains(n.target) || D.current?.contains(n.target) || a(!1);
|
|
54
50
|
};
|
|
55
51
|
return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
|
|
56
|
-
}, [
|
|
57
|
-
const
|
|
52
|
+
}, [t, a]);
|
|
53
|
+
const K = P(
|
|
58
54
|
(e) => {
|
|
59
|
-
if (!
|
|
60
|
-
(e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") && (e.preventDefault(),
|
|
55
|
+
if (!t) {
|
|
56
|
+
(e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") && (e.preventDefault(), a(!0));
|
|
61
57
|
return;
|
|
62
58
|
}
|
|
63
|
-
const n =
|
|
59
|
+
const n = D.current?.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])');
|
|
64
60
|
if (n?.length)
|
|
65
61
|
switch (e.key) {
|
|
66
62
|
case "ArrowDown":
|
|
67
|
-
e.preventDefault(),
|
|
63
|
+
e.preventDefault(), m((d) => (d + 1) % n.length);
|
|
68
64
|
break;
|
|
69
65
|
case "ArrowUp":
|
|
70
|
-
e.preventDefault(),
|
|
66
|
+
e.preventDefault(), m((d) => (d - 1 + n.length) % n.length);
|
|
71
67
|
break;
|
|
72
68
|
case "Home":
|
|
73
|
-
e.preventDefault(),
|
|
69
|
+
e.preventDefault(), m(0);
|
|
74
70
|
break;
|
|
75
71
|
case "End":
|
|
76
|
-
e.preventDefault(),
|
|
72
|
+
e.preventDefault(), m(n.length - 1);
|
|
77
73
|
break;
|
|
78
74
|
case "Escape":
|
|
79
|
-
e.preventDefault(),
|
|
75
|
+
e.preventDefault(), a(!1), w.current?.focus();
|
|
80
76
|
break;
|
|
81
77
|
case "Enter":
|
|
82
78
|
case " ":
|
|
83
|
-
e.preventDefault(),
|
|
79
|
+
e.preventDefault(), l >= 0 && n[l]?.click();
|
|
84
80
|
break;
|
|
85
81
|
}
|
|
86
82
|
},
|
|
87
|
-
[
|
|
83
|
+
[t, l, a]
|
|
88
84
|
);
|
|
89
|
-
|
|
90
|
-
if (!
|
|
91
|
-
|
|
92
|
-
}, [
|
|
93
|
-
const
|
|
94
|
-
ref:
|
|
85
|
+
v(() => {
|
|
86
|
+
if (!t || l < 0) return;
|
|
87
|
+
D.current?.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')?.[l]?.focus();
|
|
88
|
+
}, [t, l]);
|
|
89
|
+
const S = r.props, U = G(r, {
|
|
90
|
+
ref: w,
|
|
95
91
|
"aria-haspopup": "menu",
|
|
96
|
-
"aria-expanded":
|
|
92
|
+
"aria-expanded": t,
|
|
97
93
|
onClick: (e) => {
|
|
98
|
-
|
|
94
|
+
S.onClick?.(e), a(!t);
|
|
99
95
|
},
|
|
100
96
|
onKeyDown: (e) => {
|
|
101
|
-
|
|
97
|
+
S.onKeyDown?.(e), K(e);
|
|
102
98
|
}
|
|
103
|
-
}),
|
|
99
|
+
}), F = {
|
|
104
100
|
position: "absolute",
|
|
105
|
-
top:
|
|
106
|
-
left: s.endsWith("end") ? "auto" :
|
|
107
|
-
right: s.endsWith("end") ? window.innerWidth -
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
backgroundColor: "var(--brycks-background-elevated)",
|
|
111
|
-
border: "1px solid var(--brycks-border-default)",
|
|
112
|
-
borderRadius: "var(--brycks-radius-lg)",
|
|
113
|
-
boxShadow: "var(--brycks-shadow-lg)",
|
|
114
|
-
padding: K[1],
|
|
115
|
-
animation: `brycks-dropdown-in ${H.quick}ms ${U.easeOut}`,
|
|
116
|
-
outline: "none",
|
|
117
|
-
...C
|
|
101
|
+
top: L.top,
|
|
102
|
+
left: s.endsWith("end") ? "auto" : L.left,
|
|
103
|
+
right: s.endsWith("end") ? window.innerWidth - L.left : "auto",
|
|
104
|
+
minWidth: w.current?.offsetWidth ?? 160,
|
|
105
|
+
...x
|
|
118
106
|
};
|
|
119
|
-
return /* @__PURE__ */ u(
|
|
120
|
-
}, activeIndex:
|
|
107
|
+
return /* @__PURE__ */ u(X.Provider, { value: { isOpen: t, close: h ? M : () => {
|
|
108
|
+
}, activeIndex: l, setActiveIndex: m }, children: /* @__PURE__ */ O(
|
|
121
109
|
"div",
|
|
122
110
|
{
|
|
123
|
-
ref:
|
|
124
|
-
className:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
...I,
|
|
111
|
+
ref: I,
|
|
112
|
+
className: y("brycks-dropdown", g),
|
|
113
|
+
"data-testid": N,
|
|
114
|
+
...C,
|
|
128
115
|
children: [
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
/* @__PURE__ */
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
style: _,
|
|
144
|
-
onKeyDown: q,
|
|
145
|
-
tabIndex: -1,
|
|
146
|
-
children: S
|
|
147
|
-
}
|
|
148
|
-
)
|
|
149
|
-
] }),
|
|
116
|
+
U,
|
|
117
|
+
t && _ && T(
|
|
118
|
+
/* @__PURE__ */ u(
|
|
119
|
+
"div",
|
|
120
|
+
{
|
|
121
|
+
ref: D,
|
|
122
|
+
role: "menu",
|
|
123
|
+
className: "brycks-dropdown__menu",
|
|
124
|
+
style: F,
|
|
125
|
+
onKeyDown: K,
|
|
126
|
+
tabIndex: -1,
|
|
127
|
+
children: E
|
|
128
|
+
}
|
|
129
|
+
),
|
|
150
130
|
document.body
|
|
151
131
|
)
|
|
152
132
|
]
|
|
153
133
|
}
|
|
154
134
|
) });
|
|
155
135
|
});
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
const { close:
|
|
159
|
-
r || (
|
|
160
|
-
}, L = {
|
|
161
|
-
display: "flex",
|
|
162
|
-
alignItems: "center",
|
|
163
|
-
gap: se.lg,
|
|
164
|
-
padding: `${G.md}px ${T.sm}px`,
|
|
165
|
-
fontSize: Y.base,
|
|
166
|
-
color: r ? "var(--brycks-foreground-disabled)" : i ? "var(--brycks-error-default)" : "var(--brycks-foreground-default)",
|
|
167
|
-
backgroundColor: "transparent",
|
|
168
|
-
borderRadius: "var(--brycks-radius-md)",
|
|
169
|
-
cursor: r ? "not-allowed" : "pointer",
|
|
170
|
-
transition: `background-color ${H.fast}ms ${U.easeOut}`,
|
|
171
|
-
outline: "none",
|
|
172
|
-
...p
|
|
173
|
-
}, $ = {
|
|
174
|
-
width: B.sm,
|
|
175
|
-
height: B.sm,
|
|
176
|
-
color: r ? "var(--brycks-foreground-disabled)" : i ? "var(--brycks-error-default)" : "var(--brycks-foreground-muted)",
|
|
177
|
-
flexShrink: 0
|
|
178
|
-
}, z = {
|
|
179
|
-
marginLeft: "auto",
|
|
180
|
-
fontSize: Y.sm,
|
|
181
|
-
color: "var(--brycks-foreground-muted)",
|
|
182
|
-
fontFamily: "var(--brycks-font-mono)"
|
|
136
|
+
Z.displayName = "Dropdown";
|
|
137
|
+
const $ = k(function({ disabled: r = !1, icon: o, shortcut: i, destructive: c = !1, className: s, style: f, children: h, onClick: g, ...x }, E) {
|
|
138
|
+
const { close: N } = V(), C = (I) => {
|
|
139
|
+
r || (g?.(I), N());
|
|
183
140
|
};
|
|
184
|
-
return /* @__PURE__ */
|
|
141
|
+
return /* @__PURE__ */ O(
|
|
185
142
|
"div",
|
|
186
143
|
{
|
|
187
|
-
ref:
|
|
144
|
+
ref: E,
|
|
188
145
|
role: "menuitem",
|
|
189
146
|
"aria-disabled": r,
|
|
190
147
|
tabIndex: r ? -1 : 0,
|
|
191
|
-
className:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
onFocus: (t) => {
|
|
201
|
-
t.currentTarget.style.backgroundColor = "var(--brycks-background-muted)";
|
|
202
|
-
},
|
|
203
|
-
onBlur: (t) => {
|
|
204
|
-
t.currentTarget.style.backgroundColor = "transparent";
|
|
205
|
-
},
|
|
206
|
-
...C,
|
|
148
|
+
className: y(
|
|
149
|
+
"brycks-dropdown-item",
|
|
150
|
+
r && "brycks-dropdown-item--disabled",
|
|
151
|
+
c && "brycks-dropdown-item--destructive",
|
|
152
|
+
s
|
|
153
|
+
),
|
|
154
|
+
style: f,
|
|
155
|
+
onClick: C,
|
|
156
|
+
...x,
|
|
207
157
|
children: [
|
|
208
|
-
|
|
209
|
-
/* @__PURE__ */ u("span", {
|
|
210
|
-
|
|
158
|
+
o && /* @__PURE__ */ u("span", { className: "brycks-dropdown-item__icon", children: o }),
|
|
159
|
+
/* @__PURE__ */ u("span", { className: "brycks-dropdown-item__label", children: h }),
|
|
160
|
+
i && /* @__PURE__ */ u("span", { className: "brycks-dropdown-item__shortcut", children: i })
|
|
211
161
|
]
|
|
212
162
|
}
|
|
213
163
|
);
|
|
214
164
|
});
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
const s = {
|
|
218
|
-
height: 1,
|
|
219
|
-
backgroundColor: "var(--brycks-border-muted)",
|
|
220
|
-
margin: `${K[1]}px 0`,
|
|
221
|
-
...a
|
|
222
|
-
};
|
|
165
|
+
$.displayName = "DropdownItem";
|
|
166
|
+
const ee = k(function({ className: r, style: o, ...i }, c) {
|
|
223
167
|
return /* @__PURE__ */ u(
|
|
224
168
|
"div",
|
|
225
169
|
{
|
|
226
|
-
ref:
|
|
170
|
+
ref: c,
|
|
227
171
|
role: "separator",
|
|
228
|
-
className:
|
|
229
|
-
style:
|
|
230
|
-
...
|
|
172
|
+
className: y("brycks-dropdown-divider", r),
|
|
173
|
+
style: o,
|
|
174
|
+
...i
|
|
231
175
|
}
|
|
232
176
|
);
|
|
233
177
|
});
|
|
234
|
-
|
|
235
|
-
const
|
|
236
|
-
const p = {
|
|
237
|
-
padding: `${G.md}px ${T.sm}px ${K[1]}px ${T.sm}px`,
|
|
238
|
-
fontSize: Y.xs,
|
|
239
|
-
fontWeight: 600,
|
|
240
|
-
color: "var(--brycks-foreground-muted)",
|
|
241
|
-
textTransform: "uppercase",
|
|
242
|
-
letterSpacing: "0.05em",
|
|
243
|
-
...a
|
|
244
|
-
};
|
|
178
|
+
ee.displayName = "DropdownDivider";
|
|
179
|
+
const te = k(function({ className: r, style: o, children: i, ...c }, s) {
|
|
245
180
|
return /* @__PURE__ */ u(
|
|
246
181
|
"div",
|
|
247
182
|
{
|
|
248
183
|
ref: s,
|
|
249
|
-
className:
|
|
250
|
-
style:
|
|
251
|
-
...
|
|
252
|
-
children:
|
|
184
|
+
className: y("brycks-dropdown-label", r),
|
|
185
|
+
style: o,
|
|
186
|
+
...c,
|
|
187
|
+
children: i
|
|
253
188
|
}
|
|
254
189
|
);
|
|
255
190
|
});
|
|
256
|
-
|
|
191
|
+
te.displayName = "DropdownLabel";
|
|
257
192
|
export {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
193
|
+
Z as Dropdown,
|
|
194
|
+
ee as DropdownDivider,
|
|
195
|
+
$ as DropdownItem,
|
|
196
|
+
te as DropdownLabel
|
|
262
197
|
};
|
|
263
198
|
//# sourceMappingURL=Dropdown.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dropdown.js","sources":["../../../../src/components/navigation/Dropdown/Dropdown.tsx"],"sourcesContent":["/**\n * Dropdown Component\n *\n * A dropdown menu with keyboard navigation support.\n * Can be used for actions, navigation, or selection.\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n useRef,\n useEffect,\n cloneElement,\n createContext,\n useContext,\n type CSSProperties,\n type ReactNode,\n type ReactElement,\n type HTMLAttributes,\n type KeyboardEvent,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { cx } from '../../../utils/styles'\nimport { spacing, fontSizes, durations, easings } from '../../../design-system'\nimport { componentGap, componentPaddingX, componentPaddingY, iconSizes } from '../../../design-system/primitives'\n\nexport type DropdownPlacement = 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'\n\ninterface DropdownContextValue {\n isOpen: boolean\n close: () => void\n activeIndex: number\n setActiveIndex: (index: number) => void\n}\n\nconst DropdownContext = createContext<DropdownContextValue | null>(null)\n\nfunction useDropdownContext() {\n const context = useContext(DropdownContext)\n if (!context) {\n throw new Error('Dropdown components must be used within a Dropdown')\n }\n return context\n}\n\nexport interface DropdownProps extends HTMLAttributes<HTMLDivElement> {\n /** Trigger element */\n trigger: ReactElement\n /** Whether the dropdown is open (controlled) */\n isOpen?: boolean\n /** Default open state (uncontrolled) */\n defaultOpen?: boolean\n /** Callback when open state changes */\n onOpenChange?: (isOpen: boolean) => void\n /** Dropdown placement */\n placement?: DropdownPlacement\n /** Offset from trigger */\n offset?: number\n /** Whether to close on item select */\n closeOnSelect?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Dropdown = forwardRef<HTMLDivElement, DropdownProps>(function Dropdown(\n {\n trigger,\n isOpen: controlledIsOpen,\n defaultOpen = false,\n onOpenChange,\n placement = 'bottom-start',\n offset = 4,\n closeOnSelect = true,\n className,\n style,\n children,\n testId,\n ...props\n },\n ref\n) {\n const [internalIsOpen, setInternalIsOpen] = useState(defaultOpen)\n const [position, setPosition] = useState({ top: 0, left: 0 })\n const [activeIndex, setActiveIndex] = useState(-1)\n const [mounted, setMounted] = useState(false)\n const triggerRef = useRef<HTMLElement>(null)\n const menuRef = useRef<HTMLDivElement>(null)\n\n const isOpen = controlledIsOpen ?? internalIsOpen\n\n useEffect(() => {\n setMounted(true)\n return () => setMounted(false)\n }, [])\n\n const setIsOpen = useCallback(\n (open: boolean) => {\n if (controlledIsOpen === undefined) {\n setInternalIsOpen(open)\n }\n onOpenChange?.(open)\n if (!open) {\n setActiveIndex(-1)\n }\n },\n [controlledIsOpen, onOpenChange]\n )\n\n const close = useCallback(() => setIsOpen(false), [setIsOpen])\n\n // Calculate position\n useEffect(() => {\n if (!isOpen || !triggerRef.current || !mounted) return\n\n const updatePosition = () => {\n const trigger = triggerRef.current\n if (!trigger) return\n\n const rect = trigger.getBoundingClientRect()\n const scrollX = window.scrollX\n const scrollY = window.scrollY\n\n let top = 0\n let left = 0\n\n if (placement.startsWith('bottom')) {\n top = rect.bottom + scrollY + offset\n } else {\n top = rect.top + scrollY - offset\n }\n\n if (placement.endsWith('start')) {\n left = rect.left + scrollX\n } else {\n left = rect.right + scrollX\n }\n\n setPosition({ top, left })\n }\n\n updatePosition()\n window.addEventListener('resize', updatePosition)\n window.addEventListener('scroll', updatePosition, true)\n\n return () => {\n window.removeEventListener('resize', updatePosition)\n window.removeEventListener('scroll', updatePosition, true)\n }\n }, [isOpen, placement, offset, mounted])\n\n // Close on outside click\n useEffect(() => {\n if (!isOpen) return\n\n const handleClick = (e: MouseEvent) => {\n if (\n triggerRef.current?.contains(e.target as Node) ||\n menuRef.current?.contains(e.target as Node)\n ) {\n return\n }\n setIsOpen(false)\n }\n\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [isOpen, setIsOpen])\n\n // Keyboard navigation\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (!isOpen) {\n if (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n setIsOpen(true)\n }\n return\n }\n\n const items = menuRef.current?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')\n if (!items?.length) return\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n setActiveIndex((prev) => (prev + 1) % items.length)\n break\n case 'ArrowUp':\n e.preventDefault()\n setActiveIndex((prev) => (prev - 1 + items.length) % items.length)\n break\n case 'Home':\n e.preventDefault()\n setActiveIndex(0)\n break\n case 'End':\n e.preventDefault()\n setActiveIndex(items.length - 1)\n break\n case 'Escape':\n e.preventDefault()\n setIsOpen(false)\n triggerRef.current?.focus()\n break\n case 'Enter':\n case ' ':\n e.preventDefault()\n if (activeIndex >= 0) {\n items[activeIndex]?.click()\n }\n break\n }\n },\n [isOpen, activeIndex, setIsOpen]\n )\n\n // Focus active item\n useEffect(() => {\n if (!isOpen || activeIndex < 0) return\n const items = menuRef.current?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')\n items?.[activeIndex]?.focus()\n }, [isOpen, activeIndex])\n\n const triggerProps = trigger.props as Record<string, unknown>\n const triggerElement = cloneElement(trigger as ReactElement<Record<string, unknown>>, {\n ref: triggerRef,\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n onClick: (e: React.MouseEvent) => {\n (triggerProps.onClick as ((e: React.MouseEvent) => void) | undefined)?.(e)\n setIsOpen(!isOpen)\n },\n onKeyDown: (e: KeyboardEvent) => {\n (triggerProps.onKeyDown as ((e: KeyboardEvent) => void) | undefined)?.(e)\n handleKeyDown(e)\n },\n })\n\n const menuStyle: CSSProperties = {\n position: 'absolute',\n top: position.top,\n left: placement.endsWith('end') ? 'auto' : position.left,\n right: placement.endsWith('end') ? window.innerWidth - position.left : 'auto',\n zIndex: 'var(--brycks-z-dropdown)' as unknown as number,\n minWidth: triggerRef.current?.offsetWidth ?? 160,\n backgroundColor: 'var(--brycks-background-elevated)',\n border: '1px solid var(--brycks-border-default)',\n borderRadius: 'var(--brycks-radius-lg)',\n boxShadow: 'var(--brycks-shadow-lg)',\n padding: spacing[1],\n animation: `brycks-dropdown-in ${durations.quick}ms ${easings.easeOut}`,\n outline: 'none',\n ...style,\n }\n\n return (\n <DropdownContext.Provider value={{ isOpen, close: closeOnSelect ? close : () => {}, activeIndex, setActiveIndex }}>\n <div\n ref={ref}\n className={cx('brycks-dropdown', className)}\n style={{ display: 'inline-block' }}\n data-testid={testId}\n {...props}\n >\n {triggerElement}\n {isOpen && mounted && createPortal(\n <>\n <style>\n {`\n @keyframes brycks-dropdown-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `}\n </style>\n <div\n ref={menuRef}\n role=\"menu\"\n style={menuStyle}\n onKeyDown={handleKeyDown}\n tabIndex={-1}\n >\n {children}\n </div>\n </>,\n document.body\n )}\n </div>\n </DropdownContext.Provider>\n )\n})\n\nDropdown.displayName = 'Dropdown'\n\n// DropdownItem\nexport interface DropdownItemProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether the item is disabled */\n disabled?: boolean\n /** Icon before the label */\n icon?: ReactNode\n /** Shortcut text */\n shortcut?: string\n /** Whether the item is destructive */\n destructive?: boolean\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(function DropdownItem(\n { disabled = false, icon, shortcut, destructive = false, className, style, children, onClick, ...props },\n ref\n) {\n const { close } = useDropdownContext()\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n if (disabled) return\n onClick?.(e)\n close()\n }\n\n const itemStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: componentGap.lg,\n padding: `${componentPaddingY.md}px ${componentPaddingX.sm}px`,\n fontSize: fontSizes.base,\n color: disabled\n ? 'var(--brycks-foreground-disabled)'\n : destructive\n ? 'var(--brycks-error-default)'\n : 'var(--brycks-foreground-default)',\n backgroundColor: 'transparent',\n borderRadius: 'var(--brycks-radius-md)',\n cursor: disabled ? 'not-allowed' : 'pointer',\n transition: `background-color ${durations.fast}ms ${easings.easeOut}`,\n outline: 'none',\n ...style,\n }\n\n const iconStyle: CSSProperties = {\n width: iconSizes.sm,\n height: iconSizes.sm,\n color: disabled\n ? 'var(--brycks-foreground-disabled)'\n : destructive\n ? 'var(--brycks-error-default)'\n : 'var(--brycks-foreground-muted)',\n flexShrink: 0,\n }\n\n const shortcutStyle: CSSProperties = {\n marginLeft: 'auto',\n fontSize: fontSizes.sm,\n color: 'var(--brycks-foreground-muted)',\n fontFamily: 'var(--brycks-font-mono)',\n }\n\n return (\n <div\n ref={ref}\n role=\"menuitem\"\n aria-disabled={disabled}\n tabIndex={disabled ? -1 : 0}\n className={cx('brycks-dropdown-item', disabled && 'brycks-dropdown-item--disabled', className)}\n style={itemStyle}\n onClick={handleClick}\n onMouseEnter={(e) => {\n if (!disabled) {\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n onFocus={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\n }}\n onBlur={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n {...props}\n >\n {icon && <span style={iconStyle}>{icon}</span>}\n <span style={{ flex: 1 }}>{children}</span>\n {shortcut && <span style={shortcutStyle}>{shortcut}</span>}\n </div>\n )\n})\n\nDropdownItem.displayName = 'DropdownItem'\n\n// DropdownDivider\nexport interface DropdownDividerProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownDivider = forwardRef<HTMLDivElement, DropdownDividerProps>(function DropdownDivider(\n { className, style, ...props },\n ref\n) {\n const dividerStyle: CSSProperties = {\n height: 1,\n backgroundColor: 'var(--brycks-border-muted)',\n margin: `${spacing[1]}px 0`,\n ...style,\n }\n\n return (\n <div\n ref={ref}\n role=\"separator\"\n className={cx('brycks-dropdown-divider', className)}\n style={dividerStyle}\n {...props}\n />\n )\n})\n\nDropdownDivider.displayName = 'DropdownDivider'\n\n// DropdownLabel\nexport interface DropdownLabelProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownLabel = forwardRef<HTMLDivElement, DropdownLabelProps>(function DropdownLabel(\n { className, style, children, ...props },\n ref\n) {\n const labelStyle: CSSProperties = {\n padding: `${componentPaddingY.md}px ${componentPaddingX.sm}px ${spacing[1]}px ${componentPaddingX.sm}px`,\n fontSize: fontSizes.xs,\n fontWeight: 600,\n color: 'var(--brycks-foreground-muted)',\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n ...style,\n }\n\n return (\n <div\n ref={ref}\n className={cx('brycks-dropdown-label', className)}\n style={labelStyle}\n {...props}\n >\n {children}\n </div>\n )\n})\n\nDropdownLabel.displayName = 'DropdownLabel'\n"],"names":["DropdownContext","createContext","useDropdownContext","context","useContext","Dropdown","forwardRef","trigger","controlledIsOpen","defaultOpen","onOpenChange","placement","offset","closeOnSelect","className","style","children","testId","props","ref","internalIsOpen","setInternalIsOpen","useState","position","setPosition","activeIndex","setActiveIndex","mounted","setMounted","triggerRef","useRef","menuRef","isOpen","useEffect","setIsOpen","useCallback","open","close","updatePosition","rect","scrollX","scrollY","top","left","handleClick","e","handleKeyDown","items","prev","triggerProps","triggerElement","cloneElement","menuStyle","spacing","durations","easings","jsx","jsxs","cx","createPortal","Fragment","DropdownItem","disabled","icon","shortcut","destructive","onClick","itemStyle","componentGap","componentPaddingY","componentPaddingX","fontSizes","iconStyle","iconSizes","shortcutStyle","DropdownDivider","dividerStyle","DropdownLabel","labelStyle"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Dropdown.js","sources":["../../../../src/components/navigation/Dropdown/Dropdown.tsx"],"sourcesContent":["/**\n * Dropdown Component\n *\n * A dropdown menu with keyboard navigation support.\n * Can be used for actions, navigation, or selection.\n *\n * All color styles are handled via CSS classes for easy customization.\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n useRef,\n useEffect,\n cloneElement,\n createContext,\n useContext,\n type CSSProperties,\n type ReactNode,\n type ReactElement,\n type HTMLAttributes,\n type KeyboardEvent,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { cx } from '../../../utils/styles'\n\nexport type DropdownPlacement = 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'\n\ninterface DropdownContextValue {\n isOpen: boolean\n close: () => void\n activeIndex: number\n setActiveIndex: (index: number) => void\n}\n\nconst DropdownContext = createContext<DropdownContextValue | null>(null)\n\nfunction useDropdownContext() {\n const context = useContext(DropdownContext)\n if (!context) {\n throw new Error('Dropdown components must be used within a Dropdown')\n }\n return context\n}\n\nexport interface DropdownProps extends HTMLAttributes<HTMLDivElement> {\n /** Trigger element */\n trigger: ReactElement\n /** Whether the dropdown is open (controlled) */\n isOpen?: boolean\n /** Default open state (uncontrolled) */\n defaultOpen?: boolean\n /** Callback when open state changes */\n onOpenChange?: (isOpen: boolean) => void\n /** Dropdown placement */\n placement?: DropdownPlacement\n /** Offset from trigger */\n offset?: number\n /** Whether to close on item select */\n closeOnSelect?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Dropdown = forwardRef<HTMLDivElement, DropdownProps>(function Dropdown(\n {\n trigger,\n isOpen: controlledIsOpen,\n defaultOpen = false,\n onOpenChange,\n placement = 'bottom-start',\n offset = 4,\n closeOnSelect = true,\n className,\n style,\n children,\n testId,\n ...props\n },\n ref\n) {\n const [internalIsOpen, setInternalIsOpen] = useState(defaultOpen)\n const [position, setPosition] = useState({ top: 0, left: 0 })\n const [activeIndex, setActiveIndex] = useState(-1)\n const [mounted, setMounted] = useState(false)\n const triggerRef = useRef<HTMLElement>(null)\n const menuRef = useRef<HTMLDivElement>(null)\n\n const isOpen = controlledIsOpen ?? internalIsOpen\n\n useEffect(() => {\n setMounted(true)\n return () => setMounted(false)\n }, [])\n\n const setIsOpen = useCallback(\n (open: boolean) => {\n if (controlledIsOpen === undefined) {\n setInternalIsOpen(open)\n }\n onOpenChange?.(open)\n if (!open) {\n setActiveIndex(-1)\n }\n },\n [controlledIsOpen, onOpenChange]\n )\n\n const close = useCallback(() => setIsOpen(false), [setIsOpen])\n\n // Calculate position\n useEffect(() => {\n if (!isOpen || !triggerRef.current || !mounted) return\n\n const updatePosition = () => {\n const trigger = triggerRef.current\n if (!trigger) return\n\n const rect = trigger.getBoundingClientRect()\n const scrollX = window.scrollX\n const scrollY = window.scrollY\n\n let top = 0\n let left = 0\n\n if (placement.startsWith('bottom')) {\n top = rect.bottom + scrollY + offset\n } else {\n top = rect.top + scrollY - offset\n }\n\n if (placement.endsWith('start')) {\n left = rect.left + scrollX\n } else {\n left = rect.right + scrollX\n }\n\n setPosition({ top, left })\n }\n\n updatePosition()\n window.addEventListener('resize', updatePosition)\n window.addEventListener('scroll', updatePosition, true)\n\n return () => {\n window.removeEventListener('resize', updatePosition)\n window.removeEventListener('scroll', updatePosition, true)\n }\n }, [isOpen, placement, offset, mounted])\n\n // Close on outside click\n useEffect(() => {\n if (!isOpen) return\n\n const handleClick = (e: MouseEvent) => {\n if (\n triggerRef.current?.contains(e.target as Node) ||\n menuRef.current?.contains(e.target as Node)\n ) {\n return\n }\n setIsOpen(false)\n }\n\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [isOpen, setIsOpen])\n\n // Keyboard navigation\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (!isOpen) {\n if (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n setIsOpen(true)\n }\n return\n }\n\n const items = menuRef.current?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')\n if (!items?.length) return\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n setActiveIndex((prev) => (prev + 1) % items.length)\n break\n case 'ArrowUp':\n e.preventDefault()\n setActiveIndex((prev) => (prev - 1 + items.length) % items.length)\n break\n case 'Home':\n e.preventDefault()\n setActiveIndex(0)\n break\n case 'End':\n e.preventDefault()\n setActiveIndex(items.length - 1)\n break\n case 'Escape':\n e.preventDefault()\n setIsOpen(false)\n triggerRef.current?.focus()\n break\n case 'Enter':\n case ' ':\n e.preventDefault()\n if (activeIndex >= 0) {\n items[activeIndex]?.click()\n }\n break\n }\n },\n [isOpen, activeIndex, setIsOpen]\n )\n\n // Focus active item\n useEffect(() => {\n if (!isOpen || activeIndex < 0) return\n const items = menuRef.current?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]:not([aria-disabled=\"true\"])')\n items?.[activeIndex]?.focus()\n }, [isOpen, activeIndex])\n\n const triggerProps = trigger.props as Record<string, unknown>\n const triggerElement = cloneElement(trigger as ReactElement<Record<string, unknown>>, {\n ref: triggerRef,\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n onClick: (e: React.MouseEvent) => {\n (triggerProps.onClick as ((e: React.MouseEvent) => void) | undefined)?.(e)\n setIsOpen(!isOpen)\n },\n onKeyDown: (e: KeyboardEvent) => {\n (triggerProps.onKeyDown as ((e: KeyboardEvent) => void) | undefined)?.(e)\n handleKeyDown(e)\n },\n })\n\n // Only layout-related inline styles (position is dynamic)\n const menuStyle: CSSProperties = {\n position: 'absolute',\n top: position.top,\n left: placement.endsWith('end') ? 'auto' : position.left,\n right: placement.endsWith('end') ? window.innerWidth - position.left : 'auto',\n minWidth: triggerRef.current?.offsetWidth ?? 160,\n ...style,\n }\n\n return (\n <DropdownContext.Provider value={{ isOpen, close: closeOnSelect ? close : () => {}, activeIndex, setActiveIndex }}>\n <div\n ref={ref}\n className={cx('brycks-dropdown', className)}\n data-testid={testId}\n {...props}\n >\n {triggerElement}\n {isOpen && mounted && createPortal(\n <div\n ref={menuRef}\n role=\"menu\"\n className=\"brycks-dropdown__menu\"\n style={menuStyle}\n onKeyDown={handleKeyDown}\n tabIndex={-1}\n >\n {children}\n </div>,\n document.body\n )}\n </div>\n </DropdownContext.Provider>\n )\n})\n\nDropdown.displayName = 'Dropdown'\n\n// DropdownItem\nexport interface DropdownItemProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether the item is disabled */\n disabled?: boolean\n /** Icon before the label */\n icon?: ReactNode\n /** Shortcut text */\n shortcut?: string\n /** Whether the item is destructive */\n destructive?: boolean\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(function DropdownItem(\n { disabled = false, icon, shortcut, destructive = false, className, style, children, onClick, ...props },\n ref\n) {\n const { close } = useDropdownContext()\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n if (disabled) return\n onClick?.(e)\n close()\n }\n\n return (\n <div\n ref={ref}\n role=\"menuitem\"\n aria-disabled={disabled}\n tabIndex={disabled ? -1 : 0}\n className={cx(\n 'brycks-dropdown-item',\n disabled && 'brycks-dropdown-item--disabled',\n destructive && 'brycks-dropdown-item--destructive',\n className\n )}\n style={style}\n onClick={handleClick}\n {...props}\n >\n {icon && <span className=\"brycks-dropdown-item__icon\">{icon}</span>}\n <span className=\"brycks-dropdown-item__label\">{children}</span>\n {shortcut && <span className=\"brycks-dropdown-item__shortcut\">{shortcut}</span>}\n </div>\n )\n})\n\nDropdownItem.displayName = 'DropdownItem'\n\n// DropdownDivider\nexport interface DropdownDividerProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownDivider = forwardRef<HTMLDivElement, DropdownDividerProps>(function DropdownDivider(\n { className, style, ...props },\n ref\n) {\n return (\n <div\n ref={ref}\n role=\"separator\"\n className={cx('brycks-dropdown-divider', className)}\n style={style}\n {...props}\n />\n )\n})\n\nDropdownDivider.displayName = 'DropdownDivider'\n\n// DropdownLabel\nexport interface DropdownLabelProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const DropdownLabel = forwardRef<HTMLDivElement, DropdownLabelProps>(function DropdownLabel(\n { className, style, children, ...props },\n ref\n) {\n return (\n <div\n ref={ref}\n className={cx('brycks-dropdown-label', className)}\n style={style}\n {...props}\n >\n {children}\n </div>\n )\n})\n\nDropdownLabel.displayName = 'DropdownLabel'\n"],"names":["DropdownContext","createContext","useDropdownContext","context","useContext","Dropdown","forwardRef","trigger","controlledIsOpen","defaultOpen","onOpenChange","placement","offset","closeOnSelect","className","style","children","testId","props","ref","internalIsOpen","setInternalIsOpen","useState","position","setPosition","activeIndex","setActiveIndex","mounted","setMounted","triggerRef","useRef","menuRef","isOpen","useEffect","setIsOpen","useCallback","open","close","updatePosition","rect","scrollX","scrollY","top","left","handleClick","e","handleKeyDown","items","prev","triggerProps","triggerElement","cloneElement","menuStyle","jsx","jsxs","cx","createPortal","DropdownItem","disabled","icon","shortcut","destructive","onClick","DropdownDivider","DropdownLabel"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),r=require("react"),j=require("../../../utils/styles.cjs"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),r=require("react"),j=require("../../../utils/styles.cjs"),i=require("../../../design-system/primitives/sizing.cjs"),m=require("../../../design-system/tokens/spacing.cjs"),N=require("../../../design-system/tokens/motion.cjs"),C=require("../../../design-system/tokens/typography.cjs"),A=r.createContext(null);function G(){const f=r.useContext(A);if(!f)throw new Error("Menu components must be used within a Menu");return f}const H=r.forwardRef(function({activeItem:t,onChange:u,size:c="md",collapsed:s=!1,className:p,style:b,children:S,testId:g,...v},y){const[D,R]=r.useState(null),[x,o]=r.useState(-1),k=r.useRef([]),I=r.useRef(null),q=t!==void 0?t:D,l=e=>{t===void 0&&R(e),u?.(e)},d=r.useCallback(e=>{const n=k.current.indexOf(e);return n===-1?(k.current.push(e),k.current.length-1):n},[]),M=r.useCallback(e=>{const n=I.current?.querySelectorAll('[role="menuitem"]:not(:disabled)');if(!n?.length)return;const z=x>=0?x:0;switch(e.key){case"ArrowDown":e.preventDefault();const w=(z+1)%n.length;o(w),n[w]?.focus();break;case"ArrowUp":e.preventDefault();const h=(z-1+n.length)%n.length;o(h),n[h]?.focus();break;case"Home":e.preventDefault(),o(0),n[0]?.focus();break;case"End":e.preventDefault(),o(n.length-1),n[n.length-1]?.focus();break}},[x]),$={display:"flex",flexDirection:"column",gap:m.spacing[.5],padding:m.spacing[2],...b};return a.jsx(A.Provider,{value:{size:c,activeItem:q,setActiveItem:l,collapsed:s,focusedIndex:x,setFocusedIndex:o,registerItem:d},children:a.jsx("nav",{ref:e=>{I.current=e,typeof y=="function"?y(e):y&&(y.current=e)},role:"menu",className:j.cx("brycks-menu",`brycks-menu--${c}`,s&&"brycks-menu--collapsed",p),style:$,onKeyDown:M,"data-testid":g,...v,children:S})})});H.displayName="Menu";const E={sm:{height:i.componentHeights.sm,fontSize:C.fontSizes.base-1,iconSize:i.iconSizes.sm,padding:i.componentGap.lg},md:{height:i.componentHeights.md,fontSize:C.fontSizes.base,iconSize:i.iconSizes.md-2,padding:i.componentPaddingX.sm},lg:{height:i.componentHeights.lg,fontSize:C.fontSizes.md,iconSize:i.iconSizes.md,padding:m.spacing[3.5]}},F=r.forwardRef(function({value:t,icon:u,badge:c,disabled:s=!1,onClick:p,className:b,style:S,children:g,...v},y){const{size:D,activeItem:R,setActiveItem:x,collapsed:o,focusedIndex:k,setFocusedIndex:I,registerItem:q}=G(),l=R===t,d=E[D],M=q(t),$=()=>{s||(x(t),p?.(t))},e=()=>{I(M)},n={display:"flex",alignItems:"center",gap:i.componentGap.lg,width:"100%",minHeight:d.height,padding:o?d.padding:`0 ${d.padding}px`,fontSize:d.fontSize,fontWeight:l?600:500,color:s?"var(--brycks-foreground-disabled)":l?"var(--brycks-primary-default)":"var(--brycks-foreground-default)",backgroundColor:l?"var(--brycks-primary-50)":"transparent",border:"none",borderRadius:"var(--brycks-radius-md)",cursor:s?"not-allowed":"pointer",transition:`all ${N.durations.quick}ms ${N.easings.easeOut}`,textAlign:"left",outline:"none",justifyContent:o?"center":"flex-start",...S},z={width:d.iconSize,height:d.iconSize,flexShrink:0,display:"flex",alignItems:"center",justifyContent:"center"},w={marginLeft:"auto"};return a.jsxs("button",{ref:y,type:"button",role:"menuitem",disabled:s,tabIndex:k===M?0:-1,className:j.cx("brycks-menu-item",l&&"brycks-menu-item--active",b),style:n,onClick:$,onFocus:e,onMouseEnter:h=>{!s&&!l&&(h.currentTarget.style.backgroundColor="var(--brycks-background-muted)")},onMouseLeave:h=>{l||(h.currentTarget.style.backgroundColor="transparent")},title:o?String(g):void 0,...v,children:[u&&a.jsx("span",{style:z,children:u}),!o&&a.jsx("span",{style:{flex:1},children:g}),!o&&c&&a.jsx("span",{style:w,children:c})]})});F.displayName="MenuItem";const P=r.forwardRef(function({label:t,className:u,style:c,children:s,...p},b){const{collapsed:S}=G(),g={display:"flex",flexDirection:"column",gap:m.spacing[.5],...c},v={padding:`${m.spacing[3]}px ${m.spacing[3]}px ${i.componentPaddingY.sm}px ${m.spacing[3]}px`,fontSize:C.fontSizes.xs,fontWeight:600,color:"var(--brycks-foreground-muted)",textTransform:"uppercase",letterSpacing:"0.05em"};return a.jsxs("div",{ref:b,className:j.cx("brycks-menu-group",u),style:g,...p,children:[t&&!S&&a.jsx("div",{style:v,children:t}),s]})});P.displayName="MenuGroup";const T=r.forwardRef(function({className:t,style:u,...c},s){const p={height:1,backgroundColor:"var(--brycks-border-muted)",margin:`${m.spacing[2]}px 0`,...u};return a.jsx("div",{ref:s,role:"separator",className:j.cx("brycks-menu-divider",t),style:p,...c})});T.displayName="MenuDivider";exports.Menu=H;exports.MenuDivider=T;exports.MenuGroup=P;exports.MenuItem=F;
|
|
2
2
|
//# sourceMappingURL=Menu.cjs.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as d, jsxs as H } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef as C, useState as F, useRef as G, useCallback as E, createContext as K, useContext as L } from "react";
|
|
3
3
|
import { cx as w } from "../../../utils/styles.js";
|
|
4
|
+
import { iconSizes as R, componentHeights as j, componentPaddingX as O, componentGap as P, componentPaddingY as W } from "../../../design-system/primitives/sizing.js";
|
|
4
5
|
import { spacing as u } from "../../../design-system/tokens/spacing.js";
|
|
5
|
-
import { durations as
|
|
6
|
-
import { iconSizes as R, componentHeights as j, componentPaddingX as U, componentGap as P, componentPaddingY as X } from "../../../design-system/primitives/sizing.js";
|
|
6
|
+
import { durations as U, easings as X } from "../../../design-system/tokens/motion.js";
|
|
7
7
|
import { fontSizes as z } from "../../../design-system/tokens/typography.js";
|
|
8
8
|
const T = K(null);
|
|
9
9
|
function q() {
|
|
@@ -76,7 +76,7 @@ const Y = C(function({
|
|
|
76
76
|
Y.displayName = "Menu";
|
|
77
77
|
const B = {
|
|
78
78
|
sm: { height: j.sm, fontSize: z.base - 1, iconSize: R.sm, padding: P.lg },
|
|
79
|
-
md: { height: j.md, fontSize: z.base, iconSize: R.md - 2, padding:
|
|
79
|
+
md: { height: j.md, fontSize: z.base, iconSize: R.md - 2, padding: O.sm },
|
|
80
80
|
lg: { height: j.lg, fontSize: z.md, iconSize: R.md, padding: u[3.5] }
|
|
81
81
|
}, J = C(function({ value: n, icon: i, badge: s, disabled: r = !1, onClick: l, className: x, style: h, children: f, ...b }, p) {
|
|
82
82
|
const { size: D, activeItem: $, setActiveItem: g, collapsed: o, focusedIndex: k, setFocusedIndex: v, registerItem: N } = q(), c = $ === n, a = B[D], S = N(n), A = () => {
|
|
@@ -97,7 +97,7 @@ const B = {
|
|
|
97
97
|
border: "none",
|
|
98
98
|
borderRadius: "var(--brycks-radius-md)",
|
|
99
99
|
cursor: r ? "not-allowed" : "pointer",
|
|
100
|
-
transition: `all ${
|
|
100
|
+
transition: `all ${U.quick}ms ${X.easeOut}`,
|
|
101
101
|
textAlign: "left",
|
|
102
102
|
outline: "none",
|
|
103
103
|
justifyContent: o ? "center" : "flex-start",
|
|
@@ -148,7 +148,7 @@ const Q = C(function({ label: n, className: i, style: s, children: r, ...l }, x)
|
|
|
148
148
|
gap: u[0.5],
|
|
149
149
|
...s
|
|
150
150
|
}, b = {
|
|
151
|
-
padding: `${u[3]}px ${u[3]}px ${
|
|
151
|
+
padding: `${u[3]}px ${u[3]}px ${W.sm}px ${u[3]}px`,
|
|
152
152
|
fontSize: z.xs,
|
|
153
153
|
fontWeight: 600,
|
|
154
154
|
color: "var(--brycks-foreground-muted)",
|
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
2
|
-
@keyframes brycks-tab-panel-in {
|
|
3
|
-
from { opacity: 0; }
|
|
4
|
-
to { opacity: 1; }
|
|
5
|
-
}
|
|
6
|
-
`}),c.jsx("div",{ref:e,role:"tabpanel",tabIndex:0,className:m.cx("brycks-tab-panel",r),style:g,...i,children:d})]})});D.displayName="TabPanel";exports.Tab=P;exports.TabList=N;exports.TabPanel=D;exports.TabPanels=A;exports.Tabs=z;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const f=require("react/jsx-runtime"),c=require("react"),T=require("../../../utils/styles.cjs"),v=c.createContext(null);function g(){const b=c.useContext(v);if(!b)throw new Error("Tabs components must be used within a Tabs");return b}const N=c.forwardRef(function({value:e,defaultValue:t="",onChange:n,size:r="md",variant:l="line",orientation:i="horizontal",className:d,style:x,children:h,testId:k,...m},y){const[p,w]=c.useState(t),s=e??p,a=c.useCallback(u=>{e===void 0&&w(u),n?.(u)},[e,n]);return f.jsx(v.Provider,{value:{value:s,onChange:a,size:r,variant:l,orientation:i},children:f.jsx("div",{ref:y,className:T.cx("brycks-tabs",`brycks-tabs--${l}`,`brycks-tabs--${i}`,`brycks-tabs--${r}`,d),style:x,"data-testid":k,...m,children:h})})});N.displayName="Tabs";const P=c.forwardRef(function({className:e,style:t,children:n,...r},l){const{orientation:i}=g();return f.jsx("div",{ref:l,role:"tablist","aria-orientation":i,className:T.cx("brycks-tab-list",e),style:t,...r,children:n})});P.displayName="TabList";const j=c.forwardRef(function({value:e,disabled:t=!1,icon:n,className:r,style:l,children:i,...d},x){const{value:h,onChange:k,orientation:m}=g(),y=h===e,p=()=>{t||k(e)},w=s=>{if(t)return;const a=Array.from(s.currentTarget.parentElement?.querySelectorAll('[role="tab"]:not([disabled])')??[]),u=a.indexOf(s.currentTarget);let o=null;m==="horizontal"?(s.key==="ArrowRight"&&(o=(u+1)%a.length),s.key==="ArrowLeft"&&(o=(u-1+a.length)%a.length)):(s.key==="ArrowDown"&&(o=(u+1)%a.length),s.key==="ArrowUp"&&(o=(u-1+a.length)%a.length)),s.key==="Home"&&(o=0),s.key==="End"&&(o=a.length-1),o!==null&&(s.preventDefault(),a[o]?.focus(),a[o]?.click())};return f.jsxs("button",{ref:x,role:"tab",type:"button","aria-selected":y,"aria-disabled":t,disabled:t,tabIndex:y?0:-1,className:T.cx("brycks-tab",y&&"brycks-tab--selected",r),style:l,onClick:p,onKeyDown:w,...d,children:[n&&f.jsx("span",{className:"brycks-tab__icon",children:n}),i]})});j.displayName="Tab";const C=c.forwardRef(function({className:e,style:t,children:n,...r},l){return f.jsx("div",{ref:l,className:T.cx("brycks-tab-panels",e),style:t,...r,children:n})});C.displayName="TabPanels";const R=c.forwardRef(function({value:e,className:t,style:n,children:r,...l},i){const{value:d}=g();return d===e?f.jsx("div",{ref:i,role:"tabpanel",tabIndex:0,className:T.cx("brycks-tab-panel",t),style:n,...l,children:r}):null});R.displayName="TabPanel";exports.Tab=j;exports.TabList=P;exports.TabPanel=R;exports.TabPanels=C;exports.Tabs=N;
|
|
7
2
|
//# sourceMappingURL=Tabs.cjs.map
|