@cdx-ui/primitives 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/drawer/DrawerClose.js +32 -0
- package/lib/commonjs/drawer/DrawerClose.js.map +1 -0
- package/lib/commonjs/drawer/DrawerOverlay.js +48 -0
- package/lib/commonjs/drawer/DrawerOverlay.js.map +1 -0
- package/lib/commonjs/drawer/DrawerPortal.js +33 -0
- package/lib/commonjs/drawer/DrawerPortal.js.map +1 -0
- package/lib/commonjs/drawer/DrawerRoot.js +55 -0
- package/lib/commonjs/drawer/DrawerRoot.js.map +1 -0
- package/lib/commonjs/drawer/context.js +11 -0
- package/lib/commonjs/drawer/context.js.map +1 -0
- package/lib/commonjs/drawer/index.js +47 -0
- package/lib/commonjs/drawer/index.js.map +1 -0
- package/lib/commonjs/drawer/types.js +6 -0
- package/lib/commonjs/drawer/types.js.map +1 -0
- package/lib/commonjs/index.js +12 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/menu/MenuItem.js +15 -2
- package/lib/commonjs/menu/MenuItem.js.map +1 -1
- package/lib/commonjs/menu/MenuItemAction.js +42 -0
- package/lib/commonjs/menu/MenuItemAction.js.map +1 -0
- package/lib/commonjs/menu/MenuRoot.js +31 -1
- package/lib/commonjs/menu/MenuRoot.js.map +1 -1
- package/lib/commonjs/menu/index.js +7 -0
- package/lib/commonjs/menu/index.js.map +1 -1
- package/lib/commonjs/menu/useMenuNavigation.js +1 -1
- package/lib/commonjs/menu/useMenuNavigation.js.map +1 -1
- package/lib/module/drawer/DrawerClose.js +28 -0
- package/lib/module/drawer/DrawerClose.js.map +1 -0
- package/lib/module/drawer/DrawerOverlay.js +44 -0
- package/lib/module/drawer/DrawerOverlay.js.map +1 -0
- package/lib/module/drawer/DrawerPortal.js +29 -0
- package/lib/module/drawer/DrawerPortal.js.map +1 -0
- package/lib/module/drawer/DrawerRoot.js +51 -0
- package/lib/module/drawer/DrawerRoot.js.map +1 -0
- package/lib/module/drawer/context.js +5 -0
- package/lib/module/drawer/context.js.map +1 -0
- package/lib/module/drawer/index.js +8 -0
- package/lib/module/drawer/index.js.map +1 -0
- package/lib/module/drawer/types.js +4 -0
- package/lib/module/drawer/types.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/menu/MenuItem.js +15 -2
- package/lib/module/menu/MenuItem.js.map +1 -1
- package/lib/module/menu/MenuItemAction.js +38 -0
- package/lib/module/menu/MenuItemAction.js.map +1 -0
- package/lib/module/menu/MenuRoot.js +31 -1
- package/lib/module/menu/MenuRoot.js.map +1 -1
- package/lib/module/menu/index.js +1 -0
- package/lib/module/menu/index.js.map +1 -1
- package/lib/module/menu/useMenuNavigation.js +1 -1
- package/lib/module/menu/useMenuNavigation.js.map +1 -1
- package/lib/typescript/drawer/DrawerClose.d.ts +5 -0
- package/lib/typescript/drawer/DrawerClose.d.ts.map +1 -0
- package/lib/typescript/drawer/DrawerOverlay.d.ts +5 -0
- package/lib/typescript/drawer/DrawerOverlay.d.ts.map +1 -0
- package/lib/typescript/drawer/DrawerPortal.d.ts +12 -0
- package/lib/typescript/drawer/DrawerPortal.d.ts.map +1 -0
- package/lib/typescript/drawer/DrawerRoot.d.ts +7 -0
- package/lib/typescript/drawer/DrawerRoot.d.ts.map +1 -0
- package/lib/typescript/drawer/context.d.ts +6 -0
- package/lib/typescript/drawer/context.d.ts.map +1 -0
- package/lib/typescript/drawer/index.d.ts +7 -0
- package/lib/typescript/drawer/index.d.ts.map +1 -0
- package/lib/typescript/drawer/types.d.ts +32 -0
- package/lib/typescript/drawer/types.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/menu/MenuItem.d.ts.map +1 -1
- package/lib/typescript/menu/MenuItemAction.d.ts +6 -0
- package/lib/typescript/menu/MenuItemAction.d.ts.map +1 -0
- package/lib/typescript/menu/MenuRoot.d.ts.map +1 -1
- package/lib/typescript/menu/index.d.ts +2 -1
- package/lib/typescript/menu/index.d.ts.map +1 -1
- package/lib/typescript/menu/types.d.ts +6 -0
- package/lib/typescript/menu/types.d.ts.map +1 -1
- package/lib/typescript/menu/useMenuNavigation.d.ts +9 -6
- package/lib/typescript/menu/useMenuNavigation.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/drawer/DrawerClose.tsx +26 -0
- package/src/drawer/DrawerOverlay.tsx +45 -0
- package/src/drawer/DrawerPortal.tsx +25 -0
- package/src/drawer/DrawerRoot.tsx +70 -0
- package/src/drawer/context.tsx +4 -0
- package/src/drawer/index.tsx +12 -0
- package/src/drawer/types.ts +36 -0
- package/src/index.ts +1 -0
- package/src/menu/MenuItem.tsx +15 -0
- package/src/menu/MenuItemAction.tsx +42 -0
- package/src/menu/MenuRoot.tsx +51 -10
- package/src/menu/index.ts +2 -0
- package/src/menu/types.ts +7 -0
- package/src/menu/useMenuNavigation.ts +11 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MenuItem.d.ts","sourceRoot":"","sources":["../../../src/menu/MenuItem.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAQf,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC;IACrE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,eAAO,MAAM,QAAQ,
|
|
1
|
+
{"version":3,"file":"MenuItem.d.ts","sourceRoot":"","sources":["../../../src/menu/MenuItem.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAQf,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC;IACrE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,eAAO,MAAM,QAAQ,uHAyLpB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { View } from 'react-native';
|
|
2
|
+
import type { IMenuItemActionProps } from './types';
|
|
3
|
+
export interface MenuItemActionProps extends IMenuItemActionProps {
|
|
4
|
+
}
|
|
5
|
+
export declare const MenuItemAction: import("react").ForwardRefExoticComponent<MenuItemActionProps & import("react").RefAttributes<View>>;
|
|
6
|
+
//# sourceMappingURL=MenuItemAction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MenuItemAction.d.ts","sourceRoot":"","sources":["../../../src/menu/MenuItemAction.tsx"],"names":[],"mappings":"AACA,OAAO,EAAY,IAAI,EAAE,MAAM,cAAc,CAAC;AAI9C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpD,MAAM,WAAW,mBAAoB,SAAQ,oBAAoB;CAAG;AAEpE,eAAO,MAAM,cAAc,sGA8B1B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MenuRoot.d.ts","sourceRoot":"","sources":["../../../src/menu/MenuRoot.tsx"],"names":[],"mappings":"AASA,OAAO,EAAY,IAAI,EAAE,MAAM,cAAc,CAAC;AAM9C,OAAO,KAAK,EAAE,UAAU,EAAsB,MAAM,SAAS,CAAC;AA8B9D,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,QAAQ,
|
|
1
|
+
{"version":3,"file":"MenuRoot.d.ts","sourceRoot":"","sources":["../../../src/menu/MenuRoot.tsx"],"names":[],"mappings":"AASA,OAAO,EAAY,IAAI,EAAE,MAAM,cAAc,CAAC;AAM9C,OAAO,KAAK,EAAE,UAAU,EAAsB,MAAM,SAAS,CAAC;AA8B9D,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,QAAQ,gGAyJpB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { IMenuCheckboxItemProps, IMenuItemProps, IMenuOverlayRootProps, IMenuPopupProps, IMenuProps, IMenuRadioGroupProps, IMenuRadioItemProps, IMenuTriggerProps, MenuCloseReason, MenuContextValue, MenuItemInteractionState, RegisteredMenuItem, } from './types';
|
|
1
|
+
export type { IMenuCheckboxItemProps, IMenuItemProps, IMenuOverlayRootProps, IMenuPopupProps, IMenuProps, IMenuRadioGroupProps, IMenuRadioItemProps, IMenuItemActionProps, IMenuTriggerProps, MenuCloseReason, MenuContextValue, MenuItemInteractionState, RegisteredMenuItem, } from './types';
|
|
2
2
|
export { useMenuContext, useMenuItemContext, useMenuRadioGroupContext, useOptionalMenuItemContext, } from './context';
|
|
3
3
|
export { MenuPopupProvider, useMenuOverlayContext, useOptionalMenuPopupContext, useOptionalMenuOverlayContext, MenuOverlayProvider, } from './overlayContext';
|
|
4
4
|
export { MenuOverlayRoot, type MenuOverlayRootProps } from './MenuOverlayRoot';
|
|
@@ -9,4 +9,5 @@ export { MenuItem, type MenuItemProps } from './MenuItem';
|
|
|
9
9
|
export { MenuCheckboxItem, type MenuCheckboxItemProps } from './MenuCheckboxItem';
|
|
10
10
|
export { MenuRadioGroup, type MenuRadioGroupProps } from './MenuRadioGroup';
|
|
11
11
|
export { MenuRadioItem, type MenuRadioItemProps } from './MenuRadioItem';
|
|
12
|
+
export { MenuItemAction, type MenuItemActionProps } from './MenuItemAction';
|
|
12
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/menu/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,sBAAsB,EACtB,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,UAAU,EACV,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,2BAA2B,EAC3B,6BAA6B,EAC7B,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/menu/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,sBAAsB,EACtB,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,UAAU,EACV,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,2BAA2B,EAC3B,6BAA6B,EAC7B,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -66,6 +66,12 @@ export interface IMenuItemProps extends PressableProps {
|
|
|
66
66
|
export interface MenuItemInteractionState extends InteractionState {
|
|
67
67
|
highlighted: boolean;
|
|
68
68
|
checked: boolean;
|
|
69
|
+
itemRole: 'menuitem' | 'menuitemcheckbox' | 'menuitemradio';
|
|
70
|
+
consumePress: () => void;
|
|
71
|
+
}
|
|
72
|
+
export interface IMenuItemActionProps extends ViewProps {
|
|
73
|
+
asChild?: boolean;
|
|
74
|
+
children?: ReactNode;
|
|
69
75
|
}
|
|
70
76
|
export interface IMenuCheckboxItemProps extends Omit<IMenuItemProps, 'children' | 'isChecked' | 'itemRole'> {
|
|
71
77
|
children?: ReactNode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/menu/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEjD,MAAM,WAAW,qBAAsB,SAAQ,SAAS;IACtD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yDAAyD;IACzD,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACvD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,UAAW,SAAQ,SAAS;IAC3C,+FAA+F;IAC/F,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,cAAe,SAAQ,cAAc;IACpD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qFAAqF;IACrF,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB;IAChB,QAAQ,CAAC,EAAE,UAAU,GAAG,kBAAkB,GAAG,eAAe,CAAC;IAC7D,gBAAgB;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,wBAAyB,SAAQ,gBAAgB;IAChE,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/menu/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import type { RegisteredMenuItem } from './types';
|
|
2
|
+
export interface MenuNavigationKeyEvent {
|
|
3
|
+
key: string;
|
|
4
|
+
shiftKey?: boolean;
|
|
5
|
+
target: EventTarget | null;
|
|
6
|
+
preventDefault: () => void;
|
|
7
|
+
stopPropagation?: () => void;
|
|
8
|
+
}
|
|
2
9
|
export interface UseMenuNavigationOptions {
|
|
3
10
|
getItems: () => [string, RegisteredMenuItem][];
|
|
4
11
|
focusedItemId: string | undefined;
|
|
5
12
|
setFocusedItemId: (itemId: string | undefined) => void;
|
|
6
13
|
onEscape?: () => void;
|
|
7
|
-
onTab?: () => void;
|
|
14
|
+
onTab?: (event: MenuNavigationKeyEvent) => void;
|
|
8
15
|
}
|
|
9
16
|
export declare function useMenuNavigation({ getItems, focusedItemId, setFocusedItemId, onEscape, onTab, }: UseMenuNavigationOptions): {
|
|
10
|
-
handleKeyDown: (e:
|
|
11
|
-
key: string;
|
|
12
|
-
preventDefault: () => void;
|
|
13
|
-
stopPropagation?: () => void;
|
|
14
|
-
}) => void;
|
|
17
|
+
handleKeyDown: (e: MenuNavigationKeyEvent) => void;
|
|
15
18
|
};
|
|
16
19
|
//# sourceMappingURL=useMenuNavigation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMenuNavigation.d.ts","sourceRoot":"","sources":["../../../src/menu/useMenuNavigation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAIlD,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAAE,CAAC;IAC/C,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACvD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"useMenuNavigation.d.ts","sourceRoot":"","sources":["../../../src/menu/useMenuNavigation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAIlD,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAAE,CAAC;IAC/C,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACvD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;CACjD;AAED,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,QAAQ,EACR,KAAK,GACN,EAAE,wBAAwB;uBAoBnB,sBAAsB;EA8D7B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdx-ui/primitives",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -68,8 +68,8 @@
|
|
|
68
68
|
"@react-stately/disclosure": "3.1.1",
|
|
69
69
|
"@react-stately/radio": "3.12.0",
|
|
70
70
|
"@react-stately/toggle": "3.9.4",
|
|
71
|
-
"@cdx-ui/formatters": "0.1.
|
|
72
|
-
"@cdx-ui/utils": "0.1.
|
|
71
|
+
"@cdx-ui/formatters": "0.1.4",
|
|
72
|
+
"@cdx-ui/utils": "0.1.4"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
75
|
"@types/react": "19.1.17",
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { forwardRef, type ComponentRef } from 'react';
|
|
2
|
+
import { Pressable, type PressableProps } from 'react-native';
|
|
3
|
+
import { composeEventHandlers } from '@cdx-ui/utils';
|
|
4
|
+
import { Slot } from '../slot';
|
|
5
|
+
import { useDrawer } from './context';
|
|
6
|
+
import type { IDrawerCloseProps } from './types';
|
|
7
|
+
|
|
8
|
+
export interface DrawerCloseProps extends IDrawerCloseProps {}
|
|
9
|
+
|
|
10
|
+
export const DrawerClose = forwardRef<ComponentRef<typeof Pressable>, DrawerCloseProps>(
|
|
11
|
+
({ asChild = false, children, onPress, ...props }, ref) => {
|
|
12
|
+
const { onOpenChange } = useDrawer();
|
|
13
|
+
|
|
14
|
+
const handlePress = composeEventHandlers(onPress, () => onOpenChange(false));
|
|
15
|
+
|
|
16
|
+
const Comp = asChild ? Slot : Pressable;
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<Comp ref={ref} {...(props as PressableProps)} onPress={handlePress}>
|
|
20
|
+
{children}
|
|
21
|
+
</Comp>
|
|
22
|
+
);
|
|
23
|
+
},
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
DrawerClose.displayName = 'DrawerClose';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { forwardRef, useCallback, type ComponentRef } from 'react';
|
|
2
|
+
import { Pressable, type PressableProps } from 'react-native';
|
|
3
|
+
import { Slot } from '../slot';
|
|
4
|
+
import { dataAttributes, mergeDataAttributes } from '../utils/dataAttributes';
|
|
5
|
+
import { useDrawer } from './context';
|
|
6
|
+
import type { IDrawerOverlayProps } from './types';
|
|
7
|
+
|
|
8
|
+
export interface DrawerOverlayProps extends IDrawerOverlayProps {}
|
|
9
|
+
|
|
10
|
+
export const DrawerOverlay = forwardRef<ComponentRef<typeof Pressable>, DrawerOverlayProps>(
|
|
11
|
+
({ asChild = false, forceMount = false, onPress, ...props }, ref) => {
|
|
12
|
+
const { open, onOpenChange, closeOnBackdropPress } = useDrawer();
|
|
13
|
+
|
|
14
|
+
const handlePress = useCallback(
|
|
15
|
+
(e: Parameters<NonNullable<PressableProps['onPress']>>[0]) => {
|
|
16
|
+
if (closeOnBackdropPress) {
|
|
17
|
+
onOpenChange(false);
|
|
18
|
+
}
|
|
19
|
+
if (typeof onPress === 'function') {
|
|
20
|
+
onPress(e);
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
[closeOnBackdropPress, onOpenChange, onPress],
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
if (!forceMount && !open) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const Comp = asChild ? Slot : Pressable;
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<Comp
|
|
34
|
+
ref={ref}
|
|
35
|
+
accessible={false}
|
|
36
|
+
importantForAccessibility="no-hide-descendants"
|
|
37
|
+
onPress={handlePress}
|
|
38
|
+
{...(props as PressableProps)}
|
|
39
|
+
{...mergeDataAttributes(props, dataAttributes({ slot: 'drawer-overlay' }))}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
DrawerOverlay.displayName = 'DrawerOverlay';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Portal } from '../portal';
|
|
2
|
+
import { DrawerProvider, useDrawer } from './context';
|
|
3
|
+
import type { IDrawerPortalProps } from './types';
|
|
4
|
+
|
|
5
|
+
export interface DrawerPortalProps extends IDrawerPortalProps {}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Mounts drawer children into the shared PortalHost. Re-provides DrawerContext
|
|
9
|
+
* inside the portal boundary (React context does not cross the portal store).
|
|
10
|
+
*/
|
|
11
|
+
export function DrawerPortal({ forceMount = false, hostName, children }: DrawerPortalProps) {
|
|
12
|
+
const ctx = useDrawer();
|
|
13
|
+
|
|
14
|
+
if (!forceMount && !ctx.open) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<Portal name={`${ctx.nativeID}-portal`} hostName={hostName}>
|
|
20
|
+
<DrawerProvider value={ctx}>{children}</DrawerProvider>
|
|
21
|
+
</Portal>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
DrawerPortal.displayName = 'DrawerPortal';
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { forwardRef, useCallback, useId, useMemo, type ComponentRef } from 'react';
|
|
2
|
+
import { View, type ViewProps } from 'react-native';
|
|
3
|
+
import { useControllableState } from '@cdx-ui/utils';
|
|
4
|
+
import { Slot } from '../slot';
|
|
5
|
+
import { dataAttributes, mergeDataAttributes } from '../utils/dataAttributes';
|
|
6
|
+
import { DrawerProvider } from './context';
|
|
7
|
+
import type { IDrawerRootProps } from './types';
|
|
8
|
+
|
|
9
|
+
export interface DrawerRootProps extends Omit<ViewProps, 'children' | 'role'>, IDrawerRootProps {
|
|
10
|
+
asChild?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const DrawerRoot = forwardRef<ComponentRef<typeof View>, DrawerRootProps>(
|
|
14
|
+
(
|
|
15
|
+
{
|
|
16
|
+
isOpen: openProp,
|
|
17
|
+
onOpenChange,
|
|
18
|
+
defaultOpen = false,
|
|
19
|
+
closeOnBackdropPress = true,
|
|
20
|
+
closeOnEscKey = true,
|
|
21
|
+
asChild,
|
|
22
|
+
children,
|
|
23
|
+
...props
|
|
24
|
+
},
|
|
25
|
+
ref,
|
|
26
|
+
) => {
|
|
27
|
+
const [open, setOpenState] = useControllableState<boolean>({
|
|
28
|
+
prop: openProp,
|
|
29
|
+
defaultProp: defaultOpen,
|
|
30
|
+
onChange: onOpenChange,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const setOpen = useCallback(
|
|
34
|
+
(newOpen: boolean) => {
|
|
35
|
+
setOpenState(newOpen);
|
|
36
|
+
},
|
|
37
|
+
[setOpenState],
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const id = useId();
|
|
41
|
+
const nativeID = `drawer-${id}`;
|
|
42
|
+
|
|
43
|
+
const contextValue = useMemo(
|
|
44
|
+
() => ({
|
|
45
|
+
open: open ?? false,
|
|
46
|
+
onOpenChange: setOpen,
|
|
47
|
+
closeOnBackdropPress,
|
|
48
|
+
closeOnEscKey,
|
|
49
|
+
nativeID,
|
|
50
|
+
}),
|
|
51
|
+
[open, setOpen, closeOnBackdropPress, closeOnEscKey, nativeID],
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const Comp = asChild ? Slot : View;
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<DrawerProvider value={contextValue}>
|
|
58
|
+
<Comp
|
|
59
|
+
ref={ref}
|
|
60
|
+
{...(props as ViewProps)}
|
|
61
|
+
{...mergeDataAttributes(props, dataAttributes({ state: open ? 'open' : 'closed' }))}
|
|
62
|
+
>
|
|
63
|
+
{children}
|
|
64
|
+
</Comp>
|
|
65
|
+
</DrawerProvider>
|
|
66
|
+
);
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
DrawerRoot.displayName = 'DrawerRoot';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { DrawerProvider, useDrawer } from './context';
|
|
2
|
+
export { DrawerRoot, type DrawerRootProps } from './DrawerRoot';
|
|
3
|
+
export { DrawerPortal, type DrawerPortalProps } from './DrawerPortal';
|
|
4
|
+
export { DrawerOverlay, type DrawerOverlayProps } from './DrawerOverlay';
|
|
5
|
+
export { DrawerClose, type DrawerCloseProps } from './DrawerClose';
|
|
6
|
+
export type {
|
|
7
|
+
IDrawerContextType,
|
|
8
|
+
IDrawerRootProps,
|
|
9
|
+
IDrawerPortalProps,
|
|
10
|
+
IDrawerOverlayProps,
|
|
11
|
+
IDrawerCloseProps,
|
|
12
|
+
} from './types';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type { PressableProps } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export interface IDrawerContextType {
|
|
5
|
+
readonly open: boolean;
|
|
6
|
+
readonly onOpenChange: (open: boolean) => void;
|
|
7
|
+
readonly closeOnBackdropPress: boolean;
|
|
8
|
+
readonly closeOnEscKey: boolean;
|
|
9
|
+
readonly nativeID: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface IDrawerRootProps {
|
|
13
|
+
/** Controlled open state. Use `defaultOpen` for the uncontrolled variant. */
|
|
14
|
+
readonly isOpen?: boolean;
|
|
15
|
+
readonly onOpenChange?: (open: boolean) => void;
|
|
16
|
+
readonly defaultOpen?: boolean;
|
|
17
|
+
readonly closeOnBackdropPress?: boolean;
|
|
18
|
+
readonly closeOnEscKey?: boolean;
|
|
19
|
+
readonly children: React.ReactNode;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface IDrawerPortalProps {
|
|
23
|
+
readonly forceMount?: boolean;
|
|
24
|
+
readonly hostName?: string;
|
|
25
|
+
readonly children: React.ReactNode;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface IDrawerOverlayProps extends PressableProps {
|
|
29
|
+
readonly asChild?: boolean;
|
|
30
|
+
readonly forceMount?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface IDrawerCloseProps extends PressableProps {
|
|
34
|
+
readonly asChild?: boolean;
|
|
35
|
+
readonly accessibilityLabel?: string;
|
|
36
|
+
}
|
package/src/index.ts
CHANGED
package/src/menu/MenuItem.tsx
CHANGED
|
@@ -71,9 +71,20 @@ export const MenuItem = forwardRef<ComponentRef<typeof Pressable>, MenuItemProps
|
|
|
71
71
|
const mergedRef = mergeRefs(ref, nodeRef);
|
|
72
72
|
const onPressRef = useRef(onPress);
|
|
73
73
|
onPressRef.current = onPress;
|
|
74
|
+
const actionConsumedRef = useRef(false);
|
|
75
|
+
const consumePress = useCallback(() => {
|
|
76
|
+
actionConsumedRef.current = true;
|
|
77
|
+
queueMicrotask(() => {
|
|
78
|
+
actionConsumedRef.current = false;
|
|
79
|
+
});
|
|
80
|
+
}, []);
|
|
74
81
|
|
|
75
82
|
const invokePress = useCallback(
|
|
76
83
|
(event: GestureResponderEvent) => {
|
|
84
|
+
if (actionConsumedRef.current) {
|
|
85
|
+
actionConsumedRef.current = false;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
77
88
|
if (!disabled) {
|
|
78
89
|
onPressRef.current?.(event);
|
|
79
90
|
if (closeOnSelect) {
|
|
@@ -112,6 +123,8 @@ export const MenuItem = forwardRef<ComponentRef<typeof Pressable>, MenuItemProps
|
|
|
112
123
|
focusVisible: !!(isFocusVisibleProp || isFocusVisible),
|
|
113
124
|
highlighted,
|
|
114
125
|
checked: isChecked,
|
|
126
|
+
itemRole,
|
|
127
|
+
consumePress,
|
|
115
128
|
}),
|
|
116
129
|
[
|
|
117
130
|
isHoveredProp,
|
|
@@ -125,6 +138,8 @@ export const MenuItem = forwardRef<ComponentRef<typeof Pressable>, MenuItemProps
|
|
|
125
138
|
isFocusVisible,
|
|
126
139
|
highlighted,
|
|
127
140
|
isChecked,
|
|
141
|
+
itemRole,
|
|
142
|
+
consumePress,
|
|
128
143
|
],
|
|
129
144
|
);
|
|
130
145
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { forwardRef, type ComponentRef } from 'react';
|
|
2
|
+
import { Platform, View } from 'react-native';
|
|
3
|
+
import { composeEventHandlers } from '@cdx-ui/utils';
|
|
4
|
+
import { Slot } from '../slot';
|
|
5
|
+
import { useOptionalMenuItemContext } from './context';
|
|
6
|
+
import type { IMenuItemActionProps } from './types';
|
|
7
|
+
|
|
8
|
+
export interface MenuItemActionProps extends IMenuItemActionProps {}
|
|
9
|
+
|
|
10
|
+
export const MenuItemAction = forwardRef<ComponentRef<typeof View>, MenuItemActionProps>(
|
|
11
|
+
({ asChild, children, onTouchStart, ...props }, ref) => {
|
|
12
|
+
const menuItem = useOptionalMenuItemContext();
|
|
13
|
+
const Comp = asChild ? Slot : View;
|
|
14
|
+
const { onClick, ...rest } = props as typeof props & {
|
|
15
|
+
onClick?: (event: { stopPropagation: () => void }) => void;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const isolatePress = () => {
|
|
19
|
+
menuItem?.consumePress();
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Comp
|
|
24
|
+
ref={ref}
|
|
25
|
+
{...rest}
|
|
26
|
+
onTouchStart={composeEventHandlers(onTouchStart, isolatePress)}
|
|
27
|
+
{...(Platform.OS === 'web'
|
|
28
|
+
? {
|
|
29
|
+
onClick: composeEventHandlers(onClick, (event: { stopPropagation: () => void }) => {
|
|
30
|
+
isolatePress();
|
|
31
|
+
event.stopPropagation();
|
|
32
|
+
}),
|
|
33
|
+
}
|
|
34
|
+
: {})}
|
|
35
|
+
>
|
|
36
|
+
{children}
|
|
37
|
+
</Comp>
|
|
38
|
+
);
|
|
39
|
+
},
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
MenuItemAction.displayName = 'MenuItemAction';
|
package/src/menu/MenuRoot.tsx
CHANGED
|
@@ -14,7 +14,7 @@ import { dataAttributes, mergeDataAttributes } from '../utils/dataAttributes';
|
|
|
14
14
|
import { MenuProvider } from './context';
|
|
15
15
|
import { useOptionalMenuOverlayContext } from './overlayContext';
|
|
16
16
|
import type { IMenuProps, RegisteredMenuItem } from './types';
|
|
17
|
-
import { useMenuNavigation } from './useMenuNavigation';
|
|
17
|
+
import { useMenuNavigation, type MenuNavigationKeyEvent } from './useMenuNavigation';
|
|
18
18
|
import { useMenuOverlayOpenFocus } from './useMenuOverlayLifecycle';
|
|
19
19
|
|
|
20
20
|
function getItemsInRenderedOrder(
|
|
@@ -100,15 +100,31 @@ export const MenuRoot = forwardRef<ComponentRef<typeof View>, MenuRootProps>(
|
|
|
100
100
|
onEscape?.();
|
|
101
101
|
}, [overlay, onEscape]);
|
|
102
102
|
|
|
103
|
-
const handleTab = useCallback(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
103
|
+
const handleTab = useCallback(
|
|
104
|
+
(event: MenuNavigationKeyEvent) => {
|
|
105
|
+
if (!overlay) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (Platform.OS === 'web') {
|
|
110
|
+
const tabbables = getInMenuTabbables(overlay.contentRef.current);
|
|
111
|
+
const index = resolveTabbableIndex(tabbables, event.target);
|
|
112
|
+
const nextIndex = index + (event.shiftKey ? -1 : 1);
|
|
113
|
+
const next = index === -1 ? undefined : tabbables[nextIndex];
|
|
114
|
+
if (next) {
|
|
115
|
+
event.preventDefault();
|
|
116
|
+
next.focus();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
event.preventDefault();
|
|
121
|
+
(overlay.triggerRef.current as { focus?: () => void } | null)?.focus?.();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
overlay.closeMenu('tab');
|
|
125
|
+
},
|
|
126
|
+
[overlay],
|
|
127
|
+
);
|
|
112
128
|
|
|
113
129
|
const { handleKeyDown } = useMenuNavigation({
|
|
114
130
|
getItems,
|
|
@@ -188,3 +204,28 @@ export const MenuRoot = forwardRef<ComponentRef<typeof View>, MenuRootProps>(
|
|
|
188
204
|
);
|
|
189
205
|
|
|
190
206
|
MenuRoot.displayName = 'MenuRoot';
|
|
207
|
+
|
|
208
|
+
function getInMenuTabbables(container: unknown): HTMLElement[] {
|
|
209
|
+
if (typeof HTMLElement === 'undefined' || !(container instanceof HTMLElement)) {
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return Array.from(
|
|
214
|
+
container.querySelectorAll<HTMLElement>('button, [href], input, select, textarea, [tabindex]'),
|
|
215
|
+
).filter((element) => {
|
|
216
|
+
if (element.tabIndex < 0) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
if ('disabled' in element && (element as HTMLButtonElement).disabled) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
return element.getAttribute('aria-hidden') !== 'true';
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function resolveTabbableIndex(tabbables: HTMLElement[], target: EventTarget | null): number {
|
|
227
|
+
if (!(target instanceof HTMLElement)) {
|
|
228
|
+
return -1;
|
|
229
|
+
}
|
|
230
|
+
return tabbables.findIndex((element) => element === target || element.contains(target));
|
|
231
|
+
}
|
package/src/menu/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ export type {
|
|
|
6
6
|
IMenuProps,
|
|
7
7
|
IMenuRadioGroupProps,
|
|
8
8
|
IMenuRadioItemProps,
|
|
9
|
+
IMenuItemActionProps,
|
|
9
10
|
IMenuTriggerProps,
|
|
10
11
|
MenuCloseReason,
|
|
11
12
|
MenuContextValue,
|
|
@@ -34,3 +35,4 @@ export { MenuItem, type MenuItemProps } from './MenuItem';
|
|
|
34
35
|
export { MenuCheckboxItem, type MenuCheckboxItemProps } from './MenuCheckboxItem';
|
|
35
36
|
export { MenuRadioGroup, type MenuRadioGroupProps } from './MenuRadioGroup';
|
|
36
37
|
export { MenuRadioItem, type MenuRadioItemProps } from './MenuRadioItem';
|
|
38
|
+
export { MenuItemAction, type MenuItemActionProps } from './MenuItemAction';
|
package/src/menu/types.ts
CHANGED
|
@@ -72,6 +72,13 @@ export interface IMenuItemProps extends PressableProps {
|
|
|
72
72
|
export interface MenuItemInteractionState extends InteractionState {
|
|
73
73
|
highlighted: boolean;
|
|
74
74
|
checked: boolean;
|
|
75
|
+
itemRole: 'menuitem' | 'menuitemcheckbox' | 'menuitemradio';
|
|
76
|
+
consumePress: () => void;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface IMenuItemActionProps extends ViewProps {
|
|
80
|
+
asChild?: boolean;
|
|
81
|
+
children?: ReactNode;
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
export interface IMenuCheckboxItemProps extends Omit<
|
|
@@ -3,12 +3,20 @@ import type { RegisteredMenuItem } from './types';
|
|
|
3
3
|
|
|
4
4
|
// Web-only — native platforms rely on OS-managed sequential focus.
|
|
5
5
|
|
|
6
|
+
export interface MenuNavigationKeyEvent {
|
|
7
|
+
key: string;
|
|
8
|
+
shiftKey?: boolean;
|
|
9
|
+
target: EventTarget | null;
|
|
10
|
+
preventDefault: () => void;
|
|
11
|
+
stopPropagation?: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
6
14
|
export interface UseMenuNavigationOptions {
|
|
7
15
|
getItems: () => [string, RegisteredMenuItem][];
|
|
8
16
|
focusedItemId: string | undefined;
|
|
9
17
|
setFocusedItemId: (itemId: string | undefined) => void;
|
|
10
18
|
onEscape?: () => void;
|
|
11
|
-
onTab?: () => void;
|
|
19
|
+
onTab?: (event: MenuNavigationKeyEvent) => void;
|
|
12
20
|
}
|
|
13
21
|
|
|
14
22
|
export function useMenuNavigation({
|
|
@@ -37,7 +45,7 @@ export function useMenuNavigation({
|
|
|
37
45
|
);
|
|
38
46
|
|
|
39
47
|
const handleKeyDown = useCallback(
|
|
40
|
-
(e:
|
|
48
|
+
(e: MenuNavigationKeyEvent) => {
|
|
41
49
|
if (e.key === 'Escape') {
|
|
42
50
|
e.preventDefault();
|
|
43
51
|
e.stopPropagation?.();
|
|
@@ -45,7 +53,7 @@ export function useMenuNavigation({
|
|
|
45
53
|
return;
|
|
46
54
|
}
|
|
47
55
|
if (e.key === 'Tab') {
|
|
48
|
-
onTabRef.current?.();
|
|
56
|
+
onTabRef.current?.(e);
|
|
49
57
|
return;
|
|
50
58
|
}
|
|
51
59
|
|