@mortenbrudvik/waveui 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +634 -167
- package/dist/components/data-display/InfoButton.cjs +2 -0
- package/dist/components/data-display/InfoButton.cjs.map +1 -0
- package/dist/components/data-display/InfoButton.mjs +173 -0
- package/dist/components/data-display/InfoButton.mjs.map +1 -0
- package/dist/components/data-display/InfoLabel.cjs +1 -1
- package/dist/components/data-display/InfoLabel.cjs.map +1 -1
- package/dist/components/data-display/InfoLabel.mjs +39 -96
- package/dist/components/data-display/InfoLabel.mjs.map +1 -1
- package/dist/components/input/Calendar.cjs +2 -0
- package/dist/components/input/Calendar.cjs.map +1 -0
- package/dist/components/input/Calendar.mjs +352 -0
- package/dist/components/input/Calendar.mjs.map +1 -0
- package/dist/components/input/Calendar.views.cjs +2 -0
- package/dist/components/input/Calendar.views.cjs.map +1 -0
- package/dist/components/input/Calendar.views.mjs +194 -0
- package/dist/components/input/Calendar.views.mjs.map +1 -0
- package/dist/components/input/Checkbox.cjs +1 -1
- package/dist/components/input/Checkbox.cjs.map +1 -1
- package/dist/components/input/Checkbox.mjs +91 -75
- package/dist/components/input/Checkbox.mjs.map +1 -1
- package/dist/components/input/ColorArea.cjs +1 -1
- package/dist/components/input/ColorArea.cjs.map +1 -1
- package/dist/components/input/ColorArea.mjs +18 -18
- package/dist/components/input/ColorArea.mjs.map +1 -1
- package/dist/components/input/ColorPicker.parts.cjs +1 -1
- package/dist/components/input/ColorPicker.parts.cjs.map +1 -1
- package/dist/components/input/ColorPicker.parts.mjs +1 -1
- package/dist/components/input/ColorPicker.parts.mjs.map +1 -1
- package/dist/components/input/Combobox.cjs +1 -1
- package/dist/components/input/Combobox.cjs.map +1 -1
- package/dist/components/input/Combobox.expand.cjs +1 -1
- package/dist/components/input/Combobox.expand.cjs.map +1 -1
- package/dist/components/input/Combobox.expand.mjs +20 -20
- package/dist/components/input/Combobox.expand.mjs.map +1 -1
- package/dist/components/input/Combobox.mjs +219 -138
- package/dist/components/input/Combobox.mjs.map +1 -1
- package/dist/components/input/Combobox.text.cjs +2 -0
- package/dist/components/input/Combobox.text.cjs.map +1 -0
- package/dist/components/input/Combobox.text.mjs +24 -0
- package/dist/components/input/Combobox.text.mjs.map +1 -0
- package/dist/components/input/DatePicker.cjs +1 -1
- package/dist/components/input/DatePicker.cjs.map +1 -1
- package/dist/components/input/DatePicker.mjs +205 -286
- package/dist/components/input/DatePicker.mjs.map +1 -1
- package/dist/components/input/Dropdown.cjs +1 -1
- package/dist/components/input/Dropdown.cjs.map +1 -1
- package/dist/components/input/Dropdown.mjs +137 -105
- package/dist/components/input/Dropdown.mjs.map +1 -1
- package/dist/components/input/Field.cjs +1 -1
- package/dist/components/input/Field.cjs.map +1 -1
- package/dist/components/input/Field.mjs +99 -66
- package/dist/components/input/Field.mjs.map +1 -1
- package/dist/components/input/Input.cjs +1 -1
- package/dist/components/input/Input.cjs.map +1 -1
- package/dist/components/input/Input.mjs +79 -55
- package/dist/components/input/Input.mjs.map +1 -1
- package/dist/components/input/Label.cjs +1 -1
- package/dist/components/input/Label.cjs.map +1 -1
- package/dist/components/input/Label.mjs +19 -13
- package/dist/components/input/Label.mjs.map +1 -1
- package/dist/components/input/Listbox.cjs +2 -0
- package/dist/components/input/Listbox.cjs.map +1 -0
- package/dist/components/input/Listbox.mjs +134 -0
- package/dist/components/input/Listbox.mjs.map +1 -0
- package/dist/components/input/Option.cjs +1 -1
- package/dist/components/input/Option.cjs.map +1 -1
- package/dist/components/input/Option.mjs +158 -97
- package/dist/components/input/Option.mjs.map +1 -1
- package/dist/components/input/Rating.cjs +1 -1
- package/dist/components/input/Rating.cjs.map +1 -1
- package/dist/components/input/Rating.item.cjs +2 -0
- package/dist/components/input/Rating.item.cjs.map +1 -0
- package/dist/components/input/Rating.item.mjs +255 -0
- package/dist/components/input/Rating.item.mjs.map +1 -0
- package/dist/components/input/Rating.mjs +150 -151
- package/dist/components/input/Rating.mjs.map +1 -1
- package/dist/components/input/SearchBox.cjs +1 -1
- package/dist/components/input/SearchBox.cjs.map +1 -1
- package/dist/components/input/SearchBox.mjs +146 -115
- package/dist/components/input/SearchBox.mjs.map +1 -1
- package/dist/components/input/Select.cjs +1 -1
- package/dist/components/input/Select.cjs.map +1 -1
- package/dist/components/input/Select.mjs +34 -25
- package/dist/components/input/Select.mjs.map +1 -1
- package/dist/components/input/Slider.cjs +1 -1
- package/dist/components/input/Slider.cjs.map +1 -1
- package/dist/components/input/Slider.mjs +77 -54
- package/dist/components/input/Slider.mjs.map +1 -1
- package/dist/components/input/SpinButton.cjs +1 -1
- package/dist/components/input/SpinButton.cjs.map +1 -1
- package/dist/components/input/SpinButton.mjs +198 -96
- package/dist/components/input/SpinButton.mjs.map +1 -1
- package/dist/components/input/SwatchPicker.cjs +1 -1
- package/dist/components/input/SwatchPicker.cjs.map +1 -1
- package/dist/components/input/SwatchPicker.context.cjs +2 -0
- package/dist/components/input/SwatchPicker.context.cjs.map +1 -0
- package/dist/components/input/SwatchPicker.context.mjs +35 -0
- package/dist/components/input/SwatchPicker.context.mjs.map +1 -0
- package/dist/components/input/SwatchPicker.mjs +131 -103
- package/dist/components/input/SwatchPicker.mjs.map +1 -1
- package/dist/components/input/SwatchPicker.swatches.cjs +2 -0
- package/dist/components/input/SwatchPicker.swatches.cjs.map +1 -0
- package/dist/components/input/SwatchPicker.swatches.mjs +207 -0
- package/dist/components/input/SwatchPicker.swatches.mjs.map +1 -0
- package/dist/components/input/Switch.cjs +1 -1
- package/dist/components/input/Switch.cjs.map +1 -1
- package/dist/components/input/Switch.mjs +71 -55
- package/dist/components/input/Switch.mjs.map +1 -1
- package/dist/components/input/TagPicker.cjs +1 -1
- package/dist/components/input/TagPicker.cjs.map +1 -1
- package/dist/components/input/TagPicker.mjs +154 -123
- package/dist/components/input/TagPicker.mjs.map +1 -1
- package/dist/components/input/Textarea.cjs +1 -1
- package/dist/components/input/Textarea.cjs.map +1 -1
- package/dist/components/input/Textarea.mjs +28 -21
- package/dist/components/input/Textarea.mjs.map +1 -1
- package/dist/components/input/TimePicker.cjs +1 -1
- package/dist/components/input/TimePicker.cjs.map +1 -1
- package/dist/components/input/TimePicker.mjs +204 -199
- package/dist/components/input/TimePicker.mjs.map +1 -1
- package/dist/components/input/dateUtils.cjs +1 -1
- package/dist/components/input/dateUtils.cjs.map +1 -1
- package/dist/components/input/dateUtils.mjs +114 -96
- package/dist/components/input/dateUtils.mjs.map +1 -1
- package/dist/components/input/fieldLabel.cjs +2 -0
- package/dist/components/input/fieldLabel.cjs.map +1 -0
- package/dist/components/input/fieldLabel.mjs +17 -0
- package/dist/components/input/fieldLabel.mjs.map +1 -0
- package/dist/components/input/inputLook.cjs +2 -0
- package/dist/components/input/inputLook.cjs.map +1 -0
- package/dist/components/input/inputLook.mjs +28 -0
- package/dist/components/input/inputLook.mjs.map +1 -0
- package/dist/components/input/pickerLabels.cjs +2 -0
- package/dist/components/input/pickerLabels.cjs.map +1 -0
- package/dist/components/input/pickerLabels.mjs +16 -0
- package/dist/components/input/pickerLabels.mjs.map +1 -0
- package/dist/components/input/pickerStyles.cjs +1 -1
- package/dist/components/input/pickerStyles.cjs.map +1 -1
- package/dist/components/input/pickerStyles.mjs +42 -4
- package/dist/components/input/pickerStyles.mjs.map +1 -1
- package/dist/components/input/pickerValues.cjs +2 -0
- package/dist/components/input/pickerValues.cjs.map +1 -0
- package/dist/components/input/pickerValues.mjs +24 -0
- package/dist/components/input/pickerValues.mjs.map +1 -0
- package/dist/components/navigation/Menu.popover.cjs +1 -1
- package/dist/components/navigation/Menu.popover.cjs.map +1 -1
- package/dist/components/navigation/Menu.popover.mjs +10 -10
- package/dist/components/navigation/Menu.root.cjs +1 -1
- package/dist/components/navigation/Menu.root.cjs.map +1 -1
- package/dist/components/navigation/Menu.root.mjs +10 -10
- package/dist/components/overlays/Popover.cjs +1 -1
- package/dist/components/overlays/Popover.cjs.map +1 -1
- package/dist/components/overlays/Popover.mjs +203 -208
- package/dist/components/overlays/Popover.mjs.map +1 -1
- package/dist/components/overlays/Popover.shared.cjs +1 -1
- package/dist/components/overlays/Popover.shared.cjs.map +1 -1
- package/dist/components/overlays/Popover.shared.mjs +82 -77
- package/dist/components/overlays/Popover.shared.mjs.map +1 -1
- package/dist/components/provider/WaveProvider.cjs +1 -1
- package/dist/components/provider/WaveProvider.cjs.map +1 -1
- package/dist/components/provider/WaveProvider.mjs +25 -19
- package/dist/components/provider/WaveProvider.mjs.map +1 -1
- package/dist/components/table/useGridNavigation.cjs +1 -1
- package/dist/components/table/useGridNavigation.cjs.map +1 -1
- package/dist/components/table/useGridNavigation.mjs +67 -70
- package/dist/components/table/useGridNavigation.mjs.map +1 -1
- package/dist/hooks/useActiveDescendant.cjs +2 -0
- package/dist/hooks/useActiveDescendant.cjs.map +1 -0
- package/dist/hooks/useActiveDescendant.mjs +56 -0
- package/dist/hooks/useActiveDescendant.mjs.map +1 -0
- package/dist/hooks/useFieldControl.cjs.map +1 -1
- package/dist/hooks/useFieldControl.mjs.map +1 -1
- package/dist/hooks/useListbox.cjs +1 -1
- package/dist/hooks/useListbox.cjs.map +1 -1
- package/dist/hooks/useListbox.mjs +250 -210
- package/dist/hooks/useListbox.mjs.map +1 -1
- package/dist/hooks/useRovingGrid.cjs +2 -0
- package/dist/hooks/useRovingGrid.cjs.map +1 -0
- package/dist/hooks/useRovingGrid.mjs +69 -0
- package/dist/hooks/useRovingGrid.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2901 -203
- package/dist/index.d.ts +2901 -203
- package/dist/index.mjs +107 -99
- package/dist/lib/classNames.cjs +1 -1
- package/dist/lib/classNames.cjs.map +1 -1
- package/dist/lib/classNames.mjs +111 -67
- package/dist/lib/classNames.mjs.map +1 -1
- package/dist/lib/date.cjs +2 -0
- package/dist/lib/date.cjs.map +1 -0
- package/dist/lib/date.mjs +44 -0
- package/dist/lib/date.mjs.map +1 -0
- package/dist/lib/focus.cjs +1 -1
- package/dist/lib/focus.cjs.map +1 -1
- package/dist/lib/focus.mjs +5 -2
- package/dist/lib/focus.mjs.map +1 -1
- package/dist/lib/layers.cjs.map +1 -1
- package/dist/lib/layers.mjs.map +1 -1
- package/dist/lib/styles.cjs +1 -1
- package/dist/lib/styles.cjs.map +1 -1
- package/dist/lib/styles.mjs +21 -4
- package/dist/lib/styles.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/styles/tokens.css +13 -0
|
@@ -3,42 +3,47 @@ import { cn as e } from "../../lib/cn.mjs";
|
|
|
3
3
|
import { getGlobalRegistry as t } from "../../lib/globalRegistry.mjs";
|
|
4
4
|
import { useEventCallback as n } from "../../hooks/useEventCallback.mjs";
|
|
5
5
|
import { focusElement as r, getLastTabbable as i, getTabbableElements as a } from "../../lib/focus.mjs";
|
|
6
|
-
import
|
|
7
|
-
import
|
|
6
|
+
import { getLayerTreeElements as o } from "../../lib/layers.mjs";
|
|
7
|
+
import * as s from "react";
|
|
8
|
+
import { jsx as c } from "react/jsx-runtime";
|
|
8
9
|
//#region src/components/overlays/Popover.shared.tsx
|
|
9
|
-
var
|
|
10
|
+
var l = {
|
|
10
11
|
top: "border-b border-r",
|
|
11
12
|
bottom: "border-t border-l",
|
|
12
13
|
left: "border-t border-r",
|
|
13
14
|
right: "border-b border-l"
|
|
14
|
-
},
|
|
15
|
+
}, u = ({ side: t, className: n, ref: r, ...i }) => /* @__PURE__ */ c("div", {
|
|
15
16
|
ref: r,
|
|
16
17
|
"aria-hidden": "true",
|
|
17
18
|
...i,
|
|
18
|
-
className: e("size-2 rotate-45 border-inherit bg-inherit",
|
|
19
|
+
className: e("size-2 rotate-45 border-inherit bg-inherit", l[t], n)
|
|
19
20
|
});
|
|
20
|
-
|
|
21
|
-
function
|
|
21
|
+
u.displayName = "PopoverBeak";
|
|
22
|
+
function d(e, t) {
|
|
23
|
+
let n = e?.ownerDocument.activeElement;
|
|
24
|
+
return !e || !n ? !1 : e.contains(n) ? !0 : o(t, { includeOwnElements: !1 }).some((e) => e.contains(n));
|
|
25
|
+
}
|
|
26
|
+
function f(e, t, n = a(e.ownerDocument.body)) {
|
|
22
27
|
let r = e.closest("[data-wave-portal]");
|
|
23
28
|
return n.filter((e) => !t.contains(e) && e.closest("[data-wave-portal]") === r);
|
|
24
29
|
}
|
|
25
|
-
function
|
|
26
|
-
return
|
|
30
|
+
function p(e, t, n) {
|
|
31
|
+
return f(e, t, n).find((t) => !e.contains(t) && !!(e.compareDocumentPosition(t) & Node.DOCUMENT_POSITION_FOLLOWING)) ?? null;
|
|
27
32
|
}
|
|
28
|
-
function
|
|
29
|
-
let r =
|
|
33
|
+
function m(e, t, n) {
|
|
34
|
+
let r = f(e, t, n).filter((t) => e.contains(t) || !!(e.compareDocumentPosition(t) & Node.DOCUMENT_POSITION_PRECEDING));
|
|
30
35
|
return r[r.length - 1] ?? null;
|
|
31
36
|
}
|
|
32
|
-
function
|
|
33
|
-
return !e || r.includes(e) ? e :
|
|
37
|
+
function h(e, t, n, r) {
|
|
38
|
+
return !e || r.includes(e) ? e : m(t, n, r);
|
|
34
39
|
}
|
|
35
|
-
function
|
|
40
|
+
function g(e, t) {
|
|
36
41
|
t && (e.preventDefault(), t.focus());
|
|
37
42
|
}
|
|
38
|
-
function
|
|
43
|
+
function _(e, t) {
|
|
39
44
|
return !t || t === e.body || t === e.documentElement;
|
|
40
45
|
}
|
|
41
|
-
function
|
|
46
|
+
function v(e) {
|
|
42
47
|
let t = e.ownerDocument, n = t.defaultView, { style: r } = e, i = r.getPropertyValue("visibility"), a = r.getPropertyPriority("visibility");
|
|
43
48
|
r.setProperty("visibility", "hidden", "important");
|
|
44
49
|
let o, s = () => {
|
|
@@ -46,7 +51,7 @@ function g(e) {
|
|
|
46
51
|
};
|
|
47
52
|
t.addEventListener("focusout", s, !0), n && (o = n.requestAnimationFrame(s));
|
|
48
53
|
}
|
|
49
|
-
var
|
|
54
|
+
var y = {
|
|
50
55
|
users: 0,
|
|
51
56
|
pressed: !1,
|
|
52
57
|
refocus: null,
|
|
@@ -55,128 +60,128 @@ var _ = {
|
|
|
55
60
|
epoch: 0,
|
|
56
61
|
uninstall: null
|
|
57
62
|
};
|
|
58
|
-
function
|
|
59
|
-
let n =
|
|
63
|
+
function b(e, t) {
|
|
64
|
+
let n = y.lastFocused;
|
|
60
65
|
if (!n) return !1;
|
|
61
66
|
let r = n.element.deref();
|
|
62
67
|
return r?.isConnected ? !!(e.compareDocumentPosition(r) & Node.DOCUMENT_POSITION_FOLLOWING) : n.surface?.deref() === t;
|
|
63
68
|
}
|
|
64
|
-
function
|
|
69
|
+
function x() {
|
|
65
70
|
return t("orderedSurfaces", () => /* @__PURE__ */ new Set());
|
|
66
71
|
}
|
|
67
|
-
function
|
|
72
|
+
function S() {
|
|
68
73
|
if (typeof document > "u") return () => {};
|
|
69
|
-
if (
|
|
74
|
+
if (y.users += 1, !y.uninstall) {
|
|
70
75
|
let e = document, t = e.defaultView, n = () => {
|
|
71
|
-
|
|
76
|
+
y.epoch += 1, y.pressed = !0, y.windowFocused = !1;
|
|
72
77
|
}, r = () => {
|
|
73
|
-
|
|
78
|
+
y.epoch += 1, y.windowFocused = !1;
|
|
74
79
|
}, i = () => {
|
|
75
|
-
|
|
80
|
+
y.epoch += 1, y.pressed = !1, y.windowFocused = !1;
|
|
76
81
|
let t = e.activeElement;
|
|
77
|
-
|
|
82
|
+
y.refocus = !t || _(e, t) ? null : new WeakRef(t);
|
|
78
83
|
}, a = () => {
|
|
79
|
-
|
|
84
|
+
y.epoch += 1, y.windowFocused = !0;
|
|
80
85
|
}, o = (e) => {
|
|
81
|
-
let t = e.target, n = t && [...
|
|
82
|
-
|
|
86
|
+
let t = e.target, n = t && [...x()].find((e) => e.contains(t));
|
|
87
|
+
y.lastFocused = t && {
|
|
83
88
|
element: new WeakRef(t),
|
|
84
89
|
surface: n ? new WeakRef(n) : null
|
|
85
90
|
};
|
|
86
91
|
}, s = () => {
|
|
87
|
-
|
|
92
|
+
y.epoch += 1, y.refocus = null, y.windowFocused = !1;
|
|
88
93
|
};
|
|
89
|
-
e.addEventListener("pointerdown", n, !0), e.addEventListener("mousedown", n, !0), e.addEventListener("keydown", r, !0), e.addEventListener("keyup", r, !0), e.addEventListener("focusin", o, !0), e.addEventListener("focusin", s), t?.addEventListener("blur", i), t?.addEventListener("focus", a),
|
|
90
|
-
e.removeEventListener("pointerdown", n, !0), e.removeEventListener("mousedown", n, !0), e.removeEventListener("keydown", r, !0), e.removeEventListener("keyup", r, !0), e.removeEventListener("focusin", o, !0), e.removeEventListener("focusin", s), t?.removeEventListener("blur", i), t?.removeEventListener("focus", a),
|
|
94
|
+
e.addEventListener("pointerdown", n, !0), e.addEventListener("mousedown", n, !0), e.addEventListener("keydown", r, !0), e.addEventListener("keyup", r, !0), e.addEventListener("focusin", o, !0), e.addEventListener("focusin", s), t?.addEventListener("blur", i), t?.addEventListener("focus", a), y.uninstall = () => {
|
|
95
|
+
e.removeEventListener("pointerdown", n, !0), e.removeEventListener("mousedown", n, !0), e.removeEventListener("keydown", r, !0), e.removeEventListener("keyup", r, !0), e.removeEventListener("focusin", o, !0), e.removeEventListener("focusin", s), t?.removeEventListener("blur", i), t?.removeEventListener("focus", a), y.pressed = !1, y.refocus = null, y.lastFocused = null, y.windowFocused = !1;
|
|
91
96
|
};
|
|
92
97
|
}
|
|
93
98
|
let e = !0;
|
|
94
99
|
return () => {
|
|
95
|
-
e && (e = !1,
|
|
100
|
+
e && (e = !1, y.users = Math.max(0, y.users - 1), !(y.users > 0) && (y.uninstall?.(), y.uninstall = null));
|
|
96
101
|
};
|
|
97
102
|
}
|
|
98
|
-
function
|
|
99
|
-
let l = n(c), u =
|
|
100
|
-
|
|
101
|
-
let n =
|
|
103
|
+
function C({ enabled: e, surface: t, anchorRef: o, getPreviousStop: c }) {
|
|
104
|
+
let l = n(c), u = s.useRef("anchor"), d = s.useRef(null), f = n((e) => {
|
|
105
|
+
d.current = null;
|
|
106
|
+
let n = o.current;
|
|
102
107
|
if (e.key !== "Tab" || e.defaultPrevented || !n || !t) return;
|
|
103
108
|
let r = t.ownerDocument, i = r.activeElement;
|
|
104
109
|
if (i && t.contains(i)) return;
|
|
105
|
-
let
|
|
106
|
-
if (!u || !
|
|
107
|
-
if (!i ||
|
|
108
|
-
e.shiftKey && !
|
|
109
|
-
element:
|
|
110
|
+
let s = a(r.body), c = s.filter((e) => t.contains(e)), u = c[0], f = c[c.length - 1];
|
|
111
|
+
if (!u || !f) return;
|
|
112
|
+
if (!i || _(r, i)) {
|
|
113
|
+
e.shiftKey && !y.pressed && s[s.length - 1] === f && !b(f, t) && (d.current = {
|
|
114
|
+
element: f,
|
|
110
115
|
from: "far-end",
|
|
111
|
-
epoch:
|
|
116
|
+
epoch: y.epoch
|
|
112
117
|
});
|
|
113
118
|
return;
|
|
114
119
|
}
|
|
115
|
-
let
|
|
120
|
+
let m = l(n, t, s);
|
|
116
121
|
if (e.shiftKey) {
|
|
117
|
-
|
|
122
|
+
m && i === p(n, t, s) && g(e, f);
|
|
118
123
|
return;
|
|
119
124
|
}
|
|
120
|
-
let x =
|
|
121
|
-
if (i ===
|
|
122
|
-
|
|
125
|
+
let x = h(m, n, t, s);
|
|
126
|
+
if (i === m || i === x) {
|
|
127
|
+
g(e, u);
|
|
123
128
|
return;
|
|
124
129
|
}
|
|
125
|
-
let S =
|
|
126
|
-
S !== -1 &&
|
|
130
|
+
let S = s.indexOf(i);
|
|
131
|
+
S !== -1 && s[S + 1] === u && (d.current = {
|
|
127
132
|
element: u,
|
|
128
133
|
from: "page",
|
|
129
|
-
epoch:
|
|
130
|
-
}, x &&
|
|
134
|
+
epoch: y.epoch
|
|
135
|
+
}, x && v(t));
|
|
131
136
|
});
|
|
132
|
-
return
|
|
137
|
+
return s.useEffect(() => S(), []), s.useEffect(() => {
|
|
133
138
|
if (!e || !t) return;
|
|
134
|
-
let n = t.ownerDocument,
|
|
139
|
+
let n = t.ownerDocument, s = n.defaultView;
|
|
135
140
|
u.current = "anchor";
|
|
136
|
-
let c = null,
|
|
141
|
+
let c = null, p = (e) => {
|
|
137
142
|
c = null;
|
|
138
|
-
let r =
|
|
139
|
-
|
|
140
|
-
let
|
|
141
|
-
if (
|
|
142
|
-
let
|
|
143
|
-
if (!
|
|
144
|
-
let
|
|
145
|
-
if (u.current =
|
|
146
|
-
let
|
|
147
|
-
if (!
|
|
148
|
-
let
|
|
149
|
-
C && S && S !==
|
|
143
|
+
let r = d.current;
|
|
144
|
+
d.current = null;
|
|
145
|
+
let s = e.relatedTarget;
|
|
146
|
+
if (s && t.contains(s)) return;
|
|
147
|
+
let f = e.target;
|
|
148
|
+
if (!s && f === y.refocus?.deref()) return;
|
|
149
|
+
let p = r && r.epoch === y.epoch && r.element === f ? r.from : null;
|
|
150
|
+
if (u.current = p === "page" ? "page" : "anchor", p === "page" || !_(n, s) || y.pressed || p !== "far-end" && !y.windowFocused) return;
|
|
151
|
+
let m = o.current;
|
|
152
|
+
if (!m || f !== i(t)) return;
|
|
153
|
+
let g = a(n.body), v = [...x()], b = g.filter((e) => !v.some((t) => t.contains(e))), S = b[b.length - 1], C = l(m, t, g);
|
|
154
|
+
C && S && S !== h(C, m, t, g) && (c = {
|
|
150
155
|
event: e,
|
|
151
156
|
pageEnd: S
|
|
152
157
|
});
|
|
153
158
|
}, m = (e) => {
|
|
154
159
|
let t = c;
|
|
155
160
|
c = null, t?.event === e && n.activeElement === e.target && (r(t.pageEnd) || (u.current = "page"));
|
|
156
|
-
}, g =
|
|
157
|
-
return g.add(t), t.addEventListener("focusin",
|
|
158
|
-
g.delete(t), t.removeEventListener("focusin",
|
|
161
|
+
}, g = x();
|
|
162
|
+
return g.add(t), t.addEventListener("focusin", p), s?.addEventListener("focusin", m), n.addEventListener("keydown", f), () => {
|
|
163
|
+
g.delete(t), t.removeEventListener("focusin", p), s?.removeEventListener("focusin", m), n.removeEventListener("keydown", f);
|
|
159
164
|
};
|
|
160
165
|
}, [
|
|
161
166
|
e,
|
|
162
167
|
t,
|
|
163
|
-
|
|
168
|
+
o,
|
|
164
169
|
l,
|
|
165
|
-
|
|
170
|
+
f
|
|
166
171
|
]), n((n) => {
|
|
167
|
-
let r =
|
|
172
|
+
let r = o.current;
|
|
168
173
|
if (n.key !== "Tab" || n.defaultPrevented || !e || !t || !r) return;
|
|
169
174
|
let i = t.ownerDocument.activeElement;
|
|
170
175
|
if (!i || !t.contains(i) || u.current === "page") return;
|
|
171
|
-
let
|
|
176
|
+
let s = a(t);
|
|
172
177
|
if (n.shiftKey) {
|
|
173
|
-
(i === t || i ===
|
|
178
|
+
(i === t || i === s[0]) && g(n, l(r, t));
|
|
174
179
|
return;
|
|
175
180
|
}
|
|
176
|
-
|
|
181
|
+
s.length > 0 && i !== s[s.length - 1] || g(n, p(r, t));
|
|
177
182
|
});
|
|
178
183
|
}
|
|
179
184
|
//#endregion
|
|
180
|
-
export {
|
|
185
|
+
export { u as PopoverBeak, p as getTabbableAfter, m as getTabbableThrough, d as isFocusInSurfaceTree, C as usePopoverTabOrder };
|
|
181
186
|
|
|
182
187
|
//# sourceMappingURL=Popover.shared.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popover.shared.mjs","names":["React","BEAK_BORDER","PopoverBeak","rest","cn","side","className","getScopedTabbables","getTabbableElements","anchor","scope","order","exclude","el","getTabbableAfter","getTabbableThrough","through","getEntryStop","previous","surface","focusInstead","target","event","isNothing","node","doc","hideForNativeTab","win","value","style","priority","frame","show","focusOrigin","startsAfter","last","start","getOrderedSurfaces","getGlobalRegistry","retainFocusOrigin","onPress","onKey","onWindowBlur","active","onWindowFocus","onFocusCapture","open","onFocusIn","retained","usePopoverTabOrder","getPrevious","useEventCallback","getPreviousStop","entryRef","pendingRef","onDocumentKeyDown","anchorRef","inside","first","entry","index","enabled","redirect","pending","from","entered","expected","getLastTabbable","surfaces","outside","pageEnd","onWindowFocusIn","focusElement","orderedSurfaces","tabbables"],"sources":["../../../src/components/overlays/Popover.shared.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { focusElement, getLastTabbable, getTabbableElements } from '../../lib/focus';\nimport { getGlobalRegistry } from '../../lib/globalRegistry';\nimport type { UsePopupPositionResult } from '../../hooks/usePopupPosition';\nimport { useEventCallback } from '../../hooks/useEventCallback';\n\n// Parts shared by the anchored popups of this folder: Popover.Content and TeachingPopover with a\n// `target`. Internal: not exported from the barrels.\n\n/** Final physical side of a positioned surface (the `side` result of `usePopupPosition`). */\nexport type PopoverPhysicalSide = UsePopupPositionResult['side'];\n\n/** Borders of the rotated square beak that face the anchor, per final physical side. */\nconst BEAK_BORDER: Record<PopoverPhysicalSide, string> = {\n // wave-allow-physical: the beak follows the physical side resolved by the positioning\n top: 'border-b border-r',\n // wave-allow-physical: the beak follows the physical side resolved by the positioning\n bottom: 'border-t border-l',\n // wave-allow-physical: the beak follows the physical side resolved by the positioning\n left: 'border-t border-r',\n // wave-allow-physical: the beak follows the physical side resolved by the positioning\n right: 'border-b border-l',\n};\n\n/** Properties for the internal PopoverBeak. */\nexport interface PopoverBeakProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Final physical side of the surface; the beak is drawn on the edge that faces the anchor. */\n side: PopoverPhysicalSide;\n /** Ref to the beak: pass it to `usePopupPosition` as `arrowRef`. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/**\n * The beak of an anchored surface: a rotated square, hidden from assistive technology, that\n * inherits the surface's background and border colors (so a `className` that changes them\n * restyles the beak too). Position it with the `arrowStyles` of `usePopupPosition`; its size\n * matches the `--wave-popup-arrow-size` the arrow offset is computed from.\n */\nexport const PopoverBeak = ({ side, className, ref, ...rest }: PopoverBeakProps) => (\n <div\n ref={ref}\n aria-hidden=\"true\"\n {...rest}\n className={cn('size-2 rotate-45 border-inherit bg-inherit', BEAK_BORDER[side], className)}\n />\n);\nPopoverBeak.displayName = 'PopoverBeak';\n\n/**\n * The tabbable elements of the anchor's document, in sequential focus order, that are in the same\n * portal as the anchor (or, like it, in the page) and outside `exclude`. `order` is the document's\n * tabbable elements when the caller has them already.\n */\nfunction getScopedTabbables(\n anchor: HTMLElement,\n exclude: HTMLElement,\n order: readonly HTMLElement[] = getTabbableElements(anchor.ownerDocument.body),\n): HTMLElement[] {\n const scope = anchor.closest('[data-wave-portal]');\n return order.filter((el) => !exclude.contains(el) && el.closest('[data-wave-portal]') === scope);\n}\n\n/**\n * The first tabbable element after `anchor` in document order, not inside it, in the same portal\n * as the anchor and outside `exclude`: the tab stop after a surface placed right after the anchor.\n * Pass the document's tabbable elements as `order` when you have them, to spare a second scan.\n */\nexport function getTabbableAfter(\n anchor: HTMLElement,\n exclude: HTMLElement,\n order?: readonly HTMLElement[],\n): HTMLElement | null {\n return (\n getScopedTabbables(anchor, exclude, order).find(\n (el) =>\n !anchor.contains(el) &&\n !!(anchor.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING),\n ) ?? null\n );\n}\n\n/**\n * The last tabbable element that is `anchor`, inside it or before it in document order, in the\n * same portal as the anchor and outside `exclude`: the tab stop before a surface placed right\n * after the anchor. Pass the document's tabbable elements as `order` when you have them.\n */\nexport function getTabbableThrough(\n anchor: HTMLElement,\n exclude: HTMLElement,\n order?: readonly HTMLElement[],\n): HTMLElement | null {\n const through = getScopedTabbables(anchor, exclude, order).filter(\n (el) =>\n anchor.contains(el) ||\n !!(anchor.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_PRECEDING),\n );\n return through[through.length - 1] ?? null;\n}\n\n/**\n * The tab stop that a surface placed right after `anchor` follows, given its previous stop: that\n * stop, or the tab stop at or before the anchor when the previous stop is outside the tab order\n * (a trigger with `tabIndex={-1}`). `null` when nothing in the tab order comes before the place.\n */\nfunction getEntryStop(\n previous: HTMLElement | null,\n anchor: HTMLElement,\n surface: HTMLElement,\n order: readonly HTMLElement[],\n): HTMLElement | null {\n if (!previous || order.includes(previous)) return previous;\n return getTabbableThrough(anchor, surface, order);\n}\n\nfunction focusInstead(event: { preventDefault(): void }, target: HTMLElement | null): void {\n if (!target) return;\n event.preventDefault();\n target.focus();\n}\n\nfunction isNothing(doc: Document, node: EventTarget | null): boolean {\n return !node || node === doc.body || node === doc.documentElement;\n}\n\n/**\n * Hides `surface` (`visibility: hidden`) for the native Tab in progress, so the browser moves past\n * its elements. It is shown again as soon as focus moves (the `focusout` of that Tab, before the\n * next element takes focus), or before the next frame when the Tab moves nothing.\n */\nfunction hideForNativeTab(surface: HTMLElement): void {\n const doc = surface.ownerDocument;\n const win = doc.defaultView;\n const { style } = surface;\n const value = style.getPropertyValue('visibility');\n const priority = style.getPropertyPriority('visibility');\n style.setProperty('visibility', 'hidden', 'important');\n let frame: number | undefined;\n const show = () => {\n doc.removeEventListener('focusout', show, true);\n if (frame !== undefined) win?.cancelAnimationFrame(frame);\n frame = undefined;\n // Left alone when something else changed it meanwhile.\n const ours =\n style.getPropertyValue('visibility') === 'hidden' &&\n style.getPropertyPriority('visibility') === 'important';\n if (!ours) return;\n if (value) style.setProperty('visibility', value, priority);\n else style.removeProperty('visibility');\n };\n doc.addEventListener('focusout', show, true);\n if (win) frame = win.requestAnimationFrame(show);\n}\n\n/**\n * What the document knows about focus that arrives from nothing (the body): whether it can come\n * from the browser's own controls, and where the browser starts Tab and Shift+Tab from nothing.\n * The listeners are installed while a {@link usePopoverTabOrder} is mounted, open or not, so the\n * press that opened a surface counts too. Elements are held through a `WeakRef`, so a removed\n * subtree is not kept alive while a popover is mounted: an element that is gone was removed.\n */\ninterface FocusOrigin {\n /** Mounted `usePopoverTabOrder` instances. */\n users: number;\n /**\n * A pointer press (`pointerdown`/`mousedown`) came since the window last lost focus. The user is\n * then in the page, not arriving from the browser's controls, which the window must lose focus\n * to reach: a key press does not clear it.\n */\n pressed: boolean;\n /**\n * The element that had focus when the window lost it: the browser focuses it again, from\n * nothing, when the window gets focus back. Cleared by the next `focusin`.\n */\n refocus: WeakRef<Element> | null;\n /**\n * The element that took focus last, and the ordered surface ({@link getOrderedSurfaces}) that\n * contained it then. When focus has gone from it to nothing (it was removed, hidden or blurred),\n * the browser starts sequential navigation where it is, or where it was. Recorded in the capture\n * phase, so a handler that stops a `focusin` from propagating does not hide it.\n */\n lastFocused: {\n element: WeakRef<Element>;\n surface: WeakRef<HTMLElement> | null;\n } | null;\n /**\n * The window has just got focus back: no element took focus since, and no key or pointer press\n * reached the page. Sequential navigation from the browser's own controls gives the window focus\n * right before the element it reaches; focus that arrives from nothing without it comes from the\n * page (a focus restore after the focused element was removed, a script).\n */\n windowFocused: boolean;\n /**\n * Counts the events that end a key press's focus change: key presses and releases, pointer\n * presses, `focusin` and the window's blur and focus. An entry the `keydown` of a Tab expects\n * applies only to the `focusin` of that same Tab.\n */\n epoch: number;\n /** Removes the listeners; `null` while none are installed. */\n uninstall: (() => void) | null;\n}\n\n/**\n * One per copy of the library, not in the global registry: every field is derived from document\n * and window events, and only this copy's hooks read it, each of which keeps this copy's\n * listeners installed from its mount on. A second copy (ESM and CJS side by side) installs its own\n * listeners and derives the same state; `epoch` is compared only within the copy that set it.\n */\nconst focusOrigin: FocusOrigin = {\n users: 0,\n pressed: false,\n refocus: null,\n lastFocused: null,\n windowFocused: false,\n epoch: 0,\n uninstall: null,\n};\n\n/**\n * Whether sequential navigation from nothing starts after `el`, the last tabbable element of\n * `surface`: at the element that took focus last, when that comes after `el` in the document or\n * was removed from `surface` (it may have been anywhere in it, after `el` too). An element removed\n * elsewhere does not count: from a place after the surface (a dismissed toast in a later portal),\n * Shift+Tab lands on `el` just as from the document's end, and from a place before it, it does not\n * land on `el`.\n */\nfunction startsAfter(el: HTMLElement, surface: HTMLElement): boolean {\n const last = focusOrigin.lastFocused;\n if (!last) return false;\n const start = last.element.deref();\n if (start?.isConnected) {\n return !!(el.compareDocumentPosition(start) & Node.DOCUMENT_POSITION_FOLLOWING);\n }\n return last.surface?.deref() === surface;\n}\n\n/**\n * The surfaces whose keyboard order a {@link usePopoverTabOrder} manages right now. Their content\n * takes its place after its anchor, not at the end of the document where its portal is, so none\n * of it is \"the last element of the page\". Kept in `getGlobalRegistry('orderedSurfaces')`, so an\n * app that loads both the ESM and the CJS copy of the library excludes the surfaces of both.\n */\nfunction getOrderedSurfaces(): Set<HTMLElement> {\n return getGlobalRegistry('orderedSurfaces', () => new Set<HTMLElement>());\n}\n\nfunction retainFocusOrigin(): () => void {\n if (typeof document === 'undefined') return () => {};\n focusOrigin.users += 1;\n if (!focusOrigin.uninstall) {\n const doc = document;\n const win = doc.defaultView;\n const onPress = () => {\n focusOrigin.epoch += 1;\n focusOrigin.pressed = true;\n focusOrigin.windowFocused = false;\n };\n const onKey = () => {\n focusOrigin.epoch += 1;\n focusOrigin.windowFocused = false;\n };\n // Not capture listeners: they hear only the window's own blur and focus (an element's do not\n // bubble).\n const onWindowBlur = () => {\n focusOrigin.epoch += 1;\n focusOrigin.pressed = false;\n focusOrigin.windowFocused = false;\n const active = doc.activeElement;\n focusOrigin.refocus = !active || isNothing(doc, active) ? null : new WeakRef(active);\n };\n const onWindowFocus = () => {\n focusOrigin.epoch += 1;\n focusOrigin.windowFocused = true;\n };\n // Capture, like the presses and keys, so a handler that stops a `focusin` from propagating\n // does not hide where focus went. Only the `keydown` of a later Tab reads it: recording it\n // before the surfaces' own `focusin` listeners run changes nothing for them.\n const onFocusCapture = (event: FocusEvent) => {\n const target = event.target as Element | null;\n const surface = target && [...getOrderedSurfaces()].find((open) => open.contains(target));\n focusOrigin.lastFocused = target && {\n element: new WeakRef(target),\n surface: surface ? new WeakRef(surface) : null,\n };\n };\n // Bubbling to the document, after the surfaces' own `focusin` listeners have read the state.\n const onFocusIn = () => {\n focusOrigin.epoch += 1;\n focusOrigin.refocus = null;\n focusOrigin.windowFocused = false;\n };\n // Capture: a handler that stops a press or a key from propagating must not hide it.\n doc.addEventListener('pointerdown', onPress, true);\n doc.addEventListener('mousedown', onPress, true);\n doc.addEventListener('keydown', onKey, true);\n doc.addEventListener('keyup', onKey, true);\n doc.addEventListener('focusin', onFocusCapture, true);\n doc.addEventListener('focusin', onFocusIn);\n win?.addEventListener('blur', onWindowBlur);\n win?.addEventListener('focus', onWindowFocus);\n focusOrigin.uninstall = () => {\n doc.removeEventListener('pointerdown', onPress, true);\n doc.removeEventListener('mousedown', onPress, true);\n doc.removeEventListener('keydown', onKey, true);\n doc.removeEventListener('keyup', onKey, true);\n doc.removeEventListener('focusin', onFocusCapture, true);\n doc.removeEventListener('focusin', onFocusIn);\n win?.removeEventListener('blur', onWindowBlur);\n win?.removeEventListener('focus', onWindowFocus);\n focusOrigin.pressed = false;\n focusOrigin.refocus = null;\n focusOrigin.lastFocused = null;\n focusOrigin.windowFocused = false;\n };\n }\n let retained = true;\n return () => {\n if (!retained) return;\n retained = false;\n focusOrigin.users = Math.max(0, focusOrigin.users - 1);\n if (focusOrigin.users > 0) return;\n focusOrigin.uninstall?.();\n focusOrigin.uninstall = null;\n };\n}\n\n/** Options of {@link usePopoverTabOrder}. */\nexport interface PopoverTabOrderOptions {\n /** Whether the surface is shown next to its anchor; the listeners exist only while `true`. */\n enabled: boolean;\n /** The portaled surface, held in state through its callback ref. */\n surface: HTMLElement | null;\n /** The anchor: the surface takes its place in the keyboard order right after it. */\n anchorRef: React.RefObject<HTMLElement | null>;\n /**\n * The element before the surface's place: Tab from it enters the surface, and Shift+Tab from\n * the surface's first element returns to it. When it is outside the tab order (a trigger with\n * `tabIndex={-1}`), Tab from the tab stop at or before the anchor enters the surface too; `null`\n * when nothing comes before the place. `order`, when given, is the document's tabbable elements.\n */\n getPreviousStop: (\n anchor: HTMLElement,\n surface: HTMLElement,\n order?: readonly HTMLElement[],\n ) => HTMLElement | null;\n}\n\n/**\n * Keyboard order of a surface portaled to the end of the document, as if it were rendered right\n * after its anchor (the order of 0.4's inline content). Returns the surface's `onKeyDown`; while\n * `enabled`, a document `keydown` listener and `focusin` listeners on the surface and the window\n * do the rest. While mounted, shared document listeners record pointer presses, key presses, the\n * element that took focus last and the window's blur and focus.\n *\n * - Tab from the previous stop enters the surface at its first tabbable element (so does Tab\n * from the tab stop at or before the anchor when the previous stop is outside the tab order),\n * and Shift+Tab from the tab stop after the anchor enters it at its last one.\n * - Tab past the surface's last element continues after the anchor; Shift+Tab from its first\n * element (or from the surface itself) returns to the previous stop.\n * - The surface is not visited a second time where its portal is. Tab from the element before\n * the portal moves past the surface (it is hidden for that one Tab), to what follows it or out\n * of the page. Shift+Tab from the browser's own controls (the window gets focus back just before\n * it), or from nothing without a pointer press, lands on the surface's last element as the\n * document's last one: focus goes to the last element of the page instead (outside every open\n * surface: another open popover's content has its own place after its anchor), unless that is\n * the tab stop before the surface's place (the surface then ends the order). Focus moves there\n * once the entry's `focusin` has reached the window, so the entered element's focus handlers\n * run before its blur handlers; a handler that stops that `focusin` from propagating (an\n * `onFocus` in the content that calls `stopPropagation()`) leaves focus on the surface's last\n * element, as an entry at its place after the anchor, with no trap and no Tab cycle. Shift+Tab\n * from nothing does not start at the document's end when the element that had focus comes after\n * the surface's last element or was removed from the surface (a control of the surface that hid\n * or removed itself): the browser starts where it is, or was. An element removed elsewhere (a\n * dismissed toast portaled after the surface) keeps the rule: from its place, too, Shift+Tab\n * lands on the surface's last element. A lap in either direction visits every element once, and\n * there is no Tab cycle.\n * - With no tab stop before its place (nothing in the tab order at or before the anchor), Tab\n * reaches the surface where its portal is, from the element before the portal, and it follows\n * the document order from there. When the previous stop is missing too, Shift+Tab reaches it\n * there as well: its first element leads to the element before the portal, so neither Shift+Tab\n * from the tab stop after the anchor nor from outside the page is moved to its place.\n * - Every other entry keeps the place after the anchor: a click, Shift+Tab from a pressed point,\n * focus restored from nothing (a layer opened from the surface's last element closed), a\n * script, focus that returns to an element as the window gets focus back, and focus the content\n * takes as it mounts (`autoFocus`, before the listeners exist).\n * - Content that the Tab from the page still reaches (it shows itself again before the browser\n * moves focus) follows the document order from there, so Tab past it leaves the page rather\n * than jumping back to the anchor.\n *\n * Every Tab outside the surface costs one scan of the document's tabbable elements. The listeners\n * skip events whose default is already prevented; React handlers (a trigger's own `onKeyDown`,\n * the returned one) run before them and before a dialog's focus trap.\n */\nexport function usePopoverTabOrder({\n enabled,\n surface,\n anchorRef,\n getPreviousStop,\n}: PopoverTabOrderOptions): React.KeyboardEventHandler<HTMLElement> {\n const getPrevious = useEventCallback(getPreviousStop);\n /** How focus last entered the surface: at its place after the anchor, or at the portal's. */\n const entryRef = React.useRef<'anchor' | 'page'>('anchor');\n /**\n * Where the Tab being pressed enters the surface natively: at `element`, from the page (had it\n * not moved past the surface) or, Shift+Tab from nothing, at the document's far end. Valid in\n * the `focusin` of that Tab only (same `epoch`).\n */\n const pendingRef = React.useRef<{\n element: HTMLElement;\n from: 'page' | 'far-end';\n epoch: number;\n } | null>(null);\n\n const onDocumentKeyDown = useEventCallback((event: KeyboardEvent) => {\n pendingRef.current = null;\n const anchor = anchorRef.current;\n if (event.key !== 'Tab' || event.defaultPrevented || !anchor || !surface) return;\n const doc = surface.ownerDocument;\n const active = doc.activeElement as HTMLElement | null;\n if (active && surface.contains(active)) return;\n // One scan of the document; everything below is derived from it.\n const order = getTabbableElements(doc.body);\n const inside = order.filter((el) => surface.contains(el));\n const first = inside[0];\n const last = inside[inside.length - 1];\n if (!first || !last) return;\n if (!active || isNothing(doc, active)) {\n // With no pointer press to start from, Shift+Tab from nothing reaches the document's last\n // element, unless the browser starts after it: where the element that had focus is, or was\n // (a control of the surface that removed or hid itself).\n if (\n event.shiftKey &&\n !focusOrigin.pressed &&\n order[order.length - 1] === last &&\n !startsAfter(last, surface)\n ) {\n pendingRef.current = { element: last, from: 'far-end', epoch: focusOrigin.epoch };\n }\n return;\n }\n const previous = getPrevious(anchor, surface, order);\n if (event.shiftKey) {\n // Without a previous stop, Shift+Tab from the surface's first element follows the document\n // order: entering the surface here would form a cycle.\n if (previous && active === getTabbableAfter(anchor, surface, order)) {\n focusInstead(event, last);\n }\n return;\n }\n const entry = getEntryStop(previous, anchor, surface, order);\n if (active === previous || active === entry) {\n focusInstead(event, first);\n return;\n }\n const index = order.indexOf(active);\n if (index === -1 || order[index + 1] !== first) return;\n pendingRef.current = { element: first, from: 'page', epoch: focusOrigin.epoch };\n // The browser would enter the surface where its portal is. When a tab stop comes before its\n // place, the surface was visited after the anchor: move past it. Otherwise this is its entry.\n if (entry) hideForNativeTab(surface);\n });\n\n // Installed while mounted, not only while enabled: the press that opens the surface counts.\n React.useEffect(() => retainFocusOrigin(), []);\n\n React.useEffect(() => {\n if (!enabled || !surface) return;\n const doc = surface.ownerDocument;\n const win = doc.defaultView;\n // A new surface, or one shown again: focus it took as it mounted (before this listener) was\n // not a native entry from the page, and an earlier entry no longer applies.\n entryRef.current = 'anchor';\n /**\n * An entry that goes on to the last element of the page. Focus moves there once the entry's\n * `focusin` has reached the window, after React (which listens where the portal is, above the\n * surface) has handled it: the entered element's focus handlers run before its blur handlers,\n * so a Tooltip on it does not stay open. Not in a microtask: a browser runs microtasks between\n * the listeners of its own events.\n */\n let redirect: { event: FocusEvent; pageEnd: HTMLElement } | null = null;\n const onFocusIn = (event: FocusEvent) => {\n redirect = null;\n const pending = pendingRef.current;\n pendingRef.current = null;\n const from = event.relatedTarget as Node | null;\n if (from && surface.contains(from)) return;\n const entered = event.target;\n // The window got focus back: focus returns to where it was, in the order it had there.\n if (!from && entered === focusOrigin.refocus?.deref()) return;\n const expected =\n pending && pending.epoch === focusOrigin.epoch && pending.element === entered\n ? pending.from\n : null;\n // The Tab from the page reached the surface after all: follow the document order from here,\n // so Tab past it leaves the page instead of forming a cycle through the anchor.\n entryRef.current = expected === 'page' ? 'page' : 'anchor';\n if (expected === 'page' || !isNothing(doc, from) || focusOrigin.pressed) return;\n // Shift+Tab from the browser's own controls, or from nothing: the document's last element.\n if (expected !== 'far-end' && !focusOrigin.windowFocused) return;\n const anchor = anchorRef.current;\n if (!anchor || entered !== getLastTabbable(surface)) return;\n const order = getTabbableElements(doc.body);\n const surfaces = [...getOrderedSurfaces()];\n const outside = order.filter((el) => !surfaces.some((open) => open.contains(el)));\n const pageEnd = outside[outside.length - 1];\n const previous = getPrevious(anchor, surface, order);\n // The surface ends the order when the tab stop before its place is the page's last element.\n // Without a previous stop it keeps the place of its portal, as Shift+Tab from it does.\n if (!previous || !pageEnd || pageEnd === getEntryStop(previous, anchor, surface, order)) {\n return;\n }\n redirect = { event, pageEnd };\n };\n const onWindowFocusIn = (event: FocusEvent) => {\n const pending = redirect;\n redirect = null;\n // Left alone when a handler of the entry has moved focus already.\n if (pending?.event !== event || doc.activeElement !== event.target) return;\n if (!focusElement(pending.pageEnd)) entryRef.current = 'page';\n };\n const orderedSurfaces = getOrderedSurfaces();\n orderedSurfaces.add(surface);\n surface.addEventListener('focusin', onFocusIn);\n win?.addEventListener('focusin', onWindowFocusIn);\n doc.addEventListener('keydown', onDocumentKeyDown);\n return () => {\n orderedSurfaces.delete(surface);\n surface.removeEventListener('focusin', onFocusIn);\n win?.removeEventListener('focusin', onWindowFocusIn);\n doc.removeEventListener('keydown', onDocumentKeyDown);\n };\n }, [enabled, surface, anchorRef, getPrevious, onDocumentKeyDown]);\n\n return useEventCallback((event: React.KeyboardEvent<HTMLElement>) => {\n const anchor = anchorRef.current;\n if (event.key !== 'Tab' || event.defaultPrevented || !enabled || !surface || !anchor) return;\n const active = surface.ownerDocument.activeElement;\n // Events from nested portaled layers bubble here through React: only handle our own content.\n if (!active || !surface.contains(active) || entryRef.current === 'page') return;\n const tabbables = getTabbableElements(surface);\n if (event.shiftKey) {\n if (active === surface || active === tabbables[0]) {\n focusInstead(event, getPrevious(anchor, surface));\n }\n return;\n }\n if (tabbables.length > 0 && active !== tabbables[tabbables.length - 1]) return;\n focusInstead(event, getTabbableAfter(anchor, surface));\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Popover.shared.mjs","names":["React","BEAK_BORDER","PopoverBeak","rest","cn","side","className","isFocusInSurfaceTree","active","surface","getLayerTreeElements","layerId","el","getScopedTabbables","getTabbableElements","anchor","scope","order","exclude","getTabbableAfter","getTabbableThrough","through","getEntryStop","previous","focusInstead","target","event","isNothing","node","doc","hideForNativeTab","win","value","style","priority","frame","show","focusOrigin","startsAfter","last","start","getOrderedSurfaces","getGlobalRegistry","retainFocusOrigin","onPress","onKey","onWindowBlur","onWindowFocus","onFocusCapture","open","onFocusIn","retained","usePopoverTabOrder","getPrevious","useEventCallback","getPreviousStop","entryRef","pendingRef","onDocumentKeyDown","anchorRef","inside","first","entry","index","enabled","redirect","pending","from","entered","expected","getLastTabbable","surfaces","outside","pageEnd","onWindowFocusIn","focusElement","orderedSurfaces","tabbables"],"sources":["../../../src/components/overlays/Popover.shared.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { focusElement, getLastTabbable, getTabbableElements } from '../../lib/focus';\nimport { getGlobalRegistry } from '../../lib/globalRegistry';\nimport { getLayerTreeElements } from '../../lib/layers';\nimport type { UsePopupPositionResult } from '../../hooks/usePopupPosition';\nimport { useEventCallback } from '../../hooks/useEventCallback';\n\n// Parts shared by the anchored popups: Popover.Content and TeachingPopover with a `target`, and\n// InfoButton's note (data-display). Internal: not exported from the barrels.\n\n/** Final physical side of a positioned surface (the `side` result of `usePopupPosition`). */\nexport type PopoverPhysicalSide = UsePopupPositionResult['side'];\n\n/** Borders of the rotated square beak that face the anchor, per final physical side. */\nconst BEAK_BORDER: Record<PopoverPhysicalSide, string> = {\n // wave-allow-physical: the beak follows the physical side resolved by the positioning\n top: 'border-b border-r',\n // wave-allow-physical: the beak follows the physical side resolved by the positioning\n bottom: 'border-t border-l',\n // wave-allow-physical: the beak follows the physical side resolved by the positioning\n left: 'border-t border-r',\n // wave-allow-physical: the beak follows the physical side resolved by the positioning\n right: 'border-b border-l',\n};\n\n/** Properties for the internal PopoverBeak. */\nexport interface PopoverBeakProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Final physical side of the surface; the beak is drawn on the edge that faces the anchor. */\n side: PopoverPhysicalSide;\n /** Ref to the beak: pass it to `usePopupPosition` as `arrowRef`. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/**\n * The beak of an anchored surface: a rotated square, hidden from assistive technology, that\n * inherits the surface's background and border colors (so a `className` that changes them\n * restyles the beak too). Position it with the `arrowStyles` of `usePopupPosition`; its size\n * matches the `--wave-popup-arrow-size` the arrow offset is computed from.\n */\nexport const PopoverBeak = ({ side, className, ref, ...rest }: PopoverBeakProps) => (\n <div\n ref={ref}\n aria-hidden=\"true\"\n {...rest}\n className={cn('size-2 rotate-45 border-inherit bg-inherit', BEAK_BORDER[side], className)}\n />\n);\nPopoverBeak.displayName = 'PopoverBeak';\n\n/**\n * Whether focus is inside `surface` or in a layer opened from it (a menu or popover of its\n * content, whose portal lives elsewhere): what keeps a hover-opened surface open (Phase 2 D18).\n * Focus on the trigger does not count, although the trigger belongs to the dismiss layer\n * `layerId`. Popover.Content and InfoButton's note pass it to their hover intent's `canClose`.\n */\nexport function isFocusInSurfaceTree(surface: HTMLElement | null, layerId: string): boolean {\n const active = surface?.ownerDocument.activeElement;\n if (!surface || !active) return false;\n if (surface.contains(active)) return true;\n return getLayerTreeElements(layerId, { includeOwnElements: false }).some((el) =>\n el.contains(active),\n );\n}\n\n/**\n * The tabbable elements of the anchor's document, in sequential focus order, that are in the same\n * portal as the anchor (or, like it, in the page) and outside `exclude`. `order` is the document's\n * tabbable elements when the caller has them already.\n */\nfunction getScopedTabbables(\n anchor: HTMLElement,\n exclude: HTMLElement,\n order: readonly HTMLElement[] = getTabbableElements(anchor.ownerDocument.body),\n): HTMLElement[] {\n const scope = anchor.closest('[data-wave-portal]');\n return order.filter((el) => !exclude.contains(el) && el.closest('[data-wave-portal]') === scope);\n}\n\n/**\n * The first tabbable element after `anchor` in document order, not inside it, in the same portal\n * as the anchor and outside `exclude`: the tab stop after a surface placed right after the anchor.\n * Pass the document's tabbable elements as `order` when you have them, to spare a second scan.\n */\nexport function getTabbableAfter(\n anchor: HTMLElement,\n exclude: HTMLElement,\n order?: readonly HTMLElement[],\n): HTMLElement | null {\n return (\n getScopedTabbables(anchor, exclude, order).find(\n (el) =>\n !anchor.contains(el) &&\n !!(anchor.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING),\n ) ?? null\n );\n}\n\n/**\n * The last tabbable element that is `anchor`, inside it or before it in document order, in the\n * same portal as the anchor and outside `exclude`: the tab stop before a surface placed right\n * after the anchor. Pass the document's tabbable elements as `order` when you have them.\n */\nexport function getTabbableThrough(\n anchor: HTMLElement,\n exclude: HTMLElement,\n order?: readonly HTMLElement[],\n): HTMLElement | null {\n const through = getScopedTabbables(anchor, exclude, order).filter(\n (el) =>\n anchor.contains(el) ||\n !!(anchor.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_PRECEDING),\n );\n return through[through.length - 1] ?? null;\n}\n\n/**\n * The tab stop that a surface placed right after `anchor` follows, given its previous stop: that\n * stop, or the tab stop at or before the anchor when the previous stop is outside the tab order\n * (a trigger with `tabIndex={-1}`). `null` when nothing in the tab order comes before the place.\n */\nfunction getEntryStop(\n previous: HTMLElement | null,\n anchor: HTMLElement,\n surface: HTMLElement,\n order: readonly HTMLElement[],\n): HTMLElement | null {\n if (!previous || order.includes(previous)) return previous;\n return getTabbableThrough(anchor, surface, order);\n}\n\nfunction focusInstead(event: { preventDefault(): void }, target: HTMLElement | null): void {\n if (!target) return;\n event.preventDefault();\n target.focus();\n}\n\nfunction isNothing(doc: Document, node: EventTarget | null): boolean {\n return !node || node === doc.body || node === doc.documentElement;\n}\n\n/**\n * Hides `surface` (`visibility: hidden`) for the native Tab in progress, so the browser moves past\n * its elements. It is shown again as soon as focus moves (the `focusout` of that Tab, before the\n * next element takes focus), or before the next frame when the Tab moves nothing.\n */\nfunction hideForNativeTab(surface: HTMLElement): void {\n const doc = surface.ownerDocument;\n const win = doc.defaultView;\n const { style } = surface;\n const value = style.getPropertyValue('visibility');\n const priority = style.getPropertyPriority('visibility');\n style.setProperty('visibility', 'hidden', 'important');\n let frame: number | undefined;\n const show = () => {\n doc.removeEventListener('focusout', show, true);\n if (frame !== undefined) win?.cancelAnimationFrame(frame);\n frame = undefined;\n // Left alone when something else changed it meanwhile.\n const ours =\n style.getPropertyValue('visibility') === 'hidden' &&\n style.getPropertyPriority('visibility') === 'important';\n if (!ours) return;\n if (value) style.setProperty('visibility', value, priority);\n else style.removeProperty('visibility');\n };\n doc.addEventListener('focusout', show, true);\n if (win) frame = win.requestAnimationFrame(show);\n}\n\n/**\n * What the document knows about focus that arrives from nothing (the body): whether it can come\n * from the browser's own controls, and where the browser starts Tab and Shift+Tab from nothing.\n * The listeners are installed while a {@link usePopoverTabOrder} is mounted, open or not, so the\n * press that opened a surface counts too. Elements are held through a `WeakRef`, so a removed\n * subtree is not kept alive while a popover is mounted: an element that is gone was removed.\n */\ninterface FocusOrigin {\n /** Mounted `usePopoverTabOrder` instances. */\n users: number;\n /**\n * A pointer press (`pointerdown`/`mousedown`) came since the window last lost focus. The user is\n * then in the page, not arriving from the browser's controls, which the window must lose focus\n * to reach: a key press does not clear it.\n */\n pressed: boolean;\n /**\n * The element that had focus when the window lost it: the browser focuses it again, from\n * nothing, when the window gets focus back. Cleared by the next `focusin`.\n */\n refocus: WeakRef<Element> | null;\n /**\n * The element that took focus last, and the ordered surface ({@link getOrderedSurfaces}) that\n * contained it then. When focus has gone from it to nothing (it was removed, hidden or blurred),\n * the browser starts sequential navigation where it is, or where it was. Recorded in the capture\n * phase, so a handler that stops a `focusin` from propagating does not hide it.\n */\n lastFocused: {\n element: WeakRef<Element>;\n surface: WeakRef<HTMLElement> | null;\n } | null;\n /**\n * The window has just got focus back: no element took focus since, and no key or pointer press\n * reached the page. Sequential navigation from the browser's own controls gives the window focus\n * right before the element it reaches; focus that arrives from nothing without it comes from the\n * page (a focus restore after the focused element was removed, a script).\n */\n windowFocused: boolean;\n /**\n * Counts the events that end a key press's focus change: key presses and releases, pointer\n * presses, `focusin` and the window's blur and focus. An entry the `keydown` of a Tab expects\n * applies only to the `focusin` of that same Tab.\n */\n epoch: number;\n /** Removes the listeners; `null` while none are installed. */\n uninstall: (() => void) | null;\n}\n\n/**\n * One per copy of the library, not in the global registry: every field is derived from document\n * and window events, and only this copy's hooks read it, each of which keeps this copy's\n * listeners installed from its mount on. A second copy (ESM and CJS side by side) installs its own\n * listeners and derives the same state; `epoch` is compared only within the copy that set it.\n */\nconst focusOrigin: FocusOrigin = {\n users: 0,\n pressed: false,\n refocus: null,\n lastFocused: null,\n windowFocused: false,\n epoch: 0,\n uninstall: null,\n};\n\n/**\n * Whether sequential navigation from nothing starts after `el`, the last tabbable element of\n * `surface`: at the element that took focus last, when that comes after `el` in the document or\n * was removed from `surface` (it may have been anywhere in it, after `el` too). An element removed\n * elsewhere does not count: from a place after the surface (a dismissed toast in a later portal),\n * Shift+Tab lands on `el` just as from the document's end, and from a place before it, it does not\n * land on `el`.\n */\nfunction startsAfter(el: HTMLElement, surface: HTMLElement): boolean {\n const last = focusOrigin.lastFocused;\n if (!last) return false;\n const start = last.element.deref();\n if (start?.isConnected) {\n return !!(el.compareDocumentPosition(start) & Node.DOCUMENT_POSITION_FOLLOWING);\n }\n return last.surface?.deref() === surface;\n}\n\n/**\n * The surfaces whose keyboard order a {@link usePopoverTabOrder} manages right now. Their content\n * takes its place after its anchor, not at the end of the document where its portal is, so none\n * of it is \"the last element of the page\". Kept in `getGlobalRegistry('orderedSurfaces')`, so an\n * app that loads both the ESM and the CJS copy of the library excludes the surfaces of both.\n */\nfunction getOrderedSurfaces(): Set<HTMLElement> {\n return getGlobalRegistry('orderedSurfaces', () => new Set<HTMLElement>());\n}\n\nfunction retainFocusOrigin(): () => void {\n if (typeof document === 'undefined') return () => {};\n focusOrigin.users += 1;\n if (!focusOrigin.uninstall) {\n const doc = document;\n const win = doc.defaultView;\n const onPress = () => {\n focusOrigin.epoch += 1;\n focusOrigin.pressed = true;\n focusOrigin.windowFocused = false;\n };\n const onKey = () => {\n focusOrigin.epoch += 1;\n focusOrigin.windowFocused = false;\n };\n // Not capture listeners: they hear only the window's own blur and focus (an element's do not\n // bubble).\n const onWindowBlur = () => {\n focusOrigin.epoch += 1;\n focusOrigin.pressed = false;\n focusOrigin.windowFocused = false;\n const active = doc.activeElement;\n focusOrigin.refocus = !active || isNothing(doc, active) ? null : new WeakRef(active);\n };\n const onWindowFocus = () => {\n focusOrigin.epoch += 1;\n focusOrigin.windowFocused = true;\n };\n // Capture, like the presses and keys, so a handler that stops a `focusin` from propagating\n // does not hide where focus went. Only the `keydown` of a later Tab reads it: recording it\n // before the surfaces' own `focusin` listeners run changes nothing for them.\n const onFocusCapture = (event: FocusEvent) => {\n const target = event.target as Element | null;\n const surface = target && [...getOrderedSurfaces()].find((open) => open.contains(target));\n focusOrigin.lastFocused = target && {\n element: new WeakRef(target),\n surface: surface ? new WeakRef(surface) : null,\n };\n };\n // Bubbling to the document, after the surfaces' own `focusin` listeners have read the state.\n const onFocusIn = () => {\n focusOrigin.epoch += 1;\n focusOrigin.refocus = null;\n focusOrigin.windowFocused = false;\n };\n // Capture: a handler that stops a press or a key from propagating must not hide it.\n doc.addEventListener('pointerdown', onPress, true);\n doc.addEventListener('mousedown', onPress, true);\n doc.addEventListener('keydown', onKey, true);\n doc.addEventListener('keyup', onKey, true);\n doc.addEventListener('focusin', onFocusCapture, true);\n doc.addEventListener('focusin', onFocusIn);\n win?.addEventListener('blur', onWindowBlur);\n win?.addEventListener('focus', onWindowFocus);\n focusOrigin.uninstall = () => {\n doc.removeEventListener('pointerdown', onPress, true);\n doc.removeEventListener('mousedown', onPress, true);\n doc.removeEventListener('keydown', onKey, true);\n doc.removeEventListener('keyup', onKey, true);\n doc.removeEventListener('focusin', onFocusCapture, true);\n doc.removeEventListener('focusin', onFocusIn);\n win?.removeEventListener('blur', onWindowBlur);\n win?.removeEventListener('focus', onWindowFocus);\n focusOrigin.pressed = false;\n focusOrigin.refocus = null;\n focusOrigin.lastFocused = null;\n focusOrigin.windowFocused = false;\n };\n }\n let retained = true;\n return () => {\n if (!retained) return;\n retained = false;\n focusOrigin.users = Math.max(0, focusOrigin.users - 1);\n if (focusOrigin.users > 0) return;\n focusOrigin.uninstall?.();\n focusOrigin.uninstall = null;\n };\n}\n\n/** Options of {@link usePopoverTabOrder}. */\nexport interface PopoverTabOrderOptions {\n /** Whether the surface is shown next to its anchor; the listeners exist only while `true`. */\n enabled: boolean;\n /** The portaled surface, held in state through its callback ref. */\n surface: HTMLElement | null;\n /** The anchor: the surface takes its place in the keyboard order right after it. */\n anchorRef: React.RefObject<HTMLElement | null>;\n /**\n * The element before the surface's place: Tab from it enters the surface, and Shift+Tab from\n * the surface's first element returns to it. When it is outside the tab order (a trigger with\n * `tabIndex={-1}`), Tab from the tab stop at or before the anchor enters the surface too; `null`\n * when nothing comes before the place. `order`, when given, is the document's tabbable elements.\n */\n getPreviousStop: (\n anchor: HTMLElement,\n surface: HTMLElement,\n order?: readonly HTMLElement[],\n ) => HTMLElement | null;\n}\n\n/**\n * Keyboard order of a surface portaled to the end of the document, as if it were rendered right\n * after its anchor (the order of 0.4's inline content). Returns the surface's `onKeyDown`; while\n * `enabled`, a document `keydown` listener and `focusin` listeners on the surface and the window\n * do the rest. While mounted, shared document listeners record pointer presses, key presses, the\n * element that took focus last and the window's blur and focus.\n *\n * - Tab from the previous stop enters the surface at its first tabbable element (so does Tab\n * from the tab stop at or before the anchor when the previous stop is outside the tab order),\n * and Shift+Tab from the tab stop after the anchor enters it at its last one.\n * - Tab past the surface's last element continues after the anchor; Shift+Tab from its first\n * element (or from the surface itself) returns to the previous stop.\n * - The surface is not visited a second time where its portal is. Tab from the element before\n * the portal moves past the surface (it is hidden for that one Tab), to what follows it or out\n * of the page. Shift+Tab from the browser's own controls (the window gets focus back just before\n * it), or from nothing without a pointer press, lands on the surface's last element as the\n * document's last one: focus goes to the last element of the page instead (outside every open\n * surface: another open popover's content has its own place after its anchor), unless that is\n * the tab stop before the surface's place (the surface then ends the order). Focus moves there\n * once the entry's `focusin` has reached the window, so the entered element's focus handlers\n * run before its blur handlers; a handler that stops that `focusin` from propagating (an\n * `onFocus` in the content that calls `stopPropagation()`) leaves focus on the surface's last\n * element, as an entry at its place after the anchor, with no trap and no Tab cycle. Shift+Tab\n * from nothing does not start at the document's end when the element that had focus comes after\n * the surface's last element or was removed from the surface (a control of the surface that hid\n * or removed itself): the browser starts where it is, or was. An element removed elsewhere (a\n * dismissed toast portaled after the surface) keeps the rule: from its place, too, Shift+Tab\n * lands on the surface's last element. A lap in either direction visits every element once, and\n * there is no Tab cycle.\n * - With no tab stop before its place (nothing in the tab order at or before the anchor), Tab\n * reaches the surface where its portal is, from the element before the portal, and it follows\n * the document order from there. When the previous stop is missing too, Shift+Tab reaches it\n * there as well: its first element leads to the element before the portal, so neither Shift+Tab\n * from the tab stop after the anchor nor from outside the page is moved to its place.\n * - Every other entry keeps the place after the anchor: a click, Shift+Tab from a pressed point,\n * focus restored from nothing (a layer opened from the surface's last element closed), a\n * script, focus that returns to an element as the window gets focus back, and focus the content\n * takes as it mounts (`autoFocus`, before the listeners exist).\n * - Content that the Tab from the page still reaches (it shows itself again before the browser\n * moves focus) follows the document order from there, so Tab past it leaves the page rather\n * than jumping back to the anchor.\n *\n * Every Tab outside the surface costs one scan of the document's tabbable elements. The listeners\n * skip events whose default is already prevented; React handlers (a trigger's own `onKeyDown`,\n * the returned one) run before them and before a dialog's focus trap.\n */\nexport function usePopoverTabOrder({\n enabled,\n surface,\n anchorRef,\n getPreviousStop,\n}: PopoverTabOrderOptions): React.KeyboardEventHandler<HTMLElement> {\n const getPrevious = useEventCallback(getPreviousStop);\n /** How focus last entered the surface: at its place after the anchor, or at the portal's. */\n const entryRef = React.useRef<'anchor' | 'page'>('anchor');\n /**\n * Where the Tab being pressed enters the surface natively: at `element`, from the page (had it\n * not moved past the surface) or, Shift+Tab from nothing, at the document's far end. Valid in\n * the `focusin` of that Tab only (same `epoch`).\n */\n const pendingRef = React.useRef<{\n element: HTMLElement;\n from: 'page' | 'far-end';\n epoch: number;\n } | null>(null);\n\n const onDocumentKeyDown = useEventCallback((event: KeyboardEvent) => {\n pendingRef.current = null;\n const anchor = anchorRef.current;\n if (event.key !== 'Tab' || event.defaultPrevented || !anchor || !surface) return;\n const doc = surface.ownerDocument;\n const active = doc.activeElement as HTMLElement | null;\n if (active && surface.contains(active)) return;\n // One scan of the document; everything below is derived from it.\n const order = getTabbableElements(doc.body);\n const inside = order.filter((el) => surface.contains(el));\n const first = inside[0];\n const last = inside[inside.length - 1];\n if (!first || !last) return;\n if (!active || isNothing(doc, active)) {\n // With no pointer press to start from, Shift+Tab from nothing reaches the document's last\n // element, unless the browser starts after it: where the element that had focus is, or was\n // (a control of the surface that removed or hid itself).\n if (\n event.shiftKey &&\n !focusOrigin.pressed &&\n order[order.length - 1] === last &&\n !startsAfter(last, surface)\n ) {\n pendingRef.current = { element: last, from: 'far-end', epoch: focusOrigin.epoch };\n }\n return;\n }\n const previous = getPrevious(anchor, surface, order);\n if (event.shiftKey) {\n // Without a previous stop, Shift+Tab from the surface's first element follows the document\n // order: entering the surface here would form a cycle.\n if (previous && active === getTabbableAfter(anchor, surface, order)) {\n focusInstead(event, last);\n }\n return;\n }\n const entry = getEntryStop(previous, anchor, surface, order);\n if (active === previous || active === entry) {\n focusInstead(event, first);\n return;\n }\n const index = order.indexOf(active);\n if (index === -1 || order[index + 1] !== first) return;\n pendingRef.current = { element: first, from: 'page', epoch: focusOrigin.epoch };\n // The browser would enter the surface where its portal is. When a tab stop comes before its\n // place, the surface was visited after the anchor: move past it. Otherwise this is its entry.\n if (entry) hideForNativeTab(surface);\n });\n\n // Installed while mounted, not only while enabled: the press that opens the surface counts.\n React.useEffect(() => retainFocusOrigin(), []);\n\n React.useEffect(() => {\n if (!enabled || !surface) return;\n const doc = surface.ownerDocument;\n const win = doc.defaultView;\n // A new surface, or one shown again: focus it took as it mounted (before this listener) was\n // not a native entry from the page, and an earlier entry no longer applies.\n entryRef.current = 'anchor';\n /**\n * An entry that goes on to the last element of the page. Focus moves there once the entry's\n * `focusin` has reached the window, after React (which listens where the portal is, above the\n * surface) has handled it: the entered element's focus handlers run before its blur handlers,\n * so a Tooltip on it does not stay open. Not in a microtask: a browser runs microtasks between\n * the listeners of its own events.\n */\n let redirect: { event: FocusEvent; pageEnd: HTMLElement } | null = null;\n const onFocusIn = (event: FocusEvent) => {\n redirect = null;\n const pending = pendingRef.current;\n pendingRef.current = null;\n const from = event.relatedTarget as Node | null;\n if (from && surface.contains(from)) return;\n const entered = event.target;\n // The window got focus back: focus returns to where it was, in the order it had there.\n if (!from && entered === focusOrigin.refocus?.deref()) return;\n const expected =\n pending && pending.epoch === focusOrigin.epoch && pending.element === entered\n ? pending.from\n : null;\n // The Tab from the page reached the surface after all: follow the document order from here,\n // so Tab past it leaves the page instead of forming a cycle through the anchor.\n entryRef.current = expected === 'page' ? 'page' : 'anchor';\n if (expected === 'page' || !isNothing(doc, from) || focusOrigin.pressed) return;\n // Shift+Tab from the browser's own controls, or from nothing: the document's last element.\n if (expected !== 'far-end' && !focusOrigin.windowFocused) return;\n const anchor = anchorRef.current;\n if (!anchor || entered !== getLastTabbable(surface)) return;\n const order = getTabbableElements(doc.body);\n const surfaces = [...getOrderedSurfaces()];\n const outside = order.filter((el) => !surfaces.some((open) => open.contains(el)));\n const pageEnd = outside[outside.length - 1];\n const previous = getPrevious(anchor, surface, order);\n // The surface ends the order when the tab stop before its place is the page's last element.\n // Without a previous stop it keeps the place of its portal, as Shift+Tab from it does.\n if (!previous || !pageEnd || pageEnd === getEntryStop(previous, anchor, surface, order)) {\n return;\n }\n redirect = { event, pageEnd };\n };\n const onWindowFocusIn = (event: FocusEvent) => {\n const pending = redirect;\n redirect = null;\n // Left alone when a handler of the entry has moved focus already.\n if (pending?.event !== event || doc.activeElement !== event.target) return;\n if (!focusElement(pending.pageEnd)) entryRef.current = 'page';\n };\n const orderedSurfaces = getOrderedSurfaces();\n orderedSurfaces.add(surface);\n surface.addEventListener('focusin', onFocusIn);\n win?.addEventListener('focusin', onWindowFocusIn);\n doc.addEventListener('keydown', onDocumentKeyDown);\n return () => {\n orderedSurfaces.delete(surface);\n surface.removeEventListener('focusin', onFocusIn);\n win?.removeEventListener('focusin', onWindowFocusIn);\n doc.removeEventListener('keydown', onDocumentKeyDown);\n };\n }, [enabled, surface, anchorRef, getPrevious, onDocumentKeyDown]);\n\n return useEventCallback((event: React.KeyboardEvent<HTMLElement>) => {\n const anchor = anchorRef.current;\n if (event.key !== 'Tab' || event.defaultPrevented || !enabled || !surface || !anchor) return;\n const active = surface.ownerDocument.activeElement;\n // Events from nested portaled layers bubble here through React: only handle our own content.\n if (!active || !surface.contains(active) || entryRef.current === 'page') return;\n const tabbables = getTabbableElements(surface);\n if (event.shiftKey) {\n if (active === surface || active === tabbables[0]) {\n focusInstead(event, getPrevious(anchor, surface));\n }\n return;\n }\n if (tabbables.length > 0 && active !== tabbables[tabbables.length - 1]) return;\n focusInstead(event, getTabbableAfter(anchor, surface));\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/classNames.cjs"),i=require("../../lib/theme.cjs");let a=require("react");a=e.__toESM(a,1);let o=require("react/jsx-runtime");var s=a.createContext({theme:`light`,dir:`ltr`,themeClassName:``,portalContainer:null,hasProvider:!1});function c(){return a.useContext(s)}var l=({theme:e,dir:c,portalContainer:l,
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/classNames.cjs"),i=require("../../lib/theme.cjs");let a=require("react");a=e.__toESM(a,1);let o=require("react/jsx-runtime");var s=a.createContext({theme:`light`,dir:`ltr`,themeClassName:``,portalContainer:null,inputDefaults:{},hasProvider:!1});function c(){return a.useContext(s)}var l=({theme:e,dir:c,portalContainer:l,inputDefaults:u,children:d,className:f,ref:p,...m})=>{let h=a.useContext(s),g=e??h.theme,_=c??h.dir,v=l===void 0?h.portalContainer:l,y=u?.size??h.inputDefaults.size,b=u?.appearance??h.inputDefaults.appearance,x=a.useMemo(()=>{let e={};return y!==void 0&&(e.size=y),b!==void 0&&(e.appearance=b),e},[y,b]),S=i.isWaveTheme(g)?g:`light`,C=i.getThemeClassName(S);a.useEffect(()=>{i.isWaveTheme(g)||n.warnOnce(`WaveProvider:theme:${String(g)}`,`WaveProvider: unknown theme "${String(g)}". Valid themes: ${i.WAVE_THEMES.join(`, `)}. Using "light".`)},[g]);let w=a.useMemo(()=>({theme:S,dir:_,themeClassName:C,portalContainer:v,inputDefaults:x,hasProvider:!0}),[S,_,C,v,x]);return(0,o.jsx)(s.Provider,{value:w,children:(0,o.jsx)(`div`,{...m,ref:p,dir:_,"data-wave-theme":S,className:t.cn(r.waveProviderClassNames.root,C,`bg-background text-foreground font-wave text-body-1`,f),children:d})})};l.displayName=`WaveProvider`,exports.WaveProvider=l,exports.getThemeClassName=i.getThemeClassName,exports.useWaveTheme=c;
|
|
2
2
|
//# sourceMappingURL=WaveProvider.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WaveProvider.cjs","names":["React","isWaveTheme","getThemeClassName","WAVE_THEMES","cn","waveProviderClassNames","require_runtime","require_cn","require_dev","require_classNames","require_theme","react","react_jsx_runtime","WaveContext","useWaveTheme","WaveProvider","themeProp","dirProp","portalContainerProp","rest","parent","theme","dir","portalContainer","resolvedTheme","themeClassName","value","className"],"sources":["../../../src/components/provider/WaveProvider.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { warnOnce } from '../../lib/dev';\nimport { waveProviderClassNames } from '../../lib/classNames';\nimport { getThemeClassName, isWaveTheme, WAVE_THEMES, type WaveTheme } from '../../lib/theme';\n\n// The theme helper lives in server-safe src/lib (no \"use client\"), so React Server Components can\n// call it; it stays exported from here too.\nexport { getThemeClassName } from '../../lib/theme';\nexport type { WaveTheme } from '../../lib/theme';\n\n/** Text direction for bidirectional layout support. */\nexport type WaveDir = 'ltr' | 'rtl';\n\n/** Props accepted by {@link WaveProvider}. */\nexport interface WaveProviderProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Visual theme applied to the subtree. Providers can be nested in any order: each root declares\n * its theme's tokens, so a light panel inside a dark app (and the reverse) renders correctly.\n * @default the enclosing WaveProvider's theme, else 'light'\n */\n theme?: WaveTheme;\n /**\n * Text direction for the subtree (also read by portaled overlays and keyboard navigation).\n * @default the enclosing WaveProvider's direction, else 'ltr'\n */\n dir?: WaveDir;\n /**\n * Element that portaled overlays (dialogs, popovers, menus, toasts) render into. `null` renders\n * them into `document.body`, also inside a provider that sets a container.\n * @default the enclosing WaveProvider's container, else document.body\n */\n portalContainer?: HTMLElement | null;\n /** Content rendered inside the themed container. */\n children: React.ReactNode;\n /** Ref to the themed root `<div>`. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** Value provided by {@link WaveProvider} and returned by {@link useWaveTheme}. */\nexport interface WaveContextValue {\n /** The active theme. */\n theme: WaveTheme;\n /** The active text direction. */\n dir: WaveDir;\n /**\n * Theme classes of the nearest provider (see {@link getThemeClassName}); portals put them on\n * their wrapper so overlays inherit the theme. `''` outside a provider (the page's own theme).\n */\n themeClassName: string;\n /** Element portaled overlays render into; `null` means `document.body`. */\n portalContainer: HTMLElement | null;\n /** `false` when no {@link WaveProvider} is above the caller (the defaults are returned). */\n hasProvider: boolean;\n}\n\nconst DEFAULT_CONTEXT: WaveContextValue = {\n theme: 'light',\n dir: 'ltr',\n themeClassName: '',\n portalContainer: null,\n hasProvider: false,\n};\n\nconst WaveContext = React.createContext<WaveContextValue>(DEFAULT_CONTEXT);\n\n/**\n * Reads the theme, direction, theme classes and portal container of the nearest\n * {@link WaveProvider}. Outside a provider it returns light/ltr defaults with `hasProvider: false`.\n *\n * @returns The {@link WaveContextValue} of the nearest provider.\n */\nexport function useWaveTheme(): WaveContextValue {\n return React.useContext(WaveContext);\n}\n\n/**\n * Applies Wave theming to an application or subtree.\n *\n * - Renders a `<div class=\"wave-root wave-<theme>\">` that declares the theme's tokens and paints\n * the themed background, text colour and font (`bg-background text-foreground font-wave\n * text-body-1`; a `className` passed by you wins). The precompiled `./styles` entry scopes its base\n * styles and native-element reset to this root, so it is required there.\n * - Sets `dir` and `data-wave-theme` on the root. An unknown `theme` value (from untyped code)\n * falls back to `'light'` — classes, `data-wave-theme` and the context value — and warns once in\n * development.\n * - Provides theme, direction, theme classes and the portal container through context, so\n * portaled overlays render with the same theme and direction.\n * - Nests: a provider inherits every prop it omits (`theme`, `dir`, `portalContainer`) from the\n * enclosing provider, so `<WaveProvider theme=\"light\">` inside an RTL app is a light panel that\n * stays right-to-left and keeps the app's portal container. At the top level the defaults are\n * `'light'`, `'ltr'` and `document.body`.\n */\nexport const WaveProvider = ({\n theme: themeProp,\n dir: dirProp,\n portalContainer: portalContainerProp,\n children,\n className,\n ref,\n ...rest\n}: WaveProviderProps) => {\n // Omitted props come from the enclosing provider; outside one, DEFAULT_CONTEXT supplies the\n // top-level defaults. An explicit `portalContainer={null}` means document.body, so only\n // `undefined` inherits.\n const parent = React.useContext(WaveContext);\n const theme = themeProp ?? parent.theme;\n const dir = dirProp ?? parent.dir;\n const portalContainer =\n portalContainerProp === undefined ? parent.portalContainer : portalContainerProp;\n\n // An unknown value (untyped callers) renders, and is reported, as the light theme.\n const resolvedTheme: WaveTheme = isWaveTheme(theme) ? theme : 'light';\n const themeClassName = getThemeClassName(resolvedTheme);\n\n React.useEffect(() => {\n if (!isWaveTheme(theme)) {\n warnOnce(\n `WaveProvider:theme:${String(theme)}`,\n `WaveProvider: unknown theme \"${String(theme)}\". Valid themes: ${WAVE_THEMES.join(', ')}. Using \"light\".`,\n );\n }\n }, [theme]);\n\n const value = React.useMemo<WaveContextValue>(\n () => ({
|
|
1
|
+
{"version":3,"file":"WaveProvider.cjs","names":["React","isWaveTheme","getThemeClassName","WAVE_THEMES","cn","waveProviderClassNames","require_runtime","require_cn","require_dev","require_classNames","require_theme","react","react_jsx_runtime","WaveContext","useWaveTheme","WaveProvider","themeProp","dirProp","portalContainerProp","inputDefaultsProp","rest","parent","theme","dir","portalContainer","size","appearance","inputDefaults","merged","resolvedTheme","themeClassName","value","className"],"sources":["../../../src/components/provider/WaveProvider.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { warnOnce } from '../../lib/dev';\nimport { waveProviderClassNames } from '../../lib/classNames';\nimport { getThemeClassName, isWaveTheme, WAVE_THEMES, type WaveTheme } from '../../lib/theme';\nimport type { CoreSize, InputAppearance } from '../../lib/types';\n\n// The theme helper lives in server-safe src/lib (no \"use client\"), so React Server Components can\n// call it; it stays exported from here too.\nexport { getThemeClassName } from '../../lib/theme';\nexport type { WaveTheme } from '../../lib/theme';\n\n/** Text direction for bidirectional layout support. */\nexport type WaveDir = 'ltr' | 'rtl';\n\n/** Default size and appearance of the text inputs and pickers in a subtree. */\nexport interface InputDefaults {\n /** Default `size` of Input, Textarea, Select, SearchBox, SpinButton and the pickers. */\n size?: CoreSize;\n /** Default `appearance` of the same controls. */\n appearance?: InputAppearance;\n}\n\n/** Props accepted by {@link WaveProvider}. */\nexport interface WaveProviderProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Visual theme applied to the subtree. Providers can be nested in any order: each root declares\n * its theme's tokens, so a light panel inside a dark app (and the reverse) renders correctly.\n * @default the enclosing WaveProvider's theme, else 'light'\n */\n theme?: WaveTheme;\n /**\n * Text direction for the subtree (also read by portaled overlays and keyboard navigation).\n * @default the enclosing WaveProvider's direction, else 'ltr'\n */\n dir?: WaveDir;\n /**\n * Element that portaled overlays (dialogs, popovers, menus, toasts) render into. `null` renders\n * them into `document.body`, also inside a provider that sets a container.\n * @default the enclosing WaveProvider's container, else document.body\n */\n portalContainer?: HTMLElement | null;\n /**\n * Default `size` and `appearance` of the text inputs and pickers in the subtree (Input,\n * Textarea, Select, SearchBox, SpinButton, Combobox, Dropdown, DatePicker, TimePicker,\n * TagPicker). Their own props and a Field's `size` win. A nested provider merges its keys over\n * the enclosing provider's; an omitted key is inherited.\n * @default the enclosing WaveProvider's defaults, else none (`medium`, `outline`)\n */\n inputDefaults?: InputDefaults;\n /** Content rendered inside the themed container. */\n children: React.ReactNode;\n /** Ref to the themed root `<div>`. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** Value provided by {@link WaveProvider} and returned by {@link useWaveTheme}. */\nexport interface WaveContextValue {\n /** The active theme. */\n theme: WaveTheme;\n /** The active text direction. */\n dir: WaveDir;\n /**\n * Theme classes of the nearest provider (see {@link getThemeClassName}); portals put them on\n * their wrapper so overlays inherit the theme. `''` outside a provider (the page's own theme).\n */\n themeClassName: string;\n /** Element portaled overlays render into; `null` means `document.body`. */\n portalContainer: HTMLElement | null;\n /** The merged input defaults of the providers above (`{}` outside a provider). */\n inputDefaults: InputDefaults;\n /** `false` when no {@link WaveProvider} is above the caller (the defaults are returned). */\n hasProvider: boolean;\n}\n\nconst DEFAULT_CONTEXT: WaveContextValue = {\n theme: 'light',\n dir: 'ltr',\n themeClassName: '',\n portalContainer: null,\n inputDefaults: {},\n hasProvider: false,\n};\n\nconst WaveContext = React.createContext<WaveContextValue>(DEFAULT_CONTEXT);\n\n/**\n * Reads the theme, direction, theme classes and portal container of the nearest\n * {@link WaveProvider}. Outside a provider it returns light/ltr defaults with `hasProvider: false`.\n *\n * @returns The {@link WaveContextValue} of the nearest provider.\n */\nexport function useWaveTheme(): WaveContextValue {\n return React.useContext(WaveContext);\n}\n\n/**\n * Applies Wave theming to an application or subtree.\n *\n * - Renders a `<div class=\"wave-root wave-<theme>\">` that declares the theme's tokens and paints\n * the themed background, text colour and font (`bg-background text-foreground font-wave\n * text-body-1`; a `className` passed by you wins). The precompiled `./styles` entry scopes its base\n * styles and native-element reset to this root, so it is required there.\n * - Sets `dir` and `data-wave-theme` on the root. An unknown `theme` value (from untyped code)\n * falls back to `'light'` — classes, `data-wave-theme` and the context value — and warns once in\n * development.\n * - Provides theme, direction, theme classes and the portal container through context, so\n * portaled overlays render with the same theme and direction.\n * - Nests: a provider inherits every prop it omits (`theme`, `dir`, `portalContainer`) from the\n * enclosing provider, so `<WaveProvider theme=\"light\">` inside an RTL app is a light panel that\n * stays right-to-left and keeps the app's portal container. At the top level the defaults are\n * `'light'`, `'ltr'` and `document.body`.\n * - `inputDefaults` nests differently: a nested provider's defined keys override the enclosing\n * provider's, and an omitted key is inherited, so setting only `appearance` in a nested provider\n * keeps the enclosing provider's `size`.\n */\nexport const WaveProvider = ({\n theme: themeProp,\n dir: dirProp,\n portalContainer: portalContainerProp,\n inputDefaults: inputDefaultsProp,\n children,\n className,\n ref,\n ...rest\n}: WaveProviderProps) => {\n // Omitted props come from the enclosing provider; outside one, DEFAULT_CONTEXT supplies the\n // top-level defaults. An explicit `portalContainer={null}` means document.body, so only\n // `undefined` inherits.\n const parent = React.useContext(WaveContext);\n const theme = themeProp ?? parent.theme;\n const dir = dirProp ?? parent.dir;\n const portalContainer =\n portalContainerProp === undefined ? parent.portalContainer : portalContainerProp;\n\n // Defined keys override the enclosing provider's; the merged object keeps its identity while the\n // two values are equal, so an inline `inputDefaults={{ … }}` does not re-render every input.\n const size = inputDefaultsProp?.size ?? parent.inputDefaults.size;\n const appearance = inputDefaultsProp?.appearance ?? parent.inputDefaults.appearance;\n const inputDefaults = React.useMemo<InputDefaults>(() => {\n const merged: InputDefaults = {};\n if (size !== undefined) merged.size = size;\n if (appearance !== undefined) merged.appearance = appearance;\n return merged;\n }, [size, appearance]);\n\n // An unknown value (untyped callers) renders, and is reported, as the light theme.\n const resolvedTheme: WaveTheme = isWaveTheme(theme) ? theme : 'light';\n const themeClassName = getThemeClassName(resolvedTheme);\n\n React.useEffect(() => {\n if (!isWaveTheme(theme)) {\n warnOnce(\n `WaveProvider:theme:${String(theme)}`,\n `WaveProvider: unknown theme \"${String(theme)}\". Valid themes: ${WAVE_THEMES.join(', ')}. Using \"light\".`,\n );\n }\n }, [theme]);\n\n const value = React.useMemo<WaveContextValue>(\n () => ({\n theme: resolvedTheme,\n dir,\n themeClassName,\n portalContainer,\n inputDefaults,\n hasProvider: true,\n }),\n [resolvedTheme, dir, themeClassName, portalContainer, inputDefaults],\n );\n\n return (\n <WaveContext.Provider value={value}>\n <div\n {...rest}\n ref={ref}\n dir={dir}\n data-wave-theme={resolvedTheme}\n className={cn(\n waveProviderClassNames.root,\n themeClassName,\n 'bg-background text-foreground font-wave text-body-1',\n className,\n )}\n >\n {children}\n </div>\n </WaveContext.Provider>\n );\n};\n\nWaveProvider.displayName = 'WaveProvider';\n"],"mappings":"oRAoFA,IAAMa,EAAcb,EAAM,cAAgC,CARxD,MAAO,QACP,IAAK,MACL,eAAgB,GAChB,gBAAiB,KACjB,cAAe,CAAC,EAChB,YAAa,EAG2C,CAAe,EAQzE,SAAgBc,GAAiC,CAC/C,OAAOd,EAAM,WAAWa,CAAW,CACrC,CAsBA,IAAaE,GAAgB,CAC3B,MAAOC,EACP,IAAKC,EACL,gBAAiBC,EACjB,cAAeC,EACf,WACA,YACA,MACA,GAAGC,KACoB,CAIvB,IAAMC,EAASrB,EAAM,WAAWa,CAAW,EACrCS,EAAQN,GAAaK,EAAO,MAC5BE,EAAMN,GAAWI,EAAO,IACxBG,EACJN,IAAwB,IAAA,GAAYG,EAAO,gBAAkBH,EAIzDO,EAAON,GAAmB,MAAQE,EAAO,cAAc,KACvDK,EAAaP,GAAmB,YAAcE,EAAO,cAAc,WACnEM,EAAgB3B,EAAM,YAA6B,CACvD,IAAM4B,EAAwB,CAAC,EAG/B,OAFIH,IAAS,IAAA,KAAW,EAAO,KAAOA,GAClCC,IAAe,IAAA,KAAW,EAAO,WAAaA,GAC3CE,CACT,EAAG,CAACH,EAAMC,CAAU,CAAC,EAGfG,EAA2B5B,EAAAA,YAAYqB,CAAK,EAAIA,EAAQ,QACxDQ,EAAiB5B,EAAAA,kBAAkB2B,CAAa,EAEtDlB,EAAM,cAAgB,CACfV,EAAAA,YAAYqB,CAAK,GACpBd,EAAA,SACE,sBAAsB,OAAOc,CAAK,IAClC,gCAAgC,OAAOA,CAAK,EAAE,mBAAmBnB,EAAAA,YAAY,KAAK,IAAI,EAAE,iBAC1F,CAEJ,EAAG,CAACmB,CAAK,CAAC,EAEV,IAAMS,EAAQ/B,EAAM,aACX,CACL,MAAO6B,EACP,MACA,iBACA,kBACA,gBACA,YAAa,EACf,GACA,CAACA,EAAeN,EAAKO,EAAgBN,EAAiBG,CAAa,CACrE,EAEA,OACE,EAAAf,EAAA,IAAA,CAACC,EAAY,SAAb,CAA6B,QAC3B,UAAA,EAAAD,EAAA,IAAA,CAAC,MAAD,CACE,GAAIQ,EACC,MACA,MACL,kBAAiBS,EACjB,UAAWzB,EAAAA,GACTC,EAAAA,uBAAuB,KACvByB,EACA,sDACAE,CACF,EAEC,UACE,CAAA,CACe,CAAA,CAE1B,EAEA,EAAa,YAAc"}
|
|
@@ -11,37 +11,43 @@ var c = o.createContext({
|
|
|
11
11
|
dir: "ltr",
|
|
12
12
|
themeClassName: "",
|
|
13
13
|
portalContainer: null,
|
|
14
|
+
inputDefaults: {},
|
|
14
15
|
hasProvider: !1
|
|
15
16
|
});
|
|
16
17
|
function l() {
|
|
17
18
|
return o.useContext(c);
|
|
18
19
|
}
|
|
19
|
-
var u = ({ theme: l, dir: u, portalContainer: d,
|
|
20
|
-
let
|
|
20
|
+
var u = ({ theme: l, dir: u, portalContainer: d, inputDefaults: f, children: p, className: m, ref: h, ...g }) => {
|
|
21
|
+
let _ = o.useContext(c), v = l ?? _.theme, y = u ?? _.dir, b = d === void 0 ? _.portalContainer : d, x = f?.size ?? _.inputDefaults.size, S = f?.appearance ?? _.inputDefaults.appearance, C = o.useMemo(() => {
|
|
22
|
+
let e = {};
|
|
23
|
+
return x !== void 0 && (e.size = x), S !== void 0 && (e.appearance = S), e;
|
|
24
|
+
}, [x, S]), w = a(v) ? v : "light", T = i(w);
|
|
21
25
|
o.useEffect(() => {
|
|
22
|
-
a(
|
|
23
|
-
}, [
|
|
24
|
-
let
|
|
25
|
-
theme:
|
|
26
|
-
dir:
|
|
27
|
-
themeClassName:
|
|
28
|
-
portalContainer:
|
|
26
|
+
a(v) || t(`WaveProvider:theme:${String(v)}`, `WaveProvider: unknown theme "${String(v)}". Valid themes: ${r.join(", ")}. Using "light".`);
|
|
27
|
+
}, [v]);
|
|
28
|
+
let E = o.useMemo(() => ({
|
|
29
|
+
theme: w,
|
|
30
|
+
dir: y,
|
|
31
|
+
themeClassName: T,
|
|
32
|
+
portalContainer: b,
|
|
33
|
+
inputDefaults: C,
|
|
29
34
|
hasProvider: !0
|
|
30
35
|
}), [
|
|
36
|
+
w,
|
|
37
|
+
y,
|
|
38
|
+
T,
|
|
31
39
|
b,
|
|
32
|
-
|
|
33
|
-
x,
|
|
34
|
-
y
|
|
40
|
+
C
|
|
35
41
|
]);
|
|
36
42
|
return /* @__PURE__ */ s(c.Provider, {
|
|
37
|
-
value:
|
|
43
|
+
value: E,
|
|
38
44
|
children: /* @__PURE__ */ s("div", {
|
|
39
|
-
...
|
|
40
|
-
ref:
|
|
41
|
-
dir:
|
|
42
|
-
"data-wave-theme":
|
|
43
|
-
className: e(n.root,
|
|
44
|
-
children:
|
|
45
|
+
...g,
|
|
46
|
+
ref: h,
|
|
47
|
+
dir: y,
|
|
48
|
+
"data-wave-theme": w,
|
|
49
|
+
className: e(n.root, T, "bg-background text-foreground font-wave text-body-1", m),
|
|
50
|
+
children: p
|
|
45
51
|
})
|
|
46
52
|
});
|
|
47
53
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WaveProvider.mjs","names":["React","WaveContext","useWaveTheme","WaveProvider","themeProp","dirProp","portalContainerProp","rest","parent","theme","dir","portalContainer","resolvedTheme","isWaveTheme","themeClassName","getThemeClassName","warnOnce","WAVE_THEMES","value","cn","waveProviderClassNames","className"],"sources":["../../../src/components/provider/WaveProvider.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { warnOnce } from '../../lib/dev';\nimport { waveProviderClassNames } from '../../lib/classNames';\nimport { getThemeClassName, isWaveTheme, WAVE_THEMES, type WaveTheme } from '../../lib/theme';\n\n// The theme helper lives in server-safe src/lib (no \"use client\"), so React Server Components can\n// call it; it stays exported from here too.\nexport { getThemeClassName } from '../../lib/theme';\nexport type { WaveTheme } from '../../lib/theme';\n\n/** Text direction for bidirectional layout support. */\nexport type WaveDir = 'ltr' | 'rtl';\n\n/** Props accepted by {@link WaveProvider}. */\nexport interface WaveProviderProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Visual theme applied to the subtree. Providers can be nested in any order: each root declares\n * its theme's tokens, so a light panel inside a dark app (and the reverse) renders correctly.\n * @default the enclosing WaveProvider's theme, else 'light'\n */\n theme?: WaveTheme;\n /**\n * Text direction for the subtree (also read by portaled overlays and keyboard navigation).\n * @default the enclosing WaveProvider's direction, else 'ltr'\n */\n dir?: WaveDir;\n /**\n * Element that portaled overlays (dialogs, popovers, menus, toasts) render into. `null` renders\n * them into `document.body`, also inside a provider that sets a container.\n * @default the enclosing WaveProvider's container, else document.body\n */\n portalContainer?: HTMLElement | null;\n /** Content rendered inside the themed container. */\n children: React.ReactNode;\n /** Ref to the themed root `<div>`. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** Value provided by {@link WaveProvider} and returned by {@link useWaveTheme}. */\nexport interface WaveContextValue {\n /** The active theme. */\n theme: WaveTheme;\n /** The active text direction. */\n dir: WaveDir;\n /**\n * Theme classes of the nearest provider (see {@link getThemeClassName}); portals put them on\n * their wrapper so overlays inherit the theme. `''` outside a provider (the page's own theme).\n */\n themeClassName: string;\n /** Element portaled overlays render into; `null` means `document.body`. */\n portalContainer: HTMLElement | null;\n /** `false` when no {@link WaveProvider} is above the caller (the defaults are returned). */\n hasProvider: boolean;\n}\n\nconst DEFAULT_CONTEXT: WaveContextValue = {\n theme: 'light',\n dir: 'ltr',\n themeClassName: '',\n portalContainer: null,\n hasProvider: false,\n};\n\nconst WaveContext = React.createContext<WaveContextValue>(DEFAULT_CONTEXT);\n\n/**\n * Reads the theme, direction, theme classes and portal container of the nearest\n * {@link WaveProvider}. Outside a provider it returns light/ltr defaults with `hasProvider: false`.\n *\n * @returns The {@link WaveContextValue} of the nearest provider.\n */\nexport function useWaveTheme(): WaveContextValue {\n return React.useContext(WaveContext);\n}\n\n/**\n * Applies Wave theming to an application or subtree.\n *\n * - Renders a `<div class=\"wave-root wave-<theme>\">` that declares the theme's tokens and paints\n * the themed background, text colour and font (`bg-background text-foreground font-wave\n * text-body-1`; a `className` passed by you wins). The precompiled `./styles` entry scopes its base\n * styles and native-element reset to this root, so it is required there.\n * - Sets `dir` and `data-wave-theme` on the root. An unknown `theme` value (from untyped code)\n * falls back to `'light'` — classes, `data-wave-theme` and the context value — and warns once in\n * development.\n * - Provides theme, direction, theme classes and the portal container through context, so\n * portaled overlays render with the same theme and direction.\n * - Nests: a provider inherits every prop it omits (`theme`, `dir`, `portalContainer`) from the\n * enclosing provider, so `<WaveProvider theme=\"light\">` inside an RTL app is a light panel that\n * stays right-to-left and keeps the app's portal container. At the top level the defaults are\n * `'light'`, `'ltr'` and `document.body`.\n */\nexport const WaveProvider = ({\n theme: themeProp,\n dir: dirProp,\n portalContainer: portalContainerProp,\n children,\n className,\n ref,\n ...rest\n}: WaveProviderProps) => {\n // Omitted props come from the enclosing provider; outside one, DEFAULT_CONTEXT supplies the\n // top-level defaults. An explicit `portalContainer={null}` means document.body, so only\n // `undefined` inherits.\n const parent = React.useContext(WaveContext);\n const theme = themeProp ?? parent.theme;\n const dir = dirProp ?? parent.dir;\n const portalContainer =\n portalContainerProp === undefined ? parent.portalContainer : portalContainerProp;\n\n // An unknown value (untyped callers) renders, and is reported, as the light theme.\n const resolvedTheme: WaveTheme = isWaveTheme(theme) ? theme : 'light';\n const themeClassName = getThemeClassName(resolvedTheme);\n\n React.useEffect(() => {\n if (!isWaveTheme(theme)) {\n warnOnce(\n `WaveProvider:theme:${String(theme)}`,\n `WaveProvider: unknown theme \"${String(theme)}\". Valid themes: ${WAVE_THEMES.join(', ')}. Using \"light\".`,\n );\n }\n }, [theme]);\n\n const value = React.useMemo<WaveContextValue>(\n () => ({
|
|
1
|
+
{"version":3,"file":"WaveProvider.mjs","names":["React","WaveContext","useWaveTheme","WaveProvider","themeProp","dirProp","portalContainerProp","inputDefaultsProp","rest","parent","theme","dir","portalContainer","size","appearance","inputDefaults","merged","resolvedTheme","isWaveTheme","themeClassName","getThemeClassName","warnOnce","WAVE_THEMES","value","cn","waveProviderClassNames","className"],"sources":["../../../src/components/provider/WaveProvider.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { warnOnce } from '../../lib/dev';\nimport { waveProviderClassNames } from '../../lib/classNames';\nimport { getThemeClassName, isWaveTheme, WAVE_THEMES, type WaveTheme } from '../../lib/theme';\nimport type { CoreSize, InputAppearance } from '../../lib/types';\n\n// The theme helper lives in server-safe src/lib (no \"use client\"), so React Server Components can\n// call it; it stays exported from here too.\nexport { getThemeClassName } from '../../lib/theme';\nexport type { WaveTheme } from '../../lib/theme';\n\n/** Text direction for bidirectional layout support. */\nexport type WaveDir = 'ltr' | 'rtl';\n\n/** Default size and appearance of the text inputs and pickers in a subtree. */\nexport interface InputDefaults {\n /** Default `size` of Input, Textarea, Select, SearchBox, SpinButton and the pickers. */\n size?: CoreSize;\n /** Default `appearance` of the same controls. */\n appearance?: InputAppearance;\n}\n\n/** Props accepted by {@link WaveProvider}. */\nexport interface WaveProviderProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Visual theme applied to the subtree. Providers can be nested in any order: each root declares\n * its theme's tokens, so a light panel inside a dark app (and the reverse) renders correctly.\n * @default the enclosing WaveProvider's theme, else 'light'\n */\n theme?: WaveTheme;\n /**\n * Text direction for the subtree (also read by portaled overlays and keyboard navigation).\n * @default the enclosing WaveProvider's direction, else 'ltr'\n */\n dir?: WaveDir;\n /**\n * Element that portaled overlays (dialogs, popovers, menus, toasts) render into. `null` renders\n * them into `document.body`, also inside a provider that sets a container.\n * @default the enclosing WaveProvider's container, else document.body\n */\n portalContainer?: HTMLElement | null;\n /**\n * Default `size` and `appearance` of the text inputs and pickers in the subtree (Input,\n * Textarea, Select, SearchBox, SpinButton, Combobox, Dropdown, DatePicker, TimePicker,\n * TagPicker). Their own props and a Field's `size` win. A nested provider merges its keys over\n * the enclosing provider's; an omitted key is inherited.\n * @default the enclosing WaveProvider's defaults, else none (`medium`, `outline`)\n */\n inputDefaults?: InputDefaults;\n /** Content rendered inside the themed container. */\n children: React.ReactNode;\n /** Ref to the themed root `<div>`. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** Value provided by {@link WaveProvider} and returned by {@link useWaveTheme}. */\nexport interface WaveContextValue {\n /** The active theme. */\n theme: WaveTheme;\n /** The active text direction. */\n dir: WaveDir;\n /**\n * Theme classes of the nearest provider (see {@link getThemeClassName}); portals put them on\n * their wrapper so overlays inherit the theme. `''` outside a provider (the page's own theme).\n */\n themeClassName: string;\n /** Element portaled overlays render into; `null` means `document.body`. */\n portalContainer: HTMLElement | null;\n /** The merged input defaults of the providers above (`{}` outside a provider). */\n inputDefaults: InputDefaults;\n /** `false` when no {@link WaveProvider} is above the caller (the defaults are returned). */\n hasProvider: boolean;\n}\n\nconst DEFAULT_CONTEXT: WaveContextValue = {\n theme: 'light',\n dir: 'ltr',\n themeClassName: '',\n portalContainer: null,\n inputDefaults: {},\n hasProvider: false,\n};\n\nconst WaveContext = React.createContext<WaveContextValue>(DEFAULT_CONTEXT);\n\n/**\n * Reads the theme, direction, theme classes and portal container of the nearest\n * {@link WaveProvider}. Outside a provider it returns light/ltr defaults with `hasProvider: false`.\n *\n * @returns The {@link WaveContextValue} of the nearest provider.\n */\nexport function useWaveTheme(): WaveContextValue {\n return React.useContext(WaveContext);\n}\n\n/**\n * Applies Wave theming to an application or subtree.\n *\n * - Renders a `<div class=\"wave-root wave-<theme>\">` that declares the theme's tokens and paints\n * the themed background, text colour and font (`bg-background text-foreground font-wave\n * text-body-1`; a `className` passed by you wins). The precompiled `./styles` entry scopes its base\n * styles and native-element reset to this root, so it is required there.\n * - Sets `dir` and `data-wave-theme` on the root. An unknown `theme` value (from untyped code)\n * falls back to `'light'` — classes, `data-wave-theme` and the context value — and warns once in\n * development.\n * - Provides theme, direction, theme classes and the portal container through context, so\n * portaled overlays render with the same theme and direction.\n * - Nests: a provider inherits every prop it omits (`theme`, `dir`, `portalContainer`) from the\n * enclosing provider, so `<WaveProvider theme=\"light\">` inside an RTL app is a light panel that\n * stays right-to-left and keeps the app's portal container. At the top level the defaults are\n * `'light'`, `'ltr'` and `document.body`.\n * - `inputDefaults` nests differently: a nested provider's defined keys override the enclosing\n * provider's, and an omitted key is inherited, so setting only `appearance` in a nested provider\n * keeps the enclosing provider's `size`.\n */\nexport const WaveProvider = ({\n theme: themeProp,\n dir: dirProp,\n portalContainer: portalContainerProp,\n inputDefaults: inputDefaultsProp,\n children,\n className,\n ref,\n ...rest\n}: WaveProviderProps) => {\n // Omitted props come from the enclosing provider; outside one, DEFAULT_CONTEXT supplies the\n // top-level defaults. An explicit `portalContainer={null}` means document.body, so only\n // `undefined` inherits.\n const parent = React.useContext(WaveContext);\n const theme = themeProp ?? parent.theme;\n const dir = dirProp ?? parent.dir;\n const portalContainer =\n portalContainerProp === undefined ? parent.portalContainer : portalContainerProp;\n\n // Defined keys override the enclosing provider's; the merged object keeps its identity while the\n // two values are equal, so an inline `inputDefaults={{ … }}` does not re-render every input.\n const size = inputDefaultsProp?.size ?? parent.inputDefaults.size;\n const appearance = inputDefaultsProp?.appearance ?? parent.inputDefaults.appearance;\n const inputDefaults = React.useMemo<InputDefaults>(() => {\n const merged: InputDefaults = {};\n if (size !== undefined) merged.size = size;\n if (appearance !== undefined) merged.appearance = appearance;\n return merged;\n }, [size, appearance]);\n\n // An unknown value (untyped callers) renders, and is reported, as the light theme.\n const resolvedTheme: WaveTheme = isWaveTheme(theme) ? theme : 'light';\n const themeClassName = getThemeClassName(resolvedTheme);\n\n React.useEffect(() => {\n if (!isWaveTheme(theme)) {\n warnOnce(\n `WaveProvider:theme:${String(theme)}`,\n `WaveProvider: unknown theme \"${String(theme)}\". Valid themes: ${WAVE_THEMES.join(', ')}. Using \"light\".`,\n );\n }\n }, [theme]);\n\n const value = React.useMemo<WaveContextValue>(\n () => ({\n theme: resolvedTheme,\n dir,\n themeClassName,\n portalContainer,\n inputDefaults,\n hasProvider: true,\n }),\n [resolvedTheme, dir, themeClassName, portalContainer, inputDefaults],\n );\n\n return (\n <WaveContext.Provider value={value}>\n <div\n {...rest}\n ref={ref}\n dir={dir}\n data-wave-theme={resolvedTheme}\n className={cn(\n waveProviderClassNames.root,\n themeClassName,\n 'bg-background text-foreground font-wave text-body-1',\n className,\n )}\n >\n {children}\n </div>\n </WaveContext.Provider>\n );\n};\n\nWaveProvider.displayName = 'WaveProvider';\n"],"mappings":";;;;;;;;AAoFA,IAAMC,IAAcD,EAAM,cAAgC;CARxD,OAAO;CACP,KAAK;CACL,gBAAgB;CAChB,iBAAiB;CACjB,eAAe,CAAC;CAChB,aAAa;AAG2C,CAAe;AAQzE,SAAgBE,IAAiC;CAC/C,OAAOF,EAAM,WAAWC,CAAW;AACrC;AAsBA,IAAaE,KAAgB,EAC3B,OAAOC,GACP,KAAKC,GACL,iBAAiBC,GACjB,eAAeC,GACf,aACA,cACA,QACA,GAAGC,QACoB;CAIvB,IAAMC,IAAST,EAAM,WAAWC,CAAW,GACrCS,IAAQN,KAAaK,EAAO,OAC5BE,IAAMN,KAAWI,EAAO,KACxBG,IACJN,MAAwB,KAAA,IAAYG,EAAO,kBAAkBH,GAIzDO,IAAON,GAAmB,QAAQE,EAAO,cAAc,MACvDK,IAAaP,GAAmB,cAAcE,EAAO,cAAc,YACnEM,IAAgBf,EAAM,cAA6B;EACvD,IAAMgB,IAAwB,CAAC;EAG/B,OAFIH,MAAS,KAAA,MAAW,EAAO,OAAOA,IAClCC,MAAe,KAAA,MAAW,EAAO,aAAaA,IAC3CE;CACT,GAAG,CAACH,GAAMC,CAAU,CAAC,GAGfG,IAA2BC,EAAYR,CAAK,IAAIA,IAAQ,SACxDS,IAAiBC,EAAkBH,CAAa;CAEtD,EAAM,gBAAgB;EACpB,AAAKC,EAAYR,CAAK,KACpBW,EACE,sBAAsB,OAAOX,CAAK,KAClC,gCAAgC,OAAOA,CAAK,EAAE,mBAAmBY,EAAY,KAAK,IAAI,EAAE,iBAC1F;CAEJ,GAAG,CAACZ,CAAK,CAAC;CAEV,IAAMa,IAAQvB,EAAM,eACX;EACL,OAAOiB;EACP;EACA;EACA;EACA;EACA,aAAa;CACf,IACA;EAACA;EAAeN;EAAKQ;EAAgBP;EAAiBG;CAAa,CACrE;CAEA,OACE,kBAACd,EAAY,UAAb;EAA6B;EAC3B,UAAA,kBAAC,OAAD;GACE,GAAIO;GACC;GACA;GACL,mBAAiBS;GACjB,WAAWO,EACTC,EAAuB,MACvBN,GACA,uDACAO,CACF;GAEC;EACE,CAAA;CACe,CAAA;AAE1B;AAEA,EAAa,cAAc"}
|