@vuu-ui/vuu-popups 0.8.98 → 0.8.99

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.
@@ -12,7 +12,6 @@ const useKeyboardNavigation = ({
12
12
  highlightedIndex: highlightedIndexProp,
13
13
  onActivate,
14
14
  onHighlight,
15
- // onKeyDown,
16
15
  onCloseMenu,
17
16
  onOpenMenu
18
17
  }) => {
@@ -48,7 +47,7 @@ const useKeyboardNavigation = ({
48
47
  const ignoreFocus = React.useRef(false);
49
48
  const setIgnoreFocus = (value) => ignoreFocus.current = value;
50
49
  const highlightedIndex = controlledHighlighting ? highlightedIndexProp : highlightedIndexRef.current;
51
- const navigateChildldItems = React.useCallback(
50
+ const navigateChildItems = React.useCallback(
52
51
  (e) => {
53
52
  const nextIdx = nextItemIdx(count, e.key, highlightedIndexRef.current);
54
53
  if (nextIdx !== highlightedIndexRef.current) {
@@ -63,7 +62,7 @@ const useKeyboardNavigation = ({
63
62
  e.preventDefault();
64
63
  e.stopPropagation();
65
64
  keyBoardNavigation.current = true;
66
- navigateChildldItems(e);
65
+ navigateChildItems(e);
67
66
  } else if ((e.key === "ArrowRight" || e.key === "Enter") && utils.hasPopup(e.target, highlightedIndex)) {
68
67
  const menuEl = e.target;
69
68
  const menuItemEl = menuEl.querySelector(
@@ -82,13 +81,7 @@ const useKeyboardNavigation = ({
82
81
  onCloseMenu(e, "tab-away");
83
82
  }
84
83
  },
85
- [
86
- highlightedIndex,
87
- navigateChildldItems,
88
- onActivate,
89
- onCloseMenu,
90
- onOpenMenu
91
- ]
84
+ [highlightedIndex, navigateChildItems, onActivate, onCloseMenu, onOpenMenu]
92
85
  );
93
86
  const listProps = React.useMemo(
94
87
  () => ({
@@ -121,7 +114,6 @@ const useKeyboardNavigation = ({
121
114
  controlledHighlighting,
122
115
  highlightedIndex,
123
116
  setHighlightedIndex,
124
- // keyBoardNavigation,
125
117
  listProps,
126
118
  setIgnoreFocus
127
119
  };
@@ -1 +1 @@
1
- {"version":3,"file":"use-keyboard-navigation.js","sources":["../../src/menu/use-keyboard-navigation.ts"],"sourcesContent":["import {\n FocusEvent,\n KeyboardEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { hasPopup, isRoot } from \"./utils\";\nimport { isNavigationKey } from \"./key-code\";\nimport { isValidNumber } from \"@vuu-ui/vuu-utils\";\nimport { MenuOpenHandler } from \"./MenuList\";\n\nexport type MenuCloseReason = \"tab-away\" | \"close-child-menu\";\n\nexport type MenuCloseHandler = (\n evt: KeyboardEvent,\n reason: MenuCloseReason,\n) => void;\n\nexport interface KeyboardNavigationProps {\n autoHighlightFirstItem?: boolean;\n count: number;\n defaultHighlightedIdx?: number;\n highlightedIndex?: number;\n onActivate: (idx: number) => void;\n onHighlight?: (idx: number) => void;\n onCloseMenu: MenuCloseHandler;\n onOpenMenu?: MenuOpenHandler;\n}\n\nexport interface KeyboardHookListProps {\n // onBlur: (evt: FocusEvent) => void;\n onFocus: (evt: FocusEvent) => void;\n onKeyDown: (evt: KeyboardEvent) => void;\n onMouseDownCapture: () => void;\n onMouseMove: () => void;\n onMouseLeave: () => void;\n}\n\nexport interface NavigationHookResult {\n focusVisible: number;\n controlledHighlighting: boolean;\n highlightedIndex: number;\n setHighlightedIndex: (idx: number) => void;\n // keyboardNavigation: RefObject<boolean>;\n listProps: KeyboardHookListProps;\n setIgnoreFocus: (ignoreFocus: boolean) => void;\n}\n\n// we need a way to set highlightedIdx when selection changes\nexport const useKeyboardNavigation = ({\n autoHighlightFirstItem = false,\n count,\n defaultHighlightedIdx,\n highlightedIndex: highlightedIndexProp,\n onActivate,\n onHighlight,\n // onKeyDown,\n onCloseMenu,\n onOpenMenu,\n}: KeyboardNavigationProps): NavigationHookResult => {\n if (\n isValidNumber(highlightedIndexProp) &&\n isValidNumber(defaultHighlightedIdx)\n ) {\n throw Error(\n \"useKeyboardNavigation do not pass values for both highlightedIndex and defaultHighlightedIdx\",\n );\n }\n\n const controlledHighlighting = isValidNumber(highlightedIndexProp);\n const highlightedIndexRef = useRef(\n defaultHighlightedIdx ??\n highlightedIndexProp ??\n (autoHighlightFirstItem ? 0 : -1),\n );\n const [, forceRender] = useState<unknown>(null);\n\n const setHighlightedIdx = useCallback(\n (idx) => {\n highlightedIndexRef.current = idx;\n onHighlight?.(idx);\n forceRender({});\n },\n [onHighlight],\n );\n\n const setHighlightedIndex = useCallback(\n (idx) => {\n if (idx !== highlightedIndexRef.current) {\n if (!controlledHighlighting) {\n setHighlightedIdx(idx);\n }\n }\n },\n [controlledHighlighting, setHighlightedIdx],\n );\n\n // does this belong here or should it be a method passed in?\n const keyBoardNavigation = useRef(true);\n const ignoreFocus = useRef(false);\n const setIgnoreFocus = (value: boolean) => (ignoreFocus.current = value);\n\n const highlightedIndex = controlledHighlighting\n ? highlightedIndexProp\n : highlightedIndexRef.current;\n\n const navigateChildldItems = useCallback(\n (e: KeyboardEvent) => {\n const nextIdx = nextItemIdx(count, e.key, highlightedIndexRef.current);\n if (nextIdx !== highlightedIndexRef.current) {\n setHighlightedIndex(nextIdx);\n }\n },\n [count, setHighlightedIndex],\n );\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isNavigationKey(e)) {\n e.preventDefault();\n e.stopPropagation();\n keyBoardNavigation.current = true;\n navigateChildldItems(e);\n } else if (\n (e.key === \"ArrowRight\" || e.key === \"Enter\") &&\n hasPopup(e.target as HTMLElement, highlightedIndex)\n ) {\n const menuEl = e.target as HTMLElement;\n const menuItemEl = menuEl.querySelector(\n `:scope > [data-index='${highlightedIndex}']`,\n ) as HTMLElement;\n\n if (menuItemEl) {\n onOpenMenu?.(menuItemEl, true);\n }\n } else if (e.key === \"ArrowLeft\" && !isRoot(e.target as HTMLElement)) {\n onCloseMenu(e, \"close-child-menu\");\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n e.stopPropagation();\n onActivate && onActivate(highlightedIndex);\n } else if (e.key === \"Tab\") {\n onCloseMenu(e, \"tab-away\");\n }\n },\n [\n highlightedIndex,\n navigateChildldItems,\n onActivate,\n onCloseMenu,\n onOpenMenu,\n ],\n );\n\n const listProps: KeyboardHookListProps = useMemo(\n () => ({\n onFocus: () => {\n if (highlightedIndex === -1) {\n setHighlightedIdx(0);\n }\n },\n onKeyDown: handleKeyDown,\n onMouseDownCapture: () => {\n keyBoardNavigation.current = false;\n setIgnoreFocus(true);\n },\n\n // onMouseEnter would seem less expensive but it misses some cases\n onMouseMove: () => {\n if (keyBoardNavigation.current) {\n keyBoardNavigation.current = false;\n }\n },\n onMouseLeave: () => {\n // label === 'ParsedInput' && console.log(`%c[useKeyboardNavigationHook]<${label}> onMouseLeave`,'color:brown')\n keyBoardNavigation.current = true;\n setIgnoreFocus(false);\n setHighlightedIndex(-1);\n },\n }),\n [handleKeyDown, highlightedIndex, setHighlightedIdx, setHighlightedIndex],\n );\n\n return {\n focusVisible: keyBoardNavigation.current ? highlightedIndex : -1,\n controlledHighlighting,\n highlightedIndex,\n setHighlightedIndex: setHighlightedIndex,\n // keyBoardNavigation,\n listProps,\n setIgnoreFocus,\n };\n};\n\n// need to be able to accommodate disabled items\nfunction nextItemIdx(count: number, key: string, idx: number) {\n if (key === \"ArrowUp\") {\n if (idx > 0) {\n return idx - 1;\n } else {\n return idx;\n }\n } else {\n if (idx === null) {\n return 0;\n } else if (idx === count - 1) {\n return idx;\n } else {\n return idx + 1;\n }\n }\n}\n"],"names":["isValidNumber","useRef","useState","useCallback","isNavigationKey","hasPopup","isRoot","useMemo"],"mappings":"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"}
1
+ {"version":3,"file":"use-keyboard-navigation.js","sources":["../../src/menu/use-keyboard-navigation.ts"],"sourcesContent":["import {\n FocusEvent,\n KeyboardEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { hasPopup, isRoot } from \"./utils\";\nimport { isNavigationKey } from \"./key-code\";\nimport { isValidNumber } from \"@vuu-ui/vuu-utils\";\nimport { MenuOpenHandler } from \"./MenuList\";\n\nexport type MenuCloseReason = \"tab-away\" | \"close-child-menu\";\n\nexport type MenuCloseHandler = (\n evt: KeyboardEvent,\n reason: MenuCloseReason,\n) => void;\n\nexport interface KeyboardNavigationProps {\n autoHighlightFirstItem?: boolean;\n count: number;\n defaultHighlightedIdx?: number;\n highlightedIndex?: number;\n onActivate: (idx: number) => void;\n onHighlight?: (idx: number) => void;\n onCloseMenu: MenuCloseHandler;\n onOpenMenu?: MenuOpenHandler;\n}\n\nexport interface KeyboardHookListProps {\n // onBlur: (evt: FocusEvent) => void;\n onFocus: (evt: FocusEvent) => void;\n onKeyDown: (evt: KeyboardEvent) => void;\n onMouseDownCapture: () => void;\n onMouseMove: () => void;\n onMouseLeave: () => void;\n}\n\nexport interface NavigationHookResult {\n focusVisible: number;\n controlledHighlighting: boolean;\n highlightedIndex: number;\n setHighlightedIndex: (idx: number) => void;\n // keyboardNavigation: RefObject<boolean>;\n listProps: KeyboardHookListProps;\n setIgnoreFocus: (ignoreFocus: boolean) => void;\n}\n\n// we need a way to set highlightedIdx when selection changes\nexport const useKeyboardNavigation = ({\n autoHighlightFirstItem = false,\n count,\n defaultHighlightedIdx,\n highlightedIndex: highlightedIndexProp,\n onActivate,\n onHighlight,\n onCloseMenu,\n onOpenMenu,\n}: KeyboardNavigationProps): NavigationHookResult => {\n if (\n isValidNumber(highlightedIndexProp) &&\n isValidNumber(defaultHighlightedIdx)\n ) {\n throw Error(\n \"useKeyboardNavigation do not pass values for both highlightedIndex and defaultHighlightedIdx\",\n );\n }\n\n const controlledHighlighting = isValidNumber(highlightedIndexProp);\n const highlightedIndexRef = useRef(\n defaultHighlightedIdx ??\n highlightedIndexProp ??\n (autoHighlightFirstItem ? 0 : -1),\n );\n const [, forceRender] = useState<unknown>(null);\n\n const setHighlightedIdx = useCallback(\n (idx) => {\n highlightedIndexRef.current = idx;\n onHighlight?.(idx);\n forceRender({});\n },\n [onHighlight],\n );\n\n const setHighlightedIndex = useCallback(\n (idx) => {\n if (idx !== highlightedIndexRef.current) {\n if (!controlledHighlighting) {\n setHighlightedIdx(idx);\n }\n }\n },\n [controlledHighlighting, setHighlightedIdx],\n );\n\n // does this belong here or should it be a method passed in?\n const keyBoardNavigation = useRef(true);\n const ignoreFocus = useRef(false);\n const setIgnoreFocus = (value: boolean) => (ignoreFocus.current = value);\n\n const highlightedIndex = controlledHighlighting\n ? highlightedIndexProp\n : highlightedIndexRef.current;\n\n const navigateChildItems = useCallback(\n (e: KeyboardEvent) => {\n const nextIdx = nextItemIdx(count, e.key, highlightedIndexRef.current);\n if (nextIdx !== highlightedIndexRef.current) {\n setHighlightedIndex(nextIdx);\n }\n },\n [count, setHighlightedIndex],\n );\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isNavigationKey(e)) {\n e.preventDefault();\n e.stopPropagation();\n keyBoardNavigation.current = true;\n navigateChildItems(e);\n } else if (\n (e.key === \"ArrowRight\" || e.key === \"Enter\") &&\n hasPopup(e.target as HTMLElement, highlightedIndex)\n ) {\n const menuEl = e.target as HTMLElement;\n const menuItemEl = menuEl.querySelector(\n `:scope > [data-index='${highlightedIndex}']`,\n ) as HTMLElement;\n\n if (menuItemEl) {\n onOpenMenu?.(menuItemEl, true);\n }\n } else if (e.key === \"ArrowLeft\" && !isRoot(e.target as HTMLElement)) {\n onCloseMenu(e, \"close-child-menu\");\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n e.stopPropagation();\n onActivate && onActivate(highlightedIndex);\n } else if (e.key === \"Tab\") {\n onCloseMenu(e, \"tab-away\");\n }\n },\n [highlightedIndex, navigateChildItems, onActivate, onCloseMenu, onOpenMenu],\n );\n\n const listProps: KeyboardHookListProps = useMemo(\n () => ({\n onFocus: () => {\n if (highlightedIndex === -1) {\n setHighlightedIdx(0);\n }\n },\n onKeyDown: handleKeyDown,\n onMouseDownCapture: () => {\n keyBoardNavigation.current = false;\n setIgnoreFocus(true);\n },\n\n // onMouseEnter would seem less expensive but it misses some cases\n onMouseMove: () => {\n if (keyBoardNavigation.current) {\n keyBoardNavigation.current = false;\n }\n },\n onMouseLeave: () => {\n keyBoardNavigation.current = true;\n setIgnoreFocus(false);\n setHighlightedIndex(-1);\n },\n }),\n [handleKeyDown, highlightedIndex, setHighlightedIdx, setHighlightedIndex],\n );\n\n return {\n focusVisible: keyBoardNavigation.current ? highlightedIndex : -1,\n controlledHighlighting,\n highlightedIndex,\n setHighlightedIndex: setHighlightedIndex,\n listProps,\n setIgnoreFocus,\n };\n};\n\n// need to be able to accommodate disabled items\nfunction nextItemIdx(count: number, key: string, idx: number) {\n if (key === \"ArrowUp\") {\n if (idx > 0) {\n return idx - 1;\n } else {\n return idx;\n }\n } else {\n if (idx === null) {\n return 0;\n } else if (idx === count - 1) {\n return idx;\n } else {\n return idx + 1;\n }\n }\n}\n"],"names":["isValidNumber","useRef","useState","useCallback","isNavigationKey","hasPopup","isRoot","useMemo"],"mappings":"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"}
@@ -10,7 +10,6 @@ const useKeyboardNavigation = ({
10
10
  highlightedIndex: highlightedIndexProp,
11
11
  onActivate,
12
12
  onHighlight,
13
- // onKeyDown,
14
13
  onCloseMenu,
15
14
  onOpenMenu
16
15
  }) => {
@@ -46,7 +45,7 @@ const useKeyboardNavigation = ({
46
45
  const ignoreFocus = useRef(false);
47
46
  const setIgnoreFocus = (value) => ignoreFocus.current = value;
48
47
  const highlightedIndex = controlledHighlighting ? highlightedIndexProp : highlightedIndexRef.current;
49
- const navigateChildldItems = useCallback(
48
+ const navigateChildItems = useCallback(
50
49
  (e) => {
51
50
  const nextIdx = nextItemIdx(count, e.key, highlightedIndexRef.current);
52
51
  if (nextIdx !== highlightedIndexRef.current) {
@@ -61,7 +60,7 @@ const useKeyboardNavigation = ({
61
60
  e.preventDefault();
62
61
  e.stopPropagation();
63
62
  keyBoardNavigation.current = true;
64
- navigateChildldItems(e);
63
+ navigateChildItems(e);
65
64
  } else if ((e.key === "ArrowRight" || e.key === "Enter") && hasPopup(e.target, highlightedIndex)) {
66
65
  const menuEl = e.target;
67
66
  const menuItemEl = menuEl.querySelector(
@@ -80,13 +79,7 @@ const useKeyboardNavigation = ({
80
79
  onCloseMenu(e, "tab-away");
81
80
  }
82
81
  },
83
- [
84
- highlightedIndex,
85
- navigateChildldItems,
86
- onActivate,
87
- onCloseMenu,
88
- onOpenMenu
89
- ]
82
+ [highlightedIndex, navigateChildItems, onActivate, onCloseMenu, onOpenMenu]
90
83
  );
91
84
  const listProps = useMemo(
92
85
  () => ({
@@ -119,7 +112,6 @@ const useKeyboardNavigation = ({
119
112
  controlledHighlighting,
120
113
  highlightedIndex,
121
114
  setHighlightedIndex,
122
- // keyBoardNavigation,
123
115
  listProps,
124
116
  setIgnoreFocus
125
117
  };
@@ -1 +1 @@
1
- {"version":3,"file":"use-keyboard-navigation.js","sources":["../../src/menu/use-keyboard-navigation.ts"],"sourcesContent":["import {\n FocusEvent,\n KeyboardEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { hasPopup, isRoot } from \"./utils\";\nimport { isNavigationKey } from \"./key-code\";\nimport { isValidNumber } from \"@vuu-ui/vuu-utils\";\nimport { MenuOpenHandler } from \"./MenuList\";\n\nexport type MenuCloseReason = \"tab-away\" | \"close-child-menu\";\n\nexport type MenuCloseHandler = (\n evt: KeyboardEvent,\n reason: MenuCloseReason,\n) => void;\n\nexport interface KeyboardNavigationProps {\n autoHighlightFirstItem?: boolean;\n count: number;\n defaultHighlightedIdx?: number;\n highlightedIndex?: number;\n onActivate: (idx: number) => void;\n onHighlight?: (idx: number) => void;\n onCloseMenu: MenuCloseHandler;\n onOpenMenu?: MenuOpenHandler;\n}\n\nexport interface KeyboardHookListProps {\n // onBlur: (evt: FocusEvent) => void;\n onFocus: (evt: FocusEvent) => void;\n onKeyDown: (evt: KeyboardEvent) => void;\n onMouseDownCapture: () => void;\n onMouseMove: () => void;\n onMouseLeave: () => void;\n}\n\nexport interface NavigationHookResult {\n focusVisible: number;\n controlledHighlighting: boolean;\n highlightedIndex: number;\n setHighlightedIndex: (idx: number) => void;\n // keyboardNavigation: RefObject<boolean>;\n listProps: KeyboardHookListProps;\n setIgnoreFocus: (ignoreFocus: boolean) => void;\n}\n\n// we need a way to set highlightedIdx when selection changes\nexport const useKeyboardNavigation = ({\n autoHighlightFirstItem = false,\n count,\n defaultHighlightedIdx,\n highlightedIndex: highlightedIndexProp,\n onActivate,\n onHighlight,\n // onKeyDown,\n onCloseMenu,\n onOpenMenu,\n}: KeyboardNavigationProps): NavigationHookResult => {\n if (\n isValidNumber(highlightedIndexProp) &&\n isValidNumber(defaultHighlightedIdx)\n ) {\n throw Error(\n \"useKeyboardNavigation do not pass values for both highlightedIndex and defaultHighlightedIdx\",\n );\n }\n\n const controlledHighlighting = isValidNumber(highlightedIndexProp);\n const highlightedIndexRef = useRef(\n defaultHighlightedIdx ??\n highlightedIndexProp ??\n (autoHighlightFirstItem ? 0 : -1),\n );\n const [, forceRender] = useState<unknown>(null);\n\n const setHighlightedIdx = useCallback(\n (idx) => {\n highlightedIndexRef.current = idx;\n onHighlight?.(idx);\n forceRender({});\n },\n [onHighlight],\n );\n\n const setHighlightedIndex = useCallback(\n (idx) => {\n if (idx !== highlightedIndexRef.current) {\n if (!controlledHighlighting) {\n setHighlightedIdx(idx);\n }\n }\n },\n [controlledHighlighting, setHighlightedIdx],\n );\n\n // does this belong here or should it be a method passed in?\n const keyBoardNavigation = useRef(true);\n const ignoreFocus = useRef(false);\n const setIgnoreFocus = (value: boolean) => (ignoreFocus.current = value);\n\n const highlightedIndex = controlledHighlighting\n ? highlightedIndexProp\n : highlightedIndexRef.current;\n\n const navigateChildldItems = useCallback(\n (e: KeyboardEvent) => {\n const nextIdx = nextItemIdx(count, e.key, highlightedIndexRef.current);\n if (nextIdx !== highlightedIndexRef.current) {\n setHighlightedIndex(nextIdx);\n }\n },\n [count, setHighlightedIndex],\n );\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isNavigationKey(e)) {\n e.preventDefault();\n e.stopPropagation();\n keyBoardNavigation.current = true;\n navigateChildldItems(e);\n } else if (\n (e.key === \"ArrowRight\" || e.key === \"Enter\") &&\n hasPopup(e.target as HTMLElement, highlightedIndex)\n ) {\n const menuEl = e.target as HTMLElement;\n const menuItemEl = menuEl.querySelector(\n `:scope > [data-index='${highlightedIndex}']`,\n ) as HTMLElement;\n\n if (menuItemEl) {\n onOpenMenu?.(menuItemEl, true);\n }\n } else if (e.key === \"ArrowLeft\" && !isRoot(e.target as HTMLElement)) {\n onCloseMenu(e, \"close-child-menu\");\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n e.stopPropagation();\n onActivate && onActivate(highlightedIndex);\n } else if (e.key === \"Tab\") {\n onCloseMenu(e, \"tab-away\");\n }\n },\n [\n highlightedIndex,\n navigateChildldItems,\n onActivate,\n onCloseMenu,\n onOpenMenu,\n ],\n );\n\n const listProps: KeyboardHookListProps = useMemo(\n () => ({\n onFocus: () => {\n if (highlightedIndex === -1) {\n setHighlightedIdx(0);\n }\n },\n onKeyDown: handleKeyDown,\n onMouseDownCapture: () => {\n keyBoardNavigation.current = false;\n setIgnoreFocus(true);\n },\n\n // onMouseEnter would seem less expensive but it misses some cases\n onMouseMove: () => {\n if (keyBoardNavigation.current) {\n keyBoardNavigation.current = false;\n }\n },\n onMouseLeave: () => {\n // label === 'ParsedInput' && console.log(`%c[useKeyboardNavigationHook]<${label}> onMouseLeave`,'color:brown')\n keyBoardNavigation.current = true;\n setIgnoreFocus(false);\n setHighlightedIndex(-1);\n },\n }),\n [handleKeyDown, highlightedIndex, setHighlightedIdx, setHighlightedIndex],\n );\n\n return {\n focusVisible: keyBoardNavigation.current ? highlightedIndex : -1,\n controlledHighlighting,\n highlightedIndex,\n setHighlightedIndex: setHighlightedIndex,\n // keyBoardNavigation,\n listProps,\n setIgnoreFocus,\n };\n};\n\n// need to be able to accommodate disabled items\nfunction nextItemIdx(count: number, key: string, idx: number) {\n if (key === \"ArrowUp\") {\n if (idx > 0) {\n return idx - 1;\n } else {\n return idx;\n }\n } else {\n if (idx === null) {\n return 0;\n } else if (idx === count - 1) {\n return idx;\n } else {\n return idx + 1;\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"use-keyboard-navigation.js","sources":["../../src/menu/use-keyboard-navigation.ts"],"sourcesContent":["import {\n FocusEvent,\n KeyboardEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { hasPopup, isRoot } from \"./utils\";\nimport { isNavigationKey } from \"./key-code\";\nimport { isValidNumber } from \"@vuu-ui/vuu-utils\";\nimport { MenuOpenHandler } from \"./MenuList\";\n\nexport type MenuCloseReason = \"tab-away\" | \"close-child-menu\";\n\nexport type MenuCloseHandler = (\n evt: KeyboardEvent,\n reason: MenuCloseReason,\n) => void;\n\nexport interface KeyboardNavigationProps {\n autoHighlightFirstItem?: boolean;\n count: number;\n defaultHighlightedIdx?: number;\n highlightedIndex?: number;\n onActivate: (idx: number) => void;\n onHighlight?: (idx: number) => void;\n onCloseMenu: MenuCloseHandler;\n onOpenMenu?: MenuOpenHandler;\n}\n\nexport interface KeyboardHookListProps {\n // onBlur: (evt: FocusEvent) => void;\n onFocus: (evt: FocusEvent) => void;\n onKeyDown: (evt: KeyboardEvent) => void;\n onMouseDownCapture: () => void;\n onMouseMove: () => void;\n onMouseLeave: () => void;\n}\n\nexport interface NavigationHookResult {\n focusVisible: number;\n controlledHighlighting: boolean;\n highlightedIndex: number;\n setHighlightedIndex: (idx: number) => void;\n // keyboardNavigation: RefObject<boolean>;\n listProps: KeyboardHookListProps;\n setIgnoreFocus: (ignoreFocus: boolean) => void;\n}\n\n// we need a way to set highlightedIdx when selection changes\nexport const useKeyboardNavigation = ({\n autoHighlightFirstItem = false,\n count,\n defaultHighlightedIdx,\n highlightedIndex: highlightedIndexProp,\n onActivate,\n onHighlight,\n onCloseMenu,\n onOpenMenu,\n}: KeyboardNavigationProps): NavigationHookResult => {\n if (\n isValidNumber(highlightedIndexProp) &&\n isValidNumber(defaultHighlightedIdx)\n ) {\n throw Error(\n \"useKeyboardNavigation do not pass values for both highlightedIndex and defaultHighlightedIdx\",\n );\n }\n\n const controlledHighlighting = isValidNumber(highlightedIndexProp);\n const highlightedIndexRef = useRef(\n defaultHighlightedIdx ??\n highlightedIndexProp ??\n (autoHighlightFirstItem ? 0 : -1),\n );\n const [, forceRender] = useState<unknown>(null);\n\n const setHighlightedIdx = useCallback(\n (idx) => {\n highlightedIndexRef.current = idx;\n onHighlight?.(idx);\n forceRender({});\n },\n [onHighlight],\n );\n\n const setHighlightedIndex = useCallback(\n (idx) => {\n if (idx !== highlightedIndexRef.current) {\n if (!controlledHighlighting) {\n setHighlightedIdx(idx);\n }\n }\n },\n [controlledHighlighting, setHighlightedIdx],\n );\n\n // does this belong here or should it be a method passed in?\n const keyBoardNavigation = useRef(true);\n const ignoreFocus = useRef(false);\n const setIgnoreFocus = (value: boolean) => (ignoreFocus.current = value);\n\n const highlightedIndex = controlledHighlighting\n ? highlightedIndexProp\n : highlightedIndexRef.current;\n\n const navigateChildItems = useCallback(\n (e: KeyboardEvent) => {\n const nextIdx = nextItemIdx(count, e.key, highlightedIndexRef.current);\n if (nextIdx !== highlightedIndexRef.current) {\n setHighlightedIndex(nextIdx);\n }\n },\n [count, setHighlightedIndex],\n );\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isNavigationKey(e)) {\n e.preventDefault();\n e.stopPropagation();\n keyBoardNavigation.current = true;\n navigateChildItems(e);\n } else if (\n (e.key === \"ArrowRight\" || e.key === \"Enter\") &&\n hasPopup(e.target as HTMLElement, highlightedIndex)\n ) {\n const menuEl = e.target as HTMLElement;\n const menuItemEl = menuEl.querySelector(\n `:scope > [data-index='${highlightedIndex}']`,\n ) as HTMLElement;\n\n if (menuItemEl) {\n onOpenMenu?.(menuItemEl, true);\n }\n } else if (e.key === \"ArrowLeft\" && !isRoot(e.target as HTMLElement)) {\n onCloseMenu(e, \"close-child-menu\");\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n e.stopPropagation();\n onActivate && onActivate(highlightedIndex);\n } else if (e.key === \"Tab\") {\n onCloseMenu(e, \"tab-away\");\n }\n },\n [highlightedIndex, navigateChildItems, onActivate, onCloseMenu, onOpenMenu],\n );\n\n const listProps: KeyboardHookListProps = useMemo(\n () => ({\n onFocus: () => {\n if (highlightedIndex === -1) {\n setHighlightedIdx(0);\n }\n },\n onKeyDown: handleKeyDown,\n onMouseDownCapture: () => {\n keyBoardNavigation.current = false;\n setIgnoreFocus(true);\n },\n\n // onMouseEnter would seem less expensive but it misses some cases\n onMouseMove: () => {\n if (keyBoardNavigation.current) {\n keyBoardNavigation.current = false;\n }\n },\n onMouseLeave: () => {\n keyBoardNavigation.current = true;\n setIgnoreFocus(false);\n setHighlightedIndex(-1);\n },\n }),\n [handleKeyDown, highlightedIndex, setHighlightedIdx, setHighlightedIndex],\n );\n\n return {\n focusVisible: keyBoardNavigation.current ? highlightedIndex : -1,\n controlledHighlighting,\n highlightedIndex,\n setHighlightedIndex: setHighlightedIndex,\n listProps,\n setIgnoreFocus,\n };\n};\n\n// need to be able to accommodate disabled items\nfunction nextItemIdx(count: number, key: string, idx: number) {\n if (key === \"ArrowUp\") {\n if (idx > 0) {\n return idx - 1;\n } else {\n return idx;\n }\n } else {\n if (idx === null) {\n return 0;\n } else if (idx === count - 1) {\n return idx;\n } else {\n return idx + 1;\n }\n }\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.8.98",
2
+ "version": "0.8.99",
3
3
  "description": "VUU popup components - Context Menu, Dialog etc",
4
4
  "author": "heswell",
5
5
  "license": "Apache-2.0",
@@ -7,10 +7,10 @@
7
7
  "@salt-ds/core": "1.34.0",
8
8
  "@salt-ds/styles": "0.2.1",
9
9
  "@salt-ds/window": "0.1.1",
10
- "@vuu-ui/vuu-data-types": "0.8.98",
11
- "@vuu-ui/vuu-layout": "0.8.98",
12
- "@vuu-ui/vuu-utils": "0.8.98",
13
- "@vuu-ui/vuu-ui-controls": "0.8.98"
10
+ "@vuu-ui/vuu-data-types": "0.8.99",
11
+ "@vuu-ui/vuu-layout": "0.8.99",
12
+ "@vuu-ui/vuu-utils": "0.8.99",
13
+ "@vuu-ui/vuu-ui-controls": "0.8.99"
14
14
  },
15
15
  "peerDependencies": {
16
16
  "clsx": "^2.0.0",