@seed-design/react-menu 0.0.0-alpha-20260414104312

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.
@@ -0,0 +1,189 @@
1
+ 'use client';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { FloatingPortal, FloatingFocusManager, FloatingList, useListItem } from '@floating-ui/react';
4
+ import { composeRefs } from '@radix-ui/react-compose-refs';
5
+ import { FocusScope } from '@radix-ui/react-focus-scope';
6
+ import { DismissibleLayer } from '@seed-design/react-dismissible-layer';
7
+ import { mergeProps } from '@seed-design/dom-utils';
8
+ import { Primitive } from '@seed-design/react-primitive';
9
+ import React, { createContext, useContext, forwardRef } from 'react';
10
+ import { u as useMenu } from './useMenu-12s-WINwYlwH.js';
11
+
12
+ const MenuContext = /*#__PURE__*/ createContext(null);
13
+ const MenuProvider = MenuContext.Provider;
14
+ function useMenuContext({ strict = true } = {}) {
15
+ const context = useContext(MenuContext);
16
+ if (!context && strict) {
17
+ throw new Error("useMenuContext must be used within a Menu");
18
+ }
19
+ return context;
20
+ }
21
+
22
+ const MenuItemContext = /*#__PURE__*/ createContext(null);
23
+ const MenuItemProvider = MenuItemContext.Provider;
24
+ function useMenuItemContext({ strict = true } = {}) {
25
+ const context = useContext(MenuItemContext);
26
+ if (!context && strict) {
27
+ throw new Error("useMenuItemContext must be used within a MenuItem");
28
+ }
29
+ return context;
30
+ }
31
+
32
+ const MenuGroupLabelIdContext = /*#__PURE__*/ createContext(null);
33
+ const MenuRoot = ({ open, defaultOpen, onOpenChange, disabled, placement, gutter, overflowPadding, strategy, matchReferenceWidth, children })=>{
34
+ const api = useMenu({
35
+ open,
36
+ defaultOpen,
37
+ onOpenChange,
38
+ disabled,
39
+ placement,
40
+ gutter,
41
+ overflowPadding,
42
+ strategy,
43
+ matchReferenceWidth
44
+ });
45
+ return /*#__PURE__*/ jsx(MenuProvider, {
46
+ value: api,
47
+ children: children
48
+ });
49
+ };
50
+ const MenuAnchor = /*#__PURE__*/ forwardRef((props, ref)=>{
51
+ const api = useMenuContext();
52
+ return /*#__PURE__*/ jsx(Primitive.div, {
53
+ ref: composeRefs(api.refs.anchor, ref),
54
+ ...mergeProps(api.anchorProps, props)
55
+ });
56
+ });
57
+ MenuAnchor.displayName = "MenuAnchor";
58
+ const MenuTrigger = /*#__PURE__*/ forwardRef((props, ref)=>{
59
+ const api = useMenuContext();
60
+ return /*#__PURE__*/ jsx(Primitive.button, {
61
+ ref: composeRefs(api.refs.trigger, ref),
62
+ ...mergeProps(api.triggerProps, props)
63
+ });
64
+ });
65
+ MenuTrigger.displayName = "MenuTrigger";
66
+ const MenuPositioner = /*#__PURE__*/ forwardRef(({ container, ...props }, ref)=>{
67
+ const api = useMenuContext();
68
+ // FloatingPortal (not a generic portal) so that FloatingFocusManager
69
+ // detects the portal context and renders focus-guard sentinels.
70
+ return /*#__PURE__*/ jsx(FloatingPortal, {
71
+ root: container ?? undefined,
72
+ children: /*#__PURE__*/ jsx(Primitive.div, {
73
+ ref: composeRefs(api.refs.positioner, ref),
74
+ ...mergeProps(api.positionerProps, props)
75
+ })
76
+ });
77
+ });
78
+ MenuPositioner.displayName = "MenuPositioner";
79
+ const MenuContent = /*#__PURE__*/ forwardRef((props, ref)=>{
80
+ const { floatingContext, contentProps, open, setOpen, elementsRef, labelsRef } = useMenuContext();
81
+ const content = /*#__PURE__*/ jsx(Primitive.div, {
82
+ ref: ref,
83
+ ...mergeProps(contentProps, props)
84
+ });
85
+ // FloatingFocusManager: handles position-aware initial focus, return focus,
86
+ // closeOnFocusOut, tab order guards, and useListNavigation coordination.
87
+ //
88
+ // FocusScope: participates in Radix's focusScopesStack so that parent
89
+ // FocusScopes (e.g. Dialog, Drawer) are automatically paused while this
90
+ // Menu is open. Without this, focus cannot leave a trapped parent scope
91
+ // to reach Menu content rendered in a Portal.
92
+ //
93
+ // FocusScope is conditionally rendered (only when open) because Menu
94
+ // content is always in the DOM (hidden via data-hidden). If FocusScope
95
+ // were always mounted, it would register in the stack at page load —
96
+ // before any Dialog — and could never re-register above a Dialog that
97
+ // mounts later. Mounting only when open ensures it lands at the top of
98
+ // the stack, pausing the parent scope.
99
+ return /*#__PURE__*/ jsx(FloatingFocusManager, {
100
+ context: floatingContext,
101
+ disabled: !open,
102
+ modal: false,
103
+ children: /*#__PURE__*/ jsx(FloatingList, {
104
+ elementsRef: elementsRef,
105
+ labelsRef: labelsRef,
106
+ children: /*#__PURE__*/ jsx(DismissibleLayer, {
107
+ enabled: open,
108
+ pressBehavior: "drag",
109
+ onEscapeKeyDown: (event)=>{
110
+ setOpen(false, {
111
+ reason: "escapeKeyDown",
112
+ event
113
+ });
114
+ },
115
+ onPressOutside: (event)=>{
116
+ setOpen(false, {
117
+ reason: "interactOutside",
118
+ event
119
+ });
120
+ },
121
+ onCascadeDismiss: ({ dismissedParent })=>{
122
+ setOpen(false, {
123
+ reason: "cascadeDismiss",
124
+ dismissedParent
125
+ });
126
+ },
127
+ onFocusOutside: ()=>{
128
+ // focus trapping is handled by FloatingFocusManager — nothing to do here
129
+ },
130
+ exclude: (target)=>{
131
+ const reference = floatingContext.refs.reference.current;
132
+ if (!(reference instanceof HTMLElement)) return false;
133
+ return reference.contains(target);
134
+ },
135
+ children: open ? /*#__PURE__*/ jsx(FocusScope, {
136
+ asChild: true,
137
+ trapped: false,
138
+ loop: false,
139
+ onMountAutoFocus: (e)=>e.preventDefault(),
140
+ onUnmountAutoFocus: (e)=>e.preventDefault(),
141
+ children: content
142
+ }) : content
143
+ })
144
+ })
145
+ });
146
+ });
147
+ MenuContent.displayName = "MenuContent";
148
+ const MenuItem = /*#__PURE__*/ forwardRef(({ disabled, typeaheadLabel, onClick, ...restProps }, ref)=>{
149
+ const { getItemProps } = useMenuContext();
150
+ const { ref: listRef, index } = useListItem({
151
+ label: typeaheadLabel
152
+ });
153
+ const api = getItemProps({
154
+ disabled,
155
+ onClick
156
+ }, index);
157
+ return /*#__PURE__*/ jsx(MenuItemProvider, {
158
+ value: api,
159
+ children: /*#__PURE__*/ jsx(Primitive.div, {
160
+ ref: composeRefs(listRef, ref),
161
+ ...mergeProps(api.rootProps, restProps)
162
+ })
163
+ });
164
+ });
165
+ MenuItem.displayName = "MenuItem";
166
+ const MenuGroup = /*#__PURE__*/ forwardRef((props, ref)=>{
167
+ const { getGroupProps } = useMenuContext();
168
+ const { labelId, rootProps } = getGroupProps();
169
+ return /*#__PURE__*/ jsx(MenuGroupLabelIdContext.Provider, {
170
+ value: labelId,
171
+ children: /*#__PURE__*/ jsx(Primitive.div, {
172
+ ref: ref,
173
+ ...mergeProps(rootProps, props)
174
+ })
175
+ });
176
+ });
177
+ MenuGroup.displayName = "MenuGroup";
178
+ const MenuGroupLabel = /*#__PURE__*/ forwardRef((props, ref)=>{
179
+ const { getGroupLabelProps } = useMenuContext();
180
+ const labelId = React.useContext(MenuGroupLabelIdContext);
181
+ if (!labelId) throw new Error("MenuGroupLabel must be used within a MenuGroup");
182
+ return /*#__PURE__*/ jsx(Primitive.div, {
183
+ ref: ref,
184
+ ...mergeProps(getGroupLabelProps(labelId), props)
185
+ });
186
+ });
187
+ MenuGroupLabel.displayName = "MenuGroupLabel";
188
+
189
+ export { MenuAnchor as M, MenuContent as a, MenuGroup as b, MenuGroupLabel as c, MenuItem as d, MenuPositioner as e, MenuRoot as f, MenuTrigger as g, useMenuItemContext as h, useMenuContext as u };
@@ -0,0 +1,202 @@
1
+ 'use client';
2
+ var jsxRuntime = require('react/jsx-runtime');
3
+ var react = require('@floating-ui/react');
4
+ var reactComposeRefs = require('@radix-ui/react-compose-refs');
5
+ var reactFocusScope = require('@radix-ui/react-focus-scope');
6
+ var reactDismissibleLayer = require('@seed-design/react-dismissible-layer');
7
+ var domUtils = require('@seed-design/dom-utils');
8
+ var reactPrimitive = require('@seed-design/react-primitive');
9
+ var React = require('react');
10
+ var useMenu12s = require('./useMenu-12s-DN0SpRKs.cjs');
11
+
12
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
+
14
+ var React__default = /*#__PURE__*/_interopDefault(React);
15
+
16
+ const MenuContext = /*#__PURE__*/ React.createContext(null);
17
+ const MenuProvider = MenuContext.Provider;
18
+ function useMenuContext({ strict = true } = {}) {
19
+ const context = React.useContext(MenuContext);
20
+ if (!context && strict) {
21
+ throw new Error("useMenuContext must be used within a Menu");
22
+ }
23
+ return context;
24
+ }
25
+
26
+ const MenuItemContext = /*#__PURE__*/ React.createContext(null);
27
+ const MenuItemProvider = MenuItemContext.Provider;
28
+ function useMenuItemContext({ strict = true } = {}) {
29
+ const context = React.useContext(MenuItemContext);
30
+ if (!context && strict) {
31
+ throw new Error("useMenuItemContext must be used within a MenuItem");
32
+ }
33
+ return context;
34
+ }
35
+
36
+ const MenuGroupLabelIdContext = /*#__PURE__*/ React.createContext(null);
37
+ const MenuRoot = ({ open, defaultOpen, onOpenChange, disabled, placement, gutter, overflowPadding, strategy, matchReferenceWidth, children })=>{
38
+ const api = useMenu12s.useMenu({
39
+ open,
40
+ defaultOpen,
41
+ onOpenChange,
42
+ disabled,
43
+ placement,
44
+ gutter,
45
+ overflowPadding,
46
+ strategy,
47
+ matchReferenceWidth
48
+ });
49
+ return /*#__PURE__*/ jsxRuntime.jsx(MenuProvider, {
50
+ value: api,
51
+ children: children
52
+ });
53
+ };
54
+ const MenuAnchor = /*#__PURE__*/ React.forwardRef((props, ref)=>{
55
+ const api = useMenuContext();
56
+ return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
57
+ ref: reactComposeRefs.composeRefs(api.refs.anchor, ref),
58
+ ...domUtils.mergeProps(api.anchorProps, props)
59
+ });
60
+ });
61
+ MenuAnchor.displayName = "MenuAnchor";
62
+ const MenuTrigger = /*#__PURE__*/ React.forwardRef((props, ref)=>{
63
+ const api = useMenuContext();
64
+ return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.button, {
65
+ ref: reactComposeRefs.composeRefs(api.refs.trigger, ref),
66
+ ...domUtils.mergeProps(api.triggerProps, props)
67
+ });
68
+ });
69
+ MenuTrigger.displayName = "MenuTrigger";
70
+ const MenuPositioner = /*#__PURE__*/ React.forwardRef(({ container, ...props }, ref)=>{
71
+ const api = useMenuContext();
72
+ // FloatingPortal (not a generic portal) so that FloatingFocusManager
73
+ // detects the portal context and renders focus-guard sentinels.
74
+ return /*#__PURE__*/ jsxRuntime.jsx(react.FloatingPortal, {
75
+ root: container ?? undefined,
76
+ children: /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
77
+ ref: reactComposeRefs.composeRefs(api.refs.positioner, ref),
78
+ ...domUtils.mergeProps(api.positionerProps, props)
79
+ })
80
+ });
81
+ });
82
+ MenuPositioner.displayName = "MenuPositioner";
83
+ const MenuContent = /*#__PURE__*/ React.forwardRef((props, ref)=>{
84
+ const { floatingContext, contentProps, open, setOpen, elementsRef, labelsRef } = useMenuContext();
85
+ const content = /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
86
+ ref: ref,
87
+ ...domUtils.mergeProps(contentProps, props)
88
+ });
89
+ // FloatingFocusManager: handles position-aware initial focus, return focus,
90
+ // closeOnFocusOut, tab order guards, and useListNavigation coordination.
91
+ //
92
+ // FocusScope: participates in Radix's focusScopesStack so that parent
93
+ // FocusScopes (e.g. Dialog, Drawer) are automatically paused while this
94
+ // Menu is open. Without this, focus cannot leave a trapped parent scope
95
+ // to reach Menu content rendered in a Portal.
96
+ //
97
+ // FocusScope is conditionally rendered (only when open) because Menu
98
+ // content is always in the DOM (hidden via data-hidden). If FocusScope
99
+ // were always mounted, it would register in the stack at page load —
100
+ // before any Dialog — and could never re-register above a Dialog that
101
+ // mounts later. Mounting only when open ensures it lands at the top of
102
+ // the stack, pausing the parent scope.
103
+ return /*#__PURE__*/ jsxRuntime.jsx(react.FloatingFocusManager, {
104
+ context: floatingContext,
105
+ disabled: !open,
106
+ modal: false,
107
+ children: /*#__PURE__*/ jsxRuntime.jsx(react.FloatingList, {
108
+ elementsRef: elementsRef,
109
+ labelsRef: labelsRef,
110
+ children: /*#__PURE__*/ jsxRuntime.jsx(reactDismissibleLayer.DismissibleLayer, {
111
+ enabled: open,
112
+ pressBehavior: "drag",
113
+ onEscapeKeyDown: (event)=>{
114
+ setOpen(false, {
115
+ reason: "escapeKeyDown",
116
+ event
117
+ });
118
+ },
119
+ onPressOutside: (event)=>{
120
+ setOpen(false, {
121
+ reason: "interactOutside",
122
+ event
123
+ });
124
+ },
125
+ onCascadeDismiss: ({ dismissedParent })=>{
126
+ setOpen(false, {
127
+ reason: "cascadeDismiss",
128
+ dismissedParent
129
+ });
130
+ },
131
+ onFocusOutside: ()=>{
132
+ // focus trapping is handled by FloatingFocusManager — nothing to do here
133
+ },
134
+ exclude: (target)=>{
135
+ const reference = floatingContext.refs.reference.current;
136
+ if (!(reference instanceof HTMLElement)) return false;
137
+ return reference.contains(target);
138
+ },
139
+ children: open ? /*#__PURE__*/ jsxRuntime.jsx(reactFocusScope.FocusScope, {
140
+ asChild: true,
141
+ trapped: false,
142
+ loop: false,
143
+ onMountAutoFocus: (e)=>e.preventDefault(),
144
+ onUnmountAutoFocus: (e)=>e.preventDefault(),
145
+ children: content
146
+ }) : content
147
+ })
148
+ })
149
+ });
150
+ });
151
+ MenuContent.displayName = "MenuContent";
152
+ const MenuItem = /*#__PURE__*/ React.forwardRef(({ disabled, typeaheadLabel, onClick, ...restProps }, ref)=>{
153
+ const { getItemProps } = useMenuContext();
154
+ const { ref: listRef, index } = react.useListItem({
155
+ label: typeaheadLabel
156
+ });
157
+ const api = getItemProps({
158
+ disabled,
159
+ onClick
160
+ }, index);
161
+ return /*#__PURE__*/ jsxRuntime.jsx(MenuItemProvider, {
162
+ value: api,
163
+ children: /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
164
+ ref: reactComposeRefs.composeRefs(listRef, ref),
165
+ ...domUtils.mergeProps(api.rootProps, restProps)
166
+ })
167
+ });
168
+ });
169
+ MenuItem.displayName = "MenuItem";
170
+ const MenuGroup = /*#__PURE__*/ React.forwardRef((props, ref)=>{
171
+ const { getGroupProps } = useMenuContext();
172
+ const { labelId, rootProps } = getGroupProps();
173
+ return /*#__PURE__*/ jsxRuntime.jsx(MenuGroupLabelIdContext.Provider, {
174
+ value: labelId,
175
+ children: /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
176
+ ref: ref,
177
+ ...domUtils.mergeProps(rootProps, props)
178
+ })
179
+ });
180
+ });
181
+ MenuGroup.displayName = "MenuGroup";
182
+ const MenuGroupLabel = /*#__PURE__*/ React.forwardRef((props, ref)=>{
183
+ const { getGroupLabelProps } = useMenuContext();
184
+ const labelId = React__default.default.useContext(MenuGroupLabelIdContext);
185
+ if (!labelId) throw new Error("MenuGroupLabel must be used within a MenuGroup");
186
+ return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
187
+ ref: ref,
188
+ ...domUtils.mergeProps(getGroupLabelProps(labelId), props)
189
+ });
190
+ });
191
+ MenuGroupLabel.displayName = "MenuGroupLabel";
192
+
193
+ exports.MenuAnchor = MenuAnchor;
194
+ exports.MenuContent = MenuContent;
195
+ exports.MenuGroup = MenuGroup;
196
+ exports.MenuGroupLabel = MenuGroupLabel;
197
+ exports.MenuItem = MenuItem;
198
+ exports.MenuPositioner = MenuPositioner;
199
+ exports.MenuRoot = MenuRoot;
200
+ exports.MenuTrigger = MenuTrigger;
201
+ exports.useMenuContext = useMenuContext;
202
+ exports.useMenuItemContext = useMenuItemContext;
package/lib/index.cjs ADDED
@@ -0,0 +1,25 @@
1
+ var Menu12s = require('./Menu-12s-KCTCu-et.cjs');
2
+
3
+ var Menu_namespace = {
4
+ __proto__: null,
5
+ Anchor: Menu12s.MenuAnchor,
6
+ Content: Menu12s.MenuContent,
7
+ Group: Menu12s.MenuGroup,
8
+ GroupLabel: Menu12s.MenuGroupLabel,
9
+ Item: Menu12s.MenuItem,
10
+ Positioner: Menu12s.MenuPositioner,
11
+ Root: Menu12s.MenuRoot,
12
+ Trigger: Menu12s.MenuTrigger
13
+ };
14
+
15
+ exports.MenuAnchor = Menu12s.MenuAnchor;
16
+ exports.MenuContent = Menu12s.MenuContent;
17
+ exports.MenuGroup = Menu12s.MenuGroup;
18
+ exports.MenuGroupLabel = Menu12s.MenuGroupLabel;
19
+ exports.MenuItem = Menu12s.MenuItem;
20
+ exports.MenuPositioner = Menu12s.MenuPositioner;
21
+ exports.MenuRoot = Menu12s.MenuRoot;
22
+ exports.MenuTrigger = Menu12s.MenuTrigger;
23
+ exports.useMenuContext = Menu12s.useMenuContext;
24
+ exports.useMenuItemContext = Menu12s.useMenuItemContext;
25
+ exports.Menu = Menu_namespace;