@brycks/core-front 0.3.4 → 0.3.6
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/data/List/List.cjs +1 -1
- package/dist/components/data/List/List.cjs.map +1 -1
- package/dist/components/data/List/List.js +1 -1
- package/dist/components/data/List/List.js.map +1 -1
- package/dist/components/data/Table/Table.cjs +1 -1
- package/dist/components/data/Table/Table.cjs.map +1 -1
- package/dist/components/data/Table/Table.js +141 -124
- package/dist/components/data/Table/Table.js.map +1 -1
- package/dist/components/data/TreeView/TreeView.cjs +1 -1
- package/dist/components/data/TreeView/TreeView.cjs.map +1 -1
- package/dist/components/data/TreeView/TreeView.js +1 -1
- package/dist/components/data/TreeView/TreeView.js.map +1 -1
- 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 +20 -19
- package/dist/components/feedback/Alert/Alert.js.map +1 -1
- package/dist/components/feedback/Drawer/Drawer.cjs +2 -2
- package/dist/components/feedback/Drawer/Drawer.cjs.map +1 -1
- package/dist/components/feedback/Drawer/Drawer.js +58 -57
- package/dist/components/feedback/Drawer/Drawer.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 +63 -61
- package/dist/components/feedback/Modal/Modal.js.map +1 -1
- package/dist/components/feedback/Popover/Popover.cjs +2 -2
- package/dist/components/feedback/Popover/Popover.cjs.map +1 -1
- package/dist/components/feedback/Popover/Popover.js +88 -79
- package/dist/components/feedback/Popover/Popover.js.map +1 -1
- package/dist/components/feedback/Toast/Toast.cjs +2 -2
- package/dist/components/feedback/Toast/Toast.cjs.map +1 -1
- package/dist/components/feedback/Toast/Toast.js +102 -93
- package/dist/components/feedback/Toast/Toast.js.map +1 -1
- package/dist/components/form/Combobox/Combobox.cjs +2 -2
- package/dist/components/form/Combobox/Combobox.cjs.map +1 -1
- package/dist/components/form/Combobox/Combobox.js +139 -139
- package/dist/components/form/Combobox/Combobox.js.map +1 -1
- package/dist/components/form/DateInput/DateInput.cjs +1 -1
- package/dist/components/form/DateInput/DateInput.cjs.map +1 -1
- package/dist/components/form/DateInput/DateInput.js +2 -2
- package/dist/components/form/DateInput/DateInput.js.map +1 -1
- package/dist/components/form/DateRangePicker/DateRangePicker.cjs +1 -1
- package/dist/components/form/DateRangePicker/DateRangePicker.cjs.map +1 -1
- package/dist/components/form/DateRangePicker/DateRangePicker.js +34 -34
- package/dist/components/form/DateRangePicker/DateRangePicker.js.map +1 -1
- package/dist/components/form/DropZone/DropZone.cjs +1 -1
- package/dist/components/form/DropZone/DropZone.cjs.map +1 -1
- package/dist/components/form/DropZone/DropZone.js +10 -10
- package/dist/components/form/DropZone/DropZone.js.map +1 -1
- package/dist/components/form/FileInput/FileInput.cjs +1 -1
- package/dist/components/form/FileInput/FileInput.cjs.map +1 -1
- package/dist/components/form/FileInput/FileInput.js +1 -1
- package/dist/components/form/FileInput/FileInput.js.map +1 -1
- package/dist/components/form/FormCard/FormCard.cjs +1 -1
- package/dist/components/form/FormCard/FormCard.cjs.map +1 -1
- package/dist/components/form/FormCard/FormCard.js +9 -9
- package/dist/components/form/FormCard/FormCard.js.map +1 -1
- package/dist/components/form/FormField/FormField.cjs +1 -1
- package/dist/components/form/FormField/FormField.cjs.map +1 -1
- package/dist/components/form/FormField/FormField.js +67 -55
- package/dist/components/form/FormField/FormField.js.map +1 -1
- package/dist/components/form/MultiSelect/MultiSelect.cjs +1 -1
- package/dist/components/form/MultiSelect/MultiSelect.cjs.map +1 -1
- package/dist/components/form/MultiSelect/MultiSelect.js +2 -3
- package/dist/components/form/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/components/form/Radio/Radio.cjs +1 -1
- package/dist/components/form/Radio/Radio.cjs.map +1 -1
- package/dist/components/form/Radio/Radio.js +20 -20
- package/dist/components/form/Radio/Radio.js.map +1 -1
- package/dist/components/form/TagInput/TagInput.cjs +1 -1
- package/dist/components/form/TagInput/TagInput.cjs.map +1 -1
- package/dist/components/form/TagInput/TagInput.js +104 -102
- package/dist/components/form/TagInput/TagInput.js.map +1 -1
- package/dist/components/form/TimePicker/TimePicker.cjs +1 -1
- package/dist/components/form/TimePicker/TimePicker.cjs.map +1 -1
- package/dist/components/form/TimePicker/TimePicker.js +29 -30
- package/dist/components/form/TimePicker/TimePicker.js.map +1 -1
- package/dist/components/layout/Collapse/Collapse.cjs.map +1 -1
- package/dist/components/layout/Collapse/Collapse.js.map +1 -1
- package/dist/components/media/Image/Image.cjs +1 -1
- package/dist/components/media/Image/Image.cjs.map +1 -1
- package/dist/components/media/Image/Image.js +9 -9
- package/dist/components/media/Image/Image.js.map +1 -1
- package/dist/components/media/ImageThumbnail/ImageThumbnail.cjs +1 -1
- package/dist/components/media/ImageThumbnail/ImageThumbnail.cjs.map +1 -1
- package/dist/components/media/ImageThumbnail/ImageThumbnail.js +6 -6
- package/dist/components/media/ImageThumbnail/ImageThumbnail.js.map +1 -1
- package/dist/components/navigation/Accordion/Accordion.cjs +1 -1
- package/dist/components/navigation/Accordion/Accordion.cjs.map +1 -1
- package/dist/components/navigation/Accordion/Accordion.js +0 -1
- package/dist/components/navigation/Accordion/Accordion.js.map +1 -1
- package/dist/components/navigation/Menu/Menu.cjs +1 -1
- package/dist/components/navigation/Menu/Menu.cjs.map +1 -1
- package/dist/components/navigation/Menu/Menu.js +87 -86
- package/dist/components/navigation/Menu/Menu.js.map +1 -1
- package/dist/components/navigation/Pagination/Pagination.cjs +1 -1
- package/dist/components/navigation/Pagination/Pagination.cjs.map +1 -1
- package/dist/components/navigation/Pagination/Pagination.js +107 -99
- package/dist/components/navigation/Pagination/Pagination.js.map +1 -1
- package/dist/components/utility/Avatar/Avatar.cjs +1 -1
- package/dist/components/utility/Avatar/Avatar.cjs.map +1 -1
- package/dist/components/utility/Avatar/Avatar.js +10 -10
- package/dist/components/utility/Avatar/Avatar.js.map +1 -1
- package/dist/components/utility/Logo/Logo.cjs +1 -1
- package/dist/components/utility/Logo/Logo.cjs.map +1 -1
- package/dist/components/utility/Logo/Logo.js +10 -10
- package/dist/components/utility/Logo/Logo.js.map +1 -1
- package/dist/design-system/themes/ThemeProvider.cjs +1 -1
- package/dist/design-system/themes/ThemeProvider.cjs.map +1 -1
- package/dist/design-system/themes/ThemeProvider.js +46 -46
- package/dist/design-system/themes/ThemeProvider.js.map +1 -1
- package/dist/design-system/tokens/zIndex.cjs +1 -1
- package/dist/design-system/tokens/zIndex.cjs.map +1 -1
- package/dist/design-system/tokens/zIndex.js +2 -0
- package/dist/design-system/tokens/zIndex.js.map +1 -1
- package/dist/feedback.d.ts +8 -0
- package/dist/form.d.ts +10 -0
- package/dist/index.d.ts +29 -0
- package/dist/navigation.d.ts +19 -0
- package/dist/styles.css +1 -1
- package/dist/tokens.d.ts +2 -0
- package/package.json +2 -1
|
@@ -1,126 +1,135 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { forwardRef as
|
|
3
|
-
import { createPortal as
|
|
4
|
-
import { cx as
|
|
5
|
-
import { useClickOutside as
|
|
6
|
-
import { usePrefersReducedMotion as
|
|
7
|
-
const ae =
|
|
8
|
-
content:
|
|
9
|
-
children:
|
|
10
|
-
placement:
|
|
11
|
-
trigger:
|
|
12
|
-
isOpen:
|
|
13
|
-
defaultOpen:
|
|
14
|
-
onOpenChange:
|
|
15
|
-
offset:
|
|
16
|
-
openDelay:
|
|
17
|
-
closeDelay:
|
|
18
|
-
closeOnOutsideClick:
|
|
19
|
-
showArrow:
|
|
1
|
+
import { jsxs as B, Fragment as N, jsx as X } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as te, useState as T, useRef as g, useId as oe, useCallback as R, useEffect as E, cloneElement as re } from "react";
|
|
3
|
+
import { createPortal as se } from "react-dom";
|
|
4
|
+
import { cx as ne } from "../../../utils/styles.js";
|
|
5
|
+
import { useClickOutside as ce } from "../../../hooks/useClickOutside.js";
|
|
6
|
+
import { usePrefersReducedMotion as ie } from "../../../hooks/useMediaQuery.js";
|
|
7
|
+
const ae = te(function({
|
|
8
|
+
content: Y,
|
|
9
|
+
children: x,
|
|
10
|
+
placement: L = "bottom",
|
|
11
|
+
trigger: r = "click",
|
|
12
|
+
isOpen: M,
|
|
13
|
+
defaultOpen: F = !1,
|
|
14
|
+
onOpenChange: C,
|
|
15
|
+
offset: a = 8,
|
|
16
|
+
openDelay: P = 200,
|
|
17
|
+
closeDelay: I = 200,
|
|
18
|
+
closeOnOutsideClick: K = !0,
|
|
19
|
+
showArrow: ue = !0,
|
|
20
20
|
className: W,
|
|
21
21
|
style: _,
|
|
22
22
|
testId: q,
|
|
23
23
|
...G
|
|
24
|
-
},
|
|
25
|
-
const [H, J] =
|
|
24
|
+
}, p) {
|
|
25
|
+
const [H, J] = T(F), [O, Q] = T({ top: 0, left: 0 }), [m, z] = T(!1), h = g(null), S = g(null), l = g(null), u = g(null), j = oe(), U = ie(), o = M ?? H, s = R(
|
|
26
26
|
(e) => {
|
|
27
|
-
|
|
27
|
+
M === void 0 && J(e), C?.(e);
|
|
28
28
|
},
|
|
29
|
-
[
|
|
30
|
-
),
|
|
31
|
-
|
|
32
|
-
}, { enabled:
|
|
33
|
-
|
|
34
|
-
if (!
|
|
29
|
+
[M, C]
|
|
30
|
+
), V = ce(() => {
|
|
31
|
+
K && r === "click" && o && s(!1);
|
|
32
|
+
}, { enabled: o && r === "click" });
|
|
33
|
+
E(() => (z(!0), () => z(!1)), []), E(() => {
|
|
34
|
+
if (!o || !h.current || !m) return;
|
|
35
35
|
const e = () => {
|
|
36
|
-
const
|
|
37
|
-
if (!
|
|
38
|
-
const t =
|
|
39
|
-
let c = 0,
|
|
40
|
-
switch (
|
|
36
|
+
const y = h.current, A = S.current;
|
|
37
|
+
if (!y || !A) return;
|
|
38
|
+
const t = y.getBoundingClientRect(), n = A.getBoundingClientRect(), d = window.scrollX, f = window.scrollY;
|
|
39
|
+
let c = 0, i = 0;
|
|
40
|
+
switch (L) {
|
|
41
41
|
case "top":
|
|
42
42
|
case "top-start":
|
|
43
43
|
case "top-end":
|
|
44
|
-
c = t.top +
|
|
44
|
+
c = t.top + f - n.height - a;
|
|
45
45
|
break;
|
|
46
46
|
case "bottom":
|
|
47
47
|
case "bottom-start":
|
|
48
48
|
case "bottom-end":
|
|
49
|
-
c = t.bottom +
|
|
49
|
+
c = t.bottom + f + a;
|
|
50
50
|
break;
|
|
51
51
|
case "left":
|
|
52
52
|
case "left-start":
|
|
53
53
|
case "left-end":
|
|
54
|
-
|
|
54
|
+
i = t.left + d - n.width - a;
|
|
55
55
|
break;
|
|
56
56
|
case "right":
|
|
57
57
|
case "right-start":
|
|
58
58
|
case "right-end":
|
|
59
|
-
|
|
59
|
+
i = t.right + d + a;
|
|
60
60
|
break;
|
|
61
61
|
}
|
|
62
|
-
switch (
|
|
62
|
+
switch (L) {
|
|
63
63
|
case "top":
|
|
64
64
|
case "bottom":
|
|
65
|
-
|
|
65
|
+
i = t.left + d + (t.width - n.width) / 2;
|
|
66
66
|
break;
|
|
67
67
|
case "top-start":
|
|
68
68
|
case "bottom-start":
|
|
69
|
-
|
|
69
|
+
i = t.left + d;
|
|
70
70
|
break;
|
|
71
71
|
case "top-end":
|
|
72
72
|
case "bottom-end":
|
|
73
|
-
|
|
73
|
+
i = t.right + d - n.width;
|
|
74
74
|
break;
|
|
75
75
|
case "left":
|
|
76
76
|
case "right":
|
|
77
|
-
c = t.top +
|
|
77
|
+
c = t.top + f + (t.height - n.height) / 2;
|
|
78
78
|
break;
|
|
79
79
|
case "left-start":
|
|
80
80
|
case "right-start":
|
|
81
|
-
c = t.top +
|
|
81
|
+
c = t.top + f;
|
|
82
82
|
break;
|
|
83
83
|
case "left-end":
|
|
84
84
|
case "right-end":
|
|
85
|
-
c = t.bottom +
|
|
85
|
+
c = t.bottom + f - n.height;
|
|
86
86
|
break;
|
|
87
87
|
}
|
|
88
|
-
|
|
88
|
+
Q({ top: c, left: i });
|
|
89
89
|
};
|
|
90
90
|
return e(), window.addEventListener("resize", e), window.addEventListener("scroll", e, !0), () => {
|
|
91
91
|
window.removeEventListener("resize", e), window.removeEventListener("scroll", e, !0);
|
|
92
92
|
};
|
|
93
|
-
}, [
|
|
93
|
+
}, [o, L, a, m]), E(() => () => {
|
|
94
94
|
l.current && clearTimeout(l.current), u.current && clearTimeout(u.current);
|
|
95
|
-
}, [])
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
95
|
+
}, []), E(() => {
|
|
96
|
+
if (!o) return;
|
|
97
|
+
const e = (y) => {
|
|
98
|
+
y.key === "Escape" && (s(!1), h.current?.focus());
|
|
99
|
+
};
|
|
100
|
+
return document.addEventListener("keydown", e), () => document.removeEventListener("keydown", e);
|
|
101
|
+
}, [o, s]);
|
|
102
|
+
const b = R(() => {
|
|
103
|
+
u.current && clearTimeout(u.current), r === "hover" ? l.current = setTimeout(() => s(!0), P) : s(!0);
|
|
104
|
+
}, [r, P, s]), v = R(() => {
|
|
105
|
+
l.current && clearTimeout(l.current), r === "hover" ? u.current = setTimeout(() => s(!1), I) : s(!1);
|
|
106
|
+
}, [r, I, s]), Z = R(() => {
|
|
107
|
+
o ? v() : b();
|
|
108
|
+
}, [o, b, v]), k = x.props, w = k.ref, $ = re(x, {
|
|
109
|
+
// Merge refs so a ref the consumer set on the trigger keeps working
|
|
110
|
+
ref: (e) => {
|
|
111
|
+
h.current = e, typeof w == "function" ? w(e) : w && (w.current = e);
|
|
112
|
+
},
|
|
113
|
+
"aria-expanded": o,
|
|
105
114
|
"aria-haspopup": "dialog",
|
|
106
|
-
"aria-controls":
|
|
107
|
-
...
|
|
115
|
+
"aria-controls": o ? j : void 0,
|
|
116
|
+
...r === "click" && {
|
|
108
117
|
onClick: (e) => {
|
|
109
|
-
|
|
118
|
+
k.onClick?.(e), Z();
|
|
110
119
|
}
|
|
111
120
|
},
|
|
112
|
-
...
|
|
121
|
+
...r === "hover" && {
|
|
113
122
|
onMouseEnter: (e) => {
|
|
114
|
-
|
|
123
|
+
k.onMouseEnter?.(e), b();
|
|
115
124
|
},
|
|
116
125
|
onMouseLeave: (e) => {
|
|
117
|
-
|
|
126
|
+
k.onMouseLeave?.(e), v();
|
|
118
127
|
}
|
|
119
128
|
}
|
|
120
|
-
}),
|
|
129
|
+
}), D = {
|
|
121
130
|
position: "absolute",
|
|
122
|
-
top:
|
|
123
|
-
left:
|
|
131
|
+
top: O.top,
|
|
132
|
+
left: O.left,
|
|
124
133
|
zIndex: "var(--brycks-z-popover)",
|
|
125
134
|
backgroundColor: "var(--brycks-background-elevated)",
|
|
126
135
|
border: "1px solid var(--brycks-border-default)",
|
|
@@ -128,37 +137,37 @@ const ae = ee(function({
|
|
|
128
137
|
boxShadow: "var(--brycks-shadow-lg)",
|
|
129
138
|
padding: "var(--brycks-space-3)",
|
|
130
139
|
minWidth: 120,
|
|
131
|
-
animation:
|
|
140
|
+
animation: U ? "none" : "brycks-popover-in 150ms ease-out",
|
|
132
141
|
..._
|
|
133
|
-
},
|
|
134
|
-
/* @__PURE__ */
|
|
142
|
+
}, ee = o && m && /* @__PURE__ */ B(N, { children: [
|
|
143
|
+
/* @__PURE__ */ X("style", { children: `
|
|
135
144
|
@keyframes brycks-popover-in {
|
|
136
145
|
from { opacity: 0; transform: scale(0.95); }
|
|
137
146
|
to { opacity: 1; transform: scale(1); }
|
|
138
147
|
}
|
|
139
148
|
` }),
|
|
140
|
-
/* @__PURE__ */
|
|
149
|
+
/* @__PURE__ */ X(
|
|
141
150
|
"div",
|
|
142
151
|
{
|
|
143
152
|
ref: (e) => {
|
|
144
|
-
|
|
153
|
+
S.current = e, V.current = e, typeof p == "function" ? p(e) : p && (p.current = e);
|
|
145
154
|
},
|
|
146
|
-
id:
|
|
147
|
-
className:
|
|
148
|
-
style:
|
|
155
|
+
id: j,
|
|
156
|
+
className: ne("brycks-popover", W),
|
|
157
|
+
style: D,
|
|
149
158
|
role: "dialog",
|
|
150
159
|
"aria-modal": "false",
|
|
151
160
|
"data-testid": q,
|
|
152
|
-
onMouseEnter:
|
|
153
|
-
onMouseLeave:
|
|
161
|
+
onMouseEnter: r === "hover" ? b : void 0,
|
|
162
|
+
onMouseLeave: r === "hover" ? v : void 0,
|
|
154
163
|
...G,
|
|
155
|
-
children:
|
|
164
|
+
children: Y
|
|
156
165
|
}
|
|
157
166
|
)
|
|
158
167
|
] });
|
|
159
|
-
return /* @__PURE__ */
|
|
160
|
-
|
|
161
|
-
m &&
|
|
168
|
+
return /* @__PURE__ */ B(N, { children: [
|
|
169
|
+
$,
|
|
170
|
+
m && se(ee, document.body)
|
|
162
171
|
] });
|
|
163
172
|
});
|
|
164
173
|
ae.displayName = "Popover";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popover.js","sources":["../../../../src/components/feedback/Popover/Popover.tsx"],"sourcesContent":["/**\n * Popover Component\n *\n * A floating content panel that appears relative to a trigger element.\n * Supports different placements and can be triggered by click or hover.\n */\n\nimport React, {\n forwardRef,\n useState,\n useEffect,\n useRef,\n useCallback,\n cloneElement,\n useId,\n type CSSProperties,\n type ReactNode,\n type ReactElement,\n type HTMLAttributes,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { cx } from '../../../utils/styles'\nimport { useClickOutside } from '../../../hooks/useClickOutside'\nimport { usePrefersReducedMotion } from '../../../hooks/useMediaQuery'\n\nexport type PopoverPlacement =\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n\nexport type PopoverTrigger = 'click' | 'hover'\n\nexport interface PopoverProps extends Omit<HTMLAttributes<HTMLDivElement>, 'content'> {\n /** Popover content */\n content: ReactNode\n /** Trigger element */\n children: ReactElement\n /** Placement relative to trigger */\n placement?: PopoverPlacement\n /** How to trigger the popover */\n trigger?: PopoverTrigger\n /** Whether the popover 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 /** Offset from trigger in pixels */\n offset?: number\n /** Delay before showing (hover trigger) */\n openDelay?: number\n /** Delay before hiding (hover trigger) */\n closeDelay?: number\n /** Whether to close on outside click */\n closeOnOutsideClick?: boolean\n /** Whether to show arrow */\n showArrow?: boolean\n /** Custom class name for content */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Popover = forwardRef<HTMLDivElement, PopoverProps>(function Popover(\n {\n content,\n children,\n placement = 'bottom',\n trigger = 'click',\n isOpen: controlledIsOpen,\n defaultOpen = false,\n onOpenChange,\n offset = 8,\n openDelay = 200,\n closeDelay = 200,\n closeOnOutsideClick = true,\n showArrow: _showArrow = true,\n className,\n style,\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 [mounted, setMounted] = useState(false)\n const triggerRef = useRef<HTMLElement>(null)\n const contentRef = useRef<HTMLDivElement>(null)\n const openTimeoutRef = useRef<ReturnType<typeof setTimeout>>(null)\n const closeTimeoutRef = useRef<ReturnType<typeof setTimeout>>(null)\n const popoverId = useId()\n const prefersReducedMotion = usePrefersReducedMotion()\n\n const isOpen = controlledIsOpen ?? internalIsOpen\n\n const setIsOpen = useCallback(\n (open: boolean) => {\n if (controlledIsOpen === undefined) {\n setInternalIsOpen(open)\n }\n onOpenChange?.(open)\n },\n [controlledIsOpen, onOpenChange]\n )\n\n // Click outside handler\n const clickOutsideRef = useClickOutside<HTMLDivElement>(() => {\n if (closeOnOutsideClick && trigger === 'click' && isOpen) {\n setIsOpen(false)\n }\n }, { enabled: isOpen && trigger === 'click' })\n\n useEffect(() => {\n setMounted(true)\n return () => setMounted(false)\n }, [])\n\n // Calculate position\n useEffect(() => {\n if (!isOpen || !triggerRef.current || !mounted) return\n\n const updatePosition = () => {\n const trigger = triggerRef.current\n const content = contentRef.current\n if (!trigger || !content) return\n\n const triggerRect = trigger.getBoundingClientRect()\n const contentRect = content.getBoundingClientRect()\n const scrollX = window.scrollX\n const scrollY = window.scrollY\n\n let top = 0\n let left = 0\n\n // Calculate base position\n switch (placement) {\n case 'top':\n case 'top-start':\n case 'top-end':\n top = triggerRect.top + scrollY - contentRect.height - offset\n break\n case 'bottom':\n case 'bottom-start':\n case 'bottom-end':\n top = triggerRect.bottom + scrollY + offset\n break\n case 'left':\n case 'left-start':\n case 'left-end':\n left = triggerRect.left + scrollX - contentRect.width - offset\n break\n case 'right':\n case 'right-start':\n case 'right-end':\n left = triggerRect.right + scrollX + offset\n break\n }\n\n // Calculate alignment\n switch (placement) {\n case 'top':\n case 'bottom':\n left = triggerRect.left + scrollX + (triggerRect.width - contentRect.width) / 2\n break\n case 'top-start':\n case 'bottom-start':\n left = triggerRect.left + scrollX\n break\n case 'top-end':\n case 'bottom-end':\n left = triggerRect.right + scrollX - contentRect.width\n break\n case 'left':\n case 'right':\n top = triggerRect.top + scrollY + (triggerRect.height - contentRect.height) / 2\n break\n case 'left-start':\n case 'right-start':\n top = triggerRect.top + scrollY\n break\n case 'left-end':\n case 'right-end':\n top = triggerRect.bottom + scrollY - contentRect.height\n break\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 // Cleanup timeouts\n useEffect(() => {\n return () => {\n if (openTimeoutRef.current) clearTimeout(openTimeoutRef.current)\n if (closeTimeoutRef.current) clearTimeout(closeTimeoutRef.current)\n }\n }, [])\n\n const handleOpen = useCallback(() => {\n if (closeTimeoutRef.current) clearTimeout(closeTimeoutRef.current)\n if (trigger === 'hover') {\n openTimeoutRef.current = setTimeout(() => setIsOpen(true), openDelay)\n } else {\n setIsOpen(true)\n }\n }, [trigger, openDelay, setIsOpen])\n\n const handleClose = useCallback(() => {\n if (openTimeoutRef.current) clearTimeout(openTimeoutRef.current)\n if (trigger === 'hover') {\n closeTimeoutRef.current = setTimeout(() => setIsOpen(false), closeDelay)\n } else {\n setIsOpen(false)\n }\n }, [trigger, closeDelay, setIsOpen])\n\n const handleToggle = useCallback(() => {\n if (isOpen) {\n handleClose()\n } else {\n handleOpen()\n }\n }, [isOpen, handleOpen, handleClose])\n\n // Clone trigger with event handlers and ARIA attributes\n const childProps = children.props as Record<string, unknown>\n const triggerElement = cloneElement(children as ReactElement<Record<string, unknown>>, {\n ref: triggerRef,\n 'aria-expanded': isOpen,\n 'aria-haspopup': 'dialog',\n 'aria-controls': isOpen ? popoverId : undefined,\n ...(trigger === 'click' && {\n onClick: (e: React.MouseEvent) => {\n (childProps.onClick as ((e: React.MouseEvent) => void) | undefined)?.(e)\n handleToggle()\n },\n }),\n ...(trigger === 'hover' && {\n onMouseEnter: (e: React.MouseEvent) => {\n (childProps.onMouseEnter as ((e: React.MouseEvent) => void) | undefined)?.(e)\n handleOpen()\n },\n onMouseLeave: (e: React.MouseEvent) => {\n (childProps.onMouseLeave as ((e: React.MouseEvent) => void) | undefined)?.(e)\n handleClose()\n },\n }),\n })\n\n const contentStyle: CSSProperties = {\n position: 'absolute',\n top: position.top,\n left: position.left,\n zIndex: 'var(--brycks-z-popover)',\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: 'var(--brycks-space-3)',\n minWidth: 120,\n animation: prefersReducedMotion ? 'none' : 'brycks-popover-in 150ms ease-out',\n ...style,\n }\n\n const popoverContent = isOpen && mounted && (\n <>\n <style>\n {`\n @keyframes brycks-popover-in {\n from { opacity: 0; transform: scale(0.95); }\n to { opacity: 1; transform: scale(1); }\n }\n `}\n </style>\n <div\n ref={(node) => {\n (contentRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n (clickOutsideRef as React.MutableRefObject<HTMLDivElement | null>).current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) ref.current = node\n }}\n id={popoverId}\n className={cx('brycks-popover', className)}\n style={contentStyle}\n role=\"dialog\"\n aria-modal=\"false\"\n data-testid={testId}\n onMouseEnter={trigger === 'hover' ? handleOpen : undefined}\n onMouseLeave={trigger === 'hover' ? handleClose : undefined}\n {...props}\n >\n {content}\n </div>\n </>\n )\n\n return (\n <>\n {triggerElement}\n {mounted && createPortal(popoverContent, document.body)}\n </>\n )\n})\n\nPopover.displayName = 'Popover'\n"],"names":["Popover","forwardRef","content","children","placement","trigger","controlledIsOpen","defaultOpen","onOpenChange","offset","openDelay","closeDelay","closeOnOutsideClick","_showArrow","className","style","testId","props","ref","internalIsOpen","setInternalIsOpen","useState","position","setPosition","mounted","setMounted","triggerRef","useRef","contentRef","openTimeoutRef","closeTimeoutRef","popoverId","useId","prefersReducedMotion","usePrefersReducedMotion","isOpen","setIsOpen","useCallback","open","clickOutsideRef","useClickOutside","useEffect","updatePosition","triggerRect","contentRect","scrollX","scrollY","top","left","handleOpen","handleClose","handleToggle","childProps","triggerElement","cloneElement","contentStyle","popoverContent","jsxs","Fragment","jsx","node","cx","createPortal"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Popover.js","sources":["../../../../src/components/feedback/Popover/Popover.tsx"],"sourcesContent":["/**\n * Popover Component\n *\n * A floating content panel that appears relative to a trigger element.\n * Supports different placements and can be triggered by click or hover.\n */\n\nimport React, {\n forwardRef,\n useState,\n useEffect,\n useRef,\n useCallback,\n cloneElement,\n useId,\n type CSSProperties,\n type ReactNode,\n type ReactElement,\n type HTMLAttributes,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { cx } from '../../../utils/styles'\nimport { useClickOutside } from '../../../hooks/useClickOutside'\nimport { usePrefersReducedMotion } from '../../../hooks/useMediaQuery'\n\nexport type PopoverPlacement =\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n\nexport type PopoverTrigger = 'click' | 'hover'\n\nexport interface PopoverProps extends Omit<HTMLAttributes<HTMLDivElement>, 'content'> {\n /** Popover content */\n content: ReactNode\n /** Trigger element */\n children: ReactElement\n /** Placement relative to trigger */\n placement?: PopoverPlacement\n /** How to trigger the popover */\n trigger?: PopoverTrigger\n /** Whether the popover 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 /** Offset from trigger in pixels */\n offset?: number\n /** Delay before showing (hover trigger) */\n openDelay?: number\n /** Delay before hiding (hover trigger) */\n closeDelay?: number\n /** Whether to close on outside click */\n closeOnOutsideClick?: boolean\n /** Whether to show arrow */\n showArrow?: boolean\n /** Custom class name for content */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Popover = forwardRef<HTMLDivElement, PopoverProps>(function Popover(\n {\n content,\n children,\n placement = 'bottom',\n trigger = 'click',\n isOpen: controlledIsOpen,\n defaultOpen = false,\n onOpenChange,\n offset = 8,\n openDelay = 200,\n closeDelay = 200,\n closeOnOutsideClick = true,\n showArrow: _showArrow = true,\n className,\n style,\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 [mounted, setMounted] = useState(false)\n const triggerRef = useRef<HTMLElement>(null)\n const contentRef = useRef<HTMLDivElement>(null)\n const openTimeoutRef = useRef<ReturnType<typeof setTimeout>>(null)\n const closeTimeoutRef = useRef<ReturnType<typeof setTimeout>>(null)\n const popoverId = useId()\n const prefersReducedMotion = usePrefersReducedMotion()\n\n const isOpen = controlledIsOpen ?? internalIsOpen\n\n const setIsOpen = useCallback(\n (open: boolean) => {\n if (controlledIsOpen === undefined) {\n setInternalIsOpen(open)\n }\n onOpenChange?.(open)\n },\n [controlledIsOpen, onOpenChange]\n )\n\n // Click outside handler\n const clickOutsideRef = useClickOutside<HTMLDivElement>(() => {\n if (closeOnOutsideClick && trigger === 'click' && isOpen) {\n setIsOpen(false)\n }\n }, { enabled: isOpen && trigger === 'click' })\n\n useEffect(() => {\n setMounted(true)\n return () => setMounted(false)\n }, [])\n\n // Calculate position\n useEffect(() => {\n if (!isOpen || !triggerRef.current || !mounted) return\n\n const updatePosition = () => {\n const trigger = triggerRef.current\n const content = contentRef.current\n if (!trigger || !content) return\n\n const triggerRect = trigger.getBoundingClientRect()\n const contentRect = content.getBoundingClientRect()\n const scrollX = window.scrollX\n const scrollY = window.scrollY\n\n let top = 0\n let left = 0\n\n // Calculate base position\n switch (placement) {\n case 'top':\n case 'top-start':\n case 'top-end':\n top = triggerRect.top + scrollY - contentRect.height - offset\n break\n case 'bottom':\n case 'bottom-start':\n case 'bottom-end':\n top = triggerRect.bottom + scrollY + offset\n break\n case 'left':\n case 'left-start':\n case 'left-end':\n left = triggerRect.left + scrollX - contentRect.width - offset\n break\n case 'right':\n case 'right-start':\n case 'right-end':\n left = triggerRect.right + scrollX + offset\n break\n }\n\n // Calculate alignment\n switch (placement) {\n case 'top':\n case 'bottom':\n left = triggerRect.left + scrollX + (triggerRect.width - contentRect.width) / 2\n break\n case 'top-start':\n case 'bottom-start':\n left = triggerRect.left + scrollX\n break\n case 'top-end':\n case 'bottom-end':\n left = triggerRect.right + scrollX - contentRect.width\n break\n case 'left':\n case 'right':\n top = triggerRect.top + scrollY + (triggerRect.height - contentRect.height) / 2\n break\n case 'left-start':\n case 'right-start':\n top = triggerRect.top + scrollY\n break\n case 'left-end':\n case 'right-end':\n top = triggerRect.bottom + scrollY - contentRect.height\n break\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 // Cleanup timeouts\n useEffect(() => {\n return () => {\n if (openTimeoutRef.current) clearTimeout(openTimeoutRef.current)\n if (closeTimeoutRef.current) clearTimeout(closeTimeoutRef.current)\n }\n }, [])\n\n // Escape dismisses the popover and returns focus to the trigger (WCAG 1.4.13)\n useEffect(() => {\n if (!isOpen) return\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n setIsOpen(false)\n triggerRef.current?.focus()\n }\n }\n\n document.addEventListener('keydown', handleKeyDown)\n return () => document.removeEventListener('keydown', handleKeyDown)\n }, [isOpen, setIsOpen])\n\n const handleOpen = useCallback(() => {\n if (closeTimeoutRef.current) clearTimeout(closeTimeoutRef.current)\n if (trigger === 'hover') {\n openTimeoutRef.current = setTimeout(() => setIsOpen(true), openDelay)\n } else {\n setIsOpen(true)\n }\n }, [trigger, openDelay, setIsOpen])\n\n const handleClose = useCallback(() => {\n if (openTimeoutRef.current) clearTimeout(openTimeoutRef.current)\n if (trigger === 'hover') {\n closeTimeoutRef.current = setTimeout(() => setIsOpen(false), closeDelay)\n } else {\n setIsOpen(false)\n }\n }, [trigger, closeDelay, setIsOpen])\n\n const handleToggle = useCallback(() => {\n if (isOpen) {\n handleClose()\n } else {\n handleOpen()\n }\n }, [isOpen, handleOpen, handleClose])\n\n // Clone trigger with event handlers and ARIA attributes\n const childProps = children.props as Record<string, unknown>\n const childRef = childProps.ref as React.Ref<HTMLElement> | undefined\n const triggerElement = cloneElement(children as ReactElement<Record<string, unknown>>, {\n // Merge refs so a ref the consumer set on the trigger keeps working\n ref: (node: HTMLElement | null) => {\n (triggerRef as React.MutableRefObject<HTMLElement | null>).current = node\n if (typeof childRef === 'function') childRef(node)\n else if (childRef) (childRef as React.MutableRefObject<HTMLElement | null>).current = node\n },\n 'aria-expanded': isOpen,\n 'aria-haspopup': 'dialog',\n 'aria-controls': isOpen ? popoverId : undefined,\n ...(trigger === 'click' && {\n onClick: (e: React.MouseEvent) => {\n (childProps.onClick as ((e: React.MouseEvent) => void) | undefined)?.(e)\n handleToggle()\n },\n }),\n ...(trigger === 'hover' && {\n onMouseEnter: (e: React.MouseEvent) => {\n (childProps.onMouseEnter as ((e: React.MouseEvent) => void) | undefined)?.(e)\n handleOpen()\n },\n onMouseLeave: (e: React.MouseEvent) => {\n (childProps.onMouseLeave as ((e: React.MouseEvent) => void) | undefined)?.(e)\n handleClose()\n },\n }),\n })\n\n const contentStyle: CSSProperties = {\n position: 'absolute',\n top: position.top,\n left: position.left,\n zIndex: 'var(--brycks-z-popover)',\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: 'var(--brycks-space-3)',\n minWidth: 120,\n animation: prefersReducedMotion ? 'none' : 'brycks-popover-in 150ms ease-out',\n ...style,\n }\n\n const popoverContent = isOpen && mounted && (\n <>\n <style>\n {`\n @keyframes brycks-popover-in {\n from { opacity: 0; transform: scale(0.95); }\n to { opacity: 1; transform: scale(1); }\n }\n `}\n </style>\n <div\n ref={(node) => {\n (contentRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n (clickOutsideRef as React.MutableRefObject<HTMLDivElement | null>).current = node\n if (typeof ref === 'function') ref(node)\n else if (ref) ref.current = node\n }}\n id={popoverId}\n className={cx('brycks-popover', className)}\n style={contentStyle}\n role=\"dialog\"\n aria-modal=\"false\"\n data-testid={testId}\n onMouseEnter={trigger === 'hover' ? handleOpen : undefined}\n onMouseLeave={trigger === 'hover' ? handleClose : undefined}\n {...props}\n >\n {content}\n </div>\n </>\n )\n\n return (\n <>\n {triggerElement}\n {mounted && createPortal(popoverContent, document.body)}\n </>\n )\n})\n\nPopover.displayName = 'Popover'\n"],"names":["Popover","forwardRef","content","children","placement","trigger","controlledIsOpen","defaultOpen","onOpenChange","offset","openDelay","closeDelay","closeOnOutsideClick","_showArrow","className","style","testId","props","ref","internalIsOpen","setInternalIsOpen","useState","position","setPosition","mounted","setMounted","triggerRef","useRef","contentRef","openTimeoutRef","closeTimeoutRef","popoverId","useId","prefersReducedMotion","usePrefersReducedMotion","isOpen","setIsOpen","useCallback","open","clickOutsideRef","useClickOutside","useEffect","updatePosition","triggerRect","contentRect","scrollX","scrollY","top","left","handleKeyDown","e","handleOpen","handleClose","handleToggle","childProps","childRef","triggerElement","cloneElement","node","contentStyle","popoverContent","jsxs","Fragment","jsx","cx","createPortal"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("react/jsx-runtime"),e=require("react"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("react/jsx-runtime"),e=require("react"),W=require("react-dom"),Y=require("../../../utils/styles.cjs"),B=require("./ToastContext.cjs"),D={info:{bg:"var(--brycks-info-muted)",border:"var(--brycks-info-soft-hover)",icon:"var(--brycks-info-default)"},success:{bg:"var(--brycks-success-muted)",border:"var(--brycks-success-soft-hover)",icon:"var(--brycks-success-default)"},warning:{bg:"var(--brycks-warning-muted)",border:"var(--brycks-warning-soft-hover)",icon:"var(--brycks-warning-default)"},error:{bg:"var(--brycks-error-muted)",border:"var(--brycks-error-soft-hover)",icon:"var(--brycks-error-default)"}};function N({intent:y}){const r={info:"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z",success:"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z",warning:"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z",error:"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"};return t.jsx("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:t.jsx("path",{d:r[y]})})}function $(){return t.jsx("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:t.jsx("path",{d:"M4 4l8 8M12 4l-8 8",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})})}const x=e.forwardRef(function({intent:r="info",title:c,description:i,isOpen:o=!0,duration:l=5e3,onClose:u,showCloseButton:g=!0,closeLabel:b="Close toast",action:m,icon:h,className:v,style:n,testId:a,onMouseEnter:d,onMouseLeave:f,...w},C){const[M,p]=e.useState(o),[E,j]=e.useState(!1),[S,T]=e.useState(!1);if(e.useEffect(()=>{if(o)p(!0),j(!1);else{j(!0);const s=setTimeout(()=>p(!1),200);return()=>clearTimeout(s)}},[o]),e.useEffect(()=>{if(!o||l===0||S)return;const s=setTimeout(()=>{u?.()},l);return()=>clearTimeout(s)},[o,l,u,S]),!M)return null;const k=D[r],z={display:"flex",alignItems:"flex-start",gap:12,padding:"12px 16px",backgroundColor:k.bg,border:`1px solid ${k.border}`,borderRadius:"var(--brycks-radius-lg)",boxShadow:"var(--brycks-shadow-lg)",maxWidth:400,animation:E?"brycks-toast-out 200ms ease-in forwards":"brycks-toast-in 200ms ease-out",...n},I={color:k.icon,flexShrink:0,marginTop:2},L={flex:1,display:"flex",flexDirection:"column",gap:4},P={fontSize:14,fontWeight:600,color:"var(--brycks-foreground-default)",lineHeight:1.4},q={fontSize:13,color:"var(--brycks-foreground-muted)",lineHeight:1.4},R={display:"flex",alignItems:"center",justifyContent:"center",width:24,height:24,borderRadius:"var(--brycks-radius-sm)",color:"var(--brycks-foreground-muted)",transition:"all 150ms ease-out",flexShrink:0,marginLeft:"auto"};return t.jsxs(t.Fragment,{children:[t.jsx("style",{children:`
|
|
2
2
|
@keyframes brycks-toast-in {
|
|
3
3
|
from { opacity: 0; transform: translateY(-8px) scale(0.95); }
|
|
4
4
|
to { opacity: 1; transform: translateY(0) scale(1); }
|
|
@@ -7,5 +7,5 @@
|
|
|
7
7
|
from { opacity: 1; transform: translateY(0) scale(1); }
|
|
8
8
|
to { opacity: 0; transform: translateY(-8px) scale(0.95); }
|
|
9
9
|
}
|
|
10
|
-
`}),t.jsxs("div",{ref:
|
|
10
|
+
`}),t.jsxs("div",{ref:C,role:r==="error"||r==="warning"?"alert":"status","aria-live":r==="error"||r==="warning"?"assertive":"polite",className:Y.cx("brycks-toast",`brycks-toast--${r}`,v),style:z,"data-testid":a,onMouseEnter:s=>{T(!0),d?.(s)},onMouseLeave:s=>{T(!1),f?.(s)},...w,children:[t.jsx("span",{style:I,children:h||t.jsx(N,{intent:r})}),t.jsxs("div",{style:L,children:[c&&t.jsx("span",{style:P,children:c}),i&&t.jsx("span",{style:q,children:i}),m&&t.jsx("div",{style:{marginTop:8},children:m})]}),g&&t.jsx("button",{type:"button",style:R,onClick:u,"aria-label":b,onMouseEnter:s=>{s.currentTarget.style.backgroundColor="var(--brycks-background-muted)"},onMouseLeave:s=>{s.currentTarget.style.backgroundColor="transparent"},children:t.jsx($,{})})]})]})});x.displayName="Toast";const H={"top-left":{top:16,left:16},"top-center":{top:16,left:"50%",transform:"translateX(-50%)"},"top-right":{top:16,right:16},"bottom-left":{bottom:16,left:16},"bottom-center":{bottom:16,left:"50%",transform:"translateX(-50%)"},"bottom-right":{bottom:16,right:16}};let V=0;function X({children:y,position:r="top-right",maxToasts:c=5}){const[i,o]=e.useState([]),[l,u]=e.useState(!1);e.useEffect(()=>{u(!0)},[]);const g=e.useCallback(n=>{const a=`toast-${++V}`;return o(d=>{const f=[...d,{id:a,props:n}];return f.length>c?f.slice(-c):f}),a},[c]),b=e.useCallback(n=>{o(a=>a.filter(d=>d.id!==n))},[]),m=e.useCallback(()=>{o([])},[]),h={position:"fixed",zIndex:"var(--brycks-z-toast)",display:"flex",flexDirection:"column",gap:8,pointerEvents:"none",...H[r]},v={pointerEvents:"auto"};return t.jsxs(B.ToastContext.Provider,{value:{toasts:i,addToast:g,removeToast:b,removeAll:m},children:[y,l&&W.createPortal(t.jsx("div",{className:"brycks-toast-container",style:h,children:i.map(({id:n,props:a})=>t.jsx("div",{style:v,children:t.jsx(x,{...a,isOpen:!0,onClose:()=>b(n)})},n))}),document.body)]})}exports.Toast=x;exports.ToastProvider=X;
|
|
11
11
|
//# sourceMappingURL=Toast.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toast.cjs","sources":["../../../../src/components/feedback/Toast/Toast.tsx"],"sourcesContent":["/**\n * Toast Component\n *\n * A notification toast with auto-dismiss and action support.\n * Includes a toast container for managing multiple toasts.\n */\n\nimport {\n forwardRef,\n useState,\n useEffect,\n useCallback,\n type CSSProperties,\n type ReactNode,\n type HTMLAttributes,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { cx } from '../../../utils/styles'\nimport { ToastContext } from './ToastContext'\nimport type { ToastItem } from './ToastContext'\n\nexport type ToastIntent = 'info' | 'success' | 'warning' | 'error'\nexport type ToastPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'\n\nexport interface ToastProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** Toast intent/type */\n intent?: ToastIntent\n /** Toast title */\n title?: ReactNode\n /** Toast description */\n description?: ReactNode\n /** Whether the toast is visible */\n isOpen?: boolean\n /** Duration in ms before auto-dismiss (0 = no auto-dismiss) */\n duration?: number\n /** Callback when toast should close */\n onClose?: () => void\n /** Whether to show close button */\n showCloseButton?: boolean\n /** Action button */\n action?: ReactNode\n /** Custom icon */\n icon?: ReactNode\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nconst intentConfig: Record<ToastIntent, { bg: string; border: string; icon: string }> = {\n info: {\n bg: 'var(--brycks-info-50)',\n border: 'var(--brycks-info-200)',\n icon: 'var(--brycks-info-default)',\n },\n success: {\n bg: 'var(--brycks-success-50)',\n border: 'var(--brycks-success-200)',\n icon: 'var(--brycks-success-default)',\n },\n warning: {\n bg: 'var(--brycks-warning-50)',\n border: 'var(--brycks-warning-200)',\n icon: 'var(--brycks-warning-default)',\n },\n error: {\n bg: 'var(--brycks-error-50)',\n border: 'var(--brycks-error-200)',\n icon: 'var(--brycks-error-default)',\n },\n}\n\nfunction ToastIcon({ intent }: { intent: ToastIntent }) {\n const paths: Record<ToastIntent, string> = {\n info: 'M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z',\n success: 'M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z',\n warning: 'M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z',\n error: 'M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z',\n }\n\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d={paths[intent]} />\n </svg>\n )\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M4 4l8 8M12 4l-8 8\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )\n}\n\nexport const Toast = forwardRef<HTMLDivElement, ToastProps>(function Toast(\n {\n intent = 'info',\n title,\n description,\n isOpen = true,\n duration = 5000,\n onClose,\n showCloseButton = true,\n action,\n icon,\n className,\n style,\n testId,\n ...props\n },\n ref\n) {\n const [isVisible, setIsVisible] = useState(isOpen)\n const [isExiting, setIsExiting] = useState(false)\n\n useEffect(() => {\n if (isOpen) {\n setIsVisible(true)\n setIsExiting(false)\n } else {\n setIsExiting(true)\n const timer = setTimeout(() => setIsVisible(false), 200)\n return () => clearTimeout(timer)\n }\n }, [isOpen])\n\n useEffect(() => {\n if (!isOpen || duration === 0) return\n\n const timer = setTimeout(() => {\n onClose?.()\n }, duration)\n\n return () => clearTimeout(timer)\n }, [isOpen, duration, onClose])\n\n if (!isVisible) return null\n\n const config = intentConfig[intent]\n\n const toastStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'flex-start',\n gap: 12,\n padding: '12px 16px',\n backgroundColor: config.bg,\n border: `1px solid ${config.border}`,\n borderRadius: 'var(--brycks-radius-lg)',\n boxShadow: 'var(--brycks-shadow-lg)',\n maxWidth: 400,\n animation: isExiting\n ? 'brycks-toast-out 200ms ease-in forwards'\n : 'brycks-toast-in 200ms ease-out',\n ...style,\n }\n\n const iconStyle: CSSProperties = {\n color: config.icon,\n flexShrink: 0,\n marginTop: 2,\n }\n\n const contentStyle: CSSProperties = {\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n }\n\n const titleStyle: CSSProperties = {\n fontSize: 14,\n fontWeight: 600,\n color: 'var(--brycks-foreground-default)',\n lineHeight: 1.4,\n }\n\n const descriptionStyle: CSSProperties = {\n fontSize: 13,\n color: 'var(--brycks-foreground-muted)',\n lineHeight: 1.4,\n }\n\n const closeButtonStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 24,\n height: 24,\n borderRadius: 'var(--brycks-radius-sm)',\n color: 'var(--brycks-foreground-muted)',\n transition: 'all 150ms ease-out',\n flexShrink: 0,\n marginLeft: 'auto',\n }\n\n return (\n <>\n <style>\n {`\n @keyframes brycks-toast-in {\n from { opacity: 0; transform: translateY(-8px) scale(0.95); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n }\n @keyframes brycks-toast-out {\n from { opacity: 1; transform: translateY(0) scale(1); }\n to { opacity: 0; transform: translateY(-8px) scale(0.95); }\n }\n `}\n </style>\n <div\n ref={ref}\n role=\"alert\"\n aria-live=\"polite\"\n className={cx('brycks-toast', `brycks-toast--${intent}`, className)}\n style={toastStyle}\n data-testid={testId}\n {...props}\n >\n <span style={iconStyle}>\n {icon || <ToastIcon intent={intent} />}\n </span>\n <div style={contentStyle}>\n {title && <span style={titleStyle}>{title}</span>}\n {description && <span style={descriptionStyle}>{description}</span>}\n {action && <div style={{ marginTop: 8 }}>{action}</div>}\n </div>\n {showCloseButton && (\n <button\n type=\"button\"\n style={closeButtonStyle}\n onClick={onClose}\n aria-label=\"Close toast\"\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n >\n <CloseIcon />\n </button>\n )}\n </div>\n </>\n )\n})\n\nToast.displayName = 'Toast'\n\n// Toast Provider\nexport interface ToastProviderProps {\n children: ReactNode\n position?: ToastPosition\n maxToasts?: number\n}\n\nconst positionStyles: Record<ToastPosition, CSSProperties> = {\n 'top-left': { top: 16, left: 16 },\n 'top-center': { top: 16, left: '50%', transform: 'translateX(-50%)' },\n 'top-right': { top: 16, right: 16 },\n 'bottom-left': { bottom: 16, left: 16 },\n 'bottom-center': { bottom: 16, left: '50%', transform: 'translateX(-50%)' },\n 'bottom-right': { bottom: 16, right: 16 },\n}\n\nlet toastCounter = 0\n\nexport function ToastProvider({\n children,\n position = 'top-right',\n maxToasts = 5,\n}: ToastProviderProps) {\n const [toasts, setToasts] = useState<ToastItem[]>([])\n const [mounted, setMounted] = useState(false)\n\n useEffect(() => {\n setMounted(true)\n }, [])\n\n const addToast = useCallback(\n (props: Omit<ToastProps, 'isOpen' | 'onClose'>) => {\n const id = `toast-${++toastCounter}`\n setToasts((prev) => {\n const newToasts = [...prev, { id, props }]\n if (newToasts.length > maxToasts) {\n return newToasts.slice(-maxToasts)\n }\n return newToasts\n })\n return id\n },\n [maxToasts]\n )\n\n const removeToast = useCallback((id: string) => {\n setToasts((prev) => prev.filter((t) => t.id !== id))\n }, [])\n\n const removeAll = useCallback(() => {\n setToasts([])\n }, [])\n\n const containerStyle: CSSProperties = {\n position: 'fixed',\n zIndex: 'var(--brycks-z-toast)' as unknown as number,\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n pointerEvents: 'none',\n ...positionStyles[position],\n }\n\n const toastWrapperStyle: CSSProperties = {\n pointerEvents: 'auto',\n }\n\n return (\n <ToastContext.Provider value={{ toasts, addToast, removeToast, removeAll }}>\n {children}\n {mounted &&\n createPortal(\n <div className=\"brycks-toast-container\" style={containerStyle}>\n {toasts.map(({ id, props }) => (\n <div key={id} style={toastWrapperStyle}>\n <Toast {...props} isOpen onClose={() => removeToast(id)} />\n </div>\n ))}\n </div>,\n document.body\n )}\n </ToastContext.Provider>\n )\n}\n"],"names":["intentConfig","ToastIcon","intent","paths","jsx","CloseIcon","Toast","forwardRef","title","description","isOpen","duration","onClose","showCloseButton","action","icon","className","style","testId","props","ref","isVisible","setIsVisible","useState","isExiting","setIsExiting","useEffect","timer","config","toastStyle","iconStyle","contentStyle","titleStyle","descriptionStyle","closeButtonStyle","jsxs","Fragment","cx","e","positionStyles","toastCounter","ToastProvider","children","position","maxToasts","toasts","setToasts","mounted","setMounted","addToast","useCallback","id","prev","newToasts","removeToast","t","removeAll","containerStyle","toastWrapperStyle","ToastContext","createPortal"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Toast.cjs","sources":["../../../../src/components/feedback/Toast/Toast.tsx"],"sourcesContent":["/**\n * Toast Component\n *\n * A notification toast with auto-dismiss and action support.\n * Includes a toast container for managing multiple toasts.\n */\n\nimport {\n forwardRef,\n useState,\n useEffect,\n useCallback,\n type CSSProperties,\n type ReactNode,\n type HTMLAttributes,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { cx } from '../../../utils/styles'\nimport { ToastContext } from './ToastContext'\nimport type { ToastItem } from './ToastContext'\n\nexport type ToastIntent = 'info' | 'success' | 'warning' | 'error'\nexport type ToastPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'\n\nexport interface ToastProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** Toast intent/type */\n intent?: ToastIntent\n /** Toast title */\n title?: ReactNode\n /** Toast description */\n description?: ReactNode\n /** Whether the toast is visible */\n isOpen?: boolean\n /** Duration in ms before auto-dismiss (0 = no auto-dismiss) */\n duration?: number\n /** Callback when toast should close */\n onClose?: () => void\n /** Whether to show close button */\n showCloseButton?: boolean\n /** Accessible label of the close button */\n closeLabel?: string\n /** Action button */\n action?: ReactNode\n /** Custom icon */\n icon?: ReactNode\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nconst intentConfig: Record<ToastIntent, { bg: string; border: string; icon: string }> = {\n info: {\n bg: 'var(--brycks-info-muted)',\n border: 'var(--brycks-info-soft-hover)',\n icon: 'var(--brycks-info-default)',\n },\n success: {\n bg: 'var(--brycks-success-muted)',\n border: 'var(--brycks-success-soft-hover)',\n icon: 'var(--brycks-success-default)',\n },\n warning: {\n bg: 'var(--brycks-warning-muted)',\n border: 'var(--brycks-warning-soft-hover)',\n icon: 'var(--brycks-warning-default)',\n },\n error: {\n bg: 'var(--brycks-error-muted)',\n border: 'var(--brycks-error-soft-hover)',\n icon: 'var(--brycks-error-default)',\n },\n}\n\nfunction ToastIcon({ intent }: { intent: ToastIntent }) {\n const paths: Record<ToastIntent, string> = {\n info: 'M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z',\n success: 'M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z',\n warning: 'M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z',\n error: 'M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z',\n }\n\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d={paths[intent]} />\n </svg>\n )\n}\n\nfunction CloseIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\">\n <path d=\"M4 4l8 8M12 4l-8 8\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )\n}\n\nexport const Toast = forwardRef<HTMLDivElement, ToastProps>(function Toast(\n {\n intent = 'info',\n title,\n description,\n isOpen = true,\n duration = 5000,\n onClose,\n showCloseButton = true,\n closeLabel = 'Close toast',\n action,\n icon,\n className,\n style,\n testId,\n onMouseEnter,\n onMouseLeave,\n ...props\n },\n ref\n) {\n const [isVisible, setIsVisible] = useState(isOpen)\n const [isExiting, setIsExiting] = useState(false)\n const [isPaused, setIsPaused] = useState(false)\n\n useEffect(() => {\n if (isOpen) {\n setIsVisible(true)\n setIsExiting(false)\n } else {\n setIsExiting(true)\n const timer = setTimeout(() => setIsVisible(false), 200)\n return () => clearTimeout(timer)\n }\n }, [isOpen])\n\n // Auto-dismiss pauses while the pointer is over the toast\n useEffect(() => {\n if (!isOpen || duration === 0 || isPaused) return\n\n const timer = setTimeout(() => {\n onClose?.()\n }, duration)\n\n return () => clearTimeout(timer)\n }, [isOpen, duration, onClose, isPaused])\n\n if (!isVisible) return null\n\n const config = intentConfig[intent]\n\n const toastStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'flex-start',\n gap: 12,\n padding: '12px 16px',\n backgroundColor: config.bg,\n border: `1px solid ${config.border}`,\n borderRadius: 'var(--brycks-radius-lg)',\n boxShadow: 'var(--brycks-shadow-lg)',\n maxWidth: 400,\n animation: isExiting\n ? 'brycks-toast-out 200ms ease-in forwards'\n : 'brycks-toast-in 200ms ease-out',\n ...style,\n }\n\n const iconStyle: CSSProperties = {\n color: config.icon,\n flexShrink: 0,\n marginTop: 2,\n }\n\n const contentStyle: CSSProperties = {\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n }\n\n const titleStyle: CSSProperties = {\n fontSize: 14,\n fontWeight: 600,\n color: 'var(--brycks-foreground-default)',\n lineHeight: 1.4,\n }\n\n const descriptionStyle: CSSProperties = {\n fontSize: 13,\n color: 'var(--brycks-foreground-muted)',\n lineHeight: 1.4,\n }\n\n const closeButtonStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 24,\n height: 24,\n borderRadius: 'var(--brycks-radius-sm)',\n color: 'var(--brycks-foreground-muted)',\n transition: 'all 150ms ease-out',\n flexShrink: 0,\n marginLeft: 'auto',\n }\n\n return (\n <>\n <style>\n {`\n @keyframes brycks-toast-in {\n from { opacity: 0; transform: translateY(-8px) scale(0.95); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n }\n @keyframes brycks-toast-out {\n from { opacity: 1; transform: translateY(0) scale(1); }\n to { opacity: 0; transform: translateY(-8px) scale(0.95); }\n }\n `}\n </style>\n <div\n ref={ref}\n role={intent === 'error' || intent === 'warning' ? 'alert' : 'status'}\n aria-live={intent === 'error' || intent === 'warning' ? 'assertive' : 'polite'}\n className={cx('brycks-toast', `brycks-toast--${intent}`, className)}\n style={toastStyle}\n data-testid={testId}\n onMouseEnter={(e) => {\n setIsPaused(true)\n onMouseEnter?.(e)\n }}\n onMouseLeave={(e) => {\n setIsPaused(false)\n onMouseLeave?.(e)\n }}\n {...props}\n >\n <span style={iconStyle}>\n {icon || <ToastIcon intent={intent} />}\n </span>\n <div style={contentStyle}>\n {title && <span style={titleStyle}>{title}</span>}\n {description && <span style={descriptionStyle}>{description}</span>}\n {action && <div style={{ marginTop: 8 }}>{action}</div>}\n </div>\n {showCloseButton && (\n <button\n type=\"button\"\n style={closeButtonStyle}\n onClick={onClose}\n aria-label={closeLabel}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n >\n <CloseIcon />\n </button>\n )}\n </div>\n </>\n )\n})\n\nToast.displayName = 'Toast'\n\n// Toast Provider\nexport interface ToastProviderProps {\n children: ReactNode\n position?: ToastPosition\n maxToasts?: number\n}\n\nconst positionStyles: Record<ToastPosition, CSSProperties> = {\n 'top-left': { top: 16, left: 16 },\n 'top-center': { top: 16, left: '50%', transform: 'translateX(-50%)' },\n 'top-right': { top: 16, right: 16 },\n 'bottom-left': { bottom: 16, left: 16 },\n 'bottom-center': { bottom: 16, left: '50%', transform: 'translateX(-50%)' },\n 'bottom-right': { bottom: 16, right: 16 },\n}\n\nlet toastCounter = 0\n\nexport function ToastProvider({\n children,\n position = 'top-right',\n maxToasts = 5,\n}: ToastProviderProps) {\n const [toasts, setToasts] = useState<ToastItem[]>([])\n const [mounted, setMounted] = useState(false)\n\n useEffect(() => {\n setMounted(true)\n }, [])\n\n const addToast = useCallback(\n (props: Omit<ToastProps, 'isOpen' | 'onClose'>) => {\n const id = `toast-${++toastCounter}`\n setToasts((prev) => {\n const newToasts = [...prev, { id, props }]\n if (newToasts.length > maxToasts) {\n return newToasts.slice(-maxToasts)\n }\n return newToasts\n })\n return id\n },\n [maxToasts]\n )\n\n const removeToast = useCallback((id: string) => {\n setToasts((prev) => prev.filter((t) => t.id !== id))\n }, [])\n\n const removeAll = useCallback(() => {\n setToasts([])\n }, [])\n\n const containerStyle: CSSProperties = {\n position: 'fixed',\n zIndex: 'var(--brycks-z-toast)' as unknown as number,\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n pointerEvents: 'none',\n ...positionStyles[position],\n }\n\n const toastWrapperStyle: CSSProperties = {\n pointerEvents: 'auto',\n }\n\n return (\n <ToastContext.Provider value={{ toasts, addToast, removeToast, removeAll }}>\n {children}\n {mounted &&\n createPortal(\n <div className=\"brycks-toast-container\" style={containerStyle}>\n {toasts.map(({ id, props }) => (\n <div key={id} style={toastWrapperStyle}>\n <Toast {...props} isOpen onClose={() => removeToast(id)} />\n </div>\n ))}\n </div>,\n document.body\n )}\n </ToastContext.Provider>\n )\n}\n"],"names":["intentConfig","ToastIcon","intent","paths","jsx","CloseIcon","Toast","forwardRef","title","description","isOpen","duration","onClose","showCloseButton","closeLabel","action","icon","className","style","testId","onMouseEnter","onMouseLeave","props","ref","isVisible","setIsVisible","useState","isExiting","setIsExiting","isPaused","setIsPaused","useEffect","timer","config","toastStyle","iconStyle","contentStyle","titleStyle","descriptionStyle","closeButtonStyle","jsxs","Fragment","cx","e","positionStyles","toastCounter","ToastProvider","children","position","maxToasts","toasts","setToasts","mounted","setMounted","addToast","useCallback","id","prev","newToasts","removeToast","t","removeAll","containerStyle","toastWrapperStyle","ToastContext","createPortal"],"mappings":"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"}
|