@trackunit/react-components 2.10.24 → 2.10.27-alpha-7557f71cc7a.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/react-components",
3
- "version": "2.10.24",
3
+ "version": "2.10.27-alpha-7557f71cc7a.0",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "migrations": "./migrations.json",
@@ -14,16 +14,16 @@
14
14
  "@floating-ui/react": "^0.26.25",
15
15
  "string-ts": "^2.0.0",
16
16
  "tailwind-merge": "^2.0.0",
17
- "@trackunit/ui-design-tokens": "1.15.11",
18
- "@trackunit/css-class-variance-utilities": "1.14.21",
19
- "@trackunit/shared-utils": "1.16.24",
20
- "@trackunit/ui-icons": "1.14.20",
17
+ "@trackunit/ui-design-tokens": "1.15.13-alpha-7557f71cc7a.0",
18
+ "@trackunit/css-class-variance-utilities": "1.14.23-alpha-7557f71cc7a.0",
19
+ "@trackunit/shared-utils": "1.16.26-alpha-7557f71cc7a.0",
20
+ "@trackunit/ui-icons": "1.14.22-alpha-7557f71cc7a.0",
21
21
  "es-toolkit": "^1.39.10",
22
22
  "@tanstack/react-virtual": "^3.14.3",
23
23
  "dequal": "^2.0.3",
24
24
  "fflate": "^0.8.2",
25
25
  "zod": "^3.25.76",
26
- "@trackunit/i18n-library-translation": "2.4.29"
26
+ "@trackunit/i18n-library-translation": "2.4.32-alpha-7557f71cc7a.0"
27
27
  },
28
28
  "peerDependencies": {
29
29
  "react": "^19.0.0",
@@ -29,6 +29,11 @@ export interface MenuContentProps extends CommonProps, Styleable, Refable<HTMLDi
29
29
  * Callback triggered when selected items change.
30
30
  */
31
31
  onSelectionChange?: (selected: Array<string>) => void;
32
+ /**
33
+ * Accessible name for the `role="menu"` node. Prefer this (or `aria-labelledby` via the trigger)
34
+ * when the menu is not named by surrounding chrome.
35
+ */
36
+ "aria-label"?: string;
32
37
  }
33
38
  /**
34
39
  * MenuContent (formerly MenuList) is a popover menu that appears above all other content on the page. It offers a
@@ -36,6 +41,9 @@ export interface MenuContentProps extends CommonProps, Styleable, Refable<HTMLDi
36
41
  * roving-tabindex Up/Down navigation (wrapping), Home/End, typeahead, and — via `MenuItem`'s `submenu` prop —
37
42
  * nested submenu entry/exit.
38
43
  *
44
+ * Items join this menu themselves via `FloatingList` + `useListItem`, so wrapping components do not hide them
45
+ * from the keyboard loop. Non-item children (search inputs, headings, dividers) render untouched.
46
+ *
39
47
  * Typically rendered inside a `Popover` (directly, or as `PopoverContent`'s children), in which case it reads
40
48
  * the popover's floating context to power its keyboard navigation. Also works standalone (e.g. inside a
41
49
  * `Collapse`, with no ambient `Popover`), falling back to its own local, always-open floating context.
@@ -93,4 +101,4 @@ export interface MenuContentProps extends CommonProps, Styleable, Refable<HTMLDi
93
101
  * @param {MenuContentProps} props - The props for the MenuContent component
94
102
  * @returns {ReactElement} MenuContent component
95
103
  */
96
- export declare const MenuContent: ({ "data-testid": dataTestId, className, listClassName, children, isMulti, selectedItems: controlledSelectedItems, onSelectionChange, style, ref, ...args }: MenuContentProps) => ReactElement;
104
+ export declare const MenuContent: ({ "data-testid": dataTestId, className, listClassName, children, isMulti, selectedItems, onSelectionChange, style, ref, "aria-label": ariaLabel, ...args }: MenuContentProps) => ReactElement;
@@ -0,0 +1,23 @@
1
+ import { HTMLProps } from "react";
2
+ type MenuItemInteractionProps = Omit<HTMLProps<HTMLElement>, "selected" | "active"> & {
3
+ active?: boolean;
4
+ selected?: boolean;
5
+ };
6
+ export interface MenuContentContextValue {
7
+ activeIndex: number | null;
8
+ firstEnabledIndex: number;
9
+ getItemProps: (userProps?: MenuItemInteractionProps) => Record<string, unknown>;
10
+ isMulti: boolean;
11
+ selectedItems: Array<string>;
12
+ handleItemClick: (id: string) => void;
13
+ syncRegisteredList: () => void;
14
+ }
15
+ declare const MenuContentContext: import("react").Context<MenuContentContextValue | null>;
16
+ /**
17
+ * Like `useOptionalPopoverContext`, but for the nearest `MenuContent`.
18
+ * `MenuItem` is used without a menu in places, so a missing ancestor must not throw.
19
+ *
20
+ * @returns {MenuContentContextValue | null} The menu context, or `null` when there is no ancestor `MenuContent`
21
+ */
22
+ export declare const useOptionalMenuContentContext: () => MenuContentContextValue | null;
23
+ export { MenuContentContext };
@@ -0,0 +1,18 @@
1
+ import { MutableRefObject } from "react";
2
+ /**
3
+ * FloatingList only grows `elementsRef` / `labelsRef`. On unmount, `useListItem` nulls the element
4
+ * but writes the label back, so a removed row stays a live typeahead target on a dead slot.
5
+ * Re-establish both arrays from currently mounted nodes after each commit.
6
+ *
7
+ * @param elementsRef The FloatingList elements array
8
+ * @param labelsRef The FloatingList typeahead labels array, kept in lockstep with `elementsRef`
9
+ */
10
+ export declare const compactFloatingListRefs: (elementsRef: MutableRefObject<Array<HTMLElement | null>>, labelsRef: MutableRefObject<Array<string | null>>) => void;
11
+ /**
12
+ * Index of the first registered item that is not `aria-disabled`. Used as the initial tab stop
13
+ * when `activeIndex` is still null.
14
+ *
15
+ * @param elementsRef The FloatingList elements array
16
+ * @returns {number} The first enabled index, or `0` when the list has no enabled item
17
+ */
18
+ export declare const firstEnabledListIndex: (elementsRef: MutableRefObject<Array<HTMLElement | null>>) => number;
@@ -0,0 +1,23 @@
1
+ import { useInteractions, useMergeRefs } from "@floating-ui/react";
2
+ import { KeyboardEvent, MutableRefObject, ReactNode, Ref } from "react";
3
+ import { MenuContentContextValue } from "./MenuContentContext";
4
+ export interface UseMenuContentStateProps {
5
+ children: ReactNode;
6
+ isMulti: boolean;
7
+ selectedItems?: Array<string>;
8
+ onSelectionChange?: (selected: Array<string>) => void;
9
+ ref?: Ref<HTMLDivElement>;
10
+ }
11
+ export interface UseMenuContentStateResult {
12
+ floatingRef: ReturnType<typeof useMergeRefs<HTMLDivElement>>;
13
+ getFloatingProps: ReturnType<typeof useInteractions>["getFloatingProps"];
14
+ handleKeyDownCapture: (event: KeyboardEvent<HTMLDivElement>) => void;
15
+ listRef: MutableRefObject<Array<HTMLElement | null>>;
16
+ labelsRef: MutableRefObject<Array<string | null>>;
17
+ menuContext: MenuContentContextValue;
18
+ }
19
+ /**
20
+ * Owns MenuContent's list registration, selection, and typeable-child key handling so the
21
+ * component file stays the shell + JSX.
22
+ */
23
+ export declare const useMenuContentState: ({ children, isMulti, selectedItems: controlledSelectedItems, onSelectionChange, ref, }: UseMenuContentStateProps) => UseMenuContentStateResult;
@@ -12,12 +12,13 @@ export interface MenuItemProps extends CommonProps, Styleable, Refable<HTMLDivEl
12
12
  */
13
13
  id?: string;
14
14
  /**
15
- * Label of the menu item
15
+ * Label of the menu item. Also the typeahead string. When `children` is a React node rather than
16
+ * a string, keep `label` set so typeahead still matches this row.
16
17
  */
17
18
  label?: string;
18
19
  /**
19
- * The children element is a custom element that can be used to override the label.
20
- * If you use this prop, the label prop will be ignored.
20
+ * Custom content that replaces the label visually. Does not replace `label` for typeahead
21
+ * keep `label` set to the searchable string whenever `children` is not itself a string.
21
22
  */
22
23
  children?: ReactNode;
23
24
  /**
@@ -0,0 +1,21 @@
1
+ import { MutableRefObject } from "react";
2
+ export interface UseCloseWhenScrolledOutOptions {
3
+ open: boolean;
4
+ nodeRef: MutableRefObject<HTMLElement | null>;
5
+ returnFocusRef: MutableRefObject<HTMLElement | null>;
6
+ onClose: () => void;
7
+ }
8
+ /**
9
+ * A submenu's trigger row commonly lives inside a scrollable `MenuContent` list. Without this, a
10
+ * submenu opened from a row that later scrolls out of view stays open, floating disconnected from
11
+ * any visible row -- and (since nothing else would ever close it) stays that way even once the row
12
+ * scrolls back into view. `IntersectionObserver` (rather than e.g. the `Popover`'s own
13
+ * `ancestorScroll` dismissal) is what lets this react to the row's actual visibility instead of
14
+ * firing on every scroll tick of any ancestor, however small or unrelated to this row -- browsers
15
+ * compute intersection against every ancestor's overflow-clip box, not just an explicit `root`, so
16
+ * this fires as soon as *this* row's clipped out, even if some other list ancestor keeps scrolling.
17
+ * Only observing while `open` (rather than unconditionally) means the effect's own close
18
+ * never re-triggers itself, which is also exactly what keeps the submenu from reopening on its own
19
+ * once the row scrolls back into view -- there's no observer left running to notice that happen.
20
+ */
21
+ export declare const useCloseWhenScrolledOut: ({ open, nodeRef, returnFocusRef, onClose, }: UseCloseWhenScrolledOutOptions) => void;
@@ -0,0 +1,38 @@
1
+ import { useMergeRefs } from "@floating-ui/react";
2
+ import { FocusEventHandler, MouseEventHandler, MutableRefObject, PointerEventHandler, ReactNode, Ref } from "react";
3
+ interface UseMenuItemBehaviorProps {
4
+ className?: string;
5
+ label?: string;
6
+ children?: ReactNode;
7
+ selected: boolean;
8
+ disabled: boolean;
9
+ onClick?: MouseEventHandler<HTMLDivElement>;
10
+ stopPropagation: boolean;
11
+ id?: string;
12
+ tabIndex?: number;
13
+ ref?: Ref<HTMLDivElement>;
14
+ submenu?: ReactNode;
15
+ suffix?: ReactNode;
16
+ onFocus?: FocusEventHandler<HTMLDivElement>;
17
+ onMouseMove?: MouseEventHandler<HTMLDivElement>;
18
+ onPointerLeave?: PointerEventHandler<HTMLDivElement>;
19
+ }
20
+ export interface UseMenuItemBehaviorResult {
21
+ mergedRowRef: ReturnType<typeof useMergeRefs<HTMLDivElement>>;
22
+ mergedTriggerRef: ReturnType<typeof useMergeRefs<HTMLDivElement>>;
23
+ submenuOpen: boolean;
24
+ setSubmenuOpen: (open: boolean) => void;
25
+ returnFocusRef: MutableRefObject<HTMLElement | null>;
26
+ isSelected: boolean;
27
+ resolvedSuffix: ReactNode | undefined;
28
+ listClassName?: string;
29
+ resolvedTabIndex: number;
30
+ interactionProps: Record<string, unknown>;
31
+ }
32
+ /**
33
+ * Registers this row with the nearest `MenuContent` (no-op when there isn't one) and resolves the
34
+ * interaction / selection / tabIndex props the row needs. Submenu open state lives here so the
35
+ * scroll-out closer can share it.
36
+ */
37
+ export declare const useMenuItemBehavior: ({ className, label, children, selected, disabled, onClick, stopPropagation, id, tabIndex, ref, submenu, suffix, onFocus, onMouseMove, onPointerLeave, }: UseMenuItemBehaviorProps) => UseMenuItemBehaviorResult;
38
+ export {};