@djangocfg/ui-tools 2.1.404 → 2.1.408

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 (336) hide show
  1. package/README.md +9 -11
  2. package/dist/file-icon/index.cjs +449 -61
  3. package/dist/file-icon/index.cjs.map +1 -1
  4. package/dist/file-icon/index.d.cts +56 -18
  5. package/dist/file-icon/index.d.ts +56 -18
  6. package/dist/file-icon/index.mjs +448 -62
  7. package/dist/file-icon/index.mjs.map +1 -1
  8. package/dist/tree/index.cjs +49 -22
  9. package/dist/tree/index.cjs.map +1 -1
  10. package/dist/tree/index.d.cts +9 -3
  11. package/dist/tree/index.d.ts +9 -3
  12. package/dist/tree/index.mjs +49 -22
  13. package/dist/tree/index.mjs.map +1 -1
  14. package/dist/{types-B_zhyAqR.d.cts → types-eEu8SeiQ.d.cts} +4 -0
  15. package/dist/{types-B_zhyAqR.d.ts → types-eEu8SeiQ.d.ts} +4 -0
  16. package/package.json +13 -16
  17. package/src/components/FloatingToolbar/index.tsx +37 -3
  18. package/src/lib/page-snapshot/__tests__/capture-integration.test.ts +85 -0
  19. package/src/lib/page-snapshot/__tests__/engine.test.ts +36 -0
  20. package/src/lib/page-snapshot/__tests__/redaction-integration.test.ts +99 -0
  21. package/src/lib/page-snapshot/__tests__/tokens.test.ts +17 -0
  22. package/src/lib/page-snapshot/capture/__tests__/budget.test.ts +49 -0
  23. package/src/lib/page-snapshot/capture/__tests__/chrome-filter.test.ts +47 -0
  24. package/src/lib/page-snapshot/capture/__tests__/fold.test.ts +66 -0
  25. package/src/lib/page-snapshot/capture/__tests__/scope.test.ts +74 -0
  26. package/src/lib/page-snapshot/capture/__tests__/walk.test.ts +129 -0
  27. package/src/lib/page-snapshot/capture/accessible-name.ts +73 -0
  28. package/src/lib/page-snapshot/capture/budget.ts +95 -0
  29. package/src/lib/page-snapshot/capture/chrome-filter.ts +81 -0
  30. package/src/lib/page-snapshot/capture/classify.ts +111 -0
  31. package/src/lib/page-snapshot/capture/dom-utils.ts +111 -0
  32. package/src/lib/page-snapshot/capture/fold.ts +96 -0
  33. package/src/lib/page-snapshot/capture/scope.ts +169 -0
  34. package/src/lib/page-snapshot/capture/walk.ts +250 -0
  35. package/src/lib/page-snapshot/cst/__tests__/serialize.test.ts +50 -0
  36. package/src/lib/page-snapshot/cst/directives.ts +47 -0
  37. package/src/lib/page-snapshot/cst/payload.ts +50 -0
  38. package/src/lib/page-snapshot/cst/serialize.ts +84 -0
  39. package/src/lib/page-snapshot/cst/types.ts +115 -0
  40. package/src/lib/page-snapshot/engine.ts +176 -0
  41. package/src/lib/page-snapshot/index.ts +93 -0
  42. package/src/lib/page-snapshot/react/PageSnapshotChip.tsx +72 -0
  43. package/src/lib/page-snapshot/react/PageSnapshotPreview.tsx +78 -0
  44. package/src/lib/page-snapshot/react/__tests__/PageSnapshotChip.test.tsx +54 -0
  45. package/src/lib/page-snapshot/react/__tests__/provider.test.tsx +103 -0
  46. package/src/lib/page-snapshot/react/__tests__/use-page-snapshot-toggle.test.tsx +62 -0
  47. package/src/lib/page-snapshot/react/provider.tsx +162 -0
  48. package/src/lib/page-snapshot/react/use-page-snapshot-toggle.ts +47 -0
  49. package/src/lib/page-snapshot/react/use-page-snapshot.ts +67 -0
  50. package/src/lib/page-snapshot/redaction/__tests__/audit.test.ts +25 -0
  51. package/src/lib/page-snapshot/redaction/__tests__/heuristics.test.ts +73 -0
  52. package/src/lib/page-snapshot/redaction/__tests__/luhn.test.ts +26 -0
  53. package/src/lib/page-snapshot/redaction/__tests__/patterns.test.ts +60 -0
  54. package/src/lib/page-snapshot/redaction/audit.ts +58 -0
  55. package/src/lib/page-snapshot/redaction/heuristics.ts +75 -0
  56. package/src/lib/page-snapshot/redaction/index.ts +75 -0
  57. package/src/lib/page-snapshot/redaction/luhn.ts +25 -0
  58. package/src/lib/page-snapshot/redaction/patterns.ts +111 -0
  59. package/src/lib/page-snapshot/refs/__tests__/registry.test.ts +24 -0
  60. package/src/lib/page-snapshot/refs/registry.ts +46 -0
  61. package/src/lib/page-snapshot/staleness/__tests__/hash.test.ts +34 -0
  62. package/src/lib/page-snapshot/staleness/hash.ts +20 -0
  63. package/src/lib/page-snapshot/tokens.ts +15 -0
  64. package/src/tools/AudioPlayer/context/PlayerProvider.tsx +13 -14
  65. package/src/tools/AudioPlayer/hooks/useAudioElementEvents.ts +55 -6
  66. package/src/tools/AudioPlayer/lazy.tsx +13 -27
  67. package/src/tools/AudioPlayer/parts/Meta/TimeDisplay.tsx +2 -5
  68. package/src/tools/Chat/README.md +267 -39
  69. package/src/tools/Chat/composer/Composer.tsx +471 -0
  70. package/src/tools/Chat/composer/ComposerActionBar.tsx +65 -0
  71. package/src/tools/Chat/composer/ComposerBanner.tsx +128 -0
  72. package/src/tools/Chat/composer/ComposerButton.tsx +64 -0
  73. package/src/tools/Chat/composer/ComposerFooter.tsx +90 -0
  74. package/src/tools/Chat/composer/ComposerMenuButton.tsx +62 -0
  75. package/src/tools/Chat/composer/ComposerModelPicker.tsx +104 -0
  76. package/src/tools/Chat/composer/ComposerRichTextarea.tsx +88 -0
  77. package/src/tools/Chat/composer/ComposerToolPill.tsx +95 -0
  78. package/src/tools/Chat/composer/index.ts +45 -0
  79. package/src/tools/Chat/composer/size-context.tsx +26 -0
  80. package/src/tools/Chat/composer/types.ts +143 -0
  81. package/src/tools/Chat/composer/useComposerActions.tsx +164 -0
  82. package/src/tools/Chat/context/ChatProvider.tsx +54 -3
  83. package/src/tools/Chat/core/__tests__/metadata.test.ts +69 -0
  84. package/src/tools/Chat/core/index.ts +23 -1
  85. package/src/tools/Chat/core/markdown.ts +1 -1
  86. package/src/tools/Chat/core/metadata.ts +47 -0
  87. package/src/tools/Chat/core/payload-dispatch.ts +1 -1
  88. package/src/tools/Chat/core/transport/http.ts +71 -32
  89. package/src/tools/Chat/core/transport/sse.ts +18 -10
  90. package/src/tools/Chat/highlight/HighlightOverlay.tsx +101 -0
  91. package/src/tools/Chat/highlight/README.md +103 -0
  92. package/src/tools/Chat/highlight/SpotlightCanvas.tsx +153 -0
  93. package/src/tools/Chat/highlight/__tests__/HighlightOverlay.test.tsx +112 -0
  94. package/src/tools/Chat/highlight/__tests__/resolveRef.test.ts +55 -0
  95. package/src/tools/Chat/highlight/index.ts +21 -0
  96. package/src/tools/Chat/highlight/resolveRef.ts +42 -0
  97. package/src/tools/Chat/highlight/types.ts +49 -0
  98. package/src/tools/Chat/highlight/useHighlightTargets.ts +128 -0
  99. package/src/tools/Chat/hooks/index.ts +0 -5
  100. package/src/tools/Chat/hooks/useAutoFocusOnStreamEnd.ts +28 -47
  101. package/src/tools/Chat/hooks/useChat.ts +47 -14
  102. package/src/tools/Chat/hooks/useChatComposer.ts +2 -2
  103. package/src/tools/Chat/hooks/useChatLayout.ts +1 -1
  104. package/src/tools/Chat/hooks/useStreamEndFocus.ts +54 -0
  105. package/src/tools/Chat/index.ts +25 -219
  106. package/src/tools/Chat/launcher/ChatDock.tsx +1 -1
  107. package/src/tools/Chat/launcher/ChatLauncher.tsx +1 -1
  108. package/src/tools/Chat/launcher/{ChatHeader.tsx → header/ChatHeader.tsx} +24 -11
  109. package/src/tools/Chat/launcher/{ChatHeaderActionButton.tsx → header/ChatHeaderActionButton.tsx} +34 -3
  110. package/src/tools/Chat/launcher/{ChatHeaderLanguageButton.tsx → header/ChatHeaderLanguageButton.tsx} +2 -2
  111. package/src/tools/Chat/launcher/{ChatHeaderModeToggle.tsx → header/ChatHeaderModeToggle.tsx} +1 -1
  112. package/src/tools/Chat/launcher/{ChatHeaderResetButton.tsx → header/ChatHeaderResetButton.tsx} +2 -1
  113. package/src/tools/Chat/launcher/{HeaderSlots.tsx → header/HeaderSlots.tsx} +3 -3
  114. package/src/tools/Chat/launcher/header/index.ts +26 -0
  115. package/src/tools/Chat/launcher/index.ts +3 -10
  116. package/src/tools/Chat/lazy.tsx +38 -284
  117. package/src/tools/Chat/{components → messages}/MessageBubble.tsx +58 -5
  118. package/src/tools/Chat/{components → messages}/MessageList.tsx +8 -25
  119. package/src/tools/Chat/messages/blocks/MessageBlocks.tsx +131 -0
  120. package/src/tools/Chat/messages/blocks/builtin.tsx +91 -0
  121. package/src/tools/Chat/messages/blocks/index.ts +12 -0
  122. package/src/tools/Chat/messages/blocks/registry.tsx +42 -0
  123. package/src/tools/Chat/messages/blocks/renderers/AudioBlock.tsx +20 -0
  124. package/src/tools/Chat/messages/blocks/renderers/CodeBlock.tsx +19 -0
  125. package/src/tools/Chat/messages/blocks/renderers/GalleryBlock.tsx +26 -0
  126. package/src/tools/Chat/messages/blocks/renderers/ImageBlock.tsx +27 -0
  127. package/src/tools/Chat/messages/blocks/renderers/JsonBlock.tsx +12 -0
  128. package/src/tools/Chat/messages/blocks/renderers/LottieBlock.tsx +11 -0
  129. package/src/tools/Chat/messages/blocks/renderers/MapBlock.tsx +36 -0
  130. package/src/tools/Chat/messages/blocks/renderers/MermaidBlock.tsx +11 -0
  131. package/src/tools/Chat/messages/blocks/renderers/VideoBlock.tsx +24 -0
  132. package/src/tools/Chat/messages/blocks/renderers/types.ts +8 -0
  133. package/src/tools/Chat/{components → messages}/index.ts +11 -5
  134. package/src/tools/Chat/public.ts +212 -0
  135. package/src/tools/Chat/shell/ChatRoot.tsx +326 -0
  136. package/src/tools/Chat/{components → shell}/EmptyState.tsx +4 -2
  137. package/src/tools/Chat/shell/index.ts +15 -0
  138. package/src/tools/Chat/types/block.ts +120 -0
  139. package/src/tools/Chat/types/config.ts +0 -5
  140. package/src/tools/Chat/types/index.ts +17 -0
  141. package/src/tools/Chat/types/message.ts +3 -0
  142. package/src/tools/Chat/utils/index.ts +4 -0
  143. package/src/tools/CodeEditor/README.md +4 -6
  144. package/src/tools/CodeEditor/components/DiffEditor.tsx +48 -13
  145. package/src/tools/CodeEditor/components/Editor.tsx +96 -44
  146. package/src/tools/CodeEditor/context/EditorProvider.tsx +34 -17
  147. package/src/tools/CodeEditor/hooks/useEditorTheme.ts +92 -99
  148. package/src/tools/CodeEditor/hooks/useMonaco.ts +37 -22
  149. package/src/tools/CodeEditor/lazy.tsx +6 -0
  150. package/src/tools/CodeEditor/lib/index.ts +1 -1
  151. package/src/tools/CodeEditor/lib/themes.ts +3 -39
  152. package/src/tools/CronScheduler/CronScheduler.client.tsx +230 -61
  153. package/src/tools/CronScheduler/components/CustomInput.tsx +21 -4
  154. package/src/tools/CronScheduler/components/DayChips.tsx +13 -11
  155. package/src/tools/CronScheduler/components/MonthDayGrid.tsx +4 -4
  156. package/src/tools/CronScheduler/components/SchedulePreview.tsx +7 -3
  157. package/src/tools/CronScheduler/components/TimeSelector.tsx +1 -1
  158. package/src/tools/CronScheduler/index.tsx +1 -1
  159. package/src/tools/CronScheduler/types/index.ts +8 -3
  160. package/src/tools/CronScheduler/utils/cron-humanize.ts +61 -16
  161. package/src/tools/CronScheduler/utils/cron-parser.ts +13 -4
  162. package/src/tools/FileIcon/FileIcon.tsx +24 -39
  163. package/src/tools/FileIcon/get-file-icon.ts +73 -0
  164. package/src/tools/FileIcon/icons/icon-data.ts +399 -0
  165. package/src/tools/FileIcon/index.ts +4 -0
  166. package/src/tools/FileIcon/loader.ts +17 -35
  167. package/src/tools/FileIcon/specialFolders.ts +18 -0
  168. package/src/tools/Gallery/components/lightbox/GalleryLightbox.tsx +112 -35
  169. package/src/tools/Gallery/components/media/GalleryVideo.tsx +21 -2
  170. package/src/tools/Gallery/components/preview/GalleryCarousel.tsx +11 -1
  171. package/src/tools/Gallery/hooks/usePreloadImages.ts +54 -7
  172. package/src/tools/ImageViewer/components/ImageInfo.tsx +12 -1
  173. package/src/tools/ImageViewer/components/ImageToolbar.tsx +51 -43
  174. package/src/tools/ImageViewer/components/ImageViewer.tsx +106 -26
  175. package/src/tools/ImageViewer/hooks/useImageLoading.ts +13 -0
  176. package/src/tools/ImageViewer/utils/constants.ts +3 -0
  177. package/src/tools/ImageViewer/utils/index.ts +1 -0
  178. package/src/tools/JsonForm/JsonSchemaForm.tsx +4 -1
  179. package/src/tools/JsonForm/templates/ArrayFieldTemplate.tsx +5 -3
  180. package/src/tools/JsonForm/templates/BaseInputTemplate.tsx +7 -4
  181. package/src/tools/JsonForm/templates/ErrorListTemplate.tsx +3 -1
  182. package/src/tools/JsonForm/templates/ObjectFieldTemplate.tsx +23 -3
  183. package/src/tools/JsonForm/widgets/ColorWidget.tsx +20 -12
  184. package/src/tools/JsonForm/widgets/NumberWidget.tsx +14 -9
  185. package/src/tools/JsonForm/widgets/RadioWidget.tsx +78 -0
  186. package/src/tools/JsonForm/widgets/SelectWidget.tsx +1 -0
  187. package/src/tools/JsonForm/widgets/SliderWidget.tsx +7 -4
  188. package/src/tools/JsonForm/widgets/TextWidget.tsx +41 -17
  189. package/src/tools/JsonForm/widgets/index.ts +1 -0
  190. package/src/tools/JsonTree/components/JsonContent.tsx +115 -40
  191. package/src/tools/LottiePlayer/LottiePlayer.client.tsx +177 -72
  192. package/src/tools/LottiePlayer/index.tsx +14 -4
  193. package/src/tools/LottiePlayer/lazy.tsx +11 -3
  194. package/src/tools/LottiePlayer/types.ts +31 -1
  195. package/src/tools/LottiePlayer/useLottie.ts +32 -9
  196. package/src/tools/LottiePlayer/usePrefersReducedMotion.ts +46 -0
  197. package/src/tools/Map/components/LayerSwitcher.tsx +54 -21
  198. package/src/tools/Map/components/MapCluster.tsx +28 -21
  199. package/src/tools/Map/components/MapContainer.tsx +11 -4
  200. package/src/tools/Map/components/MapLegend.tsx +46 -15
  201. package/src/tools/Map/components/MapMarker.tsx +31 -2
  202. package/src/tools/Map/hooks/useMapEvents.ts +64 -105
  203. package/src/tools/MarkdownEditor/MarkdownEditor.tsx +61 -6
  204. package/src/tools/MarkdownEditor/MentionList.tsx +37 -4
  205. package/src/tools/MarkdownEditor/createMentionSuggestion.ts +11 -0
  206. package/src/tools/MarkdownEditor/lazy.tsx +32 -7
  207. package/src/tools/MarkdownEditor/styles.css +13 -0
  208. package/src/tools/MarkdownMessage/CodeBlock.tsx +40 -17
  209. package/src/tools/MarkdownMessage/MarkdownMessage.tsx +26 -6
  210. package/src/tools/MarkdownMessage/components.tsx +22 -9
  211. package/src/tools/MarkdownMessage/types.ts +24 -1
  212. package/src/tools/Mermaid/Mermaid.client.tsx +27 -5
  213. package/src/tools/Mermaid/components/MermaidErrorPanel.tsx +31 -0
  214. package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +14 -17
  215. package/src/tools/Mermaid/hooks/useMermaidRenderer.ts +264 -168
  216. package/src/tools/Mermaid/hooks/useMermaidValidation.ts +76 -10
  217. package/src/tools/Mermaid/index.tsx +6 -0
  218. package/src/tools/Mermaid/utils/mermaid-helpers.ts +141 -18
  219. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/FieldRow.tsx +11 -1
  220. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/buildTree.ts +49 -20
  221. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/index.tsx +7 -0
  222. package/src/tools/OpenapiViewer/components/DocsLayout/grouping.ts +7 -4
  223. package/src/tools/OpenapiViewer/constants.ts +3 -0
  224. package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +73 -11
  225. package/src/tools/OpenapiViewer/utils/schemaExport.ts +26 -6
  226. package/src/tools/PrettyCode/PrettyCode.client.tsx +23 -16
  227. package/src/tools/PrettyCode/lazy.tsx +1 -1
  228. package/src/tools/SpeechRecognition/README.md +1 -1
  229. package/src/tools/SpeechRecognition/__tests__/language.test.ts +9 -3
  230. package/src/tools/SpeechRecognition/components/RecordingPulse.tsx +59 -0
  231. package/src/tools/SpeechRecognition/components/index.ts +2 -0
  232. package/src/tools/SpeechRecognition/core/engine/external.ts +24 -7
  233. package/src/tools/SpeechRecognition/core/language.ts +23 -6
  234. package/src/tools/SpeechRecognition/hooks/usePushToTalk.ts +36 -5
  235. package/src/tools/SpeechRecognition/hooks/useSpeechRecognition.ts +18 -11
  236. package/src/tools/SpeechRecognition/widgets/VoiceComposerSlot.tsx +94 -26
  237. package/src/tools/SpeechRecognition/widgets/index.ts +1 -1
  238. package/src/tools/Tree/README.md +4 -8
  239. package/src/tools/Tree/TreeRoot.tsx +22 -10
  240. package/src/tools/Tree/components/TreeContent.tsx +24 -4
  241. package/src/tools/Tree/components/TreeLabel.tsx +8 -2
  242. package/src/tools/Tree/components/TreeRow.tsx +16 -6
  243. package/src/tools/Tree/data/flatten.ts +10 -4
  244. package/src/tools/Tree/types.ts +4 -0
  245. package/src/tools/Uploader/components/UploadAddButton.tsx +29 -6
  246. package/src/tools/Uploader/components/UploadDropzone.tsx +63 -7
  247. package/src/tools/Uploader/components/UploadPageDropOverlay.tsx +19 -5
  248. package/src/tools/Uploader/components/UploadPreviewItem.tsx +47 -17
  249. package/src/tools/Uploader/components/UploadPreviewList.tsx +24 -12
  250. package/src/tools/Uploader/utils/formatters.ts +8 -3
  251. package/src/tools/VideoPlayer/README.md +87 -230
  252. package/src/tools/VideoPlayer/VideoPlayer.tsx +82 -0
  253. package/src/tools/VideoPlayer/canvas/canvas-dispatcher.tsx +34 -0
  254. package/src/tools/VideoPlayer/canvas/hls-canvas.tsx +39 -0
  255. package/src/tools/VideoPlayer/canvas/iframe-canvas.tsx +33 -0
  256. package/src/tools/VideoPlayer/canvas/index.ts +12 -0
  257. package/src/tools/VideoPlayer/canvas/jsx-augmentation.ts +47 -0
  258. package/src/tools/VideoPlayer/canvas/native-canvas.tsx +38 -0
  259. package/src/tools/VideoPlayer/canvas/vimeo-canvas.tsx +40 -0
  260. package/src/tools/VideoPlayer/canvas/youtube-canvas.tsx +78 -0
  261. package/src/tools/VideoPlayer/index.ts +51 -65
  262. package/src/tools/VideoPlayer/lazy.tsx +11 -54
  263. package/src/tools/VideoPlayer/parts/controls-bar.tsx +35 -0
  264. package/src/tools/VideoPlayer/parts/fullscreen.tsx +19 -0
  265. package/src/tools/VideoPlayer/parts/index.ts +15 -0
  266. package/src/tools/VideoPlayer/parts/pip.tsx +19 -0
  267. package/src/tools/VideoPlayer/parts/play-button.tsx +19 -0
  268. package/src/tools/VideoPlayer/parts/playback-rate.tsx +31 -0
  269. package/src/tools/VideoPlayer/parts/poster.tsx +3 -0
  270. package/src/tools/VideoPlayer/parts/seek-bar.tsx +26 -0
  271. package/src/tools/VideoPlayer/parts/volume.tsx +32 -0
  272. package/src/tools/VideoPlayer/styles/video-player.css +141 -0
  273. package/src/tools/VideoPlayer/types.ts +82 -0
  274. package/src/tools/VideoPlayer/utils/parse-embed-url.ts +70 -0
  275. package/src/tools/VideoPlayer/utils/vimeo-id.ts +24 -0
  276. package/src/tools/VideoPlayer/utils/youtube-id.ts +64 -0
  277. package/src/tools/index.ts +37 -29
  278. package/src/tools/Chat/components/AudioToggle.tsx +0 -78
  279. package/src/tools/Chat/components/ChatRoot.tsx +0 -305
  280. package/src/tools/Chat/components/Composer.tsx +0 -216
  281. package/src/tools/Chat/hooks/useChatScroll.ts +0 -145
  282. package/src/tools/Chat/types.ts +0 -9
  283. package/src/tools/JsonTree/components/JsonToolbar.tsx +0 -95
  284. package/src/tools/JsonTree/hooks/useElementCorner.ts +0 -84
  285. package/src/tools/JsonTree/hooks/useNavbarHeight.ts +0 -83
  286. package/src/tools/OpenapiViewer/components/DocsLayout/schemaFields.ts +0 -121
  287. package/src/tools/Tour/README.md +0 -373
  288. package/src/tools/Tour/components/Tour.tsx +0 -12
  289. package/src/tools/Tour/components/TourContent.tsx +0 -171
  290. package/src/tools/Tour/components/TourNavigation.tsx +0 -77
  291. package/src/tools/Tour/components/TourProgress.tsx +0 -88
  292. package/src/tools/Tour/components/TourSpotlight.tsx +0 -199
  293. package/src/tools/Tour/components/index.ts +0 -5
  294. package/src/tools/Tour/context/TourContext.ts +0 -19
  295. package/src/tools/Tour/context/TourProvider.tsx +0 -292
  296. package/src/tools/Tour/context/index.ts +0 -2
  297. package/src/tools/Tour/hooks/index.ts +0 -3
  298. package/src/tools/Tour/hooks/useKeyboardNavigation.ts +0 -59
  299. package/src/tools/Tour/hooks/useStepTarget.ts +0 -121
  300. package/src/tools/Tour/hooks/useTour.ts +0 -42
  301. package/src/tools/Tour/index.ts +0 -38
  302. package/src/tools/Tour/types/index.ts +0 -224
  303. package/src/tools/Tour/utils/dom.ts +0 -98
  304. package/src/tools/Tour/utils/index.ts +0 -3
  305. package/src/tools/Tour/utils/logger.ts +0 -3
  306. package/src/tools/Tour/utils/scrollIntoView.ts +0 -24
  307. package/src/tools/VideoPlayer/components/VideoControls.tsx +0 -138
  308. package/src/tools/VideoPlayer/components/VideoErrorFallback.tsx +0 -172
  309. package/src/tools/VideoPlayer/components/VideoPlayer.tsx +0 -201
  310. package/src/tools/VideoPlayer/components/index.ts +0 -14
  311. package/src/tools/VideoPlayer/context/VideoPlayerContext.tsx +0 -52
  312. package/src/tools/VideoPlayer/context/index.ts +0 -8
  313. package/src/tools/VideoPlayer/hooks/index.ts +0 -12
  314. package/src/tools/VideoPlayer/hooks/useVideoPlayerSettings.ts +0 -71
  315. package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +0 -117
  316. package/src/tools/VideoPlayer/providers/NativeProvider.tsx +0 -284
  317. package/src/tools/VideoPlayer/providers/StreamProvider.tsx +0 -505
  318. package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +0 -397
  319. package/src/tools/VideoPlayer/providers/index.ts +0 -8
  320. package/src/tools/VideoPlayer/types/index.ts +0 -38
  321. package/src/tools/VideoPlayer/types/player.ts +0 -116
  322. package/src/tools/VideoPlayer/types/provider.ts +0 -93
  323. package/src/tools/VideoPlayer/types/sources.ts +0 -97
  324. package/src/tools/VideoPlayer/utils/debug.ts +0 -14
  325. package/src/tools/VideoPlayer/utils/fileSource.ts +0 -78
  326. package/src/tools/VideoPlayer/utils/index.ts +0 -12
  327. package/src/tools/VideoPlayer/utils/resolvers.ts +0 -75
  328. /package/src/tools/Chat/{config.ts → constants.ts} +0 -0
  329. /package/src/tools/Chat/launcher/{ChatHeaderAudioToggle.tsx → header/ChatHeaderAudioToggle.tsx} +0 -0
  330. /package/src/tools/Chat/{components → messages}/Attachments.tsx +0 -0
  331. /package/src/tools/Chat/{components → messages}/JumpToLatest.tsx +0 -0
  332. /package/src/tools/Chat/{components → messages}/MessageActions.tsx +0 -0
  333. /package/src/tools/Chat/{components → messages}/Sources.tsx +0 -0
  334. /package/src/tools/Chat/{components → messages}/StreamingIndicator.tsx +0 -0
  335. /package/src/tools/Chat/{components → messages}/ToolCalls.tsx +0 -0
  336. /package/src/tools/Chat/{components → shell}/ErrorBanner.tsx +0 -0
@@ -1,88 +0,0 @@
1
- 'use client';
2
-
3
- import { useMemo } from 'react';
4
- import { cn } from '@djangocfg/ui-core/lib';
5
- import { Progress } from '@djangocfg/ui-core/components';
6
- import { useT } from '@djangocfg/i18n';
7
- import type { TourProgressProps } from '../types';
8
-
9
- /**
10
- * Progress indicator for tour steps.
11
- * Supports dots, bar, fraction, and none variants.
12
- */
13
- export function TourProgress({
14
- current,
15
- total,
16
- variant = 'dots',
17
- onDotClick,
18
- className,
19
- }: TourProgressProps) {
20
- const t = useT();
21
-
22
- // Early return for hidden states
23
- if (variant === 'none' || total <= 1) return null;
24
-
25
- // Prepare data
26
- const currentStep = current + 1;
27
- const progressPercent = (currentStep / total) * 100;
28
- const stepLabel = t('tools.tour.stepOf', { current: currentStep, total });
29
- const isClickable = !!onDotClick;
30
-
31
- // Prepare dots data
32
- const dots = useMemo(() => {
33
- if (variant !== 'dots') return [];
34
-
35
- return Array.from({ length: total }, (_, index) => ({
36
- index,
37
- isActive: index === current,
38
- label: t('tools.tour.stepOf', { current: index + 1, total }),
39
- className: cn(
40
- 'h-2 w-2 rounded-full transition-all',
41
- index === current ? 'bg-primary scale-110' : 'bg-muted hover:bg-muted-foreground/50',
42
- isClickable && 'cursor-pointer'
43
- ),
44
- }));
45
- }, [variant, total, current, isClickable, t]);
46
-
47
- // Render bar variant
48
- if (variant === 'bar') {
49
- return (
50
- <Progress
51
- value={progressPercent}
52
- className={cn('h-1', className)}
53
- aria-label={stepLabel}
54
- />
55
- );
56
- }
57
-
58
- // Render fraction variant
59
- if (variant === 'fraction') {
60
- const fractionClassName = cn('text-sm text-muted-foreground tabular-nums', className);
61
-
62
- return (
63
- <div className={fractionClassName} aria-label={stepLabel}>
64
- {currentStep} / {total}
65
- </div>
66
- );
67
- }
68
-
69
- // Render dots variant (default)
70
- const dotsContainerClassName = cn('flex items-center justify-center gap-1.5', className);
71
-
72
- return (
73
- <div className={dotsContainerClassName} role="tablist" aria-label={stepLabel}>
74
- {dots.map((dot) => (
75
- <button
76
- key={dot.index}
77
- type="button"
78
- role="tab"
79
- aria-selected={dot.isActive}
80
- aria-label={dot.label}
81
- className={dot.className}
82
- onClick={() => onDotClick?.(dot.index)}
83
- disabled={!isClickable}
84
- />
85
- ))}
86
- </div>
87
- );
88
- }
@@ -1,199 +0,0 @@
1
- 'use client';
2
-
3
- import { useMemo } from 'react';
4
- import { cn } from '@djangocfg/ui-core/lib';
5
- import type { TourSpotlightProps } from '../types';
6
-
7
- // CSS for SVG animations (injected once)
8
- const SPOTLIGHT_STYLES = `
9
- @keyframes tour-spotlight-pulse {
10
- 0%, 100% { opacity: 1; }
11
- 50% { opacity: 0.5; }
12
- }
13
- @keyframes tour-spotlight-ring {
14
- 0% { transform: scale(1); opacity: 0.8; }
15
- 100% { transform: scale(1.15); opacity: 0; }
16
- }
17
- .tour-spotlight-rect {
18
- transition: x 300ms ease-out, y 300ms ease-out, width 300ms ease-out, height 300ms ease-out;
19
- }
20
- .tour-spotlight-border {
21
- transition: x 300ms ease-out, y 300ms ease-out, width 300ms ease-out, height 300ms ease-out;
22
- }
23
- .tour-spotlight-pulse {
24
- animation: tour-spotlight-pulse 2s ease-in-out infinite;
25
- }
26
- `;
27
-
28
- /**
29
- * SVG-based spotlight overlay that highlights target elements.
30
- * Uses mask technique to create cutouts for targets.
31
- * Supports animations, backdrop blur, and pulse ring effects.
32
- */
33
- export function TourSpotlight({
34
- targets,
35
- opacity = 0.5,
36
- blur = 0,
37
- animated = true,
38
- pulseRing = false,
39
- className,
40
- onClick,
41
- allowInteraction = false,
42
- }: TourSpotlightProps) {
43
- // Early return for no targets
44
- if (targets.length === 0) return null;
45
-
46
- // Prepare flags
47
- const hasBlur = blur > 0;
48
-
49
- // Prepare target rects with computed values
50
- const computedTargets = useMemo(() => {
51
- return targets.map((target, index) => {
52
- const x = target.rect.x - target.padding;
53
- const y = target.rect.y - target.padding;
54
- const width = target.rect.width + target.padding * 2;
55
- const height = target.rect.height + target.padding * 2;
56
- const rx = target.radius + 2;
57
- const centerX = target.rect.x + target.rect.width / 2;
58
- const centerY = target.rect.y + target.rect.height / 2;
59
-
60
- return {
61
- key: index,
62
- x,
63
- y,
64
- width,
65
- height,
66
- rx,
67
- ry: rx,
68
- transformOrigin: `${centerX}px ${centerY}px`,
69
- };
70
- });
71
- }, [targets]);
72
-
73
- // Prepare styles
74
- const svgClassName = cn('absolute inset-0 h-full w-full', className);
75
- const svgStyle = { pointerEvents: allowInteraction ? 'none' as const : 'auto' as const };
76
-
77
- const blurStyle = useMemo(() => {
78
- if (!hasBlur) return undefined;
79
- return {
80
- backdropFilter: `blur(${blur}px)`,
81
- WebkitBackdropFilter: `blur(${blur}px)`,
82
- mask: 'url(#tour-spotlight-mask-blur)',
83
- WebkitMask: 'url(#tour-spotlight-mask-blur)',
84
- pointerEvents: 'none' as const,
85
- };
86
- }, [hasBlur, blur]);
87
-
88
- const rectAnimatedClass = animated ? 'tour-spotlight-rect' : undefined;
89
- const overlayClass = animated ? 'transition-opacity duration-300' : undefined;
90
-
91
- return (
92
- <>
93
- {/* Inject styles for animations */}
94
- <style dangerouslySetInnerHTML={{ __html: SPOTLIGHT_STYLES }} />
95
-
96
- {/* Backdrop blur layer (separate from SVG for better performance) */}
97
- {hasBlur && (
98
- <div
99
- className="absolute inset-0 transition-all duration-300"
100
- style={blurStyle}
101
- aria-hidden="true"
102
- />
103
- )}
104
-
105
- <svg
106
- className={svgClassName}
107
- style={svgStyle}
108
- onClick={onClick}
109
- aria-hidden="true"
110
- >
111
- <defs>
112
- <mask id="tour-spotlight-mask">
113
- {/* White background - visible area */}
114
- <rect fill="white" width="100%" height="100%" />
115
- {/* Black cutouts - transparent area for targets */}
116
- {computedTargets.map((target) => (
117
- <rect
118
- key={target.key}
119
- fill="black"
120
- className={rectAnimatedClass}
121
- x={target.x}
122
- y={target.y}
123
- width={target.width}
124
- height={target.height}
125
- rx={target.rx}
126
- ry={target.ry}
127
- />
128
- ))}
129
- </mask>
130
-
131
- {/* Separate mask for blur */}
132
- {hasBlur && (
133
- <mask id="tour-spotlight-mask-blur">
134
- <rect fill="white" width="100%" height="100%" />
135
- {computedTargets.map((target) => (
136
- <rect
137
- key={target.key}
138
- fill="black"
139
- className={rectAnimatedClass}
140
- x={target.x}
141
- y={target.y}
142
- width={target.width}
143
- height={target.height}
144
- rx={target.rx}
145
- ry={target.ry}
146
- />
147
- ))}
148
- </mask>
149
- )}
150
- </defs>
151
-
152
- {/* Overlay with mask */}
153
- <rect
154
- fill="black"
155
- fillOpacity={opacity}
156
- width="100%"
157
- height="100%"
158
- mask="url(#tour-spotlight-mask)"
159
- className={overlayClass}
160
- />
161
-
162
- {/* Pulse ring effect */}
163
- {pulseRing && computedTargets.map((target) => (
164
- <rect
165
- key={`pulse-${target.key}`}
166
- className="fill-none stroke-primary stroke-2"
167
- style={{
168
- transformOrigin: target.transformOrigin,
169
- animation: 'tour-spotlight-ring 1.5s ease-out infinite',
170
- }}
171
- x={target.x}
172
- y={target.y}
173
- width={target.width}
174
- height={target.height}
175
- rx={target.rx}
176
- ry={target.ry}
177
- />
178
- ))}
179
-
180
- {/* Border around targets */}
181
- {computedTargets.map((target) => (
182
- <rect
183
- key={`border-${target.key}`}
184
- className={cn(
185
- 'fill-none stroke-primary stroke-2',
186
- animated && 'tour-spotlight-border'
187
- )}
188
- x={target.x}
189
- y={target.y}
190
- width={target.width}
191
- height={target.height}
192
- rx={target.rx}
193
- ry={target.ry}
194
- />
195
- ))}
196
- </svg>
197
- </>
198
- );
199
- }
@@ -1,5 +0,0 @@
1
- export { TourSpotlight } from './TourSpotlight';
2
- export { TourProgress } from './TourProgress';
3
- export { TourNavigation } from './TourNavigation';
4
- export { TourContent } from './TourContent';
5
- export { Tour } from './Tour';
@@ -1,19 +0,0 @@
1
- 'use client';
2
-
3
- import { createContext, useContext } from 'react';
4
- import type { TourState, TourStep, UseTourReturn } from '../types';
5
-
6
- export interface TourContextValue extends UseTourReturn {
7
- state: TourState;
8
- steps: TourStep[];
9
- }
10
-
11
- export const TourContext = createContext<TourContextValue | null>(null);
12
-
13
- export function useTourContext(): TourContextValue {
14
- const context = useContext(TourContext);
15
- if (!context) {
16
- throw new Error('useTourContext must be used within a TourProvider');
17
- }
18
- return context;
19
- }
@@ -1,292 +0,0 @@
1
- 'use client';
2
-
3
- import { useState, useCallback, useMemo, useEffect } from 'react';
4
- import { createPortal } from 'react-dom';
5
- import { TourContext, type TourContextValue } from './TourContext';
6
- import { TourSpotlight } from '../components/TourSpotlight';
7
- import { TourContent } from '../components/TourContent';
8
- import { useStepTarget } from '../hooks/useStepTarget';
9
- import { useKeyboardNavigation } from '../hooks/useKeyboardNavigation';
10
- import { logger } from '../utils/logger';
11
- import type { TourProviderProps, TourState, TourStep } from '../types';
12
-
13
- /**
14
- * Tour context provider.
15
- * Manages tour state and renders overlay.
16
- */
17
- export function TourProvider({
18
- tours,
19
- children,
20
- spotlight = true,
21
- spotlightOpacity = 0.5,
22
- spotlightBlur = 0,
23
- animated = true,
24
- pulseRing = false,
25
- showArrow = false,
26
- keyboardNavigation = true,
27
- closeOnOverlayClick = false,
28
- closeOnEscape = true,
29
- scrollToTarget = true,
30
- scrollBehavior = 'smooth',
31
- progressVariant = 'dots',
32
- showSkipButton = true,
33
- skipLabel,
34
- finishLabel,
35
- portalContainer,
36
- zIndex = 50,
37
- onStart,
38
- onComplete,
39
- onSkip,
40
- onStepChange,
41
- onBeforeStepChange,
42
- }: TourProviderProps) {
43
- const [state, setState] = useState<TourState>({
44
- isActive: false,
45
- activeTourId: null,
46
- currentStepIndex: 0,
47
- isTransitioning: false,
48
- direction: 'forward',
49
- });
50
-
51
- const [mounted, setMounted] = useState(false);
52
-
53
- useEffect(() => {
54
- setMounted(true);
55
- }, []);
56
-
57
- // Get active tour and current step
58
- const activeTour = useMemo(
59
- () => tours.find((t) => t.id === state.activeTourId),
60
- [tours, state.activeTourId]
61
- );
62
-
63
- const steps = useMemo(() => {
64
- if (!activeTour) return [];
65
- // Apply tour defaults to each step
66
- return activeTour.steps.map((step) => ({
67
- ...activeTour.defaults,
68
- ...step,
69
- }));
70
- }, [activeTour]);
71
-
72
- const currentStep = steps[state.currentStepIndex] as TourStep | undefined;
73
-
74
- // Track target elements
75
- const { targets, isReady } = useStepTarget(currentStep?.target, currentStep?.id, {
76
- scrollToTarget,
77
- scrollBehavior,
78
- spotlightPadding: currentStep?.spotlightPadding ?? 8,
79
- });
80
-
81
- // Start tour
82
- const start = useCallback(
83
- (tourId: string, startIndex = 0) => {
84
- const tour = tours.find((t) => t.id === tourId);
85
- if (!tour) {
86
- logger.warn(`Tour "${tourId}" not found`);
87
- return;
88
- }
89
- if (tour.steps.length === 0) {
90
- logger.warn(`Tour "${tourId}" has no steps`);
91
- return;
92
- }
93
-
94
- logger.info(`Starting tour "${tourId}"`);
95
- setState({
96
- isActive: true,
97
- activeTourId: tourId,
98
- currentStepIndex: Math.min(startIndex, tour.steps.length - 1),
99
- isTransitioning: false,
100
- direction: 'forward',
101
- });
102
- onStart?.(tourId);
103
- },
104
- [tours, onStart]
105
- );
106
-
107
- // Close tour
108
- const close = useCallback(() => {
109
- if (state.activeTourId) {
110
- logger.info(`Tour "${state.activeTourId}" closed at step ${state.currentStepIndex}`);
111
- onSkip?.(state.activeTourId, state.currentStepIndex);
112
- }
113
- setState({
114
- isActive: false,
115
- activeTourId: null,
116
- currentStepIndex: 0,
117
- isTransitioning: false,
118
- direction: 'forward',
119
- });
120
- }, [state.activeTourId, state.currentStepIndex, onSkip]);
121
-
122
- // Next step
123
- const next = useCallback(async () => {
124
- if (!activeTour) return;
125
-
126
- const nextIndex = state.currentStepIndex + 1;
127
-
128
- // Complete tour if at last step
129
- if (nextIndex >= steps.length) {
130
- logger.info(`Tour "${state.activeTourId}" completed`);
131
- onComplete?.(state.activeTourId!);
132
- setState({
133
- isActive: false,
134
- activeTourId: null,
135
- currentStepIndex: 0,
136
- isTransitioning: false,
137
- direction: 'forward',
138
- });
139
- return;
140
- }
141
-
142
- // Check if can proceed
143
- const canProceed = (await onBeforeStepChange?.(state.currentStepIndex, nextIndex)) ?? true;
144
- if (!canProceed) return;
145
-
146
- // Call step onHide callback
147
- currentStep?.onHide?.();
148
-
149
- setState((prev) => ({
150
- ...prev,
151
- currentStepIndex: nextIndex,
152
- direction: 'forward',
153
- }));
154
-
155
- const nextStep = steps[nextIndex];
156
- onStepChange?.(nextIndex, nextStep, 'forward');
157
- nextStep?.onShow?.();
158
- }, [activeTour, state, steps, currentStep, onComplete, onBeforeStepChange, onStepChange]);
159
-
160
- // Previous step
161
- const previous = useCallback(async () => {
162
- if (state.currentStepIndex <= 0) return;
163
-
164
- const prevIndex = state.currentStepIndex - 1;
165
-
166
- const canProceed = (await onBeforeStepChange?.(state.currentStepIndex, prevIndex)) ?? true;
167
- if (!canProceed) return;
168
-
169
- currentStep?.onHide?.();
170
-
171
- setState((prev) => ({
172
- ...prev,
173
- currentStepIndex: prevIndex,
174
- direction: 'backward',
175
- }));
176
-
177
- const prevStep = steps[prevIndex];
178
- onStepChange?.(prevIndex, prevStep, 'backward');
179
- prevStep?.onShow?.();
180
- }, [state.currentStepIndex, steps, currentStep, onBeforeStepChange, onStepChange]);
181
-
182
- // Go to specific step
183
- const goTo = useCallback(
184
- async (index: number) => {
185
- if (!activeTour || index < 0 || index >= steps.length) return;
186
- if (index === state.currentStepIndex) return;
187
-
188
- const canProceed = (await onBeforeStepChange?.(state.currentStepIndex, index)) ?? true;
189
- if (!canProceed) return;
190
-
191
- currentStep?.onHide?.();
192
-
193
- const direction = index > state.currentStepIndex ? 'forward' : 'backward';
194
- setState((prev) => ({
195
- ...prev,
196
- currentStepIndex: index,
197
- direction,
198
- }));
199
-
200
- const targetStep = steps[index];
201
- onStepChange?.(index, targetStep, direction);
202
- targetStep?.onShow?.();
203
- },
204
- [activeTour, steps, state.currentStepIndex, currentStep, onBeforeStepChange, onStepChange]
205
- );
206
-
207
- // Keyboard navigation
208
- useKeyboardNavigation({
209
- enabled: keyboardNavigation && state.isActive,
210
- onNext: next,
211
- onPrevious: previous,
212
- onClose: closeOnEscape ? close : undefined,
213
- });
214
-
215
- // Lock body scroll when tour is active
216
- useEffect(() => {
217
- if (state.isActive) {
218
- const originalOverflow = document.body.style.overflow;
219
- document.body.style.overflow = 'hidden';
220
- return () => {
221
- document.body.style.overflow = originalOverflow;
222
- };
223
- }
224
- }, [state.isActive]);
225
-
226
- // Context value
227
- const contextValue: TourContextValue = useMemo(
228
- () => ({
229
- state,
230
- steps,
231
- currentStep: currentStep ?? null,
232
- start,
233
- next,
234
- previous,
235
- goTo,
236
- close,
237
- isActive: state.isActive,
238
- activeTourId: state.activeTourId,
239
- currentStepIndex: state.currentStepIndex,
240
- totalSteps: steps.length,
241
- isFirstStep: state.currentStepIndex === 0,
242
- isLastStep: state.currentStepIndex === steps.length - 1,
243
- progress: steps.length > 0 ? (state.currentStepIndex + 1) / steps.length : 0,
244
- }),
245
- [state, steps, currentStep, start, next, previous, goTo, close]
246
- );
247
-
248
- // Overlay content
249
- const overlay = state.isActive && currentStep && isReady && targets.length > 0 && (
250
- <div
251
- className="fixed inset-0"
252
- style={{ zIndex }}
253
- role="presentation"
254
- aria-hidden="true"
255
- >
256
- {spotlight && !currentStep.disableSpotlight && (
257
- <TourSpotlight
258
- targets={targets}
259
- opacity={spotlightOpacity}
260
- blur={spotlightBlur}
261
- animated={animated}
262
- pulseRing={pulseRing}
263
- onClick={closeOnOverlayClick ? close : undefined}
264
- allowInteraction={currentStep.allowTargetInteraction}
265
- />
266
- )}
267
-
268
- <TourContent
269
- step={currentStep}
270
- targetRect={targets[0].rect}
271
- currentIndex={state.currentStepIndex}
272
- totalSteps={steps.length}
273
- onNext={next}
274
- onPrevious={previous}
275
- onClose={close}
276
- progressVariant={progressVariant}
277
- showSkipButton={showSkipButton}
278
- showArrow={showArrow}
279
- skipLabel={skipLabel}
280
- finishLabel={finishLabel}
281
- onGoTo={goTo}
282
- />
283
- </div>
284
- );
285
-
286
- return (
287
- <TourContext.Provider value={contextValue}>
288
- {children}
289
- {mounted && createPortal(overlay, portalContainer ?? document.body)}
290
- </TourContext.Provider>
291
- );
292
- }
@@ -1,2 +0,0 @@
1
- export { TourProvider } from './TourProvider';
2
- export { TourContext, useTourContext, type TourContextValue } from './TourContext';
@@ -1,3 +0,0 @@
1
- export { useTour } from './useTour';
2
- export { useStepTarget } from './useStepTarget';
3
- export { useKeyboardNavigation } from './useKeyboardNavigation';
@@ -1,59 +0,0 @@
1
- 'use client';
2
-
3
- import { useEffect } from 'react';
4
-
5
- interface UseKeyboardNavigationOptions {
6
- enabled: boolean;
7
- onNext?: () => void;
8
- onPrevious?: () => void;
9
- onClose?: () => void;
10
- }
11
-
12
- /**
13
- * Hook for keyboard navigation in tours.
14
- * - ArrowRight/ArrowDown: Next step
15
- * - ArrowLeft/ArrowUp: Previous step
16
- * - Escape: Close tour
17
- */
18
- export function useKeyboardNavigation({
19
- enabled,
20
- onNext,
21
- onPrevious,
22
- onClose,
23
- }: UseKeyboardNavigationOptions): void {
24
- useEffect(() => {
25
- if (!enabled) return;
26
-
27
- const handleKeyDown = (event: KeyboardEvent) => {
28
- // Ignore if user is typing in an input
29
- const target = event.target as HTMLElement;
30
- if (
31
- target.tagName === 'INPUT' ||
32
- target.tagName === 'TEXTAREA' ||
33
- target.isContentEditable
34
- ) {
35
- return;
36
- }
37
-
38
- switch (event.key) {
39
- case 'ArrowRight':
40
- case 'ArrowDown':
41
- event.preventDefault();
42
- onNext?.();
43
- break;
44
- case 'ArrowLeft':
45
- case 'ArrowUp':
46
- event.preventDefault();
47
- onPrevious?.();
48
- break;
49
- case 'Escape':
50
- event.preventDefault();
51
- onClose?.();
52
- break;
53
- }
54
- };
55
-
56
- document.addEventListener('keydown', handleKeyDown);
57
- return () => document.removeEventListener('keydown', handleKeyDown);
58
- }, [enabled, onNext, onPrevious, onClose]);
59
- }