@crisp-ui-kit/crisp 0.14.0 → 0.15.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.
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.ContextMenu = ContextMenu;
|
|
37
37
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
38
38
|
const React = __importStar(require("react"));
|
|
39
|
+
const menu_1 = require("../menu");
|
|
39
40
|
const contextmenu_recipe_1 = require("./contextmenu.recipe");
|
|
40
41
|
/**
|
|
41
42
|
* A right-click context menu — the popover surface positioned at the cursor.
|
|
@@ -63,16 +64,19 @@ function ContextMenu({ children, items, menuLabel = "Context menu", className, }
|
|
|
63
64
|
returnFocusTo.current?.focus?.();
|
|
64
65
|
returnFocusTo.current = null;
|
|
65
66
|
}, []);
|
|
66
|
-
/** The items a roving focus may land on: not separators, not disabled. */
|
|
67
|
-
const enabled = React.useCallback(() => Array.from(menuRef.current?.querySelectorAll('[role="menuitem"]:not([disabled])') ?? []), []);
|
|
68
67
|
// `role="menu"` puts a screen reader in application mode, where the arrow
|
|
69
|
-
// keys are the only navigation there is
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
// keys are the only navigation there is (#188). The model itself is crisp's
|
|
69
|
+
// shared one (#192) — Menu and all three RecordsTable surfaces run the same
|
|
70
|
+
// hook, and a fourth hand-written copy is how typeahead, menuitemcheckbox
|
|
71
|
+
// and the `[data-disabled]` spelling get lost one surface at a time.
|
|
72
|
+
const { onKeyDown: onMenuKeyDown } = (0, menu_1.useMenuKeyboard)({
|
|
73
|
+
open: !!pos,
|
|
74
|
+
close: () => close(true),
|
|
75
|
+
// Tab: the browser is already moving focus somewhere, so pulling it back
|
|
76
|
+
// to the trigger first would land the user in the wrong place
|
|
77
|
+
dismiss: () => close(),
|
|
78
|
+
contentRef: menuRef,
|
|
79
|
+
});
|
|
76
80
|
React.useEffect(() => {
|
|
77
81
|
if (!pos)
|
|
78
82
|
return;
|
|
@@ -88,29 +92,6 @@ function ContextMenu({ children, items, menuLabel = "Context menu", className, }
|
|
|
88
92
|
document.removeEventListener("keydown", onKey);
|
|
89
93
|
};
|
|
90
94
|
}, [pos, close]);
|
|
91
|
-
const onMenuKeyDown = (e) => {
|
|
92
|
-
// a menu is not a focus trap: Tab leaves, and leaving means closing
|
|
93
|
-
if (e.key === "Tab") {
|
|
94
|
-
close(true);
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
const step = e.key === "ArrowDown" ? 1 : e.key === "ArrowUp" ? -1 : 0;
|
|
98
|
-
const items = enabled();
|
|
99
|
-
if (!items.length)
|
|
100
|
-
return;
|
|
101
|
-
const at = items.indexOf(document.activeElement);
|
|
102
|
-
let next = null;
|
|
103
|
-
if (step)
|
|
104
|
-
next = (at + step + items.length) % items.length;
|
|
105
|
-
else if (e.key === "Home")
|
|
106
|
-
next = 0;
|
|
107
|
-
else if (e.key === "End")
|
|
108
|
-
next = items.length - 1;
|
|
109
|
-
if (next === null)
|
|
110
|
-
return;
|
|
111
|
-
e.preventDefault();
|
|
112
|
-
items[next]?.focus();
|
|
113
|
-
};
|
|
114
95
|
return ((0, jsx_runtime_1.jsxs)("div", { ref: rootRef, className: (0, contextmenu_recipe_1.contextmenuRecipe)({ className }), children: [(0, jsx_runtime_1.jsx)("div", { onContextMenu: open, children: children }), pos && ((0, jsx_runtime_1.jsx)("div", { ref: menuRef, className: "contextmenu-content", role: "menu", "aria-label": menuLabel, style: { left: pos.x, top: pos.y }, onKeyDown: onMenuKeyDown, children: items.map((item, i) => item.separator ? ((0, jsx_runtime_1.jsx)("hr", { className: "contextmenu-sep" }, i)) : ((0, jsx_runtime_1.jsxs)("button", { type: "button", role: "menuitem", disabled: item.disabled, className: item.danger
|
|
115
96
|
? "contextmenu-item contextmenu-item--danger"
|
|
116
97
|
: "contextmenu-item", tabIndex: -1, onClick: () => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import * as React from "react";
|
|
3
|
+
import { useMenuKeyboard } from "../menu/index.js";
|
|
3
4
|
import { contextmenuRecipe } from "./contextmenu.recipe.js";
|
|
4
5
|
/**
|
|
5
6
|
* A right-click context menu — the popover surface positioned at the cursor.
|
|
@@ -27,16 +28,19 @@ export function ContextMenu({ children, items, menuLabel = "Context menu", class
|
|
|
27
28
|
returnFocusTo.current?.focus?.();
|
|
28
29
|
returnFocusTo.current = null;
|
|
29
30
|
}, []);
|
|
30
|
-
/** The items a roving focus may land on: not separators, not disabled. */
|
|
31
|
-
const enabled = React.useCallback(() => Array.from(menuRef.current?.querySelectorAll('[role="menuitem"]:not([disabled])') ?? []), []);
|
|
32
31
|
// `role="menu"` puts a screen reader in application mode, where the arrow
|
|
33
|
-
// keys are the only navigation there is
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
// keys are the only navigation there is (#188). The model itself is crisp's
|
|
33
|
+
// shared one (#192) — Menu and all three RecordsTable surfaces run the same
|
|
34
|
+
// hook, and a fourth hand-written copy is how typeahead, menuitemcheckbox
|
|
35
|
+
// and the `[data-disabled]` spelling get lost one surface at a time.
|
|
36
|
+
const { onKeyDown: onMenuKeyDown } = useMenuKeyboard({
|
|
37
|
+
open: !!pos,
|
|
38
|
+
close: () => close(true),
|
|
39
|
+
// Tab: the browser is already moving focus somewhere, so pulling it back
|
|
40
|
+
// to the trigger first would land the user in the wrong place
|
|
41
|
+
dismiss: () => close(),
|
|
42
|
+
contentRef: menuRef,
|
|
43
|
+
});
|
|
40
44
|
React.useEffect(() => {
|
|
41
45
|
if (!pos)
|
|
42
46
|
return;
|
|
@@ -52,29 +56,6 @@ export function ContextMenu({ children, items, menuLabel = "Context menu", class
|
|
|
52
56
|
document.removeEventListener("keydown", onKey);
|
|
53
57
|
};
|
|
54
58
|
}, [pos, close]);
|
|
55
|
-
const onMenuKeyDown = (e) => {
|
|
56
|
-
// a menu is not a focus trap: Tab leaves, and leaving means closing
|
|
57
|
-
if (e.key === "Tab") {
|
|
58
|
-
close(true);
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
const step = e.key === "ArrowDown" ? 1 : e.key === "ArrowUp" ? -1 : 0;
|
|
62
|
-
const items = enabled();
|
|
63
|
-
if (!items.length)
|
|
64
|
-
return;
|
|
65
|
-
const at = items.indexOf(document.activeElement);
|
|
66
|
-
let next = null;
|
|
67
|
-
if (step)
|
|
68
|
-
next = (at + step + items.length) % items.length;
|
|
69
|
-
else if (e.key === "Home")
|
|
70
|
-
next = 0;
|
|
71
|
-
else if (e.key === "End")
|
|
72
|
-
next = items.length - 1;
|
|
73
|
-
if (next === null)
|
|
74
|
-
return;
|
|
75
|
-
e.preventDefault();
|
|
76
|
-
items[next]?.focus();
|
|
77
|
-
};
|
|
78
59
|
return (_jsxs("div", { ref: rootRef, className: contextmenuRecipe({ className }), children: [_jsx("div", { onContextMenu: open, children: children }), pos && (_jsx("div", { ref: menuRef, className: "contextmenu-content", role: "menu", "aria-label": menuLabel, style: { left: pos.x, top: pos.y }, onKeyDown: onMenuKeyDown, children: items.map((item, i) => item.separator ? (_jsx("hr", { className: "contextmenu-sep" }, i)) : (_jsxs("button", { type: "button", role: "menuitem", disabled: item.disabled, className: item.danger
|
|
79
60
|
? "contextmenu-item contextmenu-item--danger"
|
|
80
61
|
: "contextmenu-item", tabIndex: -1, onClick: () => {
|