@jini-ai/ui 0.5.4 → 0.5.6

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 (270) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/core/theme/validation.js +40 -38
  3. package/dist/features/a2ui/renderer.js +15 -13
  4. package/dist/features/about/react/components/AboutTab.js +64 -34
  5. package/dist/features/about/rules.d.ts +2 -2
  6. package/dist/features/about/rules.js +156 -129
  7. package/dist/features/admin-widgets/components/ImagePreviewModal.d.ts +4 -3
  8. package/dist/features/admin-widgets/components/ImagePreviewModal.js +6 -10
  9. package/dist/features/admin-widgets/components/InfoTip.d.ts +3 -2
  10. package/dist/features/admin-widgets/components/InfoTip.hooks.js +2 -0
  11. package/dist/features/admin-widgets/components/InfoTip.js +34 -7
  12. package/dist/features/admin-widgets/components/InfoTip.rules.d.ts +13 -0
  13. package/dist/features/admin-widgets/components/InfoTip.rules.js +43 -10
  14. package/dist/features/admin-widgets/components/Lightbox/Lightbox.d.ts +30 -0
  15. package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.d.ts +40 -0
  16. package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.js +128 -0
  17. package/dist/features/admin-widgets/components/Lightbox/Lightbox.js +18 -0
  18. package/dist/features/admin-widgets/components/MiddleTruncate.d.ts +14 -0
  19. package/dist/features/admin-widgets/components/MiddleTruncate.js +12 -0
  20. package/dist/features/admin-widgets/components/MiddleTruncate.rules.d.ts +20 -0
  21. package/dist/features/admin-widgets/components/MiddleTruncate.rules.js +21 -0
  22. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.d.ts +18 -0
  23. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.d.ts +16 -0
  24. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.js +45 -0
  25. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.js +18 -0
  26. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.d.ts +32 -0
  27. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.js +26 -0
  28. package/dist/features/admin-widgets/components/Select/Select.hooks.d.ts +21 -0
  29. package/dist/features/admin-widgets/components/Select/Select.hooks.js +24 -2
  30. package/dist/features/admin-widgets/components/Select/Select.js +4 -3
  31. package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.hooks.js +29 -14
  32. package/dist/features/admin-widgets/index.d.ts +14 -2
  33. package/dist/features/admin-widgets/index.js +7 -1
  34. package/dist/features/admin-widgets/styles/admin-widgets.css +1 -0
  35. package/dist/features/asset-grid/react/components/AssetCard.js +7 -1
  36. package/dist/features/asset-grid/react/components/AssetGrid.d.ts +1 -1
  37. package/dist/features/asset-grid/react/components/AssetGrid.js +38 -18
  38. package/dist/features/asset-grid/react/components/useAssetGridFilters.d.ts +21 -0
  39. package/dist/features/asset-grid/react/components/useAssetGridFilters.js +19 -0
  40. package/dist/features/asset-grid/react/hooks/useAssetGridKeyboardShortcuts.js +16 -11
  41. package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.d.ts +2 -0
  42. package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.js +35 -11
  43. package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.d.ts +6 -6
  44. package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.js +10 -129
  45. package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.d.ts +50 -0
  46. package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.js +95 -0
  47. package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.d.ts +56 -0
  48. package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.js +80 -0
  49. package/dist/features/asset-tree-browser/rules.js +40 -22
  50. package/dist/features/browser-chrome/rules.js +74 -70
  51. package/dist/features/charts/browser.js +11 -5
  52. package/dist/features/charts/react.js +2 -2
  53. package/dist/features/charts/table.js +2 -2
  54. package/dist/features/command-palette/react/hooks/useCommandPalette.js +3 -9
  55. package/dist/features/connectors/ConnectorsBrowser.d.ts +4 -4
  56. package/dist/features/connectors/ConnectorsBrowser.js +26 -14
  57. package/dist/features/connectors/components/ConnectorCard.js +67 -38
  58. package/dist/features/connectors/components/ConnectorDetailDrawer.js +62 -31
  59. package/dist/features/connectors/components/ConnectorGrid.js +11 -6
  60. package/dist/features/connectors/hooks/useConnectorAuthorization.js +6 -0
  61. package/dist/features/connectors/hooks/useConnectorCatalog.d.ts +2 -0
  62. package/dist/features/connectors/hooks/useConnectorCatalog.js +32 -13
  63. package/dist/features/connectors/hooks/useWiredConnectorsBrowser.d.ts +3 -3
  64. package/dist/features/connectors/rules.d.ts +8 -1
  65. package/dist/features/connectors/rules.js +42 -20
  66. package/dist/features/connectors/types.d.ts +11 -0
  67. package/dist/features/execution/constants.d.ts +4 -10
  68. package/dist/features/execution/constants.js +9 -94
  69. package/dist/features/execution/react/components/ByokProviderForm.d.ts +2 -4
  70. package/dist/features/execution/react/components/ByokProviderForm.js +140 -43
  71. package/dist/features/execution/react/components/ExecutionTab.d.ts +1 -2
  72. package/dist/features/execution/react/components/ExecutionTab.js +52 -30
  73. package/dist/features/execution/react/components/LocalCliAgentCard.js +12 -3
  74. package/dist/features/execution/react/components/LocalCliAgentList.js +14 -3
  75. package/dist/features/execution/react/components/LocalCliAgentSettings.js +14 -3
  76. package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +54 -36
  77. package/dist/features/execution/react/hooks/useReasoningControl.d.ts +1 -1
  78. package/dist/features/execution/react/hooks/useReasoningControl.js +116 -75
  79. package/dist/features/execution/rules.d.ts +13 -2
  80. package/dist/features/execution/rules.js +51 -11
  81. package/dist/features/execution/types.d.ts +6 -42
  82. package/dist/features/execution/types.js +0 -17
  83. package/dist/features/external-mcp/react/components/ExternalMcpTab.d.ts +6 -2
  84. package/dist/features/external-mcp/react/components/ExternalMcpTab.js +9 -2
  85. package/dist/features/file-dropzone/react/components/FileDropzone.js +24 -25
  86. package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.d.ts +2 -2
  87. package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.js +35 -30
  88. package/dist/features/file-dropzone/react/components/FileDropzoneThumbnailGrid.js +30 -24
  89. package/dist/features/file-dropzone/react/components/FileDropzoneZone.d.ts +14 -0
  90. package/dist/features/file-dropzone/react/components/FileDropzoneZone.js +26 -0
  91. package/dist/features/html-editor/canvas-content-wrapper.js +13 -13
  92. package/dist/features/html-editor/canvas-embed-placeholders.js +46 -37
  93. package/dist/features/html-editor/css.js +76 -69
  94. package/dist/features/html-editor/editor-blocks.js +47 -33
  95. package/dist/features/html-editor/editor-serialization.js +6 -5
  96. package/dist/features/html-editor/protected-elements.js +39 -28
  97. package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +4 -4
  98. package/dist/features/html-editor/source-splice.js +51 -30
  99. package/dist/features/i18n/dictionaries/settings-dialog.ja.js +1 -0
  100. package/dist/features/i18n/dictionaries/settings-dialog.zh-CN.js +1 -0
  101. package/dist/features/i18n/dictionaries/settings-dialog.zh-TW.js +1 -0
  102. package/dist/features/i18n/locale.js +20 -16
  103. package/dist/features/iframe-pool/react/dom-sync.js +8 -6
  104. package/dist/features/integrations/react/components/CodexInstallToggleButton.js +19 -4
  105. package/dist/features/integrations/react/components/IntegrationsTab.js +60 -14
  106. package/dist/features/interactive-ui/interactive-ui.css +1 -1
  107. package/dist/features/interactive-ui/providers/native/data-table.manifest.d.ts +6 -6
  108. package/dist/features/interactive-ui/providers/shadcn/data-table.js +10 -7
  109. package/dist/features/interactive-ui/providers/shadcn/data-table.manifest.d.ts +6 -6
  110. package/dist/features/lexical-rich-text-editor/mention-parser.js +60 -57
  111. package/dist/features/lexical-rich-text-editor/react/hooks/useKeyboardCommands.js +33 -38
  112. package/dist/features/lexical-rich-text-editor/rules.js +87 -74
  113. package/dist/features/lexical-rich-text-editor/serialize.js +27 -25
  114. package/dist/features/mcp-ui/secret-card.js +111 -61
  115. package/dist/features/mcp-ui/surfaces/confirmation.js +39 -21
  116. package/dist/features/mcp-ui/surfaces/document.d.ts +1 -1
  117. package/dist/features/mcp-ui/surfaces/document.js +10 -2
  118. package/dist/features/mcp-ui/surfaces/fields.js +30 -50
  119. package/dist/features/mcp-ui/surfaces/form.d.ts +6 -0
  120. package/dist/features/mcp-ui/surfaces/form.js +43 -21
  121. package/dist/features/mcp-ui/surfaces/outcome.js +30 -20
  122. package/dist/features/mcp-ui/surfaces/text-input.js +33 -21
  123. package/dist/features/mcp-ui/surfaces/tokens.d.ts +6 -1
  124. package/dist/features/mcp-ui/surfaces/tokens.js +5 -2
  125. package/dist/features/media-providers/constants.d.ts +1 -0
  126. package/dist/features/media-providers/constants.js +2 -81
  127. package/dist/features/media-providers/index.d.ts +1 -1
  128. package/dist/features/media-providers/ports.d.ts +2 -0
  129. package/dist/features/media-providers/react/components/MediaProviderCard.d.ts +22 -0
  130. package/dist/features/media-providers/react/components/MediaProviderCard.js +50 -0
  131. package/dist/features/media-providers/react/components/MediaProvidersTab.d.ts +5 -6
  132. package/dist/features/media-providers/react/components/MediaProvidersTab.js +40 -72
  133. package/dist/features/media-providers/react/components/media-providers-tab-labels.d.ts +11 -0
  134. package/dist/features/media-providers/react/components/media-providers-tab-labels.js +57 -0
  135. package/dist/features/media-providers/react/hooks/useMediaProvidersTab.d.ts +4 -2
  136. package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +37 -23
  137. package/dist/features/media-providers/rules.js +17 -10
  138. package/dist/features/media-providers/types.d.ts +4 -22
  139. package/dist/features/media-providers/types.js +3 -8
  140. package/dist/features/memory/formatters.js +127 -92
  141. package/dist/features/memory/react/components/MemoryConnectedPanel.js +92 -36
  142. package/dist/features/memory/react/components/MemoryList.js +37 -18
  143. package/dist/features/memory/react/hooks/useMemoryExtractions.store.js +42 -36
  144. package/dist/features/notifications/react/components/NotificationsTab.js +28 -28
  145. package/dist/features/observability/long-task.d.ts +0 -12
  146. package/dist/features/observability/long-task.js +15 -19
  147. package/dist/features/observability/resource-error.d.ts +0 -10
  148. package/dist/features/observability/resource-error.js +18 -13
  149. package/dist/features/observability/stuck-run.js +10 -6
  150. package/dist/features/observability/telemetry-url.d.ts +6 -0
  151. package/dist/features/observability/telemetry-url.js +16 -0
  152. package/dist/features/observability/white-screen.js +12 -24
  153. package/dist/features/panel-kit/fetch-query/adapter.react.d.ts +2 -2
  154. package/dist/features/panel-kit/fetch-query/adapter.react.js +4 -2
  155. package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +46 -33
  156. package/dist/features/panel-kit/helpers/standing-draft-local-backup.js +3 -1
  157. package/dist/features/panel-kit/hooks/use-settings-slice.hooks.js +3 -1
  158. package/dist/features/privacy/react/components/PrivacyTab.js +24 -13
  159. package/dist/features/progress-card/components/ProgressCard.js +7 -3
  160. package/dist/features/progress-card/reference-adapters.js +59 -54
  161. package/dist/features/project-locations/react/components/ProjectLocationsTab.js +24 -15
  162. package/dist/features/project-locations/react/hooks/useProjectLocationsTab.d.ts +8 -0
  163. package/dist/features/project-locations/react/hooks/useProjectLocationsTab.js +31 -23
  164. package/dist/features/resource-dashboard/react/components/ResourceBoard.js +6 -47
  165. package/dist/features/resource-dashboard/react/components/ResourceBoardView.d.ts +2 -2
  166. package/dist/features/resource-dashboard/react/components/ResourceBoardView.js +3 -6
  167. package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.d.ts +15 -0
  168. package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.js +35 -0
  169. package/dist/features/resource-dashboard/react/components/ResourceCard.js +5 -16
  170. package/dist/features/resource-dashboard/react/components/ResourceCardParts.d.ts +34 -0
  171. package/dist/features/resource-dashboard/react/components/ResourceCardParts.js +34 -0
  172. package/dist/features/resource-dashboard/react/components/ResourceRowList.js +3 -1
  173. package/dist/features/resource-dashboard/react/components/ResourceRowListItem.js +2 -2
  174. package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.d.ts +19 -0
  175. package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.js +11 -0
  176. package/dist/features/resource-dashboard/react/components/ResourceRowListView.d.ts +1 -1
  177. package/dist/features/resource-dashboard/react/components/ResourceRowListView.js +4 -4
  178. package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.d.ts +10 -0
  179. package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.js +20 -0
  180. package/dist/features/resource-dashboard/react/components/resourceBoardProps.d.ts +48 -0
  181. package/dist/features/resource-dashboard/react/components/resourceBoardProps.js +70 -0
  182. package/dist/features/resource-dashboard/react/components/resourceRowListProps.d.ts +19 -0
  183. package/dist/features/resource-dashboard/react/components/resourceRowListProps.js +14 -0
  184. package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.d.ts +16 -0
  185. package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.js +13 -0
  186. package/dist/features/resource-dashboard/rules.js +2 -8
  187. package/dist/features/sketch-editor/dom.js +150 -99
  188. package/dist/features/sketch-editor/react/components/SketchEditor.js +26 -15
  189. package/dist/features/skills/react/components/SkillDraftForm.js +13 -19
  190. package/dist/features/skills/react/components/SkillDraftForm.labels.d.ts +31 -0
  191. package/dist/features/skills/react/components/SkillDraftForm.labels.js +54 -0
  192. package/dist/features/skills/react/components/SkillRow.js +38 -18
  193. package/dist/features/skills/react/components/SkillRow.labels.d.ts +7 -0
  194. package/dist/features/skills/react/components/SkillRow.labels.js +18 -0
  195. package/dist/features/skills/react/components/SkillsTab.js +24 -14
  196. package/dist/features/skills/react/components/SkillsTab.labels.d.ts +7 -0
  197. package/dist/features/skills/react/components/SkillsTab.labels.js +11 -0
  198. package/dist/features/skills/rules.js +32 -23
  199. package/dist/features/source-config-list/agent-handles.js +2 -1
  200. package/dist/features/source-config-list/dependencies.js +53 -49
  201. package/dist/features/source-config-list/index.d.ts +3 -3
  202. package/dist/features/source-config-list/react/components/SourceConfigAddForm.d.ts +6 -5
  203. package/dist/features/source-config-list/react/components/SourceConfigAddForm.js +38 -7
  204. package/dist/features/source-config-list/react/components/SourceConfigField.js +69 -25
  205. package/dist/features/source-config-list/react/components/SourceConfigItemCard.d.ts +6 -5
  206. package/dist/features/source-config-list/react/components/SourceConfigItemCard.js +76 -20
  207. package/dist/features/source-config-list/react/components/SourceConfigListView.d.ts +5 -3
  208. package/dist/features/source-config-list/react/components/SourceConfigListView.js +33 -3
  209. package/dist/features/source-config-list/react/components/SourceConfigTestControl.js +17 -1
  210. package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.d.ts +11 -0
  211. package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.js +12 -0
  212. package/dist/features/source-config-list/types.d.ts +14 -0
  213. package/dist/features/tab-launcher-menu/react/components/TabLauncherMenu.js +25 -1
  214. package/dist/features/tab-launcher-menu/react/hooks/useTabLauncherMenu.js +15 -16
  215. package/dist/features/tab-strip/react/components/TabBar.js +8 -1
  216. package/dist/features/tabbed-dialog/react/components/TabbedDialog.js +8 -30
  217. package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.d.ts +15 -0
  218. package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.js +8 -0
  219. package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.d.ts +12 -0
  220. package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.js +6 -0
  221. package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.d.ts +27 -0
  222. package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.js +12 -0
  223. package/dist/features/tabbed-dialog/react/components/tabbedDialogView.d.ts +43 -0
  224. package/dist/features/tabbed-dialog/react/components/tabbedDialogView.js +59 -0
  225. package/dist/features/version-manager/dependencies.d.ts +3 -1
  226. package/dist/features/version-manager/dependencies.js +3 -2
  227. package/dist/features/version-manager/react/components/VersionManagerModal.js +10 -6
  228. package/dist/features/version-manager/react/hooks/useVersionManager.js +7 -4
  229. package/dist/features/viewer-shell/react/components/CommentSidePanel.js +103 -50
  230. package/dist/features/viewer-shell/react/components/MarkdownSplitPane.js +28 -8
  231. package/dist/features/viewer-shell/react/hooks/useCommentReorder.js +22 -16
  232. package/dist/features/viewer-shell/rules.js +19 -23
  233. package/dist/react/components/CustomSelect.d.ts +38 -1
  234. package/dist/react/components/CustomSelect.js +94 -38
  235. package/dist/react/components/OnboardingDropdown.js +20 -8
  236. package/dist/react/components/RemixIcon.stylesheet.js +3 -1
  237. package/dist/react/components/Toast.js +13 -2
  238. package/dist/react/components/TooltipLayer.js +5 -14
  239. package/dist/react/components/WorkingDirPicker.js +78 -50
  240. package/dist/react/components/remixicon-font-recovery.js +38 -30
  241. package/dist/react/components/select-popover.d.ts +8 -6
  242. package/dist/react/components/select-popover.js +33 -29
  243. package/dist/react/mcp-ui/McpUiHost.d.ts +1 -1
  244. package/dist/react/mcp-ui/McpUiHost.js +10 -11
  245. package/dist/react/mcp-ui/host-message-source.d.ts +14 -2
  246. package/dist/react/mcp-ui/host-message-source.js +15 -5
  247. package/dist/react/mcp-ui/mcp-ui-host-frame.d.ts +41 -0
  248. package/dist/react/mcp-ui/mcp-ui-host-frame.js +39 -0
  249. package/dist/renderers/annotation-canvas/react/components/AnnotationCanvas.js +97 -69
  250. package/dist/renderers/preview-modal-shell/react/components/PreviewModalShell.js +59 -30
  251. package/dist/renderers/preview-modal-shell/react/components/icons.js +4 -1
  252. package/dist/renderers/react/components/ArtifactView.js +9 -6
  253. package/dist/renderers/srcdoc/build.d.ts +4 -1
  254. package/dist/renderers/srcdoc/build.js +62 -48
  255. package/dist/styles/admin.css +29 -14
  256. package/dist/styles/lightbox.css +142 -0
  257. package/dist/styles/variables.css +128 -0
  258. package/dist/theme/apply.js +9 -5
  259. package/dist/utils/auto-open-file.d.ts +2 -1
  260. package/dist/utils/auto-open-file.js +69 -85
  261. package/dist/utils/markdown-scroll-sync.js +108 -87
  262. package/dist/utils/polygon-selection.js +25 -26
  263. package/dist/utils/smooth-scroll-to-top.d.ts +1 -1
  264. package/dist/utils/smooth-scroll-to-top.js +2 -32
  265. package/dist/utils/sse.js +26 -26
  266. package/dist/utils/unit-bezier.d.ts +7 -0
  267. package/dist/utils/unit-bezier.js +38 -0
  268. package/package.json +7 -10
  269. package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.d.ts +0 -13
  270. package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.js +0 -46
@@ -1,6 +1,5 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
- import { Icon } from '../../../../react/components/Icon.js';
4
3
  import { useGlobalKeydown } from '../../../../browser/useGlobalKeydown.js';
5
4
  import { useT } from '../../../i18n/index.js';
6
5
  import { useFileDropzone } from '../hooks/useFileDropzone.js';
@@ -8,6 +7,7 @@ import { useFileDropzonePreviews } from '../hooks/useFileDropzonePreviews.js';
8
7
  import { FileDropzoneThumbnailGrid } from './FileDropzoneThumbnailGrid.js';
9
8
  import { FileDropzoneLightbox } from './FileDropzoneLightbox.js';
10
9
  import { FileDropzoneNameList } from './FileDropzoneNameList.js';
10
+ import { FileDropzoneZone } from './FileDropzoneZone.js';
11
11
  // Stable identity for the "no files" case — `files ?? []` would otherwise
12
12
  // allocate a fresh array every render, and `useFileDropzonePreviews` keys its
13
13
  // effects on `files` by reference: a fresh array every render re-triggers
@@ -25,7 +25,7 @@ const NO_FILES = [];
25
25
  * drag/drop + click-to-browse resolving to a flat `File[]` — configured
26
26
  * differently; see `packages/ui/source-map.md` for the full writeup.
27
27
  */
28
- export function FileDropzone({ label, prompt, helper, accept, directory = false, enablePaste = false, files, onRemove, names, onRemoveName, onFiles, onZoneClick, onError, onProcessingStart, onBrowseFolder, secondaryAction, useFileDropzone: useFileDropzoneHook = useFileDropzone, useFileDropzonePreviews: useFileDropzonePreviewsHook = useFileDropzonePreviews, }) {
28
+ export function FileDropzone({ label, prompt, helper, accept, directory, enablePaste = false, files, onRemove, names, onRemoveName, onFiles, onZoneClick, onError, onProcessingStart, onBrowseFolder, secondaryAction, useFileDropzone: useFileDropzoneHook = useFileDropzone, useFileDropzonePreviews: useFileDropzonePreviewsHook = useFileDropzonePreviews, }) {
29
29
  const t = useT();
30
30
  const [lightboxFile, setLightboxFile] = useState(null);
31
31
  const dropzone = useFileDropzoneHook({ onFiles, onZoneClick, onError, onProcessingStart, enablePaste });
@@ -36,28 +36,27 @@ export function FileDropzone({ label, prompt, helper, accept, directory = false,
36
36
  setLightboxFile(null);
37
37
  },
38
38
  }, { enabled: lightboxFile !== null });
39
- function onZoneKeyDown(event) {
40
- if (event.key === 'Enter' || event.key === ' ') {
41
- event.preventDefault();
42
- dropzone.openPicker();
43
- }
44
- }
45
- const defaultPrompt = enablePaste ? t('Drag & drop, paste, or browse') : t('Drag & drop or browse');
46
- const promptText = prompt ? t(prompt) : defaultPrompt;
47
39
  const isSimpleVariant = names !== undefined;
48
- const showNamesInZone = !!names && names.length > 0 && !onRemoveName;
49
- const zoneText = showNamesInZone ? names.join(', ') : promptText;
50
- const directoryInputProps = directory ? { webkitdirectory: '', directory: '' } : {};
51
- return (_jsxs("div", { className: "jini-file-dropzone", children: [label ? _jsx("strong", { className: "jini-file-dropzone__label", children: t(label) }) : null, _jsxs("div", { className: "jini-file-dropzone__wrap", children: [_jsxs("div", { className: `jini-file-dropzone__zone${dropzone.dragOver ? ' is-drag-over' : ''}`, role: "button", tabIndex: 0, "aria-label": t('Add files — drag and drop{paste}, or click to browse', {
52
- paste: enablePaste ? t(', paste') : '',
53
- }), "data-testid": "file-dropzone-zone", onClick: dropzone.openPicker, onKeyDown: onZoneKeyDown, onDragEnter: dropzone.onZoneDragEnter, onDragOver: dropzone.onZoneDragOver, onDragLeave: dropzone.onZoneDragLeave, onDrop: dropzone.onZoneDrop, children: [_jsx("input", { ref: dropzone.inputRef, type: "file", multiple: true, accept: accept, className: "jini-file-dropzone__input", onClick: (event) => {
54
- // The input is nested inside the zone div so a real user
55
- // click on it (e.g. via `openPicker`'s own `input.click()`
56
- // call) would otherwise bubble straight back into the zone's
57
- // own `onClick={dropzone.openPicker}`, re-triggering it and
58
- // opening the file dialog a second time.
59
- event.stopPropagation();
60
- dropzone.onInputClick();
61
- }, onChange: dropzone.onInputChange, ...directoryInputProps }), _jsx("span", { className: "jini-file-dropzone__icon", children: _jsx(Icon, { name: "upload", size: 19 }) }), _jsx("span", { className: "jini-file-dropzone__prompt", children: zoneText }), !isSimpleVariant && helper ? _jsx("span", { className: "jini-file-dropzone__hint", children: t(helper) }) : null] }), onBrowseFolder ? (_jsx("button", { type: "button", className: "jini-file-dropzone__browse-folder", onClick: onBrowseFolder, children: t('Browse folder') })) : null] }), secondaryAction ? (_jsx("div", { className: "jini-file-dropzone__secondary", children: _jsx("button", { type: "button", className: "jini-file-dropzone__secondary-action", onClick: secondaryAction.onClick, children: t(secondaryAction.label) }) })) : null, names && names.length > 0 && onRemoveName ? (_jsx(FileDropzoneNameList, { names: names, onRemoveName: onRemoveName, ariaLabel: label ? t('{label} selections', { label: t(label) }) : t('Selections') })) : null, files && files.length > 0 ? (_jsx(FileDropzoneThumbnailGrid, { files: files, previews: previews, onSelect: setLightboxFile, onRemove: onRemove })) : null, isSimpleVariant && helper ? _jsx("p", { className: "jini-file-dropzone__helper", children: t(helper) }) : null, lightboxFile ? (_jsx(FileDropzoneLightbox, { file: lightboxFile, previews: previews, onClose: () => setLightboxFile(null) })) : null] }));
40
+ // The helper renders inside the zone for the thumbnail-grid variant, and as a
41
+ // paragraph under the staged names for the simple (`names`) variant.
42
+ const helperText = helper ? t(helper) : undefined;
43
+ return (_jsxs("div", { className: "jini-file-dropzone", children: [label ? _jsx("strong", { className: "jini-file-dropzone__label", children: t(label) }) : null, _jsxs("div", { className: "jini-file-dropzone__wrap", children: [_jsx(FileDropzoneZone, { dropzone: dropzone, zoneText: resolveZoneText({ t, enablePaste, names }, { prompt, onRemoveName }), accept: accept, directory: directory, enablePaste: enablePaste, hint: isSimpleVariant ? undefined : helperText }), onBrowseFolder ? (_jsx("button", { type: "button", className: "jini-file-dropzone__browse-folder", onClick: onBrowseFolder, children: t('Browse folder') })) : null] }), _jsx(FileDropzoneStaged, { previews: previews, lightboxFile: lightboxFile, setLightboxFile: setLightboxFile, secondaryAction: secondaryAction, label: label, names: names, onRemoveName: onRemoveName, files: files, onRemove: onRemove, simpleHelper: isSimpleVariant ? helperText : undefined })] }));
44
+ }
45
+ /**
46
+ * The zone's inner text: the staged names themselves for the simple variant
47
+ * when they can't be removed individually (no `onRemoveName` → no chip list),
48
+ * otherwise the host prompt or a default drag/drop(/paste)/browse prompt.
49
+ */
50
+ function resolveZoneText({ t, enablePaste, names }, { prompt, onRemoveName }) {
51
+ if (names && names.length > 0 && !onRemoveName)
52
+ return names.join(', ');
53
+ if (prompt)
54
+ return t(prompt);
55
+ return enablePaste ? t('Drag & drop, paste, or browse') : t('Drag & drop or browse');
56
+ }
57
+ /** Everything below the zone: the secondary action, the staged names/thumbnails, the simple-variant helper, and the lightbox. Empty `names`/`files` render nothing — `FileDropzoneNameList` and `FileDropzoneThumbnailGrid` both return `null` for an empty list. */
58
+ function FileDropzoneStaged({ previews, lightboxFile, setLightboxFile, secondaryAction, label, names, onRemoveName, files, onRemove, simpleHelper, }) {
59
+ const t = useT();
60
+ return (_jsxs(_Fragment, { children: [secondaryAction ? (_jsx("div", { className: "jini-file-dropzone__secondary", children: _jsx("button", { type: "button", className: "jini-file-dropzone__secondary-action", onClick: secondaryAction.onClick, children: t(secondaryAction.label) }) })) : null, names && onRemoveName ? (_jsx(FileDropzoneNameList, { names: names, onRemoveName: onRemoveName, ariaLabel: label ? t('{label} selections', { label: t(label) }) : t('Selections') })) : null, files ? (_jsx(FileDropzoneThumbnailGrid, { files: files, previews: previews, onSelect: setLightboxFile, onRemove: onRemove })) : null, simpleHelper ? _jsx("p", { className: "jini-file-dropzone__helper", children: simpleHelper }) : null, lightboxFile ? (_jsx(FileDropzoneLightbox, { file: lightboxFile, previews: previews, onClose: () => setLightboxFile(null) })) : null] }));
62
61
  }
63
62
  //# sourceMappingURL=FileDropzone.js.map
@@ -4,6 +4,6 @@ export interface FileDropzoneLightboxProps {
4
4
  previews: FileDropzonePreviewState;
5
5
  onClose: () => void;
6
6
  }
7
- /** Click-to-enlarge, kind-aware preview for one staged file — image, PDF embed, HTML mini-render, video/audio player, font specimen, or a text snippet, with a name/size fallback card for everything else. Portaled to `document.body`. Ported from `DesignSystemAssetDropzone.tsx`'s lightbox. */
8
- export declare function FileDropzoneLightbox({ file, previews, onClose }: FileDropzoneLightboxProps): import("react").ReactPortal;
7
+ /** Click-to-enlarge, kind-aware preview for one staged file — image, PDF embed, HTML mini-render, video/audio player, font specimen, or a text snippet, with a name/size fallback card for everything else. Rendered in the shared `Lightbox` (a top-layer native dialog, so no portal is needed). Ported from `DesignSystemAssetDropzone.tsx`'s lightbox. */
8
+ export declare function FileDropzoneLightbox({ file, previews, onClose }: FileDropzoneLightboxProps): import("react").JSX.Element;
9
9
  //# sourceMappingURL=FileDropzoneLightbox.d.ts.map
@@ -1,44 +1,49 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { createPortal } from 'react-dom';
3
2
  import { Icon } from '../../../../react/components/Icon.js';
3
+ import { Lightbox } from '../../../admin-widgets/components/Lightbox/Lightbox.js';
4
4
  import { useT } from '../../../i18n/index.js';
5
5
  import { FILE_DROPZONE_FONT_PANGRAM, FILE_DROPZONE_FONT_SPECIMEN, FILE_DROPZONE_GLYPH_ICON } from '../../constants.js';
6
6
  import { fileDropzoneExtensionLabel, fileDropzoneKind, fileDropzoneSizeLabel } from '../../rules.js';
7
- function renderStage(t, file, kind, previews) {
8
- const url = previews.previewUrls.get(file);
9
- if (kind === 'image' && url) {
10
- return _jsx("img", { src: url, alt: file.name, className: "jini-file-dropzone__lightbox-img" });
11
- }
12
- if (kind === 'video' && url) {
13
- return _jsx("video", { src: url, className: "jini-file-dropzone__lightbox-video", controls: true, autoPlay: true, playsInline: true });
14
- }
15
- if (kind === 'audio' && url) {
16
- return (_jsxs("div", { className: "jini-file-dropzone__lightbox-audio", children: [_jsx("span", { className: "jini-file-dropzone__lightbox-audio-icon", children: _jsx(Icon, { name: "volume", size: 34 }) }), _jsx("audio", { src: url, controls: true, className: "jini-file-dropzone__lightbox-audio-player" })] }));
17
- }
18
- if (kind === 'pdf' && url) {
19
- return _jsx("iframe", { src: url, className: "jini-file-dropzone__lightbox-frame", title: file.name });
20
- }
21
- if (kind === 'html' && url) {
22
- return (_jsx("iframe", { src: url, className: "jini-file-dropzone__lightbox-frame", title: file.name, sandbox: "allow-scripts allow-popups" }));
23
- }
24
- if (kind === 'font') {
7
+ /** Renders `render(url)` once the file's object URL has resolved, `null` (→ fallback card) until then. */
8
+ function withUrl(render) {
9
+ return ({ file, previews }) => {
10
+ const url = previews.previewUrls.get(file);
11
+ return url ? render(url, file) : null;
12
+ };
13
+ }
14
+ /**
15
+ * Per-kind stage renderers. Each returns `null` while its preview source is
16
+ * not available yet (no object URL, no loaded font family, no text snippet),
17
+ * so `renderStage` shows the name/size fallback card. Kinds with no entry
18
+ * (slides/other) always render the fallback card.
19
+ */
20
+ const STAGE_RENDERERS = {
21
+ image: withUrl((url, file) => _jsx("img", { src: url, alt: file.name, className: "jini-file-dropzone__lightbox-img" })),
22
+ video: withUrl((url) => _jsx("video", { src: url, className: "jini-file-dropzone__lightbox-video", controls: true, autoPlay: true, playsInline: true })),
23
+ audio: withUrl((url) => (_jsxs("div", { className: "jini-file-dropzone__lightbox-audio", children: [_jsx("span", { className: "jini-file-dropzone__lightbox-audio-icon", children: _jsx(Icon, { name: "volume", size: 34 }) }), _jsx("audio", { src: url, controls: true, className: "jini-file-dropzone__lightbox-audio-player" })] }))),
24
+ pdf: withUrl((url, file) => _jsx("iframe", { src: url, className: "jini-file-dropzone__lightbox-frame", title: file.name })),
25
+ html: withUrl((url, file) => (_jsx("iframe", { src: url, className: "jini-file-dropzone__lightbox-frame", title: file.name, sandbox: "allow-scripts allow-popups" }))),
26
+ font: ({ file, previews }) => {
25
27
  const family = previews.fontFamilies.get(file);
26
- if (family) {
27
- return (_jsxs("div", { className: "jini-file-dropzone__lightbox-font", style: { fontFamily: `'${family}'` }, children: [_jsxs("div", { className: "jini-file-dropzone__lightbox-font-hero", children: [FILE_DROPZONE_FONT_SPECIMEN, "Bb Cc"] }), _jsx("div", { className: "jini-file-dropzone__lightbox-font-pangram", children: FILE_DROPZONE_FONT_PANGRAM }), _jsxs("div", { className: "jini-file-dropzone__lightbox-font-scale", children: [_jsx("span", { style: { fontSize: 13 }, children: FILE_DROPZONE_FONT_PANGRAM }), _jsx("span", { style: { fontSize: 18 }, children: FILE_DROPZONE_FONT_PANGRAM }), _jsx("span", { style: { fontSize: 26 }, children: FILE_DROPZONE_FONT_PANGRAM })] })] }));
28
- }
29
- }
30
- if (kind === 'text') {
28
+ if (!family)
29
+ return null;
30
+ return (_jsxs("div", { className: "jini-file-dropzone__lightbox-font", style: { fontFamily: `'${family}'` }, children: [_jsxs("div", { className: "jini-file-dropzone__lightbox-font-hero", children: [FILE_DROPZONE_FONT_SPECIMEN, "Bb Cc"] }), _jsx("div", { className: "jini-file-dropzone__lightbox-font-pangram", children: FILE_DROPZONE_FONT_PANGRAM }), _jsxs("div", { className: "jini-file-dropzone__lightbox-font-scale", children: [_jsx("span", { style: { fontSize: 13 }, children: FILE_DROPZONE_FONT_PANGRAM }), _jsx("span", { style: { fontSize: 18 }, children: FILE_DROPZONE_FONT_PANGRAM }), _jsx("span", { style: { fontSize: 26 }, children: FILE_DROPZONE_FONT_PANGRAM })] })] }));
31
+ },
32
+ text: ({ t, file, previews }) => {
31
33
  const snippet = previews.textSnippets.get(file);
32
- if (snippet != null) {
33
- return _jsx("pre", { className: "jini-file-dropzone__lightbox-text", children: snippet || t('(empty file)') });
34
- }
35
- }
34
+ return snippet != null ? _jsx("pre", { className: "jini-file-dropzone__lightbox-text", children: snippet || t('(empty file)') }) : null;
35
+ },
36
+ };
37
+ function renderFallback({ t, file, kind }) {
36
38
  return (_jsxs("div", { className: "jini-file-dropzone__lightbox-fallback", children: [_jsx("span", { className: "jini-file-dropzone__lightbox-fallback-glyph", "data-kind": kind, children: _jsx(Icon, { name: FILE_DROPZONE_GLYPH_ICON[kind], size: 40 }) }), _jsx("p", { className: "jini-file-dropzone__lightbox-fallback-name", children: file.name }), _jsxs("p", { className: "jini-file-dropzone__lightbox-fallback-meta", children: [fileDropzoneExtensionLabel(file), " \u00B7 ", fileDropzoneSizeLabel(file.size) || '—'] }), _jsx("p", { className: "jini-file-dropzone__lightbox-fallback-hint", children: t('No inline preview for this file type.') })] }));
37
39
  }
38
- /** Click-to-enlarge, kind-aware preview for one staged file — image, PDF embed, HTML mini-render, video/audio player, font specimen, or a text snippet, with a name/size fallback card for everything else. Portaled to `document.body`. Ported from `DesignSystemAssetDropzone.tsx`'s lightbox. */
40
+ function renderStage({ t, file, kind, previews }) {
41
+ return STAGE_RENDERERS[kind]?.({ t, file, previews }) ?? renderFallback({ t, file, kind });
42
+ }
43
+ /** Click-to-enlarge, kind-aware preview for one staged file — image, PDF embed, HTML mini-render, video/audio player, font specimen, or a text snippet, with a name/size fallback card for everything else. Rendered in the shared `Lightbox` (a top-layer native dialog, so no portal is needed). Ported from `DesignSystemAssetDropzone.tsx`'s lightbox. */
39
44
  export function FileDropzoneLightbox({ file, previews, onClose }) {
40
45
  const t = useT();
41
46
  const kind = fileDropzoneKind(file);
42
- return createPortal(_jsx("div", { className: "jini-file-dropzone__lightbox", onClick: onClose, role: "presentation", children: _jsxs("div", { className: "jini-file-dropzone__lightbox-inner", onClick: (event) => event.stopPropagation(), role: "dialog", "aria-modal": "true", "aria-label": file.name, children: [_jsx("div", { className: "jini-file-dropzone__lightbox-stage", "data-kind": kind, children: renderStage(t, file, kind, previews) }), _jsxs("div", { className: "jini-file-dropzone__lightbox-bar", children: [_jsx("span", { className: "jini-file-dropzone__lightbox-name", title: file.name, children: file.name }), _jsx("span", { className: "jini-file-dropzone__lightbox-meta", children: fileDropzoneSizeLabel(file.size) }), _jsx("button", { type: "button", className: "jini-file-dropzone__lightbox-close", onClick: onClose, "aria-label": t('Close preview'), children: _jsx(Icon, { name: "close", size: 18 }) })] })] }) }), document.body);
47
+ return (_jsx(Lightbox, { open: true, title: file.name, onClose: onClose, className: "jini-file-dropzone__lightbox", labels: { close: t('Close preview') }, actions: _jsx("span", { className: "jini-file-dropzone__lightbox-meta", children: fileDropzoneSizeLabel(file.size) }), children: _jsx("div", { className: "jini-file-dropzone__lightbox-stage", "data-kind": kind, children: renderStage({ t, file, kind, previews }) }) }));
43
48
  }
44
49
  //# sourceMappingURL=FileDropzoneLightbox.js.map
@@ -3,33 +3,39 @@ import { Icon } from '../../../../react/components/Icon.js';
3
3
  import { useT } from '../../../i18n/index.js';
4
4
  import { FILE_DROPZONE_FONT_SPECIMEN, FILE_DROPZONE_GLYPH_ICON, FILE_DROPZONE_TEXT_THUMB_CHARS } from '../../constants.js';
5
5
  import { fileDropzoneExtensionLabel, fileDropzoneKind, fileDropzoneStagingKey } from '../../rules.js';
6
- function renderGlyph(file, kind) {
6
+ function renderGlyph({ file, kind }) {
7
7
  return (_jsxs("span", { className: "jini-file-dropzone__glyph", "data-kind": kind, children: [_jsx(Icon, { name: FILE_DROPZONE_GLYPH_ICON[kind], size: 20 }), _jsx("span", { className: "jini-file-dropzone__glyph-ext", children: fileDropzoneExtensionLabel(file) })] }));
8
8
  }
9
- function renderThumb(file, kind, previews) {
10
- const url = previews.previewUrls.get(file);
11
- if (kind === 'image' && url) {
12
- return _jsx("img", { src: url, alt: "", className: "jini-file-dropzone__thumb", loading: "lazy" });
13
- }
14
- if (kind === 'video' && url) {
15
- return (_jsx("video", { className: "jini-file-dropzone__thumb", src: url, muted: true, playsInline: true, preload: "metadata", tabIndex: -1 }));
16
- }
17
- if (kind === 'font') {
9
+ /**
10
+ * Per-kind thumbnail renderers. Each returns `null` while its preview source
11
+ * (object URL, loaded font family, non-blank text snippet) is not available
12
+ * yet, so `renderThumb` falls back to the extension glyph. Kinds with no entry
13
+ * (pdf/audio/slides/other) always render the glyph.
14
+ */
15
+ const THUMB_RENDERERS = {
16
+ image: ({ file, previews }) => {
17
+ const url = previews.previewUrls.get(file);
18
+ return url ? _jsx("img", { src: url, alt: "", className: "jini-file-dropzone__thumb", loading: "lazy" }) : null;
19
+ },
20
+ video: ({ file, previews }) => {
21
+ const url = previews.previewUrls.get(file);
22
+ return url ? (_jsx("video", { className: "jini-file-dropzone__thumb", src: url, muted: true, playsInline: true, preload: "metadata", tabIndex: -1 })) : null;
23
+ },
24
+ font: ({ file, previews }) => {
18
25
  const family = previews.fontFamilies.get(file);
19
- if (family) {
20
- return (_jsx("span", { className: "jini-file-dropzone__font-thumb", style: { fontFamily: `'${family}'` }, "aria-hidden": true, children: FILE_DROPZONE_FONT_SPECIMEN }));
21
- }
22
- }
23
- if (kind === 'html' && url) {
24
- return (_jsx("span", { className: "jini-file-dropzone__frame-thumb", "aria-hidden": true, children: _jsx("iframe", { className: "jini-file-dropzone__html-thumb", src: url, title: "", sandbox: "", tabIndex: -1 }) }));
25
- }
26
- if (kind === 'text') {
26
+ return family ? (_jsx("span", { className: "jini-file-dropzone__font-thumb", style: { fontFamily: `'${family}'` }, "aria-hidden": true, children: FILE_DROPZONE_FONT_SPECIMEN })) : null;
27
+ },
28
+ html: ({ file, previews }) => {
29
+ const url = previews.previewUrls.get(file);
30
+ return url ? (_jsx("span", { className: "jini-file-dropzone__frame-thumb", "aria-hidden": true, children: _jsx("iframe", { className: "jini-file-dropzone__html-thumb", src: url, title: "", sandbox: "", tabIndex: -1 }) })) : null;
31
+ },
32
+ text: ({ file, previews }) => {
27
33
  const snippet = previews.textSnippets.get(file);
28
- if (snippet && snippet.trim()) {
29
- return (_jsx("span", { className: "jini-file-dropzone__text-thumb", "aria-hidden": true, children: snippet.slice(0, FILE_DROPZONE_TEXT_THUMB_CHARS) }));
30
- }
31
- }
32
- return renderGlyph(file, kind);
34
+ return snippet?.trim() ? (_jsx("span", { className: "jini-file-dropzone__text-thumb", "aria-hidden": true, children: snippet.slice(0, FILE_DROPZONE_TEXT_THUMB_CHARS) })) : null;
35
+ },
36
+ };
37
+ function renderThumb({ file, kind, previews }) {
38
+ return THUMB_RENDERERS[kind]?.({ file, previews }) ?? renderGlyph({ file, kind });
33
39
  }
34
40
  /** Kind-aware thumbnail grid over staged files, with remove tiles and click-to-select (the host renders the lightbox — see `FileDropzoneLightbox`). Ported from `DesignSystemAssetDropzone.tsx`'s staged-asset grid. */
35
41
  export function FileDropzoneThumbnailGrid({ files, previews, onSelect, onRemove }) {
@@ -38,7 +44,7 @@ export function FileDropzoneThumbnailGrid({ files, previews, onSelect, onRemove
38
44
  return null;
39
45
  return (_jsx("ul", { className: "jini-file-dropzone__grid", "aria-label": t('Staged files'), children: files.map((file) => {
40
46
  const kind = fileDropzoneKind(file);
41
- return (_jsxs("li", { className: "jini-file-dropzone__tile", children: [_jsx("button", { type: "button", className: "jini-file-dropzone__tile-main", onClick: () => onSelect(file), title: file.name, children: renderThumb(file, kind, previews) }), onRemove ? (_jsx("button", { type: "button", className: "jini-file-dropzone__remove", "aria-label": t('Remove {name}', { name: file.name }), onClick: () => onRemove(file), children: _jsx(Icon, { name: "close", size: 12 }) })) : null, _jsx("span", { className: "jini-file-dropzone__caption", title: file.name, children: file.name })] }, fileDropzoneStagingKey(file)));
47
+ return (_jsxs("li", { className: "jini-file-dropzone__tile", children: [_jsx("button", { type: "button", className: "jini-file-dropzone__tile-main", onClick: () => onSelect(file), title: file.name, children: renderThumb({ file, kind, previews }) }), onRemove ? (_jsx("button", { type: "button", className: "jini-file-dropzone__remove", "aria-label": t('Remove {name}', { name: file.name }), onClick: () => onRemove(file), children: _jsx(Icon, { name: "close", size: 12 }) })) : null, _jsx("span", { className: "jini-file-dropzone__caption", title: file.name, children: file.name })] }, fileDropzoneStagingKey(file)));
42
48
  }) }));
43
49
  }
44
50
  //# sourceMappingURL=FileDropzoneThumbnailGrid.js.map
@@ -0,0 +1,14 @@
1
+ import type { UseFileDropzoneResult } from '../hooks/useFileDropzone.js';
2
+ export interface FileDropzoneZoneProps {
3
+ dropzone: UseFileDropzoneResult;
4
+ /** Text shown inside the zone (the prompt, or the staged names for the simple variant without remove chips). */
5
+ zoneText: string;
6
+ accept?: string | undefined;
7
+ directory?: boolean | undefined;
8
+ enablePaste?: boolean | undefined;
9
+ /** Already-translated hint shown inside the zone under the prompt. */
10
+ hint?: string | undefined;
11
+ }
12
+ /** The keyboard-activatable drag/drop/click zone of `FileDropzone`, with its nested native file input. Internal to the file-dropzone feature. */
13
+ export declare function FileDropzoneZone({ dropzone, zoneText, accept, directory, enablePaste, hint }: FileDropzoneZoneProps): import("react").JSX.Element;
14
+ //# sourceMappingURL=FileDropzoneZone.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Icon } from '../../../../react/components/Icon.js';
3
+ import { useT } from '../../../i18n/index.js';
4
+ /** The keyboard-activatable drag/drop/click zone of `FileDropzone`, with its nested native file input. Internal to the file-dropzone feature. */
5
+ export function FileDropzoneZone({ dropzone, zoneText, accept, directory, enablePaste, hint }) {
6
+ const t = useT();
7
+ function onZoneKeyDown(event) {
8
+ if (event.key === 'Enter' || event.key === ' ') {
9
+ event.preventDefault();
10
+ dropzone.openPicker();
11
+ }
12
+ }
13
+ const directoryInputProps = directory ? { webkitdirectory: '', directory: '' } : {};
14
+ return (_jsxs("div", { className: `jini-file-dropzone__zone${dropzone.dragOver ? ' is-drag-over' : ''}`, role: "button", tabIndex: 0, "aria-label": t('Add files — drag and drop{paste}, or click to browse', {
15
+ paste: enablePaste ? t(', paste') : '',
16
+ }), "data-testid": "file-dropzone-zone", onClick: dropzone.openPicker, onKeyDown: onZoneKeyDown, onDragEnter: dropzone.onZoneDragEnter, onDragOver: dropzone.onZoneDragOver, onDragLeave: dropzone.onZoneDragLeave, onDrop: dropzone.onZoneDrop, children: [_jsx("input", { ref: dropzone.inputRef, type: "file", multiple: true, accept: accept, className: "jini-file-dropzone__input", onClick: (event) => {
17
+ // The input is nested inside the zone div so a real user
18
+ // click on it (e.g. via `openPicker`'s own `input.click()`
19
+ // call) would otherwise bubble straight back into the zone's
20
+ // own `onClick={dropzone.openPicker}`, re-triggering it and
21
+ // opening the file dialog a second time.
22
+ event.stopPropagation();
23
+ dropzone.onInputClick();
24
+ }, onChange: dropzone.onInputChange, ...directoryInputProps }), _jsx("span", { className: "jini-file-dropzone__icon", children: _jsx(Icon, { name: "upload", size: 19 }) }), _jsx("span", { className: "jini-file-dropzone__prompt", children: zoneText }), hint ? _jsx("span", { className: "jini-file-dropzone__hint", children: hint }) : null] }));
25
+ }
26
+ //# sourceMappingURL=FileDropzoneZone.js.map
@@ -54,26 +54,26 @@ function buildWrapperElement(doc, node) {
54
54
  * (each moved once, no copying).
55
55
  */
56
56
  export function applyCanvasContentWrapper(body, chain) {
57
- if (!chain || chain.length === 0)
57
+ if (!chain)
58
+ return;
59
+ // `[]` is the same no-op as `undefined`; reading the innermost node here doubles as that length check.
60
+ const innermostNode = chain[chain.length - 1];
61
+ if (!innermostNode)
58
62
  return;
59
63
  // Re-entrancy guard — see WRAPPER_ROOT_MARKER's own doc.
60
64
  if (body.querySelector(`[${WRAPPER_ROOT_MARKER}]`))
61
65
  return;
62
66
  const doc = body.ownerDocument;
63
- // Built innermost-first via `reduceRight` (each level's element wraps the previous result), which
64
- // also hands back a reference to the innermost level in the same pass — avoids indexing into a
65
- // built array by position, which `chain`'s `readonly T[]` (not a fixed-length tuple) type cannot
66
- // statically prove is in bounds even though the length guard above makes it always true here.
67
- let innermost;
68
- const outermost = chain.reduceRight((child, node) => {
67
+ // Built innermost-first via `reduceRight` over the remaining ancestors (each level's element wraps
68
+ // the previous result), seeded with the innermost level itself — so both ends of the chain are
69
+ // plain `HTMLElement`s with no "maybe undefined" result to guard. (The old seed was `undefined`,
70
+ // which forced an `if (!outermost || !innermost) return` the length guard above made unreachable.)
71
+ const innermost = buildWrapperElement(doc, innermostNode);
72
+ const outermost = chain.slice(0, -1).reduceRight((child, node) => {
69
73
  const el = buildWrapperElement(doc, node);
70
- if (child)
71
- el.appendChild(child);
72
- innermost ??= el;
74
+ el.appendChild(child);
73
75
  return el;
74
- }, undefined);
75
- if (!outermost || !innermost)
76
- return; // Unreachable given the `chain.length === 0` guard above.
76
+ }, innermost);
77
77
  outermost.setAttribute(WRAPPER_ROOT_MARKER, '');
78
78
  // Move body's existing children into the innermost wrapper level, preserving order. Snapshotted
79
79
  // into an array first — `body.childNodes` is a LIVE collection that would shrink out from under a
@@ -224,39 +224,60 @@ export function applyCanvasEmbedPlaceholders(body, describe) {
224
224
  // Skip existing embed cards and all chrome before calling the host. Runtime cards still
225
225
  // re-describe their direct marker so theme changes can refresh its bounded footprint.
226
226
  const existingCard = el.closest(`[${CARD_ROOT_MARKER}]`);
227
- if (existingCard && (!existingCard.hasAttribute(CARD_RUNTIME_MARKER)
228
- || el.parentElement !== existingCard || el.hasAttribute(CARD_CHROME_MARKER)))
227
+ if (existingCard && !canRefreshRuntimeCard({ el, card: existingCard }, {}))
229
228
  continue;
230
229
  const descriptor = describe(el);
231
230
  if (!descriptor)
232
231
  continue;
233
- if (existingCard) {
234
- if (descriptor.presentation === 'runtime')
235
- applyRuntimeFootprint(el, existingCard, descriptor);
236
- continue;
237
- }
238
- const parent = el.parentNode;
239
- if (!parent)
240
- continue; // Unreachable for a live `body` descendant; defensive only.
241
- const card = buildPlaceholderCard(doc, descriptor);
242
- // Respect the author's own box (e.g. `style="max-width:600px"` on the marker) by carrying its
243
- // inline style onto the card BEFORE the card's own chrome declarations, so same-named properties
244
- // in `CARD_STYLE` win on the cascade's normal "last declaration wins" rule while anything the
245
- // author set that `CARD_STYLE` doesn't touch (like `max-width`) still applies unopposed. Guarded
246
- // on presence so a marker with no `style` attribute at all is a no-op, not a leading `;`.
247
- const authoredStyle = el.getAttribute('style');
248
- if (authoredStyle && descriptor.presentation !== 'runtime')
249
- card.setAttribute('style', `${authoredStyle};${card.getAttribute('style')}`);
250
- applyResolvedMaxWidth(el, card);
232
+ updatePlaceholder({ el, doc, descriptor, existingCard }, {});
233
+ }
234
+ }
235
+ function canRefreshRuntimeCard({ el, card }, _options = {}) {
236
+ return card.hasAttribute(CARD_RUNTIME_MARKER) && el.parentElement === card && !el.hasAttribute(CARD_CHROME_MARKER);
237
+ }
238
+ function updatePlaceholder({ el, doc, descriptor, existingCard }, _options = {}) {
239
+ if (existingCard) {
251
240
  if (descriptor.presentation === 'runtime')
252
- applyRuntimeFootprint(el, card, descriptor);
253
- parent.insertBefore(card, el);
254
- card.appendChild(el); // Moves the SAME node (auto-detaches from `parent`) — never cloned.
255
- ensureOverlayRule(doc);
241
+ applyRuntimeFootprint(el, existingCard, descriptor);
242
+ return;
256
243
  }
244
+ const parent = el.parentNode;
245
+ if (!parent)
246
+ return; // Unreachable for a live `body` descendant; defensive only.
247
+ const card = buildPlaceholderCard(doc, descriptor);
248
+ // Respect the author's own box (e.g. `style="max-width:600px"` on the marker) by carrying its
249
+ // inline style onto the card BEFORE the card's own chrome declarations, so same-named properties
250
+ // in `CARD_STYLE` win on the cascade's normal "last declaration wins" rule while anything the
251
+ // author set that `CARD_STYLE` doesn't touch (like `max-width`) still applies unopposed. Guarded
252
+ // on presence so a marker with no `style` attribute at all is a no-op, not a leading `;`.
253
+ const authoredStyle = el.getAttribute('style');
254
+ if (authoredStyle && descriptor.presentation !== 'runtime')
255
+ card.setAttribute('style', `${authoredStyle};${card.getAttribute('style')}`);
256
+ applyResolvedMaxWidth(el, card);
257
+ if (descriptor.presentation === 'runtime')
258
+ applyRuntimeFootprint(el, card, descriptor);
259
+ parent.insertBefore(card, el);
260
+ card.appendChild(el); // Moves the SAME node (auto-detaches from `parent`) — never cloned.
261
+ ensureOverlayRule(doc);
257
262
  }
258
263
  /** Geometry belongs to canvas DOM only; arbitrary transforms/min-height cannot defeat the clamp. */
259
264
  function applyRuntimeFootprint(el, card, descriptor) {
265
+ const resolved = measureAuthoredHeight({ el }, {});
266
+ const native = el.getAttribute('height');
267
+ const declared = descriptor.declaredHeight ?? (resolved?.endsWith('px') ? Number.parseFloat(resolved) : undefined);
268
+ card.style.height = `${editorBlockHeight({ declaredHeight: declared, nativeHeight: native ? Number(native) : undefined, inline: descriptor.inline }, {})}px`;
269
+ card.style.minHeight = '0';
270
+ card.style.maxHeight = descriptor.inline ? '160px' : '960px';
271
+ card.style.overflow = 'hidden';
272
+ if (descriptor.inline) {
273
+ card.style.display = 'inline-flex';
274
+ card.style.verticalAlign = 'middle';
275
+ }
276
+ // The marker is the selectable hit surface, never an authored layout/transform or media view.
277
+ el.style.setProperty('transform', 'none', 'important');
278
+ el.style.setProperty('overflow', 'hidden', 'important');
279
+ }
280
+ function measureAuthoredHeight({ el }, _options = {}) {
260
281
  // Re-measure the authored shell after theme links settle, without our selection overlay's
261
282
  // !important auto-height masking its declarations. No component/model styles are changed.
262
283
  const overlay = el.ownerDocument.head.querySelector(`style[${OVERLAY_STYLE_MARKER}]`);
@@ -272,18 +293,6 @@ function applyRuntimeFootprint(el, card, descriptor) {
272
293
  if (sheet)
273
294
  sheet.disabled = wasDisabled ?? false;
274
295
  }
275
- const native = el.getAttribute('height');
276
- const declared = descriptor.declaredHeight ?? (resolved?.endsWith('px') ? Number.parseFloat(resolved) : undefined);
277
- card.style.height = `${editorBlockHeight({ declaredHeight: declared, nativeHeight: native ? Number(native) : undefined, inline: descriptor.inline }, {})}px`;
278
- card.style.minHeight = '0';
279
- card.style.maxHeight = descriptor.inline ? '160px' : '960px';
280
- card.style.overflow = 'hidden';
281
- if (descriptor.inline) {
282
- card.style.display = 'inline-flex';
283
- card.style.verticalAlign = 'middle';
284
- }
285
- // The marker is the selectable hit surface, never an authored layout/transform or media view.
286
- el.style.setProperty('transform', 'none', 'important');
287
- el.style.setProperty('overflow', 'hidden', 'important');
296
+ return resolved;
288
297
  }
289
298
  //# sourceMappingURL=canvas-embed-placeholders.js.map