@basic-ui/core 0.0.46 → 0.0.48

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.
@@ -1904,6 +1904,7 @@ const useMenuListContext = () => react.useContext(menuListContext);
1904
1904
  const Menu = /*#__PURE__*/react.forwardRef(function Menu(props, forwardedRef) {
1905
1905
  const {
1906
1906
  as: Comp = react.Fragment,
1907
+ innerAs,
1907
1908
  open: openProp,
1908
1909
  defaultOpen = false,
1909
1910
  onChange: onChangeProp,
@@ -1915,17 +1916,29 @@ const Menu = /*#__PURE__*/react.forwardRef(function Menu(props, forwardedRef) {
1915
1916
  const [open, onChange] = useControlledState(openProp, onChangeProp, defaultOpen, setState => (e, isOpen) => {
1916
1917
  setState(isOpen);
1917
1918
  });
1919
+ const [offsetFn, setOffsetFn] = react.useState(undefined);
1918
1920
  menuListIdRef.current = react.useId();
1921
+ const isContextMenu = react.useRef(false);
1922
+
1923
+ if (!open && offsetFn) {
1924
+ setOffsetFn(undefined);
1925
+ }
1926
+
1919
1927
  const value = {
1920
1928
  menuListIdRef,
1921
1929
  openWithArrowKeyRef,
1922
1930
  open,
1923
1931
  onChange,
1924
- buttonRef
1932
+ buttonRef,
1933
+ offsetFn,
1934
+ setOffsetFn,
1935
+ isContextMenu
1925
1936
  };
1926
1937
  return /*#__PURE__*/jsxRuntime.jsx(MenuProvider, {
1927
1938
  value: value,
1928
- children: /*#__PURE__*/jsxRuntime.jsx(Comp, {
1939
+ children: /*#__PURE__*/jsxRuntime.jsx(Comp, { ...(Comp !== react.Fragment ? {
1940
+ as: innerAs
1941
+ } : {}),
1929
1942
  ref: forwardedRef,
1930
1943
  ...otherProps
1931
1944
  })
@@ -1935,6 +1948,7 @@ const Menu = /*#__PURE__*/react.forwardRef(function Menu(props, forwardedRef) {
1935
1948
  const MenuButton = /*#__PURE__*/react.forwardRef(function MenuButton(props, forwardedRef) {
1936
1949
  const {
1937
1950
  as: Comp = 'button',
1951
+ innerAs,
1938
1952
  id: preferredId,
1939
1953
  onClick,
1940
1954
  onKeyDown,
@@ -1970,7 +1984,7 @@ const MenuButton = /*#__PURE__*/react.forwardRef(function MenuButton(props, forw
1970
1984
  openWithArrowKeyRef.current = e.key;
1971
1985
  }
1972
1986
 
1973
- onChange && onChange(e, true);
1987
+ onChange(e, true);
1974
1988
  e.preventDefault();
1975
1989
  }
1976
1990
  };
@@ -1981,11 +1995,12 @@ const MenuButton = /*#__PURE__*/react.forwardRef(function MenuButton(props, forw
1981
1995
  }
1982
1996
 
1983
1997
  buttonRef.current = e.currentTarget;
1984
- onChange && onChange(e, !open);
1998
+ onChange(e, !open);
1985
1999
  };
1986
2000
 
1987
2001
  return /*#__PURE__*/jsxRuntime.jsx(Comp, {
1988
2002
  ref: forwardedRef,
2003
+ as: innerAs,
1989
2004
  id: buttonId,
1990
2005
  role: "button",
1991
2006
  type: "button",
@@ -2000,9 +2015,61 @@ const MenuButton = /*#__PURE__*/react.forwardRef(function MenuButton(props, forw
2000
2015
  });
2001
2016
  });
2002
2017
 
2018
+ const ContextMenuTrigger = /*#__PURE__*/react.forwardRef(function ContextMenuTrigger(props, forwardedRef) {
2019
+ const {
2020
+ as: Comp = 'div',
2021
+ innerAs,
2022
+ id: preferredId,
2023
+ onContextMenu,
2024
+ disabled,
2025
+ ...otherProps
2026
+ } = props;
2027
+ const {
2028
+ menuListIdRef,
2029
+ open,
2030
+ buttonRef,
2031
+ onChange,
2032
+ setOffsetFn,
2033
+ isContextMenu
2034
+ } = useMenuContext();
2035
+ const idGenerated = react.useId();
2036
+ const id = preferredId || idGenerated;
2037
+
2038
+ const handleContextMenu = e => {
2039
+ if (disabled) {
2040
+ return;
2041
+ }
2042
+
2043
+ const rect = e.currentTarget.getBoundingClientRect();
2044
+ isContextMenu.current = true;
2045
+ buttonRef.current = e.currentTarget;
2046
+ onChange(e, true);
2047
+ const mouseX = e.nativeEvent.x;
2048
+ const mouseY = e.nativeEvent.y;
2049
+ setOffsetFn(() => ({
2050
+ reference
2051
+ }) => [mouseX - rect.x, mouseY - rect.y - reference.height]);
2052
+ e.preventDefault();
2053
+ };
2054
+
2055
+ return /*#__PURE__*/jsxRuntime.jsx(Comp, {
2056
+ ref: forwardedRef,
2057
+ as: innerAs,
2058
+ id: id,
2059
+ "aria-haspopup": true,
2060
+ "aria-controls": menuListIdRef.current,
2061
+ "aria-expanded": open ? true : undefined,
2062
+ "data-menu-trigger": "",
2063
+ onContextMenu: wrapEvent(onContextMenu, handleContextMenu),
2064
+ disabled: disabled,
2065
+ ...otherProps
2066
+ });
2067
+ });
2068
+
2003
2069
  const MenuItem = /*#__PURE__*/react.forwardRef(function MenuItem(props, forwardedRef) {
2004
2070
  const {
2005
2071
  as: Comp = 'li',
2072
+ innerAs,
2006
2073
  disabled,
2007
2074
  onSelect,
2008
2075
  onClick,
@@ -2021,7 +2088,7 @@ const MenuItem = /*#__PURE__*/react.forwardRef(function MenuItem(props, forwarde
2021
2088
  const itemId = react.useId();
2022
2089
  const isActive = ref.current && ref.current === navigationItem;
2023
2090
  const handleSelect = wrapEvent(onSelect, e => {
2024
- onChange && onChange(e, false);
2091
+ onChange(e, false);
2025
2092
  buttonRef.current?.focus();
2026
2093
  e.preventDefault();
2027
2094
  });
@@ -2047,6 +2114,7 @@ const MenuItem = /*#__PURE__*/react.forwardRef(function MenuItem(props, forwarde
2047
2114
 
2048
2115
  return /*#__PURE__*/jsxRuntime.jsx(Comp, {
2049
2116
  ref: assignMultipleRefs(ref, forwardedRef),
2117
+ as: innerAs,
2050
2118
  id: disabled ? undefined : itemId,
2051
2119
  "data-menu-item": "",
2052
2120
  "data-highlighted": isActive ? '' : undefined,
@@ -2069,11 +2137,13 @@ const useEnhancedEffect$1 = typeof window !== 'undefined' ? react.useLayoutEffec
2069
2137
  const MenuList = /*#__PURE__*/react.forwardRef(function MenuList(props, forwardedRef) {
2070
2138
  const {
2071
2139
  as: Comp = 'ul',
2140
+ innerAs,
2072
2141
  onKeyDown,
2073
2142
  id: preferredId,
2074
2143
  defaultActiveItemValue,
2075
2144
  ...otherProps
2076
2145
  } = props;
2146
+ const interactedOutside = react.useRef(false);
2077
2147
  const itemSearchStr = react.useRef('');
2078
2148
  const itemSearchClearTimeout = react.useRef();
2079
2149
  const {
@@ -2081,7 +2151,8 @@ const MenuList = /*#__PURE__*/react.forwardRef(function MenuList(props, forwarde
2081
2151
  buttonRef,
2082
2152
  onChange,
2083
2153
  openWithArrowKeyRef,
2084
- open
2154
+ open,
2155
+ isContextMenu
2085
2156
  } = useMenuContext();
2086
2157
  const [navigationItem, setNavigationItem] = react.useState();
2087
2158
  const [mounted, setMounted] = react.useState(false);
@@ -2116,20 +2187,34 @@ const MenuList = /*#__PURE__*/react.forwardRef(function MenuList(props, forwarde
2116
2187
  openWithArrowKeyRef.current = null;
2117
2188
  setMounted(true);
2118
2189
  }, [mounted, navigationItem, onNavigate, openWithArrowKeyRef, scope, defaultActiveItemValue]);
2119
- useOnClickOutside(menuListRef, e => {
2120
- if (e.target instanceof HTMLElement && e.target !== buttonRef.current && !buttonRef.current?.contains(e.target)) {
2121
- onChange && onChange(e, false);
2190
+ const handleClickOutside = react.useCallback(e => {
2191
+ if (!interactedOutside.current) {
2192
+ // First interaction should be ignored, because
2193
+ // this is what triggered the context menu to open
2194
+ interactedOutside.current = true;
2195
+ return;
2196
+ }
2197
+
2198
+ if (isContextMenu.current) {
2199
+ if (e.button === 0) {
2200
+ onChange(e, false);
2201
+ }
2202
+ } else {
2203
+ if (e.target instanceof HTMLElement && e.target !== buttonRef.current && !buttonRef.current?.contains(e.target)) {
2204
+ onChange(e, false);
2205
+ }
2122
2206
  }
2123
2207
 
2124
2208
  e.preventDefault();
2125
- }, true);
2209
+ }, [buttonRef, isContextMenu, onChange]);
2210
+ useOnClickOutside(menuListRef, handleClickOutside, open);
2126
2211
 
2127
2212
  function handleKeyDown(e) {
2128
2213
  switch (e.key) {
2129
2214
  case 'Escape':
2130
2215
  case 'Tab':
2131
2216
  {
2132
- onChange && onChange(e, false);
2217
+ onChange(e, false);
2133
2218
  e.preventDefault(); // prevents focusing on next element, because we will be handling it
2134
2219
 
2135
2220
  itemSearchStr.current = '';
@@ -2216,6 +2301,7 @@ const MenuList = /*#__PURE__*/react.forwardRef(function MenuList(props, forwarde
2216
2301
  }
2217
2302
 
2218
2303
  if (!open) {
2304
+ interactedOutside.current = false;
2219
2305
  return null;
2220
2306
  }
2221
2307
 
@@ -2226,6 +2312,7 @@ const MenuList = /*#__PURE__*/react.forwardRef(function MenuList(props, forwarde
2226
2312
  },
2227
2313
  children: /*#__PURE__*/jsxRuntime.jsx(Comp, {
2228
2314
  ref: assignMultipleRefs(forwardedRef, menuListRef),
2315
+ as: innerAs,
2229
2316
  id: menuListIdRef.current,
2230
2317
  role: "menu",
2231
2318
  "aria-labelledby": buttonRef.current?.id,
@@ -2370,11 +2457,14 @@ const PopperArrow = /*#__PURE__*/react.forwardRef(function PopperArrow({
2370
2457
  const MenuPopover = /*#__PURE__*/react.forwardRef(function MenuPopover(props, forwardedRef) {
2371
2458
  const {
2372
2459
  as = 'div',
2460
+ innerAs,
2373
2461
  ...otherProps
2374
2462
  } = props;
2375
2463
  const {
2376
2464
  buttonRef,
2377
- open
2465
+ open,
2466
+ offsetFn,
2467
+ isContextMenu
2378
2468
  } = useMenuContext();
2379
2469
 
2380
2470
  if (!open) {
@@ -2383,8 +2473,11 @@ const MenuPopover = /*#__PURE__*/react.forwardRef(function MenuPopover(props, fo
2383
2473
 
2384
2474
  return /*#__PURE__*/jsxRuntime.jsx(Popper, {
2385
2475
  as: as,
2476
+ innerAs: innerAs,
2386
2477
  ref: forwardedRef,
2387
2478
  anchorEl: buttonRef,
2479
+ offsetFn: offsetFn,
2480
+ placement: isContextMenu.current ? 'bottom-start' : undefined,
2388
2481
  ...otherProps
2389
2482
  });
2390
2483
  });
@@ -3977,6 +4070,7 @@ exports.ComboboxLabel = ComboboxLabel;
3977
4070
  exports.ComboboxList = ComboboxList;
3978
4071
  exports.ComboboxOption = ComboboxOption;
3979
4072
  exports.ComboboxPopover = ComboboxPopover;
4073
+ exports.ContextMenuTrigger = ContextMenuTrigger;
3980
4074
  exports.FocusLock = FocusLock;
3981
4075
  exports.Menu = Menu;
3982
4076
  exports.MenuButton = MenuButton;