@navikt/ds-react 7.2.1 → 7.3.1
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/cjs/accordion/AccordionHeader.js +1 -1
- package/cjs/accordion/AccordionHeader.js.map +1 -1
- package/cjs/alert/Alert.d.ts +0 -3
- package/cjs/alert/Alert.js +11 -17
- package/cjs/alert/Alert.js.map +1 -1
- package/cjs/chips/Removable.d.ts +5 -5
- package/cjs/chips/Removable.js +4 -2
- package/cjs/chips/Removable.js.map +1 -1
- package/cjs/collapsible/Collapsible.context.d.ts +1 -1
- package/cjs/date/datepicker/DatePicker.d.ts +2 -2
- package/cjs/date/monthpicker/MonthPicker.d.ts +2 -2
- package/cjs/form/combobox/Input/Input.js +1 -1
- package/cjs/form/combobox/Input/Input.js.map +1 -1
- package/cjs/form/combobox/types.d.ts +3 -1
- package/cjs/form/file-upload/FileUpload.context.d.ts +1 -1
- package/cjs/index.d.ts +1 -0
- package/cjs/index.js +4 -2
- package/cjs/index.js.map +1 -1
- package/cjs/layout/base/BasePrimitive.d.ts +3 -0
- package/cjs/layout/base/BasePrimitive.js.map +1 -1
- package/cjs/layout/box/Box.d.ts +2 -2
- package/cjs/layout/box/Box.js.map +1 -1
- package/cjs/layout/grid/HGrid.d.ts +2 -2
- package/cjs/layout/grid/HGrid.js.map +1 -1
- package/cjs/layout/stack/Stack.d.ts +2 -2
- package/cjs/layout/stack/Stack.js.map +1 -1
- package/cjs/modal/ModalHeader.js +6 -1
- package/cjs/modal/ModalHeader.js.map +1 -1
- package/cjs/modal/dialog-polyfill.js +2 -2
- package/cjs/modal/dialog-polyfill.js.map +1 -1
- package/cjs/overlays/action-menu/ActionMenu.d.ts +310 -0
- package/cjs/overlays/action-menu/ActionMenu.js +227 -0
- package/cjs/overlays/action-menu/ActionMenu.js.map +1 -0
- package/cjs/overlays/action-menu/index.d.ts +1 -0
- package/cjs/overlays/action-menu/index.js +19 -0
- package/cjs/overlays/action-menu/index.js.map +1 -0
- package/cjs/overlays/floating/Floating.js +9 -10
- package/cjs/overlays/floating/Floating.js.map +1 -1
- package/cjs/overlays/floating/Floating.utils.d.ts +3 -5
- package/cjs/overlays/floating/Floating.utils.js +0 -2
- package/cjs/overlays/floating/Floating.utils.js.map +1 -1
- package/cjs/overlays/floating-menu/Menu.d.ts +15 -21
- package/cjs/overlays/floating-menu/Menu.js +119 -230
- package/cjs/overlays/floating-menu/Menu.js.map +1 -1
- package/cjs/overlays/floating-menu/parts/RovingFocus.d.ts +1 -1
- package/cjs/overlays/floating-menu/parts/RovingFocus.js.map +1 -1
- package/cjs/pagination/Pagination.d.ts +1 -6
- package/cjs/pagination/Pagination.js.map +1 -1
- package/cjs/provider/i18n/LanguageProvider.d.ts +3 -3
- package/cjs/stepper/context.d.ts +1 -1
- package/cjs/table/Body.d.ts +2 -4
- package/cjs/table/Body.js.map +1 -1
- package/cjs/table/ColumnHeader.d.ts +1 -2
- package/cjs/table/ColumnHeader.js.map +1 -1
- package/cjs/table/ExpandableRow.d.ts +1 -2
- package/cjs/table/ExpandableRow.js.map +1 -1
- package/cjs/table/Header.d.ts +2 -4
- package/cjs/table/Header.js.map +1 -1
- package/cjs/table/HeaderCell.d.ts +1 -2
- package/cjs/table/HeaderCell.js.map +1 -1
- package/cjs/table/Row.d.ts +1 -2
- package/cjs/table/Row.js.map +1 -1
- package/cjs/tabs/Tabs.context.d.ts +1 -1
- package/cjs/toggle-group/ToggleGroup.context.d.ts +1 -1
- package/cjs/util/hooks/descendants/useDescendant.js +4 -4
- package/cjs/util/hooks/descendants/useDescendant.js.map +1 -1
- package/cjs/util/i18n/get.d.ts +2 -2
- package/cjs/util/i18n/get.js.map +1 -1
- package/cjs/util/i18n/i18n.context.d.ts +2 -3
- package/cjs/util/i18n/i18n.context.js.map +1 -1
- package/cjs/util/i18n/i18n.types.d.ts +5 -9
- package/cjs/util/i18n/locales/en.d.ts +39 -0
- package/cjs/util/i18n/locales/en.js +41 -0
- package/cjs/util/i18n/locales/en.js.map +1 -0
- package/cjs/util/i18n/locales/nb.d.ts +14 -0
- package/cjs/util/i18n/locales/nb.js +14 -0
- package/cjs/util/i18n/locales/nb.js.map +1 -1
- package/cjs/util/i18n/locales/nn.d.ts +39 -0
- package/cjs/util/i18n/locales/nn.js +41 -0
- package/cjs/util/i18n/locales/nn.js.map +1 -0
- package/cjs/util/requireReactElement.d.ts +2 -0
- package/cjs/util/requireReactElement.js +22 -0
- package/cjs/util/requireReactElement.js.map +1 -0
- package/cjs/util/virtualfocus/Context.d.ts +1 -1
- package/cjs/util/virtualfocus/parts/VirtualFocusContent.d.ts +1 -2
- package/cjs/util/virtualfocus/parts/VirtualFocusContent.js.map +1 -1
- package/esm/accordion/AccordionHeader.js +1 -1
- package/esm/accordion/AccordionHeader.js.map +1 -1
- package/esm/alert/Alert.d.ts +0 -3
- package/esm/alert/Alert.js +11 -17
- package/esm/alert/Alert.js.map +1 -1
- package/esm/chips/Removable.d.ts +5 -5
- package/esm/chips/Removable.js +4 -2
- package/esm/chips/Removable.js.map +1 -1
- package/esm/collapsible/Collapsible.context.d.ts +1 -1
- package/esm/date/datepicker/DatePicker.d.ts +2 -2
- package/esm/date/monthpicker/MonthPicker.d.ts +2 -2
- package/esm/form/combobox/Input/Input.js +1 -1
- package/esm/form/combobox/Input/Input.js.map +1 -1
- package/esm/form/combobox/types.d.ts +3 -1
- package/esm/form/file-upload/FileUpload.context.d.ts +1 -1
- package/esm/index.d.ts +1 -0
- package/esm/index.js +1 -0
- package/esm/index.js.map +1 -1
- package/esm/layout/base/BasePrimitive.d.ts +3 -0
- package/esm/layout/base/BasePrimitive.js.map +1 -1
- package/esm/layout/box/Box.d.ts +2 -2
- package/esm/layout/box/Box.js.map +1 -1
- package/esm/layout/grid/HGrid.d.ts +2 -2
- package/esm/layout/grid/HGrid.js.map +1 -1
- package/esm/layout/stack/Stack.d.ts +2 -2
- package/esm/layout/stack/Stack.js.map +1 -1
- package/esm/modal/ModalHeader.js +6 -1
- package/esm/modal/ModalHeader.js.map +1 -1
- package/esm/modal/dialog-polyfill.js +2 -2
- package/esm/modal/dialog-polyfill.js.map +1 -1
- package/esm/overlays/action-menu/ActionMenu.d.ts +310 -0
- package/esm/overlays/action-menu/ActionMenu.js +197 -0
- package/esm/overlays/action-menu/ActionMenu.js.map +1 -0
- package/esm/overlays/action-menu/index.d.ts +1 -0
- package/esm/overlays/action-menu/index.js +3 -0
- package/esm/overlays/action-menu/index.js.map +1 -0
- package/esm/overlays/floating/Floating.js +9 -10
- package/esm/overlays/floating/Floating.js.map +1 -1
- package/esm/overlays/floating/Floating.utils.d.ts +3 -5
- package/esm/overlays/floating/Floating.utils.js +0 -2
- package/esm/overlays/floating/Floating.utils.js.map +1 -1
- package/esm/overlays/floating-menu/Menu.d.ts +15 -21
- package/esm/overlays/floating-menu/Menu.js +119 -230
- package/esm/overlays/floating-menu/Menu.js.map +1 -1
- package/esm/overlays/floating-menu/parts/RovingFocus.d.ts +1 -1
- package/esm/overlays/floating-menu/parts/RovingFocus.js.map +1 -1
- package/esm/pagination/Pagination.d.ts +1 -6
- package/esm/pagination/Pagination.js.map +1 -1
- package/esm/provider/i18n/LanguageProvider.d.ts +3 -3
- package/esm/stepper/context.d.ts +1 -1
- package/esm/table/Body.d.ts +2 -4
- package/esm/table/Body.js.map +1 -1
- package/esm/table/ColumnHeader.d.ts +1 -2
- package/esm/table/ColumnHeader.js.map +1 -1
- package/esm/table/ExpandableRow.d.ts +1 -2
- package/esm/table/ExpandableRow.js.map +1 -1
- package/esm/table/Header.d.ts +2 -4
- package/esm/table/Header.js.map +1 -1
- package/esm/table/HeaderCell.d.ts +1 -2
- package/esm/table/HeaderCell.js.map +1 -1
- package/esm/table/Row.d.ts +1 -2
- package/esm/table/Row.js.map +1 -1
- package/esm/tabs/Tabs.context.d.ts +1 -1
- package/esm/toggle-group/ToggleGroup.context.d.ts +1 -1
- package/esm/util/hooks/descendants/useDescendant.js +4 -4
- package/esm/util/hooks/descendants/useDescendant.js.map +1 -1
- package/esm/util/i18n/get.d.ts +2 -2
- package/esm/util/i18n/get.js.map +1 -1
- package/esm/util/i18n/i18n.context.d.ts +2 -3
- package/esm/util/i18n/i18n.context.js.map +1 -1
- package/esm/util/i18n/i18n.types.d.ts +5 -9
- package/esm/util/i18n/locales/en.d.ts +39 -0
- package/esm/util/i18n/locales/en.js +39 -0
- package/esm/util/i18n/locales/en.js.map +1 -0
- package/esm/util/i18n/locales/nb.d.ts +14 -0
- package/esm/util/i18n/locales/nb.js +14 -0
- package/esm/util/i18n/locales/nb.js.map +1 -1
- package/esm/util/i18n/locales/nn.d.ts +39 -0
- package/esm/util/i18n/locales/nn.js +39 -0
- package/esm/util/i18n/locales/nn.js.map +1 -0
- package/esm/util/requireReactElement.d.ts +2 -0
- package/esm/util/requireReactElement.js +15 -0
- package/esm/util/requireReactElement.js.map +1 -0
- package/esm/util/virtualfocus/Context.d.ts +1 -1
- package/esm/util/virtualfocus/parts/VirtualFocusContent.d.ts +1 -2
- package/esm/util/virtualfocus/parts/VirtualFocusContent.js.map +1 -1
- package/package.json +15 -7
- package/src/accordion/AccordionHeader.tsx +0 -1
- package/src/alert/Alert.tsx +11 -20
- package/src/chips/Removable.tsx +13 -9
- package/src/date/datepicker/DatePicker.tsx +2 -2
- package/src/date/monthpicker/MonthPicker.tsx +2 -2
- package/src/form/checkbox/Checkbox.test.tsx +2 -3
- package/src/form/combobox/Input/Input.tsx +1 -1
- package/src/form/combobox/types.ts +3 -1
- package/src/form/confirmation-panel/ConfirmationPanel.test.tsx +1 -2
- package/src/form/radio/Radio.test.tsx +4 -5
- package/src/index.ts +1 -0
- package/src/layout/base/BasePrimitive.tsx +3 -0
- package/src/layout/box/Box.tsx +35 -36
- package/src/layout/grid/HGrid.tsx +26 -27
- package/src/layout/stack/Stack.tsx +53 -54
- package/src/modal/ModalHeader.tsx +6 -0
- package/src/modal/dialog-polyfill.ts +2 -2
- package/src/overlays/action-menu/ActionMenu.tsx +971 -0
- package/src/overlays/action-menu/index.ts +29 -0
- package/src/overlays/floating/Floating.tsx +6 -12
- package/src/overlays/floating/Floating.utils.ts +2 -5
- package/src/overlays/floating-menu/Menu.tsx +183 -332
- package/src/overlays/floating-menu/parts/RovingFocus.tsx +3 -3
- package/src/pagination/Pagination.tsx +4 -1
- package/src/pagination/steps.test.ts +15 -16
- package/src/provider/i18n/LanguageProvider.tsx +3 -3
- package/src/table/Body.tsx +4 -6
- package/src/table/ColumnHeader.tsx +3 -4
- package/src/table/ExpandableRow.tsx +3 -4
- package/src/table/Header.tsx +4 -6
- package/src/table/HeaderCell.tsx +3 -4
- package/src/table/Row.tsx +3 -4
- package/src/util/hooks/descendants/useDescendant.tsx +5 -5
- package/src/util/i18n/get.ts +3 -3
- package/src/util/i18n/i18n.context.ts +2 -3
- package/src/util/i18n/i18n.types.ts +7 -11
- package/src/util/i18n/locales/en.ts +40 -0
- package/src/util/i18n/locales/nb.ts +23 -1
- package/src/util/i18n/locales/nn.ts +40 -0
- package/src/util/i18n/locales.test.tsx +23 -0
- package/src/util/requireReactElement.ts +25 -0
- package/src/util/virtualfocus/parts/VirtualFocusContent.tsx +4 -2
- package/cjs/util/i18n/merge.d.ts +0 -2
- package/cjs/util/i18n/merge.js +0 -28
- package/cjs/util/i18n/merge.js.map +0 -1
- package/esm/util/i18n/merge.d.ts +0 -2
- package/esm/util/i18n/merge.js +0 -25
- package/esm/util/i18n/merge.js.map +0 -1
- package/src/util/i18n/merge.ts +0 -35
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
forwardRef,
|
|
3
|
-
useCallback,
|
|
4
|
-
useEffect,
|
|
5
|
-
useRef,
|
|
6
|
-
useState,
|
|
7
|
-
} from "react";
|
|
1
|
+
import React, { forwardRef, useEffect, useRef, useState } from "react";
|
|
8
2
|
import ReactDOM from "react-dom";
|
|
9
3
|
import { Portal } from "../../portal";
|
|
10
4
|
import { composeEventHandlers } from "../../util/composeEventHandlers";
|
|
@@ -24,17 +18,10 @@ import {
|
|
|
24
18
|
/* -------------------------------------------------------------------------- */
|
|
25
19
|
/* Constants */
|
|
26
20
|
/* -------------------------------------------------------------------------- */
|
|
27
|
-
const SELECTION_KEYS = ["Enter", " "];
|
|
28
|
-
const SUB_OPEN_KEYS = [...SELECTION_KEYS, "ArrowRight"];
|
|
29
|
-
const SUB_CLOSE_KEYS = ["ArrowLeft"];
|
|
30
21
|
const FIRST_KEYS = ["ArrowDown", "PageUp", "Home"];
|
|
31
22
|
const LAST_KEYS = ["ArrowUp", "PageDown", "End"];
|
|
32
23
|
const FIRST_LAST_KEYS = [...FIRST_KEYS, ...LAST_KEYS];
|
|
33
24
|
|
|
34
|
-
type Point = { x: number; y: number };
|
|
35
|
-
type Polygon = Point[];
|
|
36
|
-
type SubMenuSide = "left" | "right";
|
|
37
|
-
type GraceIntent = { area: Polygon; side: SubMenuSide };
|
|
38
25
|
type CheckedState = boolean | "indeterminate";
|
|
39
26
|
|
|
40
27
|
/* -------------------------------------------------------------------------- */
|
|
@@ -56,7 +43,7 @@ interface MenuComponent extends React.FC<MenuProps> {
|
|
|
56
43
|
CheckboxItem: typeof MenuCheckboxItem;
|
|
57
44
|
RadioGroup: typeof MenuRadioGroup;
|
|
58
45
|
RadioItem: typeof MenuRadioItem;
|
|
59
|
-
|
|
46
|
+
Divider: typeof MenuDivider;
|
|
60
47
|
Sub: typeof MenuSub;
|
|
61
48
|
SubTrigger: typeof MenuSubTrigger;
|
|
62
49
|
SubContent: typeof MenuSubContent;
|
|
@@ -68,7 +55,12 @@ const [
|
|
|
68
55
|
useMenuDescendantsContext,
|
|
69
56
|
useMenuDescendants,
|
|
70
57
|
useMenuDescendant,
|
|
71
|
-
] = createDescendantContext<
|
|
58
|
+
] = createDescendantContext<
|
|
59
|
+
SlottedDivElementRef,
|
|
60
|
+
{
|
|
61
|
+
closeMenu: () => void;
|
|
62
|
+
}
|
|
63
|
+
>();
|
|
72
64
|
|
|
73
65
|
type MenuContentElementRef = React.ElementRef<typeof Floating.Content>;
|
|
74
66
|
|
|
@@ -180,22 +172,8 @@ const MenuAnchor = forwardRef<MenuAnchorElement, MenuAnchorProps>(
|
|
|
180
172
|
/* -------------------------------------------------------------------------- */
|
|
181
173
|
/* Menu Content */
|
|
182
174
|
/* -------------------------------------------------------------------------- */
|
|
183
|
-
type MenuContentContextValue = {
|
|
184
|
-
onItemEnter: (event: React.PointerEvent) => void;
|
|
185
|
-
onItemLeave: (event: React.PointerEvent) => void;
|
|
186
|
-
onPointerLeaveTrigger: (event: React.PointerEvent) => void;
|
|
187
|
-
pointerGraceTimerRef: React.MutableRefObject<number>;
|
|
188
|
-
onPointerGraceIntentChange: (intent: GraceIntent | null) => void;
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
const [MenuContentProvider, useMenuContentContext] =
|
|
192
|
-
createContext<MenuContentContextValue>({
|
|
193
|
-
providerName: "MenuContentProvider",
|
|
194
|
-
hookName: "useMenuContentContext",
|
|
195
|
-
});
|
|
196
|
-
|
|
197
175
|
type MenuContentElement = MenuContentInternalElement;
|
|
198
|
-
|
|
176
|
+
type MenuContentProps = MenuContentInternalTypeProps;
|
|
199
177
|
|
|
200
178
|
const MenuContent = React.forwardRef<
|
|
201
179
|
MenuContentInternalElement,
|
|
@@ -286,6 +264,7 @@ interface MenuContentInternalProps
|
|
|
286
264
|
onPointerDownOutside?: DismissableLayerProps["onPointerDownOutside"];
|
|
287
265
|
onFocusOutside?: DismissableLayerProps["onFocusOutside"];
|
|
288
266
|
onInteractOutside?: DismissableLayerProps["onInteractOutside"];
|
|
267
|
+
safeZone?: DismissableLayerProps["safeZone"];
|
|
289
268
|
}
|
|
290
269
|
|
|
291
270
|
const MenuContentInternal = forwardRef<
|
|
@@ -303,6 +282,7 @@ const MenuContentInternal = forwardRef<
|
|
|
303
282
|
onFocusOutside,
|
|
304
283
|
onInteractOutside,
|
|
305
284
|
onDismiss,
|
|
285
|
+
safeZone,
|
|
306
286
|
...rest
|
|
307
287
|
}: MenuContentInternalProps,
|
|
308
288
|
forwardedRef,
|
|
@@ -318,149 +298,80 @@ const MenuContentInternal = forwardRef<
|
|
|
318
298
|
contentRef,
|
|
319
299
|
context.onContentChange,
|
|
320
300
|
);
|
|
321
|
-
const pointerGraceTimerRef = React.useRef(0);
|
|
322
|
-
const pointerGraceIntentRef = React.useRef<GraceIntent | null>(null);
|
|
323
|
-
const pointerDirRef = React.useRef<SubMenuSide>("right");
|
|
324
|
-
const lastPointerXRef = React.useRef(0);
|
|
325
|
-
|
|
326
|
-
const isPointerMovingToSubmenu = React.useCallback(
|
|
327
|
-
(event: React.PointerEvent) => {
|
|
328
|
-
const isMovingTowards =
|
|
329
|
-
pointerDirRef.current === pointerGraceIntentRef.current?.side;
|
|
330
|
-
return (
|
|
331
|
-
isMovingTowards &&
|
|
332
|
-
isPointerInGraceArea(event, pointerGraceIntentRef.current?.area)
|
|
333
|
-
);
|
|
334
|
-
},
|
|
335
|
-
[],
|
|
336
|
-
);
|
|
337
301
|
|
|
338
302
|
return (
|
|
339
|
-
<
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
)}
|
|
346
|
-
|
|
347
|
-
(event) => {
|
|
348
|
-
if (isPointerMovingToSubmenu(event)) return;
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Resets focus from current active item to content area
|
|
352
|
-
* This is to prevent focus from being stuck on an item when we move pointer outside the menu or onto a disabled item
|
|
353
|
-
*/
|
|
354
|
-
contentRef.current?.focus();
|
|
355
|
-
},
|
|
356
|
-
[isPointerMovingToSubmenu],
|
|
357
|
-
)}
|
|
358
|
-
onPointerLeaveTrigger={React.useCallback(
|
|
359
|
-
(event) => {
|
|
360
|
-
if (isPointerMovingToSubmenu(event)) event.preventDefault();
|
|
361
|
-
},
|
|
362
|
-
[isPointerMovingToSubmenu],
|
|
363
|
-
)}
|
|
364
|
-
pointerGraceTimerRef={pointerGraceTimerRef}
|
|
365
|
-
onPointerGraceIntentChange={React.useCallback((intent) => {
|
|
366
|
-
pointerGraceIntentRef.current = intent;
|
|
367
|
-
}, [])}
|
|
303
|
+
<FocusScope
|
|
304
|
+
onMountHandler={composeEventHandlers(onOpenAutoFocus, (event) => {
|
|
305
|
+
// when opening, explicitly focus the content area only and leave
|
|
306
|
+
// `onEntryFocus` in control of focusing first item
|
|
307
|
+
event.preventDefault();
|
|
308
|
+
contentRef.current?.focus({ preventScroll: true });
|
|
309
|
+
})}
|
|
310
|
+
onUnmountHandler={onCloseAutoFocus}
|
|
368
311
|
>
|
|
369
|
-
<
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
}
|
|
376
|
-
|
|
312
|
+
<DismissableLayer
|
|
313
|
+
asChild
|
|
314
|
+
disableOutsidePointerEvents={disableOutsidePointerEvents}
|
|
315
|
+
onEscapeKeyDown={onEscapeKeyDown}
|
|
316
|
+
onPointerDownOutside={onPointerDownOutside}
|
|
317
|
+
onFocusOutside={onFocusOutside}
|
|
318
|
+
onInteractOutside={onInteractOutside}
|
|
319
|
+
onDismiss={onDismiss}
|
|
320
|
+
safeZone={safeZone}
|
|
377
321
|
>
|
|
378
|
-
<
|
|
322
|
+
<RovingFocus
|
|
379
323
|
asChild
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
324
|
+
descendants={descendants}
|
|
325
|
+
onEntryFocus={composeEventHandlers(onEntryFocus, (event) => {
|
|
326
|
+
// only focus first item when using keyboard
|
|
327
|
+
if (!rootContext.isUsingKeyboardRef.current)
|
|
328
|
+
event.preventDefault();
|
|
329
|
+
})}
|
|
386
330
|
>
|
|
387
|
-
<
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
331
|
+
<Floating.Content
|
|
332
|
+
role="menu"
|
|
333
|
+
aria-orientation="vertical"
|
|
334
|
+
data-state={getOpenState(context.open)}
|
|
335
|
+
data-aksel-menu-content=""
|
|
336
|
+
dir="ltr"
|
|
337
|
+
{...rest}
|
|
338
|
+
ref={composedRefs}
|
|
339
|
+
style={{ outline: "none", ...rest.style }}
|
|
340
|
+
onKeyDown={composeEventHandlers(rest.onKeyDown, (event) => {
|
|
341
|
+
// submenu key events bubble through portals. We only care about keys in this menu.
|
|
342
|
+
const target = event.target as HTMLElement;
|
|
343
|
+
const isKeyDownInside =
|
|
344
|
+
target.closest("[data-aksel-menu-content]") ===
|
|
345
|
+
event.currentTarget;
|
|
346
|
+
if (isKeyDownInside) {
|
|
347
|
+
// menus should not be navigated using tab key so we prevent it
|
|
348
|
+
if (event.key === "Tab") event.preventDefault();
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// focus first/last item based on key pressed
|
|
352
|
+
const content = contentRef.current;
|
|
353
|
+
if (event.target !== content) return;
|
|
354
|
+
if (!FIRST_LAST_KEYS.includes(event.key)) return;
|
|
355
|
+
event.preventDefault();
|
|
356
|
+
|
|
357
|
+
if (LAST_KEYS.includes(event.key)) {
|
|
358
|
+
descendants.lastEnabled()?.node?.focus();
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
descendants.firstEnabled()?.node?.focus();
|
|
394
362
|
})}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
data-state={getOpenState(context.open)}
|
|
400
|
-
data-aksel-menu-content=""
|
|
401
|
-
dir="ltr"
|
|
402
|
-
{...rest}
|
|
403
|
-
ref={composedRefs}
|
|
404
|
-
style={{ outline: "none", ...rest.style }}
|
|
405
|
-
onKeyDown={composeEventHandlers(rest.onKeyDown, (event) => {
|
|
406
|
-
// submenu key events bubble through portals. We only care about keys in this menu.
|
|
407
|
-
const target = event.target as HTMLElement;
|
|
408
|
-
const isKeyDownInside =
|
|
409
|
-
target.closest("[data-aksel-menu-content]") ===
|
|
410
|
-
event.currentTarget;
|
|
411
|
-
if (isKeyDownInside) {
|
|
412
|
-
// menus should not be navigated using tab key so we prevent it
|
|
413
|
-
if (event.key === "Tab") event.preventDefault();
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
// focus first/last item based on key pressed
|
|
417
|
-
const content = contentRef.current;
|
|
418
|
-
if (event.target !== content) return;
|
|
419
|
-
if (!FIRST_LAST_KEYS.includes(event.key)) return;
|
|
420
|
-
event.preventDefault();
|
|
421
|
-
|
|
422
|
-
if (LAST_KEYS.includes(event.key)) {
|
|
423
|
-
descendants.lastEnabled()?.node?.focus();
|
|
424
|
-
return;
|
|
425
|
-
}
|
|
426
|
-
descendants.firstEnabled()?.node?.focus();
|
|
427
|
-
})}
|
|
428
|
-
onPointerMove={composeEventHandlers(
|
|
429
|
-
rest.onPointerMove,
|
|
430
|
-
whenMouse((event) => {
|
|
431
|
-
const target = event.target as HTMLElement;
|
|
432
|
-
const pointerXHasChanged =
|
|
433
|
-
lastPointerXRef.current !== event.clientX;
|
|
434
|
-
|
|
435
|
-
// We don't use `event.movementX` for this check because Safari will
|
|
436
|
-
// always return `0` on a pointer event.
|
|
437
|
-
if (
|
|
438
|
-
event.currentTarget.contains(target) &&
|
|
439
|
-
pointerXHasChanged
|
|
440
|
-
) {
|
|
441
|
-
const newDir =
|
|
442
|
-
event.clientX > lastPointerXRef.current
|
|
443
|
-
? "right"
|
|
444
|
-
: "left";
|
|
445
|
-
pointerDirRef.current = newDir;
|
|
446
|
-
lastPointerXRef.current = event.clientX;
|
|
447
|
-
}
|
|
448
|
-
}),
|
|
449
|
-
)}
|
|
450
|
-
/>
|
|
451
|
-
</RovingFocus>
|
|
452
|
-
</DismissableLayer>
|
|
453
|
-
</FocusScope>
|
|
454
|
-
</MenuContentProvider>
|
|
363
|
+
/>
|
|
364
|
+
</RovingFocus>
|
|
365
|
+
</DismissableLayer>
|
|
366
|
+
</FocusScope>
|
|
455
367
|
);
|
|
456
368
|
},
|
|
457
369
|
);
|
|
458
370
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
> {}
|
|
371
|
+
type MenuContentInternalTypeProps = Omit<
|
|
372
|
+
MenuContentInternalProps,
|
|
373
|
+
keyof MenuContentInternalPrivateProps
|
|
374
|
+
>;
|
|
464
375
|
|
|
465
376
|
/* -------------------------------------------------------------------------- */
|
|
466
377
|
/* Menu item */
|
|
@@ -482,6 +393,7 @@ const MenuItem = forwardRef<MenuItemElement, MenuItemProps>(
|
|
|
482
393
|
onPointerUp,
|
|
483
394
|
onPointerDown,
|
|
484
395
|
onKeyDown,
|
|
396
|
+
onKeyUp,
|
|
485
397
|
...rest
|
|
486
398
|
}: MenuItemProps,
|
|
487
399
|
forwardedRef,
|
|
@@ -510,6 +422,28 @@ const MenuItem = forwardRef<MenuItemElement, MenuItemProps>(
|
|
|
510
422
|
} else {
|
|
511
423
|
rootContext.onClose();
|
|
512
424
|
}
|
|
425
|
+
} else if (!disabled && menuItem) {
|
|
426
|
+
rootContext.onClose();
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
const handleKey = (
|
|
431
|
+
event: React.KeyboardEvent<HTMLDivElement>,
|
|
432
|
+
key: "Enter" | " ",
|
|
433
|
+
) => {
|
|
434
|
+
if (disabled || event.repeat) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (key === event.key) {
|
|
439
|
+
event.currentTarget.click();
|
|
440
|
+
/**
|
|
441
|
+
* We prevent default browser behaviour for selection keys as they should only trigger
|
|
442
|
+
* selection.
|
|
443
|
+
* - Prevents space from scrolling the page.
|
|
444
|
+
* - If keydown causes focus to move, prevents keydown from firing on the new target.
|
|
445
|
+
*/
|
|
446
|
+
event.preventDefault();
|
|
513
447
|
}
|
|
514
448
|
};
|
|
515
449
|
|
|
@@ -519,7 +453,13 @@ const MenuItem = forwardRef<MenuItemElement, MenuItemProps>(
|
|
|
519
453
|
tabIndex={disabled ? -1 : 0}
|
|
520
454
|
ref={composedRefs}
|
|
521
455
|
disabled={disabled}
|
|
522
|
-
onClick={composeEventHandlers(onClick, handleSelect
|
|
456
|
+
onClick={composeEventHandlers(onClick, handleSelect, {
|
|
457
|
+
/**
|
|
458
|
+
* Nextjs prevents default on click when using Link component, so we have to force click-event
|
|
459
|
+
* https://github.com/vercel/next.js/blob/77dcd4c66a35d0e8ef639bda4d05873bd3c0f52d/packages/next/src/client/link.tsx#L211
|
|
460
|
+
*/
|
|
461
|
+
checkForDefaultPrevented: false,
|
|
462
|
+
})}
|
|
523
463
|
onPointerDown={composeEventHandlers(
|
|
524
464
|
onPointerDown,
|
|
525
465
|
() => {
|
|
@@ -533,21 +473,12 @@ const MenuItem = forwardRef<MenuItemElement, MenuItemProps>(
|
|
|
533
473
|
// prevent Firefox from getting stuck in text selection mode when the menu closes.
|
|
534
474
|
if (!isPointerDownRef.current) event.currentTarget?.click();
|
|
535
475
|
})}
|
|
536
|
-
onKeyDown={composeEventHandlers(onKeyDown, (event) =>
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
/**
|
|
543
|
-
* We prevent default browser behaviour for selection keys as they should only trigger
|
|
544
|
-
* selection.
|
|
545
|
-
* - Prevents space from scrolling the page.
|
|
546
|
-
* - If keydown causes focus to move, prevents keydown from firing on the new target.
|
|
547
|
-
*/
|
|
548
|
-
event.preventDefault();
|
|
549
|
-
}
|
|
550
|
-
})}
|
|
476
|
+
onKeyDown={composeEventHandlers(onKeyDown, (event) =>
|
|
477
|
+
handleKey(event, "Enter"),
|
|
478
|
+
)}
|
|
479
|
+
onKeyUp={composeEventHandlers(onKeyUp, (event) =>
|
|
480
|
+
handleKey(event, " "),
|
|
481
|
+
)}
|
|
551
482
|
/>
|
|
552
483
|
);
|
|
553
484
|
},
|
|
@@ -573,9 +504,16 @@ const MenuItemInternal = forwardRef<
|
|
|
573
504
|
}: MenuItemInternalProps,
|
|
574
505
|
forwardedRef,
|
|
575
506
|
) => {
|
|
576
|
-
const
|
|
507
|
+
const context = useMenuContext();
|
|
508
|
+
const { register } = useMenuDescendant({
|
|
509
|
+
disabled,
|
|
510
|
+
closeMenu: () => {
|
|
511
|
+
rest["data-submenu-trigger"] &&
|
|
512
|
+
context.open &&
|
|
513
|
+
context.onOpenChange(false);
|
|
514
|
+
},
|
|
515
|
+
});
|
|
577
516
|
|
|
578
|
-
const contentContext = useMenuContentContext();
|
|
579
517
|
const ref = useRef<HTMLDivElement>(null);
|
|
580
518
|
const composedRefs = useMergeRefs(forwardedRef, ref, register);
|
|
581
519
|
|
|
@@ -601,18 +539,15 @@ const MenuItemInternal = forwardRef<
|
|
|
601
539
|
* In the edgecase the focus is still stuck on a previous item, we make sure to reset it
|
|
602
540
|
* even when the disabled item can't be focused itself to reset it.
|
|
603
541
|
*/
|
|
604
|
-
|
|
542
|
+
context.content?.focus();
|
|
605
543
|
} else {
|
|
606
|
-
|
|
607
|
-
if (!event.defaultPrevented) {
|
|
608
|
-
event.currentTarget.focus();
|
|
609
|
-
}
|
|
544
|
+
event.currentTarget.focus();
|
|
610
545
|
}
|
|
611
546
|
}),
|
|
612
547
|
)}
|
|
613
548
|
onPointerLeave={composeEventHandlers(
|
|
614
549
|
onPointerLeave,
|
|
615
|
-
whenMouse(
|
|
550
|
+
whenMouse(() => context.content?.focus()),
|
|
616
551
|
)}
|
|
617
552
|
/>
|
|
618
553
|
);
|
|
@@ -622,7 +557,7 @@ const MenuItemInternal = forwardRef<
|
|
|
622
557
|
/* -------------------------------------------------------------------------- */
|
|
623
558
|
/* Menu Group */
|
|
624
559
|
/* -------------------------------------------------------------------------- */
|
|
625
|
-
|
|
560
|
+
type MenuGroupProps = SlottedDivProps;
|
|
626
561
|
|
|
627
562
|
const MenuGroup = forwardRef<SlottedDivElementRef, MenuGroupProps>(
|
|
628
563
|
(props: MenuGroupProps, ref) => {
|
|
@@ -696,7 +631,7 @@ const [MenuItemIndicatorProvider, useMenuItemIndicatorContext] = createContext<{
|
|
|
696
631
|
hookName: "useMenuItemIndicatorContext",
|
|
697
632
|
});
|
|
698
633
|
|
|
699
|
-
|
|
634
|
+
type MenuItemIndicatorProps = SlottedDivProps;
|
|
700
635
|
|
|
701
636
|
const MenuItemIndicator = forwardRef<
|
|
702
637
|
SlottedDivElementRef,
|
|
@@ -786,12 +721,12 @@ const MenuCheckboxItem = forwardRef<MenuItemElement, MenuCheckboxItemProps>(
|
|
|
786
721
|
);
|
|
787
722
|
|
|
788
723
|
/* -------------------------------------------------------------------------- */
|
|
789
|
-
/* Menu
|
|
724
|
+
/* Menu Divider */
|
|
790
725
|
/* -------------------------------------------------------------------------- */
|
|
791
|
-
|
|
726
|
+
type MenuDividerProps = SlottedDivProps;
|
|
792
727
|
|
|
793
|
-
const
|
|
794
|
-
(props:
|
|
728
|
+
const MenuDivider = forwardRef<SlottedDivElementRef, MenuDividerProps>(
|
|
729
|
+
(props: MenuDividerProps, ref) => {
|
|
795
730
|
return (
|
|
796
731
|
<SlottedDivElement
|
|
797
732
|
role="separator"
|
|
@@ -833,6 +768,8 @@ const MenuSub: React.FC<MenuSubProps> = ({
|
|
|
833
768
|
}: MenuSubProps) => {
|
|
834
769
|
const parentMenuContext = useMenuContext();
|
|
835
770
|
|
|
771
|
+
const { values } = useMenuDescendantsContext();
|
|
772
|
+
|
|
836
773
|
const [trigger, setTrigger] = useState<MenuItemElement | null>(null);
|
|
837
774
|
const [content, setContent] = useState<MenuContentInternalElement | null>(
|
|
838
775
|
null,
|
|
@@ -851,7 +788,17 @@ const MenuSub: React.FC<MenuSubProps> = ({
|
|
|
851
788
|
<Floating>
|
|
852
789
|
<MenuProvider
|
|
853
790
|
open={open}
|
|
854
|
-
onOpenChange={
|
|
791
|
+
onOpenChange={(_open) => {
|
|
792
|
+
handleOpenChange(_open);
|
|
793
|
+
if (_open) {
|
|
794
|
+
/* Makes sure to close all adjacent submenus if they are open */
|
|
795
|
+
values().forEach((descendant) => {
|
|
796
|
+
if (descendant.node !== trigger) {
|
|
797
|
+
descendant.closeMenu();
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
}}
|
|
855
802
|
content={content}
|
|
856
803
|
onContentChange={setContent}
|
|
857
804
|
>
|
|
@@ -871,34 +818,31 @@ const MenuSub: React.FC<MenuSubProps> = ({
|
|
|
871
818
|
/* -------------------------------------------------------------------------- */
|
|
872
819
|
/* Menu SubMenu Trigger */
|
|
873
820
|
/* -------------------------------------------------------------------------- */
|
|
874
|
-
|
|
821
|
+
type MenuSubTriggerProps = MenuItemInternalProps;
|
|
875
822
|
|
|
876
823
|
const MenuSubTrigger = forwardRef<MenuItemElement, MenuSubTriggerProps>(
|
|
877
824
|
(props: MenuSubTriggerProps, forwardedRef) => {
|
|
878
825
|
const context = useMenuContext();
|
|
879
826
|
const subContext = useMenuSubContext();
|
|
880
|
-
const contentContext = useMenuContentContext();
|
|
881
|
-
const openTimerRef = useRef<number | null>(null);
|
|
882
|
-
const { pointerGraceTimerRef, onPointerGraceIntentChange } = contentContext;
|
|
883
827
|
|
|
884
828
|
const composedRefs = useMergeRefs(forwardedRef, subContext.onTriggerChange);
|
|
885
829
|
|
|
886
|
-
const
|
|
887
|
-
|
|
888
|
-
|
|
830
|
+
const handleKey = (
|
|
831
|
+
event: React.KeyboardEvent<HTMLDivElement>,
|
|
832
|
+
keys: string[],
|
|
833
|
+
) => {
|
|
834
|
+
if (props.disabled) {
|
|
835
|
+
return;
|
|
889
836
|
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
onPointerGraceIntentChange(null);
|
|
900
|
-
};
|
|
901
|
-
}, [pointerGraceTimerRef, onPointerGraceIntentChange]);
|
|
837
|
+
if (keys.includes(event.key)) {
|
|
838
|
+
context.onOpenChange(true);
|
|
839
|
+
// The trigger may hold focus if opened via pointer interaction
|
|
840
|
+
// so we ensure content is given focus again when switching to keyboard.
|
|
841
|
+
context.content?.focus();
|
|
842
|
+
// prevent window from scrolling
|
|
843
|
+
event.preventDefault();
|
|
844
|
+
}
|
|
845
|
+
};
|
|
902
846
|
|
|
903
847
|
return (
|
|
904
848
|
<MenuAnchor asChild>
|
|
@@ -910,85 +854,25 @@ const MenuSubTrigger = forwardRef<MenuItemElement, MenuSubTriggerProps>(
|
|
|
910
854
|
data-state={getOpenState(context.open)}
|
|
911
855
|
{...props}
|
|
912
856
|
ref={composedRefs}
|
|
913
|
-
|
|
914
|
-
* onClick is added to solve edgecase where the user clicks the trigger,
|
|
915
|
-
* but the focus is outside browser-window or viewport at first.
|
|
916
|
-
*/
|
|
857
|
+
data-submenu-trigger
|
|
917
858
|
onClick={(event) => {
|
|
859
|
+
if (props.disabled || event.defaultPrevented) {
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
918
862
|
props.onClick?.(event);
|
|
919
|
-
|
|
920
|
-
|
|
863
|
+
/*
|
|
864
|
+
* Solves edgecase where the user clicks the trigger,
|
|
865
|
+
* but the focus is outside browser-window or viewport at first.
|
|
866
|
+
*/
|
|
921
867
|
event.currentTarget.focus();
|
|
922
|
-
|
|
868
|
+
context.onOpenChange(!context.open);
|
|
923
869
|
}}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
whenMouse((event) => {
|
|
927
|
-
if (event.defaultPrevented) return;
|
|
928
|
-
if (!props.disabled && !context.open && !openTimerRef.current) {
|
|
929
|
-
contentContext.onPointerGraceIntentChange(null);
|
|
930
|
-
openTimerRef.current = window.setTimeout(() => {
|
|
931
|
-
context.onOpenChange(true);
|
|
932
|
-
clearOpenTimer();
|
|
933
|
-
}, 100);
|
|
934
|
-
}
|
|
935
|
-
}),
|
|
870
|
+
onKeyDown={composeEventHandlers(props.onKeyDown, (event) =>
|
|
871
|
+
handleKey(event, ["Enter", "ArrowRight"]),
|
|
936
872
|
)}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
whenMouse((event) => {
|
|
940
|
-
clearOpenTimer();
|
|
941
|
-
|
|
942
|
-
const contentRect = context.content?.getBoundingClientRect();
|
|
943
|
-
if (contentRect) {
|
|
944
|
-
const side = context.content?.dataset.side as SubMenuSide;
|
|
945
|
-
const rightSide = side === "right";
|
|
946
|
-
const bleed = rightSide ? -5 : +5;
|
|
947
|
-
const contentNearEdge =
|
|
948
|
-
contentRect[rightSide ? "left" : "right"];
|
|
949
|
-
const contentFarEdge =
|
|
950
|
-
contentRect[rightSide ? "right" : "left"];
|
|
951
|
-
|
|
952
|
-
contentContext.onPointerGraceIntentChange({
|
|
953
|
-
area: [
|
|
954
|
-
// Apply a bleed on clientX to ensure that our exit point is
|
|
955
|
-
// consistently within polygon bounds
|
|
956
|
-
{ x: event.clientX + bleed, y: event.clientY },
|
|
957
|
-
{ x: contentNearEdge, y: contentRect.top },
|
|
958
|
-
{ x: contentFarEdge, y: contentRect.top },
|
|
959
|
-
{ x: contentFarEdge, y: contentRect.bottom },
|
|
960
|
-
{ x: contentNearEdge, y: contentRect.bottom },
|
|
961
|
-
],
|
|
962
|
-
side,
|
|
963
|
-
});
|
|
964
|
-
|
|
965
|
-
window.clearTimeout(pointerGraceTimerRef.current);
|
|
966
|
-
pointerGraceTimerRef.current = window.setTimeout(
|
|
967
|
-
() => contentContext.onPointerGraceIntentChange(null),
|
|
968
|
-
300,
|
|
969
|
-
);
|
|
970
|
-
} else {
|
|
971
|
-
contentContext.onPointerLeaveTrigger(event);
|
|
972
|
-
if (event.defaultPrevented) return;
|
|
973
|
-
|
|
974
|
-
// There's 100ms where the user may leave an item before the submenu was opened.
|
|
975
|
-
contentContext.onPointerGraceIntentChange(null);
|
|
976
|
-
}
|
|
977
|
-
}),
|
|
873
|
+
onKeyUp={composeEventHandlers(props.onKeyUp, (event) =>
|
|
874
|
+
handleKey(event, [" "]),
|
|
978
875
|
)}
|
|
979
|
-
onKeyDown={composeEventHandlers(props.onKeyDown, (event) => {
|
|
980
|
-
if (props.disabled) {
|
|
981
|
-
return;
|
|
982
|
-
}
|
|
983
|
-
if (SUB_OPEN_KEYS.includes(event.key)) {
|
|
984
|
-
context.onOpenChange(true);
|
|
985
|
-
// The trigger may hold focus if opened via pointer interaction
|
|
986
|
-
// so we ensure content is given focus again when switching to keyboard.
|
|
987
|
-
context.content?.focus();
|
|
988
|
-
// prevent window from scrolling
|
|
989
|
-
event.preventDefault();
|
|
990
|
-
}
|
|
991
|
-
})}
|
|
992
876
|
/>
|
|
993
877
|
</MenuAnchor>
|
|
994
878
|
);
|
|
@@ -998,15 +882,14 @@ const MenuSubTrigger = forwardRef<MenuItemElement, MenuSubTriggerProps>(
|
|
|
998
882
|
/* -------------------------------------------------------------------------- */
|
|
999
883
|
/* Menu SubMenu Content */
|
|
1000
884
|
/* -------------------------------------------------------------------------- */
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
> {}
|
|
885
|
+
type MenuSubContentProps = Omit<
|
|
886
|
+
MenuContentInternalProps,
|
|
887
|
+
| keyof MenuContentInternalPrivateProps
|
|
888
|
+
| "onCloseAutoFocus"
|
|
889
|
+
| "onEntryFocus"
|
|
890
|
+
| "side"
|
|
891
|
+
| "align"
|
|
892
|
+
>;
|
|
1010
893
|
|
|
1011
894
|
const MenuSubContent = forwardRef<
|
|
1012
895
|
MenuContentInternalElement,
|
|
@@ -1037,14 +920,8 @@ const MenuSubContent = forwardRef<
|
|
|
1037
920
|
}
|
|
1038
921
|
event.preventDefault();
|
|
1039
922
|
}}
|
|
1040
|
-
|
|
1041
|
-
// don't want it to refocus the trigger in that case so we handle trigger focus ourselves.
|
|
923
|
+
/* Since we manually focus Subtrigger, we prevent use of auto-focus */
|
|
1042
924
|
onCloseAutoFocus={(event) => event.preventDefault()}
|
|
1043
|
-
onFocusOutside={composeEventHandlers(props.onFocusOutside, (event) => {
|
|
1044
|
-
// We prevent closing when the trigger is focused to avoid triggering a re-open animation
|
|
1045
|
-
// on pointer interaction.
|
|
1046
|
-
if (event.target !== subContext.trigger) context.onOpenChange(false);
|
|
1047
|
-
})}
|
|
1048
925
|
onEscapeKeyDown={composeEventHandlers(
|
|
1049
926
|
props.onEscapeKeyDown,
|
|
1050
927
|
(event) => {
|
|
@@ -1058,7 +935,7 @@ const MenuSubContent = forwardRef<
|
|
|
1058
935
|
const isKeyDownInside = event.currentTarget.contains(
|
|
1059
936
|
event.target as HTMLElement,
|
|
1060
937
|
);
|
|
1061
|
-
let isCloseKey =
|
|
938
|
+
let isCloseKey = event.key === "ArrowLeft";
|
|
1062
939
|
|
|
1063
940
|
/* When submenu opens to the left, we allow closing it with ArrowRight */
|
|
1064
941
|
if (context.content?.dataset.side === "left") {
|
|
@@ -1097,32 +974,6 @@ function getCheckedState(checked: CheckedState) {
|
|
|
1097
974
|
: "unchecked";
|
|
1098
975
|
}
|
|
1099
976
|
|
|
1100
|
-
/**
|
|
1101
|
-
* Determine if a point is inside of a polygon.
|
|
1102
|
-
*/
|
|
1103
|
-
function isPointInPolygon(point: Point, polygon: Polygon) {
|
|
1104
|
-
const { x, y } = point;
|
|
1105
|
-
let inside = false;
|
|
1106
|
-
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
|
1107
|
-
const xi = polygon[i].x;
|
|
1108
|
-
const yi = polygon[i].y;
|
|
1109
|
-
const xj = polygon[j].x;
|
|
1110
|
-
const yj = polygon[j].y;
|
|
1111
|
-
|
|
1112
|
-
// prettier-ignore
|
|
1113
|
-
const intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
|
1114
|
-
if (intersect) inside = !inside;
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
return inside;
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
function isPointerInGraceArea(event: React.PointerEvent, area?: Polygon) {
|
|
1121
|
-
if (!area) return false;
|
|
1122
|
-
const cursorPos = { x: event.clientX, y: event.clientY };
|
|
1123
|
-
return isPointInPolygon(cursorPos, area);
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
977
|
function whenMouse<E>(
|
|
1127
978
|
handler: React.PointerEventHandler<E>,
|
|
1128
979
|
): React.PointerEventHandler<E> {
|
|
@@ -1139,7 +990,7 @@ Menu.Item = MenuItem;
|
|
|
1139
990
|
Menu.CheckboxItem = MenuCheckboxItem;
|
|
1140
991
|
Menu.RadioGroup = MenuRadioGroup;
|
|
1141
992
|
Menu.RadioItem = MenuRadioItem;
|
|
1142
|
-
Menu.
|
|
993
|
+
Menu.Divider = MenuDivider;
|
|
1143
994
|
Menu.Sub = MenuSub;
|
|
1144
995
|
Menu.SubTrigger = MenuSubTrigger;
|
|
1145
996
|
Menu.SubContent = MenuSubContent;
|
|
@@ -1150,19 +1001,20 @@ export {
|
|
|
1150
1001
|
MenuAnchor,
|
|
1151
1002
|
MenuCheckboxItem,
|
|
1152
1003
|
MenuContent,
|
|
1004
|
+
MenuDivider,
|
|
1153
1005
|
MenuGroup,
|
|
1154
1006
|
MenuItem,
|
|
1155
1007
|
MenuItemIndicator,
|
|
1156
1008
|
MenuPortal,
|
|
1157
1009
|
MenuRadioGroup,
|
|
1158
1010
|
MenuRadioItem,
|
|
1159
|
-
MenuSeparator,
|
|
1160
1011
|
MenuSub,
|
|
1161
1012
|
MenuSubContent,
|
|
1162
1013
|
MenuSubTrigger,
|
|
1163
1014
|
type MenuAnchorProps,
|
|
1164
1015
|
type MenuCheckboxItemProps,
|
|
1165
1016
|
type MenuContentProps,
|
|
1017
|
+
type MenuDividerProps,
|
|
1166
1018
|
type MenuGroupProps,
|
|
1167
1019
|
type MenuItemElement,
|
|
1168
1020
|
type MenuItemIndicatorProps,
|
|
@@ -1170,7 +1022,6 @@ export {
|
|
|
1170
1022
|
type MenuProps,
|
|
1171
1023
|
type MenuRadioGroupProps,
|
|
1172
1024
|
type MenuRadioItemProps,
|
|
1173
|
-
type MenuSeparatorProps,
|
|
1174
1025
|
type MenuSubContentProps,
|
|
1175
1026
|
type MenuSubProps,
|
|
1176
1027
|
type MenuSubTriggerProps,
|