@stack-spot/portal-components 2.27.0 → 2.27.2

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.
Files changed (250) hide show
  1. package/CHANGELOG.md +635 -621
  2. package/dist/components/AnimatedHeight.d.ts +1 -1
  3. package/dist/components/AnimatedHeight.js +26 -26
  4. package/dist/components/AsyncContent.d.ts +1 -1
  5. package/dist/components/AsyncContent.js +1 -1
  6. package/dist/components/BannerWarning.d.ts +1 -1
  7. package/dist/components/BannerWarning.js +1 -1
  8. package/dist/components/Breadcrumb/index.d.ts +2 -2
  9. package/dist/components/Breadcrumb/index.js +1 -1
  10. package/dist/components/Breadcrumb/styled.js +31 -31
  11. package/dist/components/ButtonLoading.d.ts +1 -1
  12. package/dist/components/ButtonLoading.js +1 -1
  13. package/dist/components/ChatBot.d.ts +1 -1
  14. package/dist/components/ChatBot.js +1 -1
  15. package/dist/components/ContentValidateFilter.d.ts +1 -1
  16. package/dist/components/ContentValidateFilter.js +1 -1
  17. package/dist/components/FadingOverflow.d.ts +1 -1
  18. package/dist/components/FadingOverflow.js +69 -69
  19. package/dist/components/FileTreeView/More.d.ts +1 -1
  20. package/dist/components/FileTreeView/More.js +1 -1
  21. package/dist/components/FileTreeView/index.d.ts +1 -1
  22. package/dist/components/FileTreeView/index.js +1 -1
  23. package/dist/components/InfiniteScroll.d.ts +1 -1
  24. package/dist/components/InfiniteScroll.js +1 -1
  25. package/dist/components/InfoMaintenanceBanner.d.ts +1 -1
  26. package/dist/components/InfoMaintenanceBanner.js +2 -2
  27. package/dist/components/LazyMarkdown/BlockquoteMd.d.ts +1 -1
  28. package/dist/components/LazyMarkdown/BlockquoteMd.js +1 -1
  29. package/dist/components/LazyMarkdown/CodeViewer.d.ts +1 -1
  30. package/dist/components/LazyMarkdown/CodeViewer.js +76 -76
  31. package/dist/components/LazyMarkdown/Markdown.d.ts +1 -1
  32. package/dist/components/LazyMarkdown/Markdown.js +1 -1
  33. package/dist/components/LazyMarkdown/MarkdownButton.d.ts +1 -1
  34. package/dist/components/LazyMarkdown/MarkdownButton.js +1 -1
  35. package/dist/components/LazyMarkdown/Video.d.ts +1 -1
  36. package/dist/components/LazyMarkdown/Video.js +1 -1
  37. package/dist/components/LazyMarkdown/index.d.ts +1 -1
  38. package/dist/components/LazyMarkdown/index.js +1 -1
  39. package/dist/components/Placeholder.d.ts +7 -3
  40. package/dist/components/Placeholder.d.ts.map +1 -1
  41. package/dist/components/Placeholder.js +3 -3
  42. package/dist/components/Placeholder.js.map +1 -1
  43. package/dist/components/ScrollView.js +16 -16
  44. package/dist/components/Select/BadgeItem.d.ts +1 -1
  45. package/dist/components/Select/BadgeItem.js +1 -1
  46. package/dist/components/Select/ClearInput.d.ts +1 -1
  47. package/dist/components/Select/ClearInput.js +1 -1
  48. package/dist/components/Select/CloseItem.d.ts +1 -1
  49. package/dist/components/Select/CloseItem.js +1 -1
  50. package/dist/components/Select/CreatableSelect.js +1 -1
  51. package/dist/components/Select/CustomMenu.d.ts +1 -1
  52. package/dist/components/Select/CustomMenu.js +1 -1
  53. package/dist/components/Select/LabelItem.d.ts +1 -1
  54. package/dist/components/Select/LabelItem.js +1 -1
  55. package/dist/components/Select/MultiValue.d.ts +1 -1
  56. package/dist/components/Select/MultiValue.js +1 -1
  57. package/dist/components/Select/SelectInfiniteScroll.d.ts +1 -1
  58. package/dist/components/Select/SelectInfiniteScroll.js +1 -1
  59. package/dist/components/Select/SelectSearch.d.ts +1 -1
  60. package/dist/components/Select/SelectSearch.js +1 -1
  61. package/dist/components/SelectionList.d.ts +1 -1
  62. package/dist/components/SelectionList.js +61 -61
  63. package/dist/components/StatusCircle.d.ts +1 -1
  64. package/dist/components/StatusCircle.js +6 -6
  65. package/dist/components/Stepper/Navigation.js +4 -4
  66. package/dist/components/Stepper/Step.js +3 -3
  67. package/dist/components/Stepper/Stepper.js +6 -6
  68. package/dist/components/Stepper/headers.js +22 -22
  69. package/dist/components/Table/HeaderItem.js +1 -1
  70. package/dist/components/Table/SettingsVerticalMenu.d.ts +1 -1
  71. package/dist/components/Table/SettingsVerticalMenu.js +1 -1
  72. package/dist/components/Table/StyledLinkTable.d.ts +1 -1
  73. package/dist/components/Table/StyledLinkTable.js +5 -5
  74. package/dist/components/Table/TableData.d.ts +1 -1
  75. package/dist/components/Table/TableData.js +25 -25
  76. package/dist/components/TimelineSection.d.ts +1 -1
  77. package/dist/components/TimelineSection.js +14 -14
  78. package/dist/components/error/ErrorFeedback.d.ts +1 -1
  79. package/dist/components/error/ErrorFeedback.js +35 -35
  80. package/dist/components/error/NotFound.d.ts +1 -1
  81. package/dist/components/error/NotFound.js +1 -1
  82. package/dist/components/error/UnderMaintenance.d.ts +1 -1
  83. package/dist/components/error/UnderMaintenance.js +1 -1
  84. package/dist/components/form/Form/Form.d.ts +1 -1
  85. package/dist/components/form/Form/Form.js +1 -1
  86. package/dist/components/form/Form/FormGroup.d.ts +2 -2
  87. package/dist/components/form/Form/FormGroup.js +1 -1
  88. package/dist/components/form/SearchInput.d.ts +1 -1
  89. package/dist/components/form/SearchInput.js +1 -1
  90. package/dist/components/form/Select/CustomSelect.d.ts +1 -1
  91. package/dist/components/form/Select/CustomSelect.js +1 -1
  92. package/dist/components/form/Select/DetailedSelect.d.ts +1 -1
  93. package/dist/components/form/Select/DetailedSelect.js +1 -1
  94. package/dist/components/form/Select/Select.d.ts +1 -1
  95. package/dist/components/form/Select/Select.js +1 -1
  96. package/dist/components/form/Select/styled.js +161 -161
  97. package/dist/components/form/Select/utils.js +1 -1
  98. package/dist/components/notification/NotificationComponent.d.ts +1 -1
  99. package/dist/components/notification/NotificationComponent.js +54 -54
  100. package/dist/components/notification/NotificationItem.d.ts +1 -1
  101. package/dist/components/notification/NotificationItem.d.ts.map +1 -1
  102. package/dist/components/notification/NotificationItem.js +11 -5
  103. package/dist/components/notification/NotificationItem.js.map +1 -1
  104. package/dist/components/notification/NotificationList.d.ts +1 -1
  105. package/dist/components/notification/NotificationList.d.ts.map +1 -1
  106. package/dist/components/notification/NotificationList.js +44 -44
  107. package/dist/components/notification/NotificationList.js.map +1 -1
  108. package/dist/components/notification/NotificationPlaceholder.d.ts +1 -1
  109. package/dist/components/notification/NotificationPlaceholder.d.ts.map +1 -1
  110. package/dist/components/notification/NotificationPlaceholder.js +2 -2
  111. package/dist/components/notification/NotificationPlaceholder.js.map +1 -1
  112. package/dist/containers/NotificationsPage.d.ts +1 -1
  113. package/dist/containers/NotificationsPage.d.ts.map +1 -1
  114. package/dist/containers/NotificationsPage.js +24 -11
  115. package/dist/containers/NotificationsPage.js.map +1 -1
  116. package/dist/context/anchor.d.ts +1 -1
  117. package/dist/context/anchor.js +1 -1
  118. package/dist/context/loading.d.ts +1 -1
  119. package/dist/context/loading.js +1 -1
  120. package/dist/context/notification/context.d.ts +1 -1
  121. package/dist/context/notification/context.js +1 -1
  122. package/dist/context/notification/types.d.ts +1 -0
  123. package/dist/context/notification/types.d.ts.map +1 -1
  124. package/dist/hooks/date.js +1 -1
  125. package/dist/hooks/service-now.js +28 -28
  126. package/dist/svg/AI.d.ts +1 -1
  127. package/dist/svg/AI.js +1 -1
  128. package/dist/svg/CS.d.ts +1 -1
  129. package/dist/svg/CS.js +1 -1
  130. package/dist/svg/EDP.d.ts +1 -1
  131. package/dist/svg/EDP.js +1 -1
  132. package/dist/svg/Forbidden.d.ts +1 -1
  133. package/dist/svg/Forbidden.js +1 -1
  134. package/dist/svg/GenericPlaceholder.d.ts +4 -2
  135. package/dist/svg/GenericPlaceholder.d.ts.map +1 -1
  136. package/dist/svg/GenericPlaceholder.js +2 -2
  137. package/dist/svg/GenericPlaceholder.js.map +1 -1
  138. package/dist/svg/HUB.d.ts +1 -1
  139. package/dist/svg/HUB.js +1 -1
  140. package/dist/svg/Logo.d.ts +1 -1
  141. package/dist/svg/Logo.js +1 -1
  142. package/dist/svg/MiniLogo.d.ts +1 -1
  143. package/dist/svg/MiniLogo.js +1 -1
  144. package/dist/svg/NotFound.d.ts +1 -1
  145. package/dist/svg/NotFound.js +1 -1
  146. package/dist/svg/ServerError.d.ts +1 -1
  147. package/dist/svg/ServerError.js +1 -1
  148. package/dist/svg/Unauthenticated.d.ts +1 -1
  149. package/dist/svg/Unauthenticated.js +1 -1
  150. package/package.json +6 -6
  151. package/readme.md +66 -66
  152. package/src/components/AnimatedHeight.tsx +174 -174
  153. package/src/components/AsyncContent.tsx +78 -78
  154. package/src/components/BannerWarning.tsx +91 -91
  155. package/src/components/Breadcrumb/index.tsx +76 -76
  156. package/src/components/Breadcrumb/styled.ts +37 -37
  157. package/src/components/ButtonLoading.tsx +29 -29
  158. package/src/components/ChatBot.tsx +82 -82
  159. package/src/components/ContentValidateFilter.tsx +15 -15
  160. package/src/components/FadingOverflow.tsx +265 -265
  161. package/src/components/FileTreeView/More.tsx +114 -114
  162. package/src/components/FileTreeView/index.tsx +186 -186
  163. package/src/components/InfiniteScroll.tsx +24 -24
  164. package/src/components/InfoMaintenanceBanner.tsx +29 -29
  165. package/src/components/LazyMarkdown/BlockquoteMd.tsx +107 -107
  166. package/src/components/LazyMarkdown/CodeViewer.tsx +161 -161
  167. package/src/components/LazyMarkdown/Markdown.tsx +122 -122
  168. package/src/components/LazyMarkdown/MarkdownButton.tsx +24 -24
  169. package/src/components/LazyMarkdown/Video.tsx +13 -13
  170. package/src/components/LazyMarkdown/index.tsx +21 -21
  171. package/src/components/Placeholder.tsx +123 -118
  172. package/src/components/ScrollView.tsx +57 -57
  173. package/src/components/Select/BadgeItem.tsx +58 -58
  174. package/src/components/Select/ClearInput.tsx +24 -24
  175. package/src/components/Select/CloseItem.tsx +38 -38
  176. package/src/components/Select/CreatableSelect.tsx +155 -155
  177. package/src/components/Select/CustomMenu.tsx +16 -16
  178. package/src/components/Select/LabelItem.tsx +8 -8
  179. package/src/components/Select/MultiValue.tsx +49 -49
  180. package/src/components/Select/SelectInfiniteScroll.tsx +82 -82
  181. package/src/components/Select/SelectSearch.tsx +195 -195
  182. package/src/components/Select/index.tsx +7 -7
  183. package/src/components/Select/types.ts +8 -8
  184. package/src/components/SelectionList.tsx +427 -427
  185. package/src/components/StatusCircle.tsx +67 -67
  186. package/src/components/Stepper/Navigation.tsx +97 -97
  187. package/src/components/Stepper/Step.tsx +30 -30
  188. package/src/components/Stepper/Stepper.tsx +113 -113
  189. package/src/components/Stepper/headers.tsx +64 -64
  190. package/src/components/Stepper/index.ts +3 -3
  191. package/src/components/Table/HeaderItem.tsx +52 -52
  192. package/src/components/Table/SettingsVerticalMenu.tsx +50 -50
  193. package/src/components/Table/StyledLinkTable.tsx +22 -22
  194. package/src/components/Table/TableData.tsx +251 -251
  195. package/src/components/Table/index.tsx +2 -2
  196. package/src/components/TimelineSection.tsx +66 -66
  197. package/src/components/error/ErrorFeedback.tsx +217 -217
  198. package/src/components/error/NotFound.tsx +24 -24
  199. package/src/components/error/UnderMaintenance.tsx +30 -30
  200. package/src/components/error/index.ts +4 -4
  201. package/src/components/form/Form/Form.tsx +101 -101
  202. package/src/components/form/Form/FormGroup.tsx +221 -221
  203. package/src/components/form/Form/index.ts +2 -2
  204. package/src/components/form/SearchInput.tsx +69 -69
  205. package/src/components/form/Select/CustomSelect.tsx +232 -232
  206. package/src/components/form/Select/DetailedSelect.tsx +85 -85
  207. package/src/components/form/Select/Select.tsx +67 -67
  208. package/src/components/form/Select/index.ts +4 -4
  209. package/src/components/form/Select/styled.ts +165 -165
  210. package/src/components/form/Select/types.ts +112 -112
  211. package/src/components/form/Select/utils.tsx +28 -28
  212. package/src/components/notification/NotificationComponent.tsx +340 -340
  213. package/src/components/notification/NotificationItem.tsx +345 -336
  214. package/src/components/notification/NotificationList.tsx +179 -178
  215. package/src/components/notification/NotificationPlaceholder.tsx +44 -43
  216. package/src/components/notification/types.ts +72 -72
  217. package/src/containers/NotificationsPage.tsx +119 -98
  218. package/src/context/anchor.tsx +37 -37
  219. package/src/context/loading.tsx +36 -36
  220. package/src/context/notification/LazyNotificationList.ts +103 -103
  221. package/src/context/notification/NotificationController.ts +104 -104
  222. package/src/context/notification/context.tsx +23 -23
  223. package/src/context/notification/hooks.ts +98 -98
  224. package/src/context/notification/types.ts +66 -65
  225. package/src/hooks/date.ts +31 -31
  226. package/src/hooks/keyboard.tsx +128 -128
  227. package/src/hooks/manual-render.tsx +10 -10
  228. package/src/hooks/service-now.tsx +233 -233
  229. package/src/hooks/text.tsx +30 -30
  230. package/src/hooks/title.tsx +28 -28
  231. package/src/hooks/use-effect-once.tsx +43 -43
  232. package/src/index.ts +19 -19
  233. package/src/notifications.ts +11 -11
  234. package/src/svg/AI.tsx +41 -41
  235. package/src/svg/CS.tsx +48 -48
  236. package/src/svg/EDP.tsx +31 -31
  237. package/src/svg/Forbidden.tsx +22 -22
  238. package/src/svg/GenericPlaceholder.tsx +20 -20
  239. package/src/svg/HUB.tsx +48 -48
  240. package/src/svg/Logo.tsx +16 -16
  241. package/src/svg/MiniLogo.tsx +12 -12
  242. package/src/svg/NotFound.tsx +16 -16
  243. package/src/svg/ServerError.tsx +33 -33
  244. package/src/svg/Unauthenticated.tsx +16 -16
  245. package/src/svg/index.ts +11 -11
  246. package/src/utils/accessibility.ts +135 -135
  247. package/src/utils/cookie.ts +73 -73
  248. package/src/utils/promise.ts +5 -5
  249. package/src/utils/read-file.ts +16 -16
  250. package/tsconfig.json +10 -10
@@ -1,128 +1,128 @@
1
- import { useCallback, useEffect, useRef } from 'react'
2
-
3
- interface Options<T extends HTMLElement = HTMLDivElement> {
4
- /**
5
- * A query selector that returns every html element that must be navigable through the keyboard.
6
- */
7
- querySelectors: string,
8
- /**
9
- * Function to call when ESC is pressed. or when TAB is pressed at the last item in the list of items returned by the query selector.
10
- */
11
- onPressEscape?: () => void,
12
- /**
13
- * Function to call when TAB is pressed at the last item in the list of items returned by the query selector. Will be the same as
14
- * onPressEscape if not specified.
15
- *
16
- * Attention: has no effect if `disableTabBehavior` is true.
17
- */
18
- onPressLastTab?: () => void,
19
- /**
20
- * Pass this function if you want any behavior when the user presses the arrow left.
21
- */
22
- onPressArrowLeft?: () => void,
23
- /**
24
- * Pass this function if you want any behavior when the user presses the arrow right.
25
- */
26
- onPressArrowRight?: () => void,
27
- /**
28
- * Disables any alteration to the tab key.
29
- * @default false
30
- */
31
- disableTabBehavior?: boolean,
32
- /**
33
- * If you already have a ref to the element you want to attach the events to, you can pass it in this prop.
34
- *
35
- * If you pass a ref. The events won't be attached to the document, instead, they will be attached to the element referred by the ref.
36
- */
37
- ref?: React.RefObject<T>,
38
- }
39
-
40
- /**
41
- * Creates listeners for controlling a Menu UI through the keyboard.
42
- * - Arrow down: next element in the iterator returned by the query selectors. First element, if the current element is the last.
43
- * - Arrow up: previous element in the iterator returned by the query selectors. Last element, if the current element is the first.
44
- * - Tab: same as Arrow down, but has a different behavior if the element is the last (see onPressLastTab).
45
- * - Esc: determined by onPressEscape.
46
- * @param props {@link Options}.
47
- * @returns an object with the element controlled by the keyboard (useRef); a function to attach the keyboard events and a function to
48
- * detach the keyboard events.
49
- */
50
- export function useKeyboardControls<T extends HTMLElement = HTMLDivElement>(
51
- /**
52
- * Options for the keyboard controls.
53
- */
54
- {
55
- querySelectors, onPressEscape, onPressLastTab = onPressEscape, onPressArrowLeft, onPressArrowRight, disableTabBehavior, ref,
56
- }: Options<T>,
57
- /**
58
- * Calls `attachKeyboardListeners` (mount) and `detachKeyboardListeners` (unmount) whenever the deps passed as parameter changes.
59
- *
60
- * If deps are undefined, this component doesn't automatically add these listeners and you have to use the functions returned in the
61
- * result.
62
- */
63
- deps?: any[],
64
- ) {
65
- const localRef = useRef<T>(null)
66
- const keyboardControlledElement = ref ?? localRef
67
- const listeners = useRef<Pick<Options, 'onPressEscape' | 'onPressLastTab'>>({})
68
- listeners.current = { onPressEscape, onPressLastTab }
69
-
70
- const keyboardControls = useCallback((event: Event) => {
71
- const eventKey = (event as KeyboardEvent).key
72
- const target = event?.target as HTMLElement | null
73
-
74
- function getSelectableAnchors() {
75
- return keyboardControlledElement.current?.querySelectorAll(querySelectors) ?? []
76
- }
77
-
78
- function handleArrows(key = eventKey) {
79
- const anchors = getSelectableAnchors()
80
- let i = 0
81
- while (i < anchors.length && document.activeElement !== anchors[i]) i++
82
- const next: any = key === 'ArrowDown' ? (anchors[i + 1] ?? anchors[0]) : (anchors[i - 1] ?? anchors[anchors.length - 1])
83
- next?.focus?.()
84
- }
85
-
86
- const handlers: Record<string, (() => void) | undefined> = {
87
- Escape: () => {
88
- listeners.current.onPressEscape?.()
89
- event.stopPropagation()
90
- event.preventDefault()
91
- },
92
- Enter: () => {
93
- target?.click()
94
- },
95
- Tab: () => {
96
- if (disableTabBehavior) return
97
- const anchors = getSelectableAnchors()
98
- if (document.activeElement === anchors[anchors.length - 1]) listeners.current.onPressLastTab?.()
99
- else handleArrows('ArrowDown')
100
- event.preventDefault()
101
- },
102
- ArrowUp: handleArrows,
103
- ArrowDown: handleArrows,
104
- ArrowLeft: onPressArrowLeft,
105
- ArrowRight: onPressArrowRight,
106
- }
107
-
108
- handlers[eventKey]?.()
109
- }, [])
110
-
111
- const attachKeyboardListeners = useCallback(() => {
112
- const element = ref?.current ?? document
113
- element.addEventListener('keydown', keyboardControls)
114
- }, [])
115
-
116
- const detachKeyboardListeners = useCallback(() => {
117
- const element = ref?.current ?? document
118
- element.removeEventListener('keydown', keyboardControls)
119
- }, [])
120
-
121
- useEffect(() => {
122
- if (!deps) return
123
- attachKeyboardListeners()
124
- return detachKeyboardListeners
125
- }, deps)
126
-
127
- return { keyboardControlledElement, attachKeyboardListeners, detachKeyboardListeners }
128
- }
1
+ import { useCallback, useEffect, useRef } from 'react'
2
+
3
+ interface Options<T extends HTMLElement = HTMLDivElement> {
4
+ /**
5
+ * A query selector that returns every html element that must be navigable through the keyboard.
6
+ */
7
+ querySelectors: string,
8
+ /**
9
+ * Function to call when ESC is pressed. or when TAB is pressed at the last item in the list of items returned by the query selector.
10
+ */
11
+ onPressEscape?: () => void,
12
+ /**
13
+ * Function to call when TAB is pressed at the last item in the list of items returned by the query selector. Will be the same as
14
+ * onPressEscape if not specified.
15
+ *
16
+ * Attention: has no effect if `disableTabBehavior` is true.
17
+ */
18
+ onPressLastTab?: () => void,
19
+ /**
20
+ * Pass this function if you want any behavior when the user presses the arrow left.
21
+ */
22
+ onPressArrowLeft?: () => void,
23
+ /**
24
+ * Pass this function if you want any behavior when the user presses the arrow right.
25
+ */
26
+ onPressArrowRight?: () => void,
27
+ /**
28
+ * Disables any alteration to the tab key.
29
+ * @default false
30
+ */
31
+ disableTabBehavior?: boolean,
32
+ /**
33
+ * If you already have a ref to the element you want to attach the events to, you can pass it in this prop.
34
+ *
35
+ * If you pass a ref. The events won't be attached to the document, instead, they will be attached to the element referred by the ref.
36
+ */
37
+ ref?: React.RefObject<T>,
38
+ }
39
+
40
+ /**
41
+ * Creates listeners for controlling a Menu UI through the keyboard.
42
+ * - Arrow down: next element in the iterator returned by the query selectors. First element, if the current element is the last.
43
+ * - Arrow up: previous element in the iterator returned by the query selectors. Last element, if the current element is the first.
44
+ * - Tab: same as Arrow down, but has a different behavior if the element is the last (see onPressLastTab).
45
+ * - Esc: determined by onPressEscape.
46
+ * @param props {@link Options}.
47
+ * @returns an object with the element controlled by the keyboard (useRef); a function to attach the keyboard events and a function to
48
+ * detach the keyboard events.
49
+ */
50
+ export function useKeyboardControls<T extends HTMLElement = HTMLDivElement>(
51
+ /**
52
+ * Options for the keyboard controls.
53
+ */
54
+ {
55
+ querySelectors, onPressEscape, onPressLastTab = onPressEscape, onPressArrowLeft, onPressArrowRight, disableTabBehavior, ref,
56
+ }: Options<T>,
57
+ /**
58
+ * Calls `attachKeyboardListeners` (mount) and `detachKeyboardListeners` (unmount) whenever the deps passed as parameter changes.
59
+ *
60
+ * If deps are undefined, this component doesn't automatically add these listeners and you have to use the functions returned in the
61
+ * result.
62
+ */
63
+ deps?: any[],
64
+ ) {
65
+ const localRef = useRef<T>(null)
66
+ const keyboardControlledElement = ref ?? localRef
67
+ const listeners = useRef<Pick<Options, 'onPressEscape' | 'onPressLastTab'>>({})
68
+ listeners.current = { onPressEscape, onPressLastTab }
69
+
70
+ const keyboardControls = useCallback((event: Event) => {
71
+ const eventKey = (event as KeyboardEvent).key
72
+ const target = event?.target as HTMLElement | null
73
+
74
+ function getSelectableAnchors() {
75
+ return keyboardControlledElement.current?.querySelectorAll(querySelectors) ?? []
76
+ }
77
+
78
+ function handleArrows(key = eventKey) {
79
+ const anchors = getSelectableAnchors()
80
+ let i = 0
81
+ while (i < anchors.length && document.activeElement !== anchors[i]) i++
82
+ const next: any = key === 'ArrowDown' ? (anchors[i + 1] ?? anchors[0]) : (anchors[i - 1] ?? anchors[anchors.length - 1])
83
+ next?.focus?.()
84
+ }
85
+
86
+ const handlers: Record<string, (() => void) | undefined> = {
87
+ Escape: () => {
88
+ listeners.current.onPressEscape?.()
89
+ event.stopPropagation()
90
+ event.preventDefault()
91
+ },
92
+ Enter: () => {
93
+ target?.click()
94
+ },
95
+ Tab: () => {
96
+ if (disableTabBehavior) return
97
+ const anchors = getSelectableAnchors()
98
+ if (document.activeElement === anchors[anchors.length - 1]) listeners.current.onPressLastTab?.()
99
+ else handleArrows('ArrowDown')
100
+ event.preventDefault()
101
+ },
102
+ ArrowUp: handleArrows,
103
+ ArrowDown: handleArrows,
104
+ ArrowLeft: onPressArrowLeft,
105
+ ArrowRight: onPressArrowRight,
106
+ }
107
+
108
+ handlers[eventKey]?.()
109
+ }, [])
110
+
111
+ const attachKeyboardListeners = useCallback(() => {
112
+ const element = ref?.current ?? document
113
+ element.addEventListener('keydown', keyboardControls)
114
+ }, [])
115
+
116
+ const detachKeyboardListeners = useCallback(() => {
117
+ const element = ref?.current ?? document
118
+ element.removeEventListener('keydown', keyboardControls)
119
+ }, [])
120
+
121
+ useEffect(() => {
122
+ if (!deps) return
123
+ attachKeyboardListeners()
124
+ return detachKeyboardListeners
125
+ }, deps)
126
+
127
+ return { keyboardControlledElement, attachKeyboardListeners, detachKeyboardListeners }
128
+ }
@@ -1,10 +1,10 @@
1
- import { useCallback, useState } from 'react'
2
-
3
- /**
4
- * Use this hook to manually trigger a re-render from React.
5
- * @returns an object with a function to re-render the component.
6
- */
7
- export function useManualRender() {
8
- const [, setCount] = useState(0)
9
- return { repaint: useCallback(() => setCount(v => v + 1), []) }
10
- }
1
+ import { useCallback, useState } from 'react'
2
+
3
+ /**
4
+ * Use this hook to manually trigger a re-render from React.
5
+ * @returns an object with a function to re-render the component.
6
+ */
7
+ export function useManualRender() {
8
+ const [, setCount] = useState(0)
9
+ return { repaint: useCallback(() => setCount(v => v + 1), []) }
10
+ }