@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,6 +1,6 @@
1
1
  'use client'
2
2
 
3
- import { useState, useCallback, useMemo, memo } from 'react'
3
+ import { useState, useCallback, useMemo, useEffect, memo, type KeyboardEvent } from 'react'
4
4
  import { useMapLayers } from '../hooks/useMapLayers'
5
5
 
6
6
  import type { LayerSwitcherProps, LayerConfig } from '../types'
@@ -36,14 +36,29 @@ function LayerSwitcherComponent({
36
36
 
37
37
  const [visibility, setVisibility] = useState<Record<string, boolean>>(initialVisibility)
38
38
 
39
+ // Keep visibility in sync when the `layers` prop changes: add entries for
40
+ // new layers, drop stale ones, preserve user toggles for existing layers.
41
+ useEffect(() => {
42
+ setVisibility((prev) => {
43
+ const next: Record<string, boolean> = {}
44
+ for (const layer of layers) {
45
+ next[layer.id] =
46
+ layer.id in prev ? prev[layer.id] : layer.defaultVisible !== false
47
+ }
48
+ return next
49
+ })
50
+ }, [layers])
51
+
39
52
  const handleToggle = useCallback(
40
53
  (layerId: string) => {
41
- const newVisible = !visibility[layerId]
42
- setVisibility((prev) => ({ ...prev, [layerId]: newVisible }))
43
- setLayerVisibility(layerId, newVisible)
44
- onChange?.(layerId, newVisible)
54
+ setVisibility((prev) => {
55
+ const newVisible = !prev[layerId]
56
+ setLayerVisibility(layerId, newVisible)
57
+ onChange?.(layerId, newVisible)
58
+ return { ...prev, [layerId]: newVisible }
59
+ })
45
60
  },
46
- [visibility, setLayerVisibility, onChange]
61
+ [setLayerVisibility, onChange]
47
62
  )
48
63
 
49
64
  const handleToggleAll = useCallback(
@@ -66,7 +81,9 @@ function LayerSwitcherComponent({
66
81
  () => ({
67
82
  position: 'absolute',
68
83
  ...positionStyles[position],
69
- backgroundColor: 'white',
84
+ backgroundColor: 'var(--color-popover)',
85
+ color: 'var(--color-popover-foreground)',
86
+ border: '1px solid var(--color-border)',
70
87
  borderRadius: 8,
71
88
  boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
72
89
  padding: collapsed ? 8 : 12,
@@ -86,7 +103,7 @@ function LayerSwitcherComponent({
86
103
  cursor: collapsible ? 'pointer' : 'default',
87
104
  fontWeight: 600,
88
105
  fontSize: 12,
89
- color: '#333',
106
+ color: 'var(--color-foreground)',
90
107
  marginBottom: collapsed ? 0 : 8,
91
108
  }),
92
109
  [collapsible, collapsed]
@@ -99,7 +116,7 @@ function LayerSwitcherComponent({
99
116
  gap: 8,
100
117
  padding: '4px 0',
101
118
  fontSize: 12,
102
- color: '#666',
119
+ color: 'var(--color-muted-foreground)',
103
120
  cursor: 'pointer',
104
121
  }),
105
122
  []
@@ -126,23 +143,40 @@ function LayerSwitcherComponent({
126
143
  )
127
144
  }, [layers])
128
145
 
129
- const handleHeaderClick = collapsible ? () => setCollapsed(!collapsed) : undefined
146
+ const handleHeaderClick = collapsible ? () => setCollapsed((c) => !c) : undefined
130
147
 
131
148
  return (
132
149
  <div className={className} style={containerStyle}>
133
- <div style={headerStyle} onClick={handleHeaderClick}>
150
+ <div
151
+ style={headerStyle}
152
+ onClick={handleHeaderClick}
153
+ {...(collapsible
154
+ ? {
155
+ role: 'button' as const,
156
+ tabIndex: 0,
157
+ 'aria-expanded': !collapsed,
158
+ onKeyDown: (e: KeyboardEvent) => {
159
+ if (e.key === 'Enter' || e.key === ' ') {
160
+ e.preventDefault()
161
+ setCollapsed((c) => !c)
162
+ }
163
+ },
164
+ }
165
+ : {})}
166
+ >
134
167
  <span>{title}</span>
135
168
  {collapsible && (
136
169
  <svg
137
170
  width="12"
138
171
  height="12"
139
172
  viewBox="0 0 12 12"
173
+ aria-hidden="true"
140
174
  style={{
141
175
  transform: collapsed ? 'rotate(-90deg)' : 'rotate(0deg)',
142
176
  transition: 'transform 0.2s',
143
177
  }}
144
178
  >
145
- <path d="M3 4.5L6 7.5L9 4.5" stroke="#666" fill="none" />
179
+ <path d="M3 4.5L6 7.5L9 4.5" stroke="currentColor" fill="none" />
146
180
  </svg>
147
181
  )}
148
182
  </div>
@@ -152,12 +186,14 @@ function LayerSwitcherComponent({
152
186
  <div
153
187
  style={{
154
188
  ...itemStyle,
155
- borderBottom: '1px solid #eee',
189
+ cursor: 'default',
190
+ borderBottom: '1px solid var(--color-border)',
156
191
  marginBottom: 4,
157
192
  paddingBottom: 8,
158
193
  }}
159
194
  >
160
195
  <button
196
+ type="button"
161
197
  onClick={() => handleToggleAll(true)}
162
198
  disabled={allVisible}
163
199
  style={{
@@ -170,6 +206,7 @@ function LayerSwitcherComponent({
170
206
  All
171
207
  </button>
172
208
  <button
209
+ type="button"
173
210
  onClick={() => handleToggleAll(false)}
174
211
  disabled={noneVisible}
175
212
  style={{
@@ -190,7 +227,7 @@ function LayerSwitcherComponent({
190
227
  style={{
191
228
  fontSize: 10,
192
229
  fontWeight: 600,
193
- color: '#999',
230
+ color: 'var(--color-muted-foreground)',
194
231
  marginTop: 8,
195
232
  marginBottom: 4,
196
233
  textTransform: 'uppercase',
@@ -200,19 +237,15 @@ function LayerSwitcherComponent({
200
237
  </div>
201
238
  )}
202
239
  {groupLayers.map((layer) => (
203
- <div
204
- key={layer.id}
205
- style={itemStyle}
206
- onClick={() => handleToggle(layer.id)}
207
- >
240
+ <label key={layer.id} style={itemStyle}>
208
241
  <input
209
242
  type="checkbox"
210
- checked={visibility[layer.id]}
243
+ checked={visibility[layer.id] ?? false}
211
244
  onChange={() => handleToggle(layer.id)}
212
245
  style={checkboxStyle}
213
246
  />
214
247
  <span>{layer.label}</span>
215
- </div>
248
+ </label>
216
249
  ))}
217
250
  </div>
218
251
  ))}
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
 
3
- import { useCallback, useState, useEffect, memo, type ReactNode } from 'react'
3
+ import { useCallback, useState, useEffect, useMemo, memo, type ReactNode } from 'react'
4
4
  import { Source, Layer, useMap, Popup } from 'react-map-gl/maplibre'
5
5
  import type { GeoJSONSource, MapMouseEvent } from 'maplibre-gl'
6
6
  import { createClusterLayers } from '../layers'
@@ -78,15 +78,21 @@ export const MapCluster = memo(function MapCluster({
78
78
  injectPopupStyles()
79
79
  }, [])
80
80
 
81
- const layerOptions: ClusterLayerOptions = {
82
- sourceId,
83
- colors,
84
- radii,
85
- thresholds,
86
- hoverColor,
87
- }
81
+ // Memoize layers so layer ids stay referentially stable across renders.
82
+ // Without this, the click/hover effect below re-subscribes on every render.
83
+ const { cluster, clusterCount, unclusteredPoint } = useMemo(() => {
84
+ const layerOptions: ClusterLayerOptions = {
85
+ sourceId,
86
+ colors,
87
+ radii,
88
+ thresholds,
89
+ hoverColor,
90
+ }
91
+ return createClusterLayers(layerOptions)
92
+ }, [sourceId, colors, radii, thresholds, hoverColor])
88
93
 
89
- const { cluster, clusterCount, unclusteredPoint } = createClusterLayers(layerOptions)
94
+ const clusterLayerId = cluster.id as string
95
+ const pointLayerId = unclusteredPoint.id as string
90
96
 
91
97
  const handleClosePopup = useCallback(() => {
92
98
  setSelectedFeature(null)
@@ -98,7 +104,7 @@ export const MapCluster = memo(function MapCluster({
98
104
  if (!map) return
99
105
 
100
106
  const features = map.queryRenderedFeatures(event.point, {
101
- layers: [cluster.id!, unclusteredPoint.id!],
107
+ layers: [clusterLayerId, pointLayerId],
102
108
  })
103
109
 
104
110
  if (!features || features.length === 0) return
@@ -143,7 +149,7 @@ export const MapCluster = memo(function MapCluster({
143
149
  }
144
150
  }
145
151
  },
146
- [map, sourceId, cluster.id, unclusteredPoint.id, onClusterClick, onPointClick, renderPopup, panOffsetX, panOffsetY]
152
+ [map, sourceId, clusterLayerId, pointLayerId, onClusterClick, onPointClick, renderPopup, panOffsetX, panOffsetY]
147
153
  )
148
154
 
149
155
  // Close popup when clicking empty area
@@ -152,7 +158,7 @@ export const MapCluster = memo(function MapCluster({
152
158
  if (!map) return
153
159
 
154
160
  const features = map.queryRenderedFeatures(event.point, {
155
- layers: [cluster.id!, unclusteredPoint.id!],
161
+ layers: [clusterLayerId, pointLayerId],
156
162
  })
157
163
 
158
164
  // Close popup if clicked on empty area (no features)
@@ -160,24 +166,25 @@ export const MapCluster = memo(function MapCluster({
160
166
  handleClosePopup()
161
167
  }
162
168
  },
163
- [map, cluster.id, unclusteredPoint.id, handleClosePopup]
169
+ [map, clusterLayerId, pointLayerId, handleClosePopup]
164
170
  )
165
171
 
166
172
  // Register click and hover handlers with proper cleanup
167
173
  useEffect(() => {
168
174
  if (!map) return
169
175
 
170
- const clusterLayerId = cluster.id!
171
- const pointLayerId = unclusteredPoint.id!
172
176
  let currentHoveredId: number | string | null = null
173
177
 
174
- // Helper to clear hover state
178
+ // Helper to clear hover state.
179
+ // Guarded: on unmount the source may already be gone, which would throw.
175
180
  const clearHoverState = () => {
176
181
  if (currentHoveredId !== null) {
177
- map.setFeatureState(
178
- { source: sourceId, id: currentHoveredId },
179
- { hover: false }
180
- )
182
+ if (map.getSource(sourceId)) {
183
+ map.setFeatureState(
184
+ { source: sourceId, id: currentHoveredId },
185
+ { hover: false }
186
+ )
187
+ }
181
188
  currentHoveredId = null
182
189
  }
183
190
  }
@@ -231,7 +238,7 @@ export const MapCluster = memo(function MapCluster({
231
238
  map.off('mouseleave', clusterLayerId, handleMouseLeave)
232
239
  map.off('mouseleave', pointLayerId, handleMouseLeave)
233
240
  }
234
- }, [map, sourceId, cluster.id, unclusteredPoint.id, handleClick, handleMapClick])
241
+ }, [map, sourceId, clusterLayerId, pointLayerId, handleClick, handleMapClick])
235
242
 
236
243
  return (
237
244
  <>
@@ -28,6 +28,8 @@ export interface MapContainerProps {
28
28
  autoResetDelay?: number
29
29
  /** Show reset button */
30
30
  showResetButton?: boolean
31
+ /** Accessible label for the map region (screen readers) */
32
+ ariaLabel?: string
31
33
  }
32
34
 
33
35
  interface MapInnerProps extends Omit<MapContainerProps, 'initialViewport'> {}
@@ -44,6 +46,7 @@ function MapInner({
44
46
  openInMapsLabel = 'Open in Maps',
45
47
  autoResetDelay = 0,
46
48
  showResetButton = false,
49
+ ariaLabel = 'Interactive map',
47
50
  }: MapInnerProps) {
48
51
  const { mapRef, viewport, setViewport, setIsLoaded, resetToInitial, initialViewport } = useMapContext()
49
52
  const resetTimerRef = useRef<NodeJS.Timeout | null>(null)
@@ -125,6 +128,7 @@ function MapInner({
125
128
  ...style,
126
129
  }}
127
130
  cursor={cursor}
131
+ aria-label={ariaLabel}
128
132
  >
129
133
  {children}
130
134
  </Map>
@@ -136,13 +140,15 @@ function MapInner({
136
140
  <button
137
141
  type="button"
138
142
  onClick={resetToInitial}
143
+ aria-label="Reset map view"
139
144
  className={cn(
140
145
  'inline-flex items-center gap-2 px-3 py-2 rounded-lg',
141
146
  'bg-background/95 backdrop-blur-sm text-foreground text-sm font-medium',
142
- 'hover:bg-background transition-colors shadow-sm border border-border'
147
+ 'hover:bg-background transition-colors shadow-sm border border-border',
148
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring'
143
149
  )}
144
150
  >
145
- <RotateCcw className="w-4 h-4" />
151
+ <RotateCcw className="w-4 h-4" aria-hidden="true" />
146
152
  Reset
147
153
  </button>
148
154
  )}
@@ -156,10 +162,11 @@ function MapInner({
156
162
  className={cn(
157
163
  'inline-flex items-center gap-2 px-4 py-2 rounded-lg',
158
164
  'bg-background/95 backdrop-blur-sm text-foreground text-sm font-medium',
159
- 'hover:bg-background transition-colors shadow-sm border border-border'
165
+ 'hover:bg-background transition-colors shadow-sm border border-border',
166
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring'
160
167
  )}
161
168
  >
162
- <ExternalLink className="w-4 h-4" />
169
+ <ExternalLink className="w-4 h-4" aria-hidden="true" />
163
170
  {openInMapsLabel}
164
171
  </a>
165
172
  )}
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
 
3
- import { useState, useMemo, memo } from 'react'
3
+ import { useState, useMemo, memo, type KeyboardEvent } from 'react'
4
4
 
5
5
  import type { MapLegendProps, LegendItem } from '../types'
6
6
 
@@ -23,13 +23,13 @@ function LegendIcon({
23
23
  switch (type) {
24
24
  case 'circle':
25
25
  return (
26
- <svg width="16" height="16" viewBox="0 0 16 16">
26
+ <svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true">
27
27
  <circle cx="8" cy="8" r="6" fill={fill} />
28
28
  </svg>
29
29
  )
30
30
  case 'line':
31
31
  return (
32
- <svg width="16" height="16" viewBox="0 0 16 16">
32
+ <svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true">
33
33
  <line
34
34
  x1="0"
35
35
  y1="8"
@@ -43,14 +43,14 @@ function LegendIcon({
43
43
  )
44
44
  case 'fill':
45
45
  return (
46
- <svg width="16" height="16" viewBox="0 0 16 16">
46
+ <svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true">
47
47
  <rect x="1" y="1" width="14" height="14" fill={fill} rx="2" />
48
48
  </svg>
49
49
  )
50
50
  case 'symbol':
51
51
  default:
52
52
  return (
53
- <svg width="16" height="16" viewBox="0 0 16 16">
53
+ <svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true">
54
54
  <path
55
55
  d="M8 1l2.5 5 5.5.8-4 3.9.9 5.3L8 13.5l-4.9 2.5.9-5.3-4-3.9 5.5-.8z"
56
56
  fill={fill}
@@ -76,7 +76,9 @@ function MapLegendComponent({
76
76
  () => ({
77
77
  position: 'absolute',
78
78
  ...positionStyles[position],
79
- backgroundColor: 'white',
79
+ backgroundColor: 'var(--color-popover)',
80
+ color: 'var(--color-popover-foreground)',
81
+ border: '1px solid var(--color-border)',
80
82
  borderRadius: 8,
81
83
  boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
82
84
  padding: collapsed ? 8 : 12,
@@ -96,7 +98,7 @@ function MapLegendComponent({
96
98
  cursor: collapsible ? 'pointer' : 'default',
97
99
  fontWeight: 600,
98
100
  fontSize: 12,
99
- color: '#333',
101
+ color: 'var(--color-foreground)',
100
102
  marginBottom: collapsed ? 0 : 8,
101
103
  }),
102
104
  [collapsible, collapsed]
@@ -109,50 +111,79 @@ function MapLegendComponent({
109
111
  gap: 8,
110
112
  padding: '4px 0',
111
113
  fontSize: 12,
112
- color: '#666',
114
+ color: 'var(--color-muted-foreground)',
113
115
  cursor: onItemClick ? 'pointer' : 'default',
114
116
  }),
115
117
  [onItemClick]
116
118
  )
117
119
 
118
- const handleHeaderClick = collapsible ? () => setCollapsed(!collapsed) : undefined
120
+ const handleHeaderClick = collapsible ? () => setCollapsed((c) => !c) : undefined
119
121
 
120
122
  return (
121
123
  <div className={className} style={containerStyle}>
122
124
  {(title || collapsible) && (
123
- <div style={headerStyle} onClick={handleHeaderClick}>
125
+ <div
126
+ style={headerStyle}
127
+ onClick={handleHeaderClick}
128
+ {...(collapsible
129
+ ? {
130
+ role: 'button' as const,
131
+ tabIndex: 0,
132
+ 'aria-expanded': !collapsed,
133
+ onKeyDown: (e: KeyboardEvent) => {
134
+ if (e.key === 'Enter' || e.key === ' ') {
135
+ e.preventDefault()
136
+ setCollapsed((c) => !c)
137
+ }
138
+ },
139
+ }
140
+ : {})}
141
+ >
124
142
  {title && <span>{title}</span>}
125
143
  {collapsible && (
126
144
  <svg
127
145
  width="12"
128
146
  height="12"
129
147
  viewBox="0 0 12 12"
148
+ aria-hidden="true"
130
149
  style={{
131
150
  transform: collapsed ? 'rotate(-90deg)' : 'rotate(0deg)',
132
151
  transition: 'transform 0.2s',
133
152
  }}
134
153
  >
135
- <path d="M3 4.5L6 7.5L9 4.5" stroke="#666" fill="none" />
154
+ <path d="M3 4.5L6 7.5L9 4.5" stroke="currentColor" fill="none" />
136
155
  </svg>
137
156
  )}
138
157
  </div>
139
158
  )}
140
159
  {!collapsed && (
141
- <div>
160
+ <ul style={{ listStyle: 'none', margin: 0, padding: 0 }}>
142
161
  {items.map((item) => (
143
- <div
162
+ <li
144
163
  key={item.id}
145
164
  style={{
146
165
  ...itemStyle,
147
166
  opacity: item.visible === false ? 0.5 : 1,
148
167
  }}
149
168
  onClick={onItemClick ? () => onItemClick(item) : undefined}
169
+ {...(onItemClick
170
+ ? {
171
+ role: 'button' as const,
172
+ tabIndex: 0,
173
+ onKeyDown: (e: KeyboardEvent) => {
174
+ if (e.key === 'Enter' || e.key === ' ') {
175
+ e.preventDefault()
176
+ onItemClick(item)
177
+ }
178
+ },
179
+ }
180
+ : {})}
150
181
  >
151
182
  {item.icon || <LegendIcon type={item.type} color={item.color} />}
152
183
  <span>{item.label}</span>
153
- </div>
184
+ </li>
154
185
  ))}
155
- </div>
186
+ </ul>
156
187
  )}
157
188
  </div>
158
189
  )
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
 
3
- import { useCallback, memo, type ReactNode } from 'react'
3
+ import { useCallback, memo, type ReactNode, type KeyboardEvent } from 'react'
4
4
  import { Marker, type MarkerEvent, type MarkerDragEvent } from 'react-map-gl/maplibre'
5
5
  import type { LngLat } from 'maplibre-gl'
6
6
  import type { MarkerData } from '../types'
@@ -16,6 +16,8 @@ export interface MapMarkerProps {
16
16
  onDragEnd?: (marker: MarkerData, lngLat: LngLat) => void
17
17
  color?: string
18
18
  size?: number
19
+ /** Accessible label for the marker (used when onClick is set) */
20
+ ariaLabel?: string
19
21
  }
20
22
 
21
23
  const DefaultPin = memo(function DefaultPin({
@@ -31,6 +33,7 @@ const DefaultPin = memo(function DefaultPin({
31
33
  height={size}
32
34
  viewBox="0 0 24 24"
33
35
  fill="none"
36
+ aria-hidden="true"
34
37
  style={{ cursor: 'pointer' }}
35
38
  >
36
39
  <path
@@ -55,6 +58,7 @@ export const MapMarker = memo(function MapMarker({
55
58
  onDragEnd,
56
59
  color,
57
60
  size,
61
+ ariaLabel,
58
62
  }: MapMarkerProps) {
59
63
  const handleClick = useCallback(
60
64
  (e: MarkerEvent<MouseEvent>) => {
@@ -85,6 +89,19 @@ export const MapMarker = memo(function MapMarker({
85
89
  [onDragEnd, marker]
86
90
  )
87
91
 
92
+ const handleKeyDown = useCallback(
93
+ (e: KeyboardEvent) => {
94
+ if (!onClick) return
95
+ if (e.key === 'Enter' || e.key === ' ') {
96
+ e.preventDefault()
97
+ onClick(marker)
98
+ }
99
+ },
100
+ [onClick, marker]
101
+ )
102
+
103
+ const content = children ?? <DefaultPin color={color} size={size} />
104
+
88
105
  return (
89
106
  <Marker
90
107
  longitude={marker.longitude}
@@ -96,7 +113,19 @@ export const MapMarker = memo(function MapMarker({
96
113
  onDrag={handleDrag}
97
114
  onDragEnd={handleDragEnd}
98
115
  >
99
- {children ?? <DefaultPin color={color} size={size} />}
116
+ {onClick ? (
117
+ <div
118
+ role="button"
119
+ tabIndex={0}
120
+ aria-label={ariaLabel ?? `Map marker ${marker.id}`}
121
+ onKeyDown={handleKeyDown}
122
+ style={{ cursor: 'pointer', display: 'inline-flex', outline: 'none' }}
123
+ >
124
+ {content}
125
+ </div>
126
+ ) : (
127
+ content
128
+ )}
100
129
  </Marker>
101
130
  )
102
131
  })