@k2b/ui 0.9.1 → 0.11.0

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 (180) hide show
  1. package/dist/browser/actions/Button.js +15 -7
  2. package/dist/browser/actions/Button.js.map +1 -1
  3. package/dist/browser/actions/ContextMenu.js +55 -15
  4. package/dist/browser/actions/ContextMenu.js.map +1 -1
  5. package/dist/browser/actions/Dropdown.js +39 -15
  6. package/dist/browser/actions/Dropdown.js.map +1 -1
  7. package/dist/browser/actions/FilterChip.js +1 -7
  8. package/dist/browser/actions/FilterChip.js.map +1 -1
  9. package/dist/browser/actions/SplitButton.js +0 -3
  10. package/dist/browser/actions/SplitButton.js.map +1 -1
  11. package/dist/browser/chat/ChatComposer.js +78 -91
  12. package/dist/browser/chat/ChatComposer.js.map +1 -1
  13. package/dist/browser/chat/ChatContextPopup.js +47 -21
  14. package/dist/browser/chat/ChatContextPopup.js.map +1 -1
  15. package/dist/browser/chat/ChatPrimitives.js +221 -232
  16. package/dist/browser/chat/ChatPrimitives.js.map +1 -1
  17. package/dist/browser/chat/index.js +3 -2
  18. package/dist/browser/chat/index.js.map +1 -1
  19. package/dist/browser/content/Chart.js +99 -106
  20. package/dist/browser/content/Chart.js.map +1 -1
  21. package/dist/browser/content/ChartExplorer.js +3 -6
  22. package/dist/browser/content/ChartExplorer.js.map +1 -1
  23. package/dist/browser/content/FileBrowser.js +1 -1
  24. package/dist/browser/content/FileBrowser.js.map +1 -1
  25. package/dist/browser/content/FileTree.js +1 -1
  26. package/dist/browser/content/FileTree.js.map +1 -1
  27. package/dist/browser/content/FileView.js +304 -287
  28. package/dist/browser/content/FileView.js.map +1 -1
  29. package/dist/browser/content/Lightbox.js +18 -0
  30. package/dist/browser/content/Lightbox.js.map +1 -1
  31. package/dist/browser/content/PdfPreview.js +68 -43
  32. package/dist/browser/content/PdfPreview.js.map +1 -1
  33. package/dist/browser/content/ZoomPanViewport.js +51 -52
  34. package/dist/browser/content/ZoomPanViewport.js.map +1 -1
  35. package/dist/browser/feedback/HoverPreview.js +391 -0
  36. package/dist/browser/feedback/HoverPreview.js.map +1 -0
  37. package/dist/browser/feedback/Tooltip.js +50 -8
  38. package/dist/browser/feedback/Tooltip.js.map +1 -1
  39. package/dist/browser/feedback/dialog-core.js +21 -3
  40. package/dist/browser/feedback/dialog-core.js.map +1 -1
  41. package/dist/browser/feedback/index.js +1 -0
  42. package/dist/browser/feedback/index.js.map +1 -1
  43. package/dist/browser/inputs/AutocompleteEditor.js +5 -4
  44. package/dist/browser/inputs/AutocompleteEditor.js.map +1 -1
  45. package/dist/browser/inputs/DatePicker.js +10 -0
  46. package/dist/browser/inputs/DatePicker.js.map +1 -1
  47. package/dist/browser/inputs/FileInputs.js +46 -36
  48. package/dist/browser/inputs/FileInputs.js.map +1 -1
  49. package/dist/browser/inputs/SelectChip.js +2 -1
  50. package/dist/browser/inputs/SelectChip.js.map +1 -1
  51. package/dist/browser/inputs/choice.js +5 -1
  52. package/dist/browser/inputs/choice.js.map +1 -1
  53. package/dist/browser/inputs/markdown/MarkdownEditor.js +173 -173
  54. package/dist/browser/inputs/markdown/MarkdownEditor.js.map +1 -1
  55. package/dist/browser/inputs/markdown/Toolbar.js +31 -34
  56. package/dist/browser/inputs/markdown/Toolbar.js.map +1 -1
  57. package/dist/browser/internal/focus-return.js +61 -0
  58. package/dist/browser/internal/focus-return.js.map +1 -0
  59. package/dist/browser/layout/AppOverview.js +1 -1
  60. package/dist/browser/layout/AppOverview.js.map +1 -1
  61. package/dist/browser/layout/AppWorkspace.js +105 -77
  62. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  63. package/dist/browser/layout/DetailPanel.js +16 -15
  64. package/dist/browser/layout/DetailPanel.js.map +1 -1
  65. package/dist/browser/layout/FloatingWindow.js +3 -1
  66. package/dist/browser/layout/FloatingWindow.js.map +1 -1
  67. package/dist/browser/layout/PanelDialog.js +10 -9
  68. package/dist/browser/layout/PanelDialog.js.map +1 -1
  69. package/dist/browser/layout/Panes.js +82 -81
  70. package/dist/browser/layout/Panes.js.map +1 -1
  71. package/dist/browser/layout/SidebarItemPreview.js +48 -136
  72. package/dist/browser/layout/SidebarItemPreview.js.map +1 -1
  73. package/dist/browser/layout/app-workspace-controller.js +35 -4
  74. package/dist/browser/layout/app-workspace-controller.js.map +1 -1
  75. package/dist/browser/surfaces/ProgressBar.js.map +1 -1
  76. package/dist/browser/surfaces/ProgressRing.js +72 -0
  77. package/dist/browser/surfaces/ProgressRing.js.map +1 -0
  78. package/dist/browser/surfaces/index.js +1 -0
  79. package/dist/browser/surfaces/index.js.map +1 -1
  80. package/dist/ssr/actions/Button.js +15 -7
  81. package/dist/ssr/actions/Button.js.map +1 -1
  82. package/dist/ssr/actions/ContextMenu.js +55 -15
  83. package/dist/ssr/actions/ContextMenu.js.map +1 -1
  84. package/dist/ssr/actions/Dropdown.js +31 -12
  85. package/dist/ssr/actions/Dropdown.js.map +1 -1
  86. package/dist/ssr/actions/FilterChip.js +1 -7
  87. package/dist/ssr/actions/FilterChip.js.map +1 -1
  88. package/dist/ssr/actions/SplitButton.js +0 -3
  89. package/dist/ssr/actions/SplitButton.js.map +1 -1
  90. package/dist/ssr/chat/ChatComposer.js +61 -10
  91. package/dist/ssr/chat/ChatComposer.js.map +1 -1
  92. package/dist/ssr/chat/ChatContextPopup.js +19 -5
  93. package/dist/ssr/chat/ChatContextPopup.js.map +1 -1
  94. package/dist/ssr/chat/ChatPrimitives.js +104 -74
  95. package/dist/ssr/chat/ChatPrimitives.js.map +1 -1
  96. package/dist/ssr/chat/index.js +3 -2
  97. package/dist/ssr/chat/index.js.map +1 -1
  98. package/dist/ssr/content/Chart.js +22 -11
  99. package/dist/ssr/content/Chart.js.map +1 -1
  100. package/dist/ssr/content/ChartExplorer.js +3 -6
  101. package/dist/ssr/content/ChartExplorer.js.map +1 -1
  102. package/dist/ssr/content/FileBrowser.js +1 -1
  103. package/dist/ssr/content/FileBrowser.js.map +1 -1
  104. package/dist/ssr/content/FileTree.js +1 -1
  105. package/dist/ssr/content/FileTree.js.map +1 -1
  106. package/dist/ssr/content/FileView.js +105 -33
  107. package/dist/ssr/content/FileView.js.map +1 -1
  108. package/dist/ssr/content/Lightbox.js +17 -0
  109. package/dist/ssr/content/Lightbox.js.map +1 -1
  110. package/dist/ssr/content/PdfPreview.js +44 -14
  111. package/dist/ssr/content/PdfPreview.js.map +1 -1
  112. package/dist/ssr/content/ZoomPanViewport.js +11 -3
  113. package/dist/ssr/content/ZoomPanViewport.js.map +1 -1
  114. package/dist/ssr/feedback/HoverPreview.js +360 -0
  115. package/dist/ssr/feedback/HoverPreview.js.map +1 -0
  116. package/dist/ssr/feedback/Tooltip.js +50 -8
  117. package/dist/ssr/feedback/Tooltip.js.map +1 -1
  118. package/dist/ssr/feedback/dialog-core.js +21 -3
  119. package/dist/ssr/feedback/dialog-core.js.map +1 -1
  120. package/dist/ssr/feedback/index.js +1 -0
  121. package/dist/ssr/feedback/index.js.map +1 -1
  122. package/dist/ssr/inputs/AutocompleteEditor.js +5 -4
  123. package/dist/ssr/inputs/AutocompleteEditor.js.map +1 -1
  124. package/dist/ssr/inputs/DatePicker.js +5 -0
  125. package/dist/ssr/inputs/DatePicker.js.map +1 -1
  126. package/dist/ssr/inputs/FileInputs.js +29 -11
  127. package/dist/ssr/inputs/FileInputs.js.map +1 -1
  128. package/dist/ssr/inputs/SelectChip.js +2 -1
  129. package/dist/ssr/inputs/SelectChip.js.map +1 -1
  130. package/dist/ssr/inputs/choice.js +5 -1
  131. package/dist/ssr/inputs/choice.js.map +1 -1
  132. package/dist/ssr/inputs/markdown/MarkdownEditor.js +46 -10
  133. package/dist/ssr/inputs/markdown/MarkdownEditor.js.map +1 -1
  134. package/dist/ssr/inputs/markdown/Toolbar.js +30 -2
  135. package/dist/ssr/inputs/markdown/Toolbar.js.map +1 -1
  136. package/dist/ssr/internal/focus-return.js +61 -0
  137. package/dist/ssr/internal/focus-return.js.map +1 -0
  138. package/dist/ssr/layout/AppOverview.js +1 -1
  139. package/dist/ssr/layout/AppOverview.js.map +1 -1
  140. package/dist/ssr/layout/AppWorkspace.js +84 -66
  141. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  142. package/dist/ssr/layout/DetailPanel.js +16 -15
  143. package/dist/ssr/layout/DetailPanel.js.map +1 -1
  144. package/dist/ssr/layout/FloatingWindow.js +3 -1
  145. package/dist/ssr/layout/FloatingWindow.js.map +1 -1
  146. package/dist/ssr/layout/PanelDialog.js +10 -9
  147. package/dist/ssr/layout/PanelDialog.js.map +1 -1
  148. package/dist/ssr/layout/Panes.js +39 -8
  149. package/dist/ssr/layout/Panes.js.map +1 -1
  150. package/dist/ssr/layout/SidebarItemPreview.js +36 -108
  151. package/dist/ssr/layout/SidebarItemPreview.js.map +1 -1
  152. package/dist/ssr/layout/app-workspace-controller.js +35 -4
  153. package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
  154. package/dist/ssr/surfaces/ProgressBar.js.map +1 -1
  155. package/dist/ssr/surfaces/ProgressRing.js +31 -0
  156. package/dist/ssr/surfaces/ProgressRing.js.map +1 -0
  157. package/dist/ssr/surfaces/index.js +1 -0
  158. package/dist/ssr/surfaces/index.js.map +1 -1
  159. package/dist/styles.css +1 -1
  160. package/dist/types/actions/Button.d.ts +5 -0
  161. package/dist/types/actions/Dropdown.d.ts +5 -1
  162. package/dist/types/actions/SplitButton.d.ts +1 -0
  163. package/dist/types/chat/ChatContextPopup.d.ts +8 -0
  164. package/dist/types/chat/index.d.ts +3 -2
  165. package/dist/types/feedback/HoverPreview.d.ts +83 -0
  166. package/dist/types/feedback/Tooltip.d.ts +6 -0
  167. package/dist/types/feedback/index.d.ts +2 -0
  168. package/dist/types/feedback/prompts.d.ts +9 -6
  169. package/dist/types/inputs/SelectChip.d.ts +1 -0
  170. package/dist/types/inputs/completion/overlay.d.ts +3 -1
  171. package/dist/types/internal/focus-return.d.ts +20 -0
  172. package/dist/types/intl/Format.d.ts +16 -8
  173. package/dist/types/layout/AppWorkspace.d.ts +14 -0
  174. package/dist/types/layout/BottomSheet.d.ts +6 -1
  175. package/dist/types/layout/SidebarItemPreview.d.ts +1 -1
  176. package/dist/types/layout/app-workspace-controller.d.ts +5 -0
  177. package/dist/types/surfaces/ProgressBar.d.ts +1 -1
  178. package/dist/types/surfaces/ProgressRing.d.ts +13 -0
  179. package/dist/types/surfaces/index.d.ts +2 -0
  180. package/package.json +3 -2
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["content/FileView.tsx"],"sourcesContent":["/**\n * FileView — renders one file through a small renderer registry keyed by\n * media type / path. Editing is enabled purely by the presence of `save`;\n * without it every renderer is read-only. IDE-style chrome: editors reuse\n * the markdown editor's surface (toolbar with an in-toolbar save, Ctrl/Cmd+S),\n * previews are quiet paper panels with icon-only actions overlaid top-right.\n * Custom renderers are passed per instance, which keeps SSR requests and\n * independently mounted applications isolated.\n */\n\nimport { mutation } from \"@k2b/stdlib/solid\";\nimport {\n type Component,\n createEffect,\n createMemo,\n createResource,\n createSignal,\n For,\n type JSX,\n Match,\n onCleanup,\n onMount,\n Show,\n Switch,\n untrack,\n} from \"solid-js\";\nimport { Button } from \"../actions/Button\";\nimport { prompts } from \"../feedback/prompts\";\nimport { toast } from \"../feedback/toast\";\nimport { MarkdownEditor } from \"../inputs/markdown/MarkdownEditor\";\nimport { Select } from \"../inputs/Select\";\nimport { useUiMessages } from \"../intl/messages\";\nimport Placeholder from \"../surfaces/Placeholder\";\nimport CodeDisplay, { type CodeDisplayLanguage } from \"./CodeDisplay\";\nimport { type DelimitedPreferences, decodeDelimitedContent, readDelimitedPreferences } from \"./delimited-preferences\";\nimport { type FileViewFile, fileViewExtension, getFileViewPreviewKind, parseDelimitedText } from \"./file-view-preview\";\nimport MarkdownView from \"./MarkdownView\";\nimport PdfPreview from \"./PdfPreview\";\nimport StructuredDataPreview, { type StructuredDataValue } from \"./StructuredDataPreview\";\n\nexport type { FileViewFile, FileViewPreviewKind } from \"./file-view-preview\";\nexport { canPreviewFile, getFileViewPreviewKind } from \"./file-view-preview\";\nexport type FileViewContent = { encoding: \"utf8\" | \"base64\"; content: string; mediaType: string };\n\nexport type FileViewProps = {\n /** Plain previews inherit the surrounding surface without a frame or inset padding. */\n variant?: \"default\" | \"plain\";\n /** Read-only excerpt limit; omitted renders the complete preview. */\n previewLines?: number;\n onExpandPreview?: () => void;\n headingScale?: \"compact\" | \"normal\" | \"large\";\n /** Optional browser-local preference scope, owned by the host. */\n previewPreferencesKey?: string;\n file: FileViewFile;\n load: () => Promise<FileViewContent>;\n /** Refetch the current path when this host-owned revision changes. */\n revision?: unknown;\n /** Register an awaitable refresh for the currently visible preview. */\n registerRefresh?: (refresh: () => Promise<void>) => void | (() => void);\n /** Presence enables editing for text-based renderers. */\n save?: (content: string) => Promise<void>;\n /** Authenticated inline URL used by browser-native image, PDF, audio, and video previews. */\n previewHref?: string | null;\n /** CORS mode for native image/audio/video previews. Omit to preserve browser defaults. */\n crossOrigin?: \"anonymous\" | \"use-credentials\";\n /** Native media failed to load; the host can renew a signed URL and offer retry. */\n onPreviewError?: () => void;\n /** Download actions only; never a preview source, because an attachment response does not render inline. */\n downloadHref?: string | null;\n /** App-specific renderers matched before the built-ins for this instance. */\n renderers?: readonly FileViewRenderer[];\n /** Reports local edit state so a parent browser can guard navigation. */\n onDirtyChange?: (dirty: boolean) => void;\n class?: string;\n};\n\nexport type FileViewRendererProps = {\n /** Read-only excerpt limit; omitted renders the complete preview. */\n previewLines?: number;\n onExpandPreview?: () => void;\n headingScale?: \"compact\" | \"normal\" | \"large\";\n /** Optional browser-local preference scope, owned by the host. */\n previewPreferencesKey?: string;\n file: FileViewFile;\n content: FileViewContent;\n previewHref: string | null;\n crossOrigin?: \"anonymous\" | \"use-credentials\";\n onPreviewError?: () => void;\n downloadHref: string | null;\n /** Null when the file is read-only. */\n editor: {\n draft: () => string;\n setDraft: (value: string) => void;\n dirty: () => boolean;\n saving: () => boolean;\n save: () => Promise<void>;\n } | null;\n};\n\nexport type FileViewRenderer = {\n id: string;\n match: (file: FileViewFile, content: FileViewContent) => boolean;\n component: Component<FileViewRendererProps>;\n /** Text renderers that support the edit affordance when `save` is present. */\n editable?: boolean;\n};\n\nconst codeLanguage = (path: string): CodeDisplayLanguage => {\n const extension = fileViewExtension(path);\n if (extension === \"ts\" || extension === \"mts\" || extension === \"cts\") return \"ts\";\n if (extension === \"tsx\") return \"tsx\";\n if (extension === \"js\" || extension === \"mjs\" || extension === \"cjs\") return \"js\";\n if (extension === \"jsx\") return \"jsx\";\n if (extension === \"md\" || extension === \"markdown\") return \"md\";\n return \"text\";\n};\n\nconst isMarkdown = (file: FileViewFile, content: FileViewContent) =>\n content.encoding === \"utf8\" && getFileViewPreviewKind({ ...file, mediaType: content.mediaType || file.mediaType }) === \"markdown\";\n\n/** Rendered previews hide a leading YAML frontmatter block — it's metadata, not content. */\nconst stripFrontmatter = (text: string): string => {\n const match = /^---\\r?\\n[\\s\\S]*?\\r?\\n---\\r?\\n?/.exec(text.trimStart());\n return match ? text.trimStart().slice(match[0].length) : text;\n};\n\n/** Icon-only action, IDE style — sits in the floating top-right cluster of previews. */\nfunction OverlayAction(props: { icon: string; title: string; onClick?: () => void; href?: string; download?: string }) {\n const classes = \"k2b-content-file-view__action\";\n return (\n <Show\n when={props.href}\n fallback={\n <button type=\"button\" class={classes} title={props.title} aria-label={props.title} onClick={props.onClick}>\n <i class={`ti ${props.icon}`} aria-hidden=\"true\" />\n </button>\n }\n >\n {(href) => (\n <a class={classes} href={href()} download={props.download ?? \"\"} title={props.title} aria-label={props.title}>\n <i class={`ti ${props.icon}`} aria-hidden=\"true\" />\n <span class=\"k2b-sr-only\">{props.title}</span>\n </a>\n )}\n </Show>\n );\n}\n\n/** Scrollable preview panel with the floating action cluster overlaid top-right. */\nfunction OverlayPanel(props: { actions?: JSX.Element; children: JSX.Element }) {\n return (\n <div class=\"k2b-content-file-view__panel\">\n <div class=\"k2b-content-file-view__preview\">{props.children}</div>\n <Show when={props.actions}>\n <div class=\"k2b-content-file-view__overlay\">{props.actions}</div>\n </Show>\n </div>\n );\n}\n\nconst DownloadAction = (props: FileViewRendererProps): JSX.Element => {\n const messages = useUiMessages();\n return (\n <Show when={props.downloadHref}>\n {(href) => (\n <OverlayAction\n icon=\"ti-download\"\n title={messages().download}\n href={href()}\n download={props.file.path.slice(props.file.path.lastIndexOf(\"/\") + 1)}\n />\n )}\n </Show>\n );\n};\n\n/** Toolbar-styled icon button — reuses the package markdown-editor tool primitive. */\nfunction EditorToolButton(props: { icon: string; title: string; onClick: () => void; disabled?: boolean }) {\n return (\n <button\n type=\"button\"\n class=\"k2b-markdown-editor__tool\"\n title={props.title}\n aria-label={props.title}\n tabIndex={-1}\n disabled={props.disabled}\n onMouseDown={(e) => e.preventDefault()}\n onClick={props.onClick}\n >\n <i class={props.icon} />\n </button>\n );\n}\n\n// ── Built-in renderers ──────────────────────────────────────────────────────\n\nfunction MoreLines(props: { count: number; onClick?: () => void }) {\n const messages = useUiMessages();\n return (\n <Show when={props.count > 0}>\n <div class=\"k2b-content-file-view__truncated\">\n <Show when={props.onClick} fallback={<span>{messages().previewMoreLines(props.count)}</span>}>\n <Button size=\"sm\" variant=\"ghost\" onClick={props.onClick}>\n {messages().previewMoreLines(props.count)}\n </Button>\n </Show>\n </div>\n </Show>\n );\n}\nfunction TextExcerpt(props: { renderer: FileViewRendererProps; text: string; markdown?: boolean }) {\n const lines = createMemo(() => props.text.replace(/\\r\\n?/g, \"\\n\").replace(/\\n$/, \"\").split(\"\\n\"));\n const limit = () => (props.renderer.previewLines === undefined ? lines().length : Math.max(1, props.renderer.previewLines));\n const text = () => lines().slice(0, limit()).join(\"\\n\");\n return (\n <>\n <div classList={{ \"k2b-content-file-view__excerpt\": props.renderer.previewLines !== undefined }}>\n <Show when={props.markdown} fallback={<CodeDisplay code={text()} language={codeLanguage(props.renderer.file.path)} />}>\n <MarkdownView markdown={text()} headingScale={props.renderer.headingScale ?? \"compact\"} />\n </Show>\n </div>\n <MoreLines count={lines().length - limit()} onClick={props.renderer.onExpandPreview} />\n </>\n );\n}\n\nfunction MarkdownRenderer(props: FileViewRendererProps) {\n const messages = useUiMessages();\n const [editing, setEditing] = createSignal(false);\n return (\n <Show\n when={props.editor && editing()}\n fallback={\n <OverlayPanel\n actions={\n <>\n <Show when={props.editor}>\n <OverlayAction icon=\"ti-pencil\" title={messages().edit} onClick={() => setEditing(true)} />\n </Show>\n <DownloadAction {...props} />\n </>\n }\n >\n <div class=\"k2b-content-file-view__document\">\n <TextExcerpt renderer={props} text={stripFrontmatter(props.editor?.draft() ?? props.content.content)} markdown />\n </div>\n </OverlayPanel>\n }\n >\n {(_) => {\n const editor = props.editor!;\n return (\n <div class=\"k2b-content-file-view__editor\">\n <MarkdownEditor\n class=\"k2b-content-file-view__markdown-field\"\n aria-label={`Edit ${props.file.path.slice(props.file.path.lastIndexOf(\"/\") + 1)}`}\n fill\n value={editor.draft()}\n onValueChange={editor.setDraft}\n showStats={false}\n onSave={() => void editor.save()}\n saveDisabled={!editor.dirty()}\n saving={editor.saving()}\n toolbarTrailing={<EditorToolButton icon=\"ti ti-eye\" title={messages().preview} onClick={() => setEditing(false)} />}\n />\n </div>\n );\n }}\n </Show>\n );\n}\n\nfunction TextRenderer(props: FileViewRendererProps) {\n const messages = useUiMessages();\n return (\n <Show\n when={props.editor}\n fallback={\n <OverlayPanel actions={<DownloadAction {...props} />}>\n <TextExcerpt renderer={props} text={props.content.content} />\n </OverlayPanel>\n }\n >\n {(editor) => (\n // Same chrome as the markdown editor — literally the same classes, so\n // border, radius, focus ring, toolbar height and text metrics cannot drift.\n <div class=\"k2b-content-file-view__editor\">\n <div\n class=\"k2b-markdown-editor\"\n data-fill=\"true\"\n role=\"group\"\n aria-label={messages().textEditor}\n onKeyDown={(event) => {\n if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === \"s\") {\n event.preventDefault();\n if (editor().dirty() && !editor().saving()) void editor().save();\n }\n }}\n >\n {/* No formatting tools here — the divider under an actions-only bar reads lost. */}\n <div class=\"k2b-markdown-editor__toolbar k2b-content-file-view__code-toolbar\">\n <span class=\"k2b-content-file-view__code-language\">{codeLanguage(props.file.path)}</span>\n <span class=\"k2b-markdown-editor__trailing\">\n <Show when={props.downloadHref}>\n {(href) => (\n <a\n class=\"k2b-markdown-editor__tool\"\n href={href()}\n download={props.file.path.slice(props.file.path.lastIndexOf(\"/\") + 1)}\n title={messages().download}\n aria-label={messages().download}\n >\n <i class=\"ti ti-download\" />\n </a>\n )}\n </Show>\n <EditorToolButton\n icon={editor().saving() ? \"ti ti-loader-2 k2b-spin\" : \"ti ti-device-floppy\"}\n title={messages().saveShortcut}\n disabled={!editor().dirty() || editor().saving()}\n onClick={() => void editor().save()}\n />\n </span>\n </div>\n <div class=\"k2b-markdown-editor__surface\">\n <textarea\n class=\"k2b-content-file-view__code-input\"\n value={editor().draft()}\n spellcheck={false}\n onInput={(event) => editor().setDraft(event.currentTarget.value)}\n />\n </div>\n </div>\n </div>\n )}\n </Show>\n );\n}\n\nfunction JsonRenderer(props: FileViewRendererProps) {\n const parsed = createMemo(() => {\n try {\n return { ok: true as const, value: JSON.parse(props.content.content) as StructuredDataValue };\n } catch {\n return { ok: false as const };\n }\n });\n const parsedValue = (): StructuredDataValue => {\n const result = parsed();\n return result.ok ? result.value : null;\n };\n\n return (\n <OverlayPanel actions={<DownloadAction {...props} />}>\n <div class=\"k2b-content-file-view__document\">\n <Show when={parsed().ok} fallback={<TextExcerpt renderer={props} text={props.content.content} />}>\n <Show\n when={props.previewLines === undefined}\n fallback={<TextExcerpt renderer={props} text={JSON.stringify(parsedValue(), null, 2)} />}\n >\n <StructuredDataPreview data={parsedValue()} maxRows={200} />\n </Show>\n </Show>\n </div>\n </OverlayPanel>\n );\n}\n\nfunction DelimitedTextRenderer(props: FileViewRendererProps) {\n const messages = useUiMessages();\n const [preferences, setPreferences] = createSignal<DelimitedPreferences>({ encoding: \"utf-8\", delimiter: \"auto\", view: \"table\" });\n onMount(() => {\n if (!props.previewPreferencesKey) return;\n try {\n setPreferences(readDelimitedPreferences(localStorage.getItem(props.previewPreferencesKey)));\n } catch {\n /* Storage may be disabled. */\n }\n });\n const update = (patch: Partial<DelimitedPreferences>) => {\n const next = { ...preferences(), ...patch };\n setPreferences(next);\n if (props.previewPreferencesKey) {\n try {\n localStorage.setItem(props.previewPreferencesKey, JSON.stringify(next));\n } catch {\n /* Keep the local selection. */\n }\n }\n };\n const text = createMemo(() => decodeDelimitedContent(props.content, preferences().encoding));\n const delimiter = () =>\n preferences().delimiter === \"auto\"\n ? fileViewExtension(props.file.path) === \"tsv\" || props.content.mediaType === \"text/tab-separated-values\"\n ? \"\\t\"\n : \",\"\n : preferences().delimiter;\n const [page, setPage] = createSignal(0);\n createEffect(() => {\n text();\n delimiter();\n props.previewLines;\n setPage(0);\n });\n const pageSize = () => (props.previewLines === undefined ? 200 : Math.max(1, props.previewLines));\n const preview = createMemo(() => parseDelimitedText(text(), delimiter(), { rows: pageSize() + 1, offset: page() * pageSize() }));\n const settings = () =>\n prompts.dialog(\n () => (\n <div class=\"k2b-content-file-view__settings\">\n <Select\n label={messages().csvEncoding}\n value={preferences().encoding}\n disabled={props.content.encoding !== \"base64\"}\n options={[\"utf-8\", \"windows-1252\", \"utf-16le\", \"utf-16be\"]}\n onValueChange={(value) => {\n if (value) update({ encoding: value });\n }}\n />\n <Select\n label={messages().csvSeparator}\n value={preferences().delimiter}\n options={[\n { value: \"auto\", label: messages().csvDefaultSeparator },\n { value: \",\", label: messages().csvComma },\n { value: \";\", label: messages().csvSemicolon },\n { value: \"\\t\", label: messages().csvTab },\n { value: \"|\", label: \"|\" },\n ]}\n onValueChange={(value) => {\n if (value) update({ delimiter: value });\n }}\n />\n <Select\n label={messages().csvView}\n value={preferences().view}\n options={[\n { value: \"table\", label: messages().dataTable },\n { value: \"raw\", label: messages().csvRaw },\n ]}\n onValueChange={(value) => {\n if (value === \"table\" || value === \"raw\") update({ view: value });\n }}\n />\n </div>\n ),\n { title: messages().csvSettings },\n );\n const headers = createMemo(() => preview().rows[0] ?? []);\n const rows = createMemo(() => preview().rows.slice(1));\n\n return (\n <OverlayPanel\n actions={\n <>\n <OverlayAction icon=\"ti-adjustments-horizontal\" title={messages().csvSettings} onClick={() => void settings()} />\n <DownloadAction {...props} />\n </>\n }\n >\n <Show when={preferences().view === \"table\"} fallback={<TextExcerpt renderer={props} text={text()} />}>\n <Show\n when={headers().length > 0}\n fallback={<Placeholder icon=\"ti ti-table\" title={messages().emptyFile} description={messages().delimitedFileEmpty} />}\n >\n <div class=\"k2b-content-file-view__sheet\">\n <table class=\"k2b-content-file-view__table\">\n <thead>\n <tr>\n <For each={headers()}>\n {(header, index) => (\n <th scope=\"col\">\n <span>{header || messages().column({ number: index() + 1 })}</span>\n </th>\n )}\n </For>\n </tr>\n </thead>\n <tbody>\n <For each={rows()}>\n {(row) => (\n <tr>\n <For each={headers()}>{(_, index) => <td>{row[index()] ?? \"\"}</td>}</For>\n </tr>\n )}\n </For>\n </tbody>\n </table>\n <Show when={preview().columnsTruncated}>\n <div class=\"k2b-content-file-view__truncated\">{messages().previewColumnsLimited}</div>\n </Show>\n <Show\n when={props.previewLines !== undefined}\n fallback={\n <Show when={preview().totalRows > 201}>\n <div class=\"k2b-content-file-view__pagination\">\n <Button size=\"sm\" variant=\"ghost\" disabled={page() === 0} onClick={() => setPage(page() - 1)}>\n {messages().previous}\n </Button>\n <span>\n {page() * pageSize() + 1}–{Math.min((page() + 1) * pageSize(), preview().totalRows - 1)} / {preview().totalRows - 1}\n </span>\n <Button\n size=\"sm\"\n variant=\"ghost\"\n disabled={(page() + 1) * pageSize() >= preview().totalRows - 1}\n onClick={() => setPage(page() + 1)}\n >\n {messages().next}\n </Button>\n </div>\n </Show>\n }\n >\n <MoreLines count={preview().totalRows - rows().length - 1} onClick={props.onExpandPreview} />\n </Show>\n </div>\n </Show>\n </Show>\n </OverlayPanel>\n );\n}\n\nconst mediaSource = (props: FileViewRendererProps): string =>\n props.previewHref ?? `data:${props.content.mediaType};base64,${props.content.content}`;\n\nfunction ImageRenderer(props: FileViewRendererProps) {\n return (\n <OverlayPanel actions={<DownloadAction {...props} />}>\n <div class=\"k2b-content-file-view__media\">\n <img crossOrigin={props.crossOrigin} onError={props.onPreviewError} src={mediaSource(props)} alt={props.file.path} />\n </div>\n </OverlayPanel>\n );\n}\n\nconst pdfBlob = (content: FileViewContent): Blob => {\n if (content.encoding === \"utf8\") return new Blob([content.content], { type: \"application/pdf\" });\n const binary = atob(content.content);\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);\n return new Blob([bytes], { type: \"application/pdf\" });\n};\n\n/**\n * A host inline URL goes to the browser's native viewer. Without one, the\n * loaded bytes become a local PDF Blob: a download URL is an attachment and\n * would leave a native viewer empty.\n */\nfunction PdfRenderer(props: FileViewRendererProps) {\n const messages = useUiMessages();\n // A new Blob remounts the preview, so changed bytes show the new file. A revision refetch\n // often returns the same bytes (the Assistant refetches on every tool step); keeping the\n // Blob then keeps the reader's page instead of reloading the viewer.\n const bytes = createMemo(() => props.content, undefined, {\n equals: (previous, next) => previous.encoding === next.encoding && previous.content === next.content,\n });\n const blob = createMemo(() => (props.previewHref || !bytes().content ? null : pdfBlob(bytes())));\n return (\n <Show\n when={props.previewHref}\n fallback={\n <Show\n keyed\n when={blob()}\n fallback={<Placeholder icon=\"ti ti-file-type-pdf\" title=\"PDF\" description={messages().noInlinePreview} />}\n >\n {(pdf) => (\n <PdfPreview\n autoLoad\n title={props.file.path.slice(props.file.path.lastIndexOf(\"/\") + 1)}\n request={async () => pdf}\n class=\"k2b-content-file-view__pdf\"\n />\n )}\n </Show>\n }\n >\n {(href) => <object data={href()} type=\"application/pdf\" class=\"k2b-content-file-view__pdf\" aria-label={props.file.path} />}\n </Show>\n );\n}\n\nfunction AudioRenderer(props: FileViewRendererProps) {\n const messages = useUiMessages();\n return (\n <OverlayPanel actions={<DownloadAction {...props} />}>\n <div class=\"k2b-content-file-view__media\" data-kind=\"audio\">\n <audio\n crossOrigin={props.crossOrigin}\n onError={props.onPreviewError}\n controls\n preload=\"metadata\"\n src={mediaSource(props)}\n aria-label={props.file.path}\n >\n {messages().audioUnsupported}\n </audio>\n </div>\n </OverlayPanel>\n );\n}\n\nfunction VideoRenderer(props: FileViewRendererProps) {\n const messages = useUiMessages();\n return (\n <OverlayPanel actions={<DownloadAction {...props} />}>\n <div class=\"k2b-content-file-view__media\" data-kind=\"video\">\n <video\n crossOrigin={props.crossOrigin}\n onError={props.onPreviewError}\n controls\n preload=\"metadata\"\n playsinline\n src={mediaSource(props)}\n aria-label={props.file.path}\n >\n {messages().videoUnsupported}\n </video>\n </div>\n </OverlayPanel>\n );\n}\n\nfunction BinaryRenderer(props: FileViewRendererProps) {\n const messages = useUiMessages();\n return (\n <Placeholder\n icon=\"ti ti-file-unknown\"\n title={messages().noPreview}\n description={props.content.mediaType || messages().binaryFile}\n action={\n <Show when={props.downloadHref}>\n {(href) => (\n <a class=\"k2b-button\" data-variant=\"secondary\" data-size=\"sm\" href={href()} download=\"\">\n <i class=\"ti ti-download\" aria-hidden=\"true\" />\n {messages().download}\n </a>\n )}\n </Show>\n }\n />\n );\n}\n\nconst BUILTIN_RENDERERS: FileViewRenderer[] = [\n { id: \"markdown\", match: isMarkdown, component: MarkdownRenderer, editable: true },\n {\n id: \"image\",\n match: (file, content) => getFileViewPreviewKind({ ...file, mediaType: content.mediaType || file.mediaType }) === \"image\",\n component: ImageRenderer,\n },\n {\n id: \"pdf\",\n match: (file, content) => getFileViewPreviewKind({ ...file, mediaType: content.mediaType || file.mediaType }) === \"pdf\",\n component: PdfRenderer,\n },\n {\n id: \"json\",\n match: (file, content) =>\n content.encoding === \"utf8\" && getFileViewPreviewKind({ ...file, mediaType: content.mediaType || file.mediaType }) === \"json\",\n component: JsonRenderer,\n },\n {\n id: \"delimited-text\",\n match: (file, content) => getFileViewPreviewKind({ ...file, mediaType: content.mediaType || file.mediaType }) === \"delimited-text\",\n component: DelimitedTextRenderer,\n },\n {\n id: \"audio\",\n match: (file, content) => getFileViewPreviewKind({ ...file, mediaType: content.mediaType || file.mediaType }) === \"audio\",\n component: AudioRenderer,\n },\n {\n id: \"video\",\n match: (file, content) => getFileViewPreviewKind({ ...file, mediaType: content.mediaType || file.mediaType }) === \"video\",\n component: VideoRenderer,\n },\n { id: \"text\", match: (_file, content) => content.encoding === \"utf8\", component: TextRenderer, editable: true },\n { id: \"binary\", match: () => true, component: BinaryRenderer },\n];\n\n// ── Component ───────────────────────────────────────────────────────────────\n\nexport const formatFileViewSize = (bytes: number): string => {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n};\n\nexport default function FileView(props: FileViewProps) {\n const messages = useUiMessages();\n const [draft, setDraft] = createSignal(\"\");\n const [savedDraft, setSavedDraft] = createSignal(\"\");\n const [nativeRevision, setNativeRevision] = createSignal(0);\n const dirty = createMemo(() => draft() !== savedDraft());\n const instanceRenderers = () => props.renderers ?? [];\n const saveMutation = mutation.create<{ path: string; content: string }, { path: string; content: string }>({\n mutation: async (input) => {\n await props.save!(input.content);\n return input;\n },\n onSuccess: (saved) => {\n if (props.file.path === saved.path) setSavedDraft(saved.content);\n toast.success(messages().fileSaved);\n },\n onError: (error) => toast.error(error.message),\n });\n const nativePreviewHref = createMemo(() => {\n const href = props.previewHref;\n if (!href) return null;\n const separator = href.includes(\"?\") ? \"&\" : \"?\";\n return `${href}${separator}preview-revision=${nativeRevision()}`;\n });\n const browserPreviewContent = createMemo<FileViewContent | null>(() => {\n const kind = getFileViewPreviewKind(props.file);\n if (kind !== \"image\" && kind !== \"pdf\" && kind !== \"audio\" && kind !== \"video\") return null;\n const href = nativePreviewHref();\n if (!href) return null;\n\n const candidate: FileViewContent = {\n encoding: \"base64\",\n content: \"\",\n mediaType: props.file.mediaType ?? \"application/octet-stream\",\n };\n return instanceRenderers().some((renderer) => renderer.match(props.file, candidate)) ? null : candidate;\n });\n const [content, { refetch }] = createResource(\n () => (browserPreviewContent() ? null : { path: props.file.path, revision: props.revision }),\n async () => {\n saveMutation.abort();\n // `load` is an imperative source adapter. Host signal reads inside it\n // must not turn this resource into a hidden reactive feedback loop.\n const loaded = await untrack(() => props.load());\n const loadedDraft = loaded.encoding === \"utf8\" ? loaded.content : \"\";\n setDraft(loadedDraft);\n setSavedDraft(loadedDraft);\n return loaded;\n },\n );\n createEffect(() => {\n if (!props.registerRefresh) return;\n const unregister = props.registerRefresh(async () => {\n if (browserPreviewContent()) setNativeRevision((value) => value + 1);\n else await refetch();\n });\n if (unregister) onCleanup(unregister);\n });\n const resolvedContent = createMemo(() => browserPreviewContent() ?? content());\n\n const renderer = createMemo(() => {\n const loaded = resolvedContent();\n if (!loaded) return null;\n return [...instanceRenderers(), ...BUILTIN_RENDERERS].find((candidate) => candidate.match(props.file, loaded)) ?? null;\n });\n\n createEffect(() => {\n props.onDirtyChange?.(dirty());\n });\n\n const save = async () => {\n if (!props.save || saveMutation.loading()) return;\n await saveMutation.mutate({ path: props.file.path, content: draft() });\n };\n\n const editor = () =>\n props.save && renderer()?.editable && resolvedContent()?.encoding === \"utf8\"\n ? {\n draft,\n setDraft,\n dirty,\n saving: saveMutation.loading,\n save,\n }\n : null;\n\n return (\n <div\n class={`k2b-content-file-view ${props.class ?? \"\"}`}\n data-variant={props.variant}\n data-excerpt={props.previewLines !== undefined ? \"true\" : undefined}\n >\n <Switch>\n <Match when={content.loading && content() === undefined}>\n <Placeholder icon=\"ti ti-loader-2\" title={messages().loading} />\n </Match>\n <Match when={content.error}>\n <Placeholder icon=\"ti ti-alert-circle\" title={messages().failedLoadFile} description={String(content.error?.message ?? \"\")} />\n </Match>\n <Match when={resolvedContent() && renderer()}>\n {(active) => {\n const Renderer = active().component;\n return (\n <Renderer\n previewLines={props.previewLines}\n onExpandPreview={props.onExpandPreview}\n headingScale={props.headingScale}\n previewPreferencesKey={props.previewPreferencesKey}\n file={props.file}\n content={resolvedContent()!}\n previewHref={nativePreviewHref()}\n crossOrigin={props.crossOrigin}\n onPreviewError={props.onPreviewError}\n downloadHref={props.downloadHref ?? null}\n editor={editor()}\n />\n );\n }}\n </Match>\n </Switch>\n </div>\n );\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["content/FileView.tsx"],"sourcesContent":["/**\n * FileView — renders one file through a small renderer registry keyed by\n * media type / path. Editing is enabled purely by the presence of `save`;\n * without it every renderer is read-only. IDE-style chrome: editors reuse\n * the markdown editor's surface (toolbar with an in-toolbar save, Ctrl/Cmd+S),\n * previews are quiet paper panels with icon-only actions overlaid top-right.\n * Custom renderers are passed per instance, which keeps SSR requests and\n * independently mounted applications isolated.\n */\n\nimport { mutation } from \"@k2b/stdlib/solid\";\nimport {\n type Component,\n createEffect,\n createMemo,\n createResource,\n createSignal,\n For,\n type JSX,\n Match,\n onCleanup,\n onMount,\n Show,\n Switch,\n untrack,\n} from \"solid-js\";\nimport { Button } from \"../actions/Button\";\nimport { prompts } from \"../feedback/prompts\";\nimport { Tooltip } from \"../feedback/Tooltip\";\nimport { toast } from \"../feedback/toast\";\nimport { MarkdownEditor } from \"../inputs/markdown/MarkdownEditor\";\nimport { Select } from \"../inputs/Select\";\nimport { useUiMessages } from \"../intl/messages\";\nimport Placeholder from \"../surfaces/Placeholder\";\nimport CodeDisplay, { type CodeDisplayLanguage } from \"./CodeDisplay\";\nimport { type DelimitedPreferences, decodeDelimitedContent, readDelimitedPreferences } from \"./delimited-preferences\";\nimport { type FileViewFile, fileViewExtension, getFileViewPreviewKind, parseDelimitedText } from \"./file-view-preview\";\nimport MarkdownView from \"./MarkdownView\";\nimport PdfPreview from \"./PdfPreview\";\nimport StructuredDataPreview, { type StructuredDataValue } from \"./StructuredDataPreview\";\n\nexport type { FileViewFile, FileViewPreviewKind } from \"./file-view-preview\";\nexport { canPreviewFile, getFileViewPreviewKind } from \"./file-view-preview\";\nexport type FileViewContent = { encoding: \"utf8\" | \"base64\"; content: string; mediaType: string };\n\nexport type FileViewProps = {\n /** Plain previews inherit the surrounding surface without a frame or inset padding. */\n variant?: \"default\" | \"plain\";\n /** Read-only excerpt limit; omitted renders the complete preview. */\n previewLines?: number;\n onExpandPreview?: () => void;\n headingScale?: \"compact\" | \"normal\" | \"large\";\n /** Optional browser-local preference scope, owned by the host. */\n previewPreferencesKey?: string;\n file: FileViewFile;\n load: () => Promise<FileViewContent>;\n /** Refetch the current path when this host-owned revision changes. */\n revision?: unknown;\n /** Register an awaitable refresh for the currently visible preview. */\n registerRefresh?: (refresh: () => Promise<void>) => void | (() => void);\n /** Presence enables editing for text-based renderers. */\n save?: (content: string) => Promise<void>;\n /** Authenticated inline URL used by browser-native image, PDF, audio, and video previews. */\n previewHref?: string | null;\n /** CORS mode for native image/audio/video previews. Omit to preserve browser defaults. */\n crossOrigin?: \"anonymous\" | \"use-credentials\";\n /** Native media failed to load; the host can renew a signed URL and offer retry. */\n onPreviewError?: () => void;\n /** Download actions only; never a preview source, because an attachment response does not render inline. */\n downloadHref?: string | null;\n /** App-specific renderers matched before the built-ins for this instance. */\n renderers?: readonly FileViewRenderer[];\n /** Reports local edit state so a parent browser can guard navigation. */\n onDirtyChange?: (dirty: boolean) => void;\n class?: string;\n};\n\nexport type FileViewRendererProps = {\n /** Read-only excerpt limit; omitted renders the complete preview. */\n previewLines?: number;\n onExpandPreview?: () => void;\n headingScale?: \"compact\" | \"normal\" | \"large\";\n /** Optional browser-local preference scope, owned by the host. */\n previewPreferencesKey?: string;\n file: FileViewFile;\n content: FileViewContent;\n previewHref: string | null;\n crossOrigin?: \"anonymous\" | \"use-credentials\";\n onPreviewError?: () => void;\n downloadHref: string | null;\n /** Null when the file is read-only. */\n editor: {\n draft: () => string;\n setDraft: (value: string) => void;\n dirty: () => boolean;\n saving: () => boolean;\n save: () => Promise<void>;\n } | null;\n};\n\nexport type FileViewRenderer = {\n id: string;\n match: (file: FileViewFile, content: FileViewContent) => boolean;\n component: Component<FileViewRendererProps>;\n /** Text renderers that support the edit affordance when `save` is present. */\n editable?: boolean;\n};\n\nconst codeLanguage = (path: string): CodeDisplayLanguage => {\n const extension = fileViewExtension(path);\n if (extension === \"ts\" || extension === \"mts\" || extension === \"cts\") return \"ts\";\n if (extension === \"tsx\") return \"tsx\";\n if (extension === \"js\" || extension === \"mjs\" || extension === \"cjs\") return \"js\";\n if (extension === \"jsx\") return \"jsx\";\n if (extension === \"md\" || extension === \"markdown\") return \"md\";\n return \"text\";\n};\n\nconst isMarkdown = (file: FileViewFile, content: FileViewContent) =>\n content.encoding === \"utf8\" && getFileViewPreviewKind({ ...file, mediaType: content.mediaType || file.mediaType }) === \"markdown\";\n\n/** Rendered previews hide a leading YAML frontmatter block — it's metadata, not content. */\nconst stripFrontmatter = (text: string): string => {\n const match = /^---\\r?\\n[\\s\\S]*?\\r?\\n---\\r?\\n?/.exec(text.trimStart());\n return match ? text.trimStart().slice(match[0].length) : text;\n};\n\n/** Icon-only download link with the shared tooltip, for toolbars that style their own controls. */\nfunction DownloadLink(props: { class: string; href: string; download: string; label: string; icon: string }) {\n let link: HTMLAnchorElement | undefined;\n return (\n <>\n <a ref={link} class={props.class} href={props.href} download={props.download} aria-label={props.label}>\n <i class={props.icon} aria-hidden=\"true\" />\n <span class=\"k2b-sr-only\">{props.label}</span>\n </a>\n <Tooltip content={props.label} target={() => link} />\n </>\n );\n}\n\n/** Icon-only action, IDE style — sits in the floating top-right cluster of previews. */\nfunction OverlayAction(props: { icon: string; title: string; onClick?: () => void; href?: string; download?: string }) {\n const classes = \"k2b-content-file-view__action\";\n return (\n <Show\n when={props.href}\n fallback={\n <Tooltip.Trigger type=\"button\" class={classes} content={props.title} aria-label={props.title} onClick={props.onClick}>\n <i class={`ti ${props.icon}`} aria-hidden=\"true\" />\n </Tooltip.Trigger>\n }\n >\n {(href) => (\n <DownloadLink class={classes} href={href()} download={props.download ?? \"\"} label={props.title} icon={`ti ${props.icon}`} />\n )}\n </Show>\n );\n}\n\n/** Scrollable preview panel with the floating action cluster overlaid top-right. */\nfunction OverlayPanel(props: { actions?: JSX.Element; children: JSX.Element }) {\n return (\n <div class=\"k2b-content-file-view__panel\">\n <div class=\"k2b-content-file-view__preview\">{props.children}</div>\n <Show when={props.actions}>\n <div class=\"k2b-content-file-view__overlay\">{props.actions}</div>\n </Show>\n </div>\n );\n}\n\nconst DownloadAction = (props: FileViewRendererProps): JSX.Element => {\n const messages = useUiMessages();\n return (\n <Show when={props.downloadHref}>\n {(href) => (\n <OverlayAction\n icon=\"ti-download\"\n title={messages().download}\n href={href()}\n download={props.file.path.slice(props.file.path.lastIndexOf(\"/\") + 1)}\n />\n )}\n </Show>\n );\n};\n\n/** Toolbar-styled icon button — reuses the package markdown-editor tool primitive. */\nfunction EditorToolButton(props: { icon: string; title: string; onClick: () => void; disabled?: boolean }) {\n return (\n <Tooltip.Trigger\n type=\"button\"\n class=\"k2b-markdown-editor__tool\"\n content={props.title}\n aria-label={props.title}\n tabIndex={-1}\n disabled={props.disabled}\n onMouseDown={(e) => e.preventDefault()}\n onClick={props.onClick}\n >\n <i class={props.icon} aria-hidden=\"true\" />\n </Tooltip.Trigger>\n );\n}\n\n// ── Built-in renderers ──────────────────────────────────────────────────────\n\nfunction MoreLines(props: { count: number; onClick?: () => void }) {\n const messages = useUiMessages();\n return (\n <Show when={props.count > 0}>\n <div class=\"k2b-content-file-view__truncated\">\n <Show when={props.onClick} fallback={<span>{messages().previewMoreLines(props.count)}</span>}>\n <Button size=\"sm\" variant=\"ghost\" onClick={props.onClick}>\n {messages().previewMoreLines(props.count)}\n </Button>\n </Show>\n </div>\n </Show>\n );\n}\nfunction TextExcerpt(props: { renderer: FileViewRendererProps; text: string; markdown?: boolean }) {\n const lines = createMemo(() => props.text.replace(/\\r\\n?/g, \"\\n\").replace(/\\n$/, \"\").split(\"\\n\"));\n const limit = () => (props.renderer.previewLines === undefined ? lines().length : Math.max(1, props.renderer.previewLines));\n const text = () => lines().slice(0, limit()).join(\"\\n\");\n return (\n <>\n <div classList={{ \"k2b-content-file-view__excerpt\": props.renderer.previewLines !== undefined }}>\n <Show when={props.markdown} fallback={<CodeDisplay code={text()} language={codeLanguage(props.renderer.file.path)} />}>\n <MarkdownView markdown={text()} headingScale={props.renderer.headingScale ?? \"compact\"} />\n </Show>\n </div>\n <MoreLines count={lines().length - limit()} onClick={props.renderer.onExpandPreview} />\n </>\n );\n}\n\nfunction MarkdownRenderer(props: FileViewRendererProps) {\n const messages = useUiMessages();\n const [editing, setEditing] = createSignal(false);\n return (\n <Show\n when={props.editor && editing()}\n fallback={\n <OverlayPanel\n actions={\n <>\n <Show when={props.editor}>\n <OverlayAction icon=\"ti-pencil\" title={messages().edit} onClick={() => setEditing(true)} />\n </Show>\n <DownloadAction {...props} />\n </>\n }\n >\n <div class=\"k2b-content-file-view__document\">\n <TextExcerpt renderer={props} text={stripFrontmatter(props.editor?.draft() ?? props.content.content)} markdown />\n </div>\n </OverlayPanel>\n }\n >\n {(_) => {\n const editor = props.editor!;\n return (\n <div class=\"k2b-content-file-view__editor\">\n <MarkdownEditor\n class=\"k2b-content-file-view__markdown-field\"\n aria-label={`Edit ${props.file.path.slice(props.file.path.lastIndexOf(\"/\") + 1)}`}\n fill\n value={editor.draft()}\n onValueChange={editor.setDraft}\n showStats={false}\n onSave={() => void editor.save()}\n saveDisabled={!editor.dirty()}\n saving={editor.saving()}\n toolbarTrailing={<EditorToolButton icon=\"ti ti-eye\" title={messages().preview} onClick={() => setEditing(false)} />}\n />\n </div>\n );\n }}\n </Show>\n );\n}\n\nfunction TextRenderer(props: FileViewRendererProps) {\n const messages = useUiMessages();\n return (\n <Show\n when={props.editor}\n fallback={\n <OverlayPanel actions={<DownloadAction {...props} />}>\n <TextExcerpt renderer={props} text={props.content.content} />\n </OverlayPanel>\n }\n >\n {(editor) => (\n // Same chrome as the markdown editor — literally the same classes, so\n // border, radius, focus ring, toolbar height and text metrics cannot drift.\n <div class=\"k2b-content-file-view__editor\">\n <div\n class=\"k2b-markdown-editor\"\n data-fill=\"true\"\n role=\"group\"\n aria-label={messages().textEditor}\n onKeyDown={(event) => {\n if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === \"s\") {\n event.preventDefault();\n if (editor().dirty() && !editor().saving()) void editor().save();\n }\n }}\n >\n {/* No formatting tools here — the divider under an actions-only bar reads lost. */}\n <div class=\"k2b-markdown-editor__toolbar k2b-content-file-view__code-toolbar\">\n <span class=\"k2b-content-file-view__code-language\">{codeLanguage(props.file.path)}</span>\n <span class=\"k2b-markdown-editor__trailing\">\n <Show when={props.downloadHref}>\n {(href) => (\n <DownloadLink\n class=\"k2b-markdown-editor__tool\"\n href={href()}\n download={props.file.path.slice(props.file.path.lastIndexOf(\"/\") + 1)}\n label={messages().download}\n icon=\"ti ti-download\"\n />\n )}\n </Show>\n <EditorToolButton\n icon={editor().saving() ? \"ti ti-loader-2 k2b-spin\" : \"ti ti-device-floppy\"}\n title={messages().saveShortcut}\n disabled={!editor().dirty() || editor().saving()}\n onClick={() => void editor().save()}\n />\n </span>\n </div>\n <div class=\"k2b-markdown-editor__surface\">\n <textarea\n class=\"k2b-content-file-view__code-input\"\n value={editor().draft()}\n spellcheck={false}\n onInput={(event) => editor().setDraft(event.currentTarget.value)}\n />\n </div>\n </div>\n </div>\n )}\n </Show>\n );\n}\n\nfunction JsonRenderer(props: FileViewRendererProps) {\n const parsed = createMemo(() => {\n try {\n return { ok: true as const, value: JSON.parse(props.content.content) as StructuredDataValue };\n } catch {\n return { ok: false as const };\n }\n });\n const parsedValue = (): StructuredDataValue => {\n const result = parsed();\n return result.ok ? result.value : null;\n };\n\n return (\n <OverlayPanel actions={<DownloadAction {...props} />}>\n <div class=\"k2b-content-file-view__document\">\n <Show when={parsed().ok} fallback={<TextExcerpt renderer={props} text={props.content.content} />}>\n <Show\n when={props.previewLines === undefined}\n fallback={<TextExcerpt renderer={props} text={JSON.stringify(parsedValue(), null, 2)} />}\n >\n <StructuredDataPreview data={parsedValue()} maxRows={200} />\n </Show>\n </Show>\n </div>\n </OverlayPanel>\n );\n}\n\nfunction DelimitedTextRenderer(props: FileViewRendererProps) {\n const messages = useUiMessages();\n const [preferences, setPreferences] = createSignal<DelimitedPreferences>({ encoding: \"utf-8\", delimiter: \"auto\", view: \"table\" });\n onMount(() => {\n if (!props.previewPreferencesKey) return;\n try {\n setPreferences(readDelimitedPreferences(localStorage.getItem(props.previewPreferencesKey)));\n } catch {\n /* Storage may be disabled. */\n }\n });\n const update = (patch: Partial<DelimitedPreferences>) => {\n const next = { ...preferences(), ...patch };\n setPreferences(next);\n if (props.previewPreferencesKey) {\n try {\n localStorage.setItem(props.previewPreferencesKey, JSON.stringify(next));\n } catch {\n /* Keep the local selection. */\n }\n }\n };\n const text = createMemo(() => decodeDelimitedContent(props.content, preferences().encoding));\n const delimiter = () =>\n preferences().delimiter === \"auto\"\n ? fileViewExtension(props.file.path) === \"tsv\" || props.content.mediaType === \"text/tab-separated-values\"\n ? \"\\t\"\n : \",\"\n : preferences().delimiter;\n const [page, setPage] = createSignal(0);\n createEffect(() => {\n text();\n delimiter();\n props.previewLines;\n setPage(0);\n });\n const pageSize = () => (props.previewLines === undefined ? 200 : Math.max(1, props.previewLines));\n const preview = createMemo(() => parseDelimitedText(text(), delimiter(), { rows: pageSize() + 1, offset: page() * pageSize() }));\n const settings = () =>\n prompts.dialog(\n () => (\n <div class=\"k2b-content-file-view__settings\">\n <Select\n label={messages().csvEncoding}\n value={preferences().encoding}\n disabled={props.content.encoding !== \"base64\"}\n options={[\"utf-8\", \"windows-1252\", \"utf-16le\", \"utf-16be\"]}\n onValueChange={(value) => {\n if (value) update({ encoding: value });\n }}\n />\n <Select\n label={messages().csvSeparator}\n value={preferences().delimiter}\n options={[\n { value: \"auto\", label: messages().csvDefaultSeparator },\n { value: \",\", label: messages().csvComma },\n { value: \";\", label: messages().csvSemicolon },\n { value: \"\\t\", label: messages().csvTab },\n { value: \"|\", label: \"|\" },\n ]}\n onValueChange={(value) => {\n if (value) update({ delimiter: value });\n }}\n />\n <Select\n label={messages().csvView}\n value={preferences().view}\n options={[\n { value: \"table\", label: messages().dataTable },\n { value: \"raw\", label: messages().csvRaw },\n ]}\n onValueChange={(value) => {\n if (value === \"table\" || value === \"raw\") update({ view: value });\n }}\n />\n </div>\n ),\n { title: messages().csvSettings },\n );\n const headers = createMemo(() => preview().rows[0] ?? []);\n const rows = createMemo(() => preview().rows.slice(1));\n\n return (\n <OverlayPanel\n actions={\n <>\n <OverlayAction icon=\"ti-adjustments-horizontal\" title={messages().csvSettings} onClick={() => void settings()} />\n <DownloadAction {...props} />\n </>\n }\n >\n <Show when={preferences().view === \"table\"} fallback={<TextExcerpt renderer={props} text={text()} />}>\n <Show\n when={headers().length > 0}\n fallback={<Placeholder icon=\"ti ti-table\" title={messages().emptyFile} description={messages().delimitedFileEmpty} />}\n >\n <div class=\"k2b-content-file-view__sheet\">\n <table class=\"k2b-content-file-view__table\">\n <thead>\n <tr>\n <For each={headers()}>\n {(header, index) => (\n <th scope=\"col\">\n <span>{header || messages().column({ number: index() + 1 })}</span>\n </th>\n )}\n </For>\n </tr>\n </thead>\n <tbody>\n <For each={rows()}>\n {(row) => (\n <tr>\n <For each={headers()}>{(_, index) => <td>{row[index()] ?? \"\"}</td>}</For>\n </tr>\n )}\n </For>\n </tbody>\n </table>\n <Show when={preview().columnsTruncated}>\n <div class=\"k2b-content-file-view__truncated\">{messages().previewColumnsLimited}</div>\n </Show>\n <Show\n when={props.previewLines !== undefined}\n fallback={\n <Show when={preview().totalRows > 201}>\n <div class=\"k2b-content-file-view__pagination\">\n <Button size=\"sm\" variant=\"ghost\" disabled={page() === 0} onClick={() => setPage(page() - 1)}>\n {messages().previous}\n </Button>\n <span>\n {page() * pageSize() + 1}–{Math.min((page() + 1) * pageSize(), preview().totalRows - 1)} / {preview().totalRows - 1}\n </span>\n <Button\n size=\"sm\"\n variant=\"ghost\"\n disabled={(page() + 1) * pageSize() >= preview().totalRows - 1}\n onClick={() => setPage(page() + 1)}\n >\n {messages().next}\n </Button>\n </div>\n </Show>\n }\n >\n <MoreLines count={preview().totalRows - rows().length - 1} onClick={props.onExpandPreview} />\n </Show>\n </div>\n </Show>\n </Show>\n </OverlayPanel>\n );\n}\n\nconst mediaSource = (props: FileViewRendererProps): string =>\n props.previewHref ?? `data:${props.content.mediaType};base64,${props.content.content}`;\n\nfunction ImageRenderer(props: FileViewRendererProps) {\n return (\n <OverlayPanel actions={<DownloadAction {...props} />}>\n <div class=\"k2b-content-file-view__media\">\n <img crossOrigin={props.crossOrigin} onError={props.onPreviewError} src={mediaSource(props)} alt={props.file.path} />\n </div>\n </OverlayPanel>\n );\n}\n\nconst pdfBlob = (content: FileViewContent): Blob => {\n if (content.encoding === \"utf8\") return new Blob([content.content], { type: \"application/pdf\" });\n const binary = atob(content.content);\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);\n return new Blob([bytes], { type: \"application/pdf\" });\n};\n\n/**\n * A host inline URL goes to the browser's native viewer. Without one, the\n * loaded bytes become a local PDF Blob: a download URL is an attachment and\n * would leave a native viewer empty.\n */\nfunction PdfRenderer(props: FileViewRendererProps) {\n const messages = useUiMessages();\n // A new Blob remounts the preview, so changed bytes show the new file. A revision refetch\n // often returns the same bytes (the Assistant refetches on every tool step); keeping the\n // Blob then keeps the reader's page instead of reloading the viewer.\n const bytes = createMemo(() => props.content, undefined, {\n equals: (previous, next) => previous.encoding === next.encoding && previous.content === next.content,\n });\n const blob = createMemo(() => (props.previewHref || !bytes().content ? null : pdfBlob(bytes())));\n return (\n <Show\n when={props.previewHref}\n fallback={\n <Show\n keyed\n when={blob()}\n fallback={<Placeholder icon=\"ti ti-file-type-pdf\" title=\"PDF\" description={messages().noInlinePreview} />}\n >\n {(pdf) => (\n <PdfPreview\n autoLoad\n title={props.file.path.slice(props.file.path.lastIndexOf(\"/\") + 1)}\n request={async () => pdf}\n class=\"k2b-content-file-view__pdf\"\n />\n )}\n </Show>\n }\n >\n {(href) => <object data={href()} type=\"application/pdf\" class=\"k2b-content-file-view__pdf\" aria-label={props.file.path} />}\n </Show>\n );\n}\n\nfunction AudioRenderer(props: FileViewRendererProps) {\n const messages = useUiMessages();\n return (\n <OverlayPanel actions={<DownloadAction {...props} />}>\n <div class=\"k2b-content-file-view__media\" data-kind=\"audio\">\n <audio\n crossOrigin={props.crossOrigin}\n onError={props.onPreviewError}\n controls\n preload=\"metadata\"\n src={mediaSource(props)}\n aria-label={props.file.path}\n >\n {messages().audioUnsupported}\n </audio>\n </div>\n </OverlayPanel>\n );\n}\n\nfunction VideoRenderer(props: FileViewRendererProps) {\n const messages = useUiMessages();\n return (\n <OverlayPanel actions={<DownloadAction {...props} />}>\n <div class=\"k2b-content-file-view__media\" data-kind=\"video\">\n <video\n crossOrigin={props.crossOrigin}\n onError={props.onPreviewError}\n controls\n preload=\"metadata\"\n playsinline\n src={mediaSource(props)}\n aria-label={props.file.path}\n >\n {messages().videoUnsupported}\n </video>\n </div>\n </OverlayPanel>\n );\n}\n\nfunction BinaryRenderer(props: FileViewRendererProps) {\n const messages = useUiMessages();\n return (\n <Placeholder\n icon=\"ti ti-file-unknown\"\n title={messages().noPreview}\n description={props.content.mediaType || messages().binaryFile}\n action={\n <Show when={props.downloadHref}>\n {(href) => (\n <a class=\"k2b-button\" data-variant=\"secondary\" data-size=\"sm\" href={href()} download=\"\">\n <i class=\"ti ti-download\" aria-hidden=\"true\" />\n {messages().download}\n </a>\n )}\n </Show>\n }\n />\n );\n}\n\nconst BUILTIN_RENDERERS: FileViewRenderer[] = [\n { id: \"markdown\", match: isMarkdown, component: MarkdownRenderer, editable: true },\n {\n id: \"image\",\n match: (file, content) => getFileViewPreviewKind({ ...file, mediaType: content.mediaType || file.mediaType }) === \"image\",\n component: ImageRenderer,\n },\n {\n id: \"pdf\",\n match: (file, content) => getFileViewPreviewKind({ ...file, mediaType: content.mediaType || file.mediaType }) === \"pdf\",\n component: PdfRenderer,\n },\n {\n id: \"json\",\n match: (file, content) =>\n content.encoding === \"utf8\" && getFileViewPreviewKind({ ...file, mediaType: content.mediaType || file.mediaType }) === \"json\",\n component: JsonRenderer,\n },\n {\n id: \"delimited-text\",\n match: (file, content) => getFileViewPreviewKind({ ...file, mediaType: content.mediaType || file.mediaType }) === \"delimited-text\",\n component: DelimitedTextRenderer,\n },\n {\n id: \"audio\",\n match: (file, content) => getFileViewPreviewKind({ ...file, mediaType: content.mediaType || file.mediaType }) === \"audio\",\n component: AudioRenderer,\n },\n {\n id: \"video\",\n match: (file, content) => getFileViewPreviewKind({ ...file, mediaType: content.mediaType || file.mediaType }) === \"video\",\n component: VideoRenderer,\n },\n { id: \"text\", match: (_file, content) => content.encoding === \"utf8\", component: TextRenderer, editable: true },\n { id: \"binary\", match: () => true, component: BinaryRenderer },\n];\n\n// ── Component ───────────────────────────────────────────────────────────────\n\nexport const formatFileViewSize = (bytes: number): string => {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n};\n\nexport default function FileView(props: FileViewProps) {\n const messages = useUiMessages();\n const [draft, setDraft] = createSignal(\"\");\n const [savedDraft, setSavedDraft] = createSignal(\"\");\n const [nativeRevision, setNativeRevision] = createSignal(0);\n const dirty = createMemo(() => draft() !== savedDraft());\n const instanceRenderers = () => props.renderers ?? [];\n const saveMutation = mutation.create<{ path: string; content: string }, { path: string; content: string }>({\n mutation: async (input) => {\n await props.save!(input.content);\n return input;\n },\n onSuccess: (saved) => {\n if (props.file.path === saved.path) setSavedDraft(saved.content);\n toast.success(messages().fileSaved);\n },\n onError: (error) => toast.error(error.message),\n });\n const nativePreviewHref = createMemo(() => {\n const href = props.previewHref;\n if (!href) return null;\n const separator = href.includes(\"?\") ? \"&\" : \"?\";\n return `${href}${separator}preview-revision=${nativeRevision()}`;\n });\n const browserPreviewContent = createMemo<FileViewContent | null>(() => {\n const kind = getFileViewPreviewKind(props.file);\n if (kind !== \"image\" && kind !== \"pdf\" && kind !== \"audio\" && kind !== \"video\") return null;\n const href = nativePreviewHref();\n if (!href) return null;\n\n const candidate: FileViewContent = {\n encoding: \"base64\",\n content: \"\",\n mediaType: props.file.mediaType ?? \"application/octet-stream\",\n };\n return instanceRenderers().some((renderer) => renderer.match(props.file, candidate)) ? null : candidate;\n });\n const [content, { refetch }] = createResource(\n () => (browserPreviewContent() ? null : { path: props.file.path, revision: props.revision }),\n async () => {\n saveMutation.abort();\n // `load` is an imperative source adapter. Host signal reads inside it\n // must not turn this resource into a hidden reactive feedback loop.\n const loaded = await untrack(() => props.load());\n const loadedDraft = loaded.encoding === \"utf8\" ? loaded.content : \"\";\n setDraft(loadedDraft);\n setSavedDraft(loadedDraft);\n return loaded;\n },\n );\n createEffect(() => {\n if (!props.registerRefresh) return;\n const unregister = props.registerRefresh(async () => {\n if (browserPreviewContent()) setNativeRevision((value) => value + 1);\n else await refetch();\n });\n if (unregister) onCleanup(unregister);\n });\n const resolvedContent = createMemo(() => browserPreviewContent() ?? content());\n\n const renderer = createMemo(() => {\n const loaded = resolvedContent();\n if (!loaded) return null;\n return [...instanceRenderers(), ...BUILTIN_RENDERERS].find((candidate) => candidate.match(props.file, loaded)) ?? null;\n });\n\n createEffect(() => {\n props.onDirtyChange?.(dirty());\n });\n\n const save = async () => {\n if (!props.save || saveMutation.loading()) return;\n await saveMutation.mutate({ path: props.file.path, content: draft() });\n };\n\n const editor = () =>\n props.save && renderer()?.editable && resolvedContent()?.encoding === \"utf8\"\n ? {\n draft,\n setDraft,\n dirty,\n saving: saveMutation.loading,\n save,\n }\n : null;\n\n return (\n <div\n class={`k2b-content-file-view ${props.class ?? \"\"}`}\n data-variant={props.variant}\n data-excerpt={props.previewLines !== undefined ? \"true\" : undefined}\n >\n <Switch>\n <Match when={content.loading && content() === undefined}>\n <Placeholder icon=\"ti ti-loader-2\" title={messages().loading} />\n </Match>\n <Match when={content.error}>\n <Placeholder icon=\"ti ti-alert-circle\" title={messages().failedLoadFile} description={String(content.error?.message ?? \"\")} />\n </Match>\n <Match when={resolvedContent() && renderer()}>\n {(active) => {\n const Renderer = active().component;\n return (\n <Renderer\n previewLines={props.previewLines}\n onExpandPreview={props.onExpandPreview}\n headingScale={props.headingScale}\n previewPreferencesKey={props.previewPreferencesKey}\n file={props.file}\n content={resolvedContent()!}\n previewHref={nativePreviewHref()}\n crossOrigin={props.crossOrigin}\n onPreviewError={props.onPreviewError}\n downloadHref={props.downloadHref ?? null}\n editor={editor()}\n />\n );\n }}\n </Match>\n </Switch>\n </div>\n );\n}\n"],"mappings":"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","ignoreList":[]}
@@ -13,6 +13,7 @@ var _tmpl$ = ["<span class=\"k2b-content-lightbox__counter\" aria-live=\"polite\
13
13
  _tmpl$8 = ["<img", " class=\"k2b-content-lightbox__image\" draggable=\"false\">"],
14
14
  _tmpl$9 = ["<button type=\"button\" class=\"k2b-content-lightbox__dot\"", "></button>"];
15
15
  import { createEffect, createSignal, For, onCleanup, onMount, Show } from "solid-js";
16
+ import { returnFocus, ringOnReturn } from "../internal/focus-return";
16
17
  import { useUiMessages } from "../intl/messages";
17
18
  /**
18
19
  * Minimal, accessible lightbox using native <dialog>.
@@ -23,6 +24,8 @@ export default function Lightbox(props) {
23
24
  const clampIndex = (value, images = props.images) => images.length === 0 ? 0 : Math.max(0, Math.min(value, images.length - 1));
24
25
  const [index, setIndex] = createSignal(clampIndex(props.initialIndex ?? 0));
25
26
  let dialogRef;
27
+ let opener = null;
28
+ let openerRing = true;
26
29
  createEffect(previous => {
27
30
  const images = props.images;
28
31
  const initialIndex = props.initialIndex;
@@ -57,6 +60,7 @@ export default function Lightbox(props) {
57
60
  };
58
61
  const close = () => {
59
62
  dialogRef.close();
63
+ returnFocus(opener, openerRing);
60
64
  props.onClose();
61
65
  };
62
66
 
@@ -64,6 +68,8 @@ export default function Lightbox(props) {
64
68
  const handleKeyDown = e => {
65
69
  switch (e.key) {
66
70
  case "Escape":
71
+ // Handled here, so WebKit does not light the returned focus for this key.
72
+ e.preventDefault();
67
73
  close();
68
74
  break;
69
75
  case "ArrowLeft":
@@ -106,9 +112,20 @@ export default function Lightbox(props) {
106
112
  }
107
113
  };
108
114
 
115
+ // The browser cancels the dialog itself, as on the Android back gesture;
116
+ // closing here still returns focus and tells the owner.
117
+ const handleCancel = e => {
118
+ e.preventDefault();
119
+ close();
120
+ };
121
+
109
122
  // Registration and teardown both live in onMount: onCleanup also runs when an
110
123
  // SSR render is disposed, where `document` does not exist.
111
124
  onMount(() => {
125
+ opener = document.activeElement instanceof HTMLElement ? document.activeElement : null;
126
+ openerRing = ringOnReturn(opener);
127
+ // The native dialog would return focus with a ring of the browser's choosing.
128
+ opener?.blur();
112
129
  dialogRef.showModal();
113
130
  document.addEventListener("keydown", handleKeyDown);
114
131
  onCleanup(() => document.removeEventListener("keydown", handleKeyDown));
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["content/Lightbox.tsx"],"sourcesContent":["import { createEffect, createSignal, For, onCleanup, onMount, Show } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\n\nexport type LightboxImage = {\n src: string;\n alt?: string;\n downloadUrl?: string;\n};\n\ntype LightboxProps = {\n images: LightboxImage[];\n initialIndex?: number;\n onClose: () => void;\n};\n\n/**\n * Minimal, accessible lightbox using native <dialog>.\n * Supports keyboard navigation, touch swipe gestures, and screen readers.\n */\nexport default function Lightbox(props: LightboxProps) {\n const messages = useUiMessages();\n const clampIndex = (value: number, images = props.images): number =>\n images.length === 0 ? 0 : Math.max(0, Math.min(value, images.length - 1));\n const [index, setIndex] = createSignal(clampIndex(props.initialIndex ?? 0));\n let dialogRef!: HTMLDialogElement;\n\n createEffect(\n (previous: { images: LightboxImage[]; initialIndex: number | undefined }) => {\n const images = props.images;\n const initialIndex = props.initialIndex;\n setIndex((currentIndex) => {\n if (initialIndex !== previous.initialIndex) return clampIndex(initialIndex ?? 0, images);\n const previousImage = previous.images[currentIndex];\n const retained = previousImage ? images.findIndex((image) => image === previousImage || image.src === previousImage.src) : -1;\n return retained >= 0 ? retained : clampIndex(currentIndex, images);\n });\n return { images, initialIndex };\n },\n { images: props.images, initialIndex: props.initialIndex },\n );\n\n // Touch gesture tracking\n let touchStartX = 0;\n let touchStartY = 0;\n const SWIPE_THRESHOLD = 50;\n\n const current = () => props.images[index()];\n const isMultiple = () => props.images.length > 1;\n const prev = () => {\n if (!isMultiple()) return;\n setIndex((i) => (i - 1 + props.images.length) % props.images.length);\n };\n const next = () => {\n if (!isMultiple()) return;\n setIndex((i) => (i + 1) % props.images.length);\n };\n\n const close = () => {\n dialogRef.close();\n props.onClose();\n };\n\n // Keyboard navigation\n const handleKeyDown = (e: KeyboardEvent) => {\n switch (e.key) {\n case \"Escape\":\n close();\n break;\n case \"ArrowLeft\":\n prev();\n break;\n case \"ArrowRight\":\n next();\n break;\n }\n };\n\n // Touch handlers for swipe gestures\n const handleTouchStart = (e: TouchEvent) => {\n const touch = e.touches[0];\n if (touch) {\n touchStartX = touch.clientX;\n touchStartY = touch.clientY;\n }\n };\n\n const handleTouchEnd = (e: TouchEvent) => {\n const touch = e.changedTouches[0];\n if (!touch) return;\n\n const deltaX = touch.clientX - touchStartX;\n const deltaY = touch.clientY - touchStartY;\n\n // Only trigger swipe if horizontal movement is dominant\n if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > SWIPE_THRESHOLD) {\n if (deltaX > 0) {\n prev();\n } else {\n next();\n }\n }\n };\n\n // Click on backdrop closes lightbox\n const handleBackdropClick = (e: MouseEvent) => {\n if (e.target === dialogRef) {\n close();\n }\n };\n\n // Registration and teardown both live in onMount: onCleanup also runs when an\n // SSR render is disposed, where `document` does not exist.\n onMount(() => {\n dialogRef.showModal();\n document.addEventListener(\"keydown\", handleKeyDown);\n onCleanup(() => document.removeEventListener(\"keydown\", handleKeyDown));\n });\n\n return (\n <dialog\n ref={dialogRef}\n class=\"k2b-content-lightbox\"\n onMouseDown={handleBackdropClick}\n onTouchStart={handleTouchStart}\n onTouchEnd={handleTouchEnd}\n aria-label={messages().imageLightbox}\n >\n {/* Top bar */}\n <div class=\"k2b-content-lightbox__bar\">\n <div class=\"k2b-content-lightbox__meta\">\n <Show when={isMultiple()}>\n <span class=\"k2b-content-lightbox__counter\" aria-live=\"polite\">\n {index() + 1} / {props.images.length}\n </span>\n </Show>\n <Show when={current()?.alt}>\n <div class=\"k2b-content-lightbox__caption\">\n <div class=\"k2b-content-lightbox__caption-text\">{current()?.alt}</div>\n </div>\n </Show>\n </div>\n\n <div class=\"k2b-content-lightbox__actions\">\n <Show when={current()?.downloadUrl}>\n <a href={current()!.downloadUrl} download=\"\" class=\"k2b-content-lightbox__button\" aria-label={messages().downloadImage}>\n <i class=\"ti ti-download\" aria-hidden=\"true\" />\n <span class=\"k2b-content-lightbox__button-label\">{messages().download}</span>\n </a>\n </Show>\n <button type=\"button\" onClick={close} class=\"k2b-content-lightbox__button\" aria-label={messages().closeLightbox}>\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n <span class=\"k2b-content-lightbox__button-label\">{messages().close}</span>\n </button>\n </div>\n </div>\n\n <div class=\"k2b-content-lightbox__stage\">\n <Show when={current()}>\n {(image) => <img src={image().src} alt={image().alt ?? \"\"} class=\"k2b-content-lightbox__image\" draggable={false} />}\n </Show>\n </div>\n\n <Show when={isMultiple()}>\n <button\n type=\"button\"\n onClick={prev}\n class=\"k2b-content-lightbox__nav\"\n data-direction=\"previous\"\n aria-label={messages().previousImage}\n >\n <i class=\"ti ti-chevron-left\" aria-hidden=\"true\" />\n </button>\n <button type=\"button\" onClick={next} class=\"k2b-content-lightbox__nav\" data-direction=\"next\" aria-label={messages().nextImage}>\n <i class=\"ti ti-chevron-right\" aria-hidden=\"true\" />\n </button>\n </Show>\n\n <Show when={isMultiple() && props.images.length <= 10}>\n <div class=\"k2b-content-lightbox__dots\" role=\"group\" aria-label={messages().imageNavigation}>\n <For each={props.images}>\n {(_, i) => (\n <button\n type=\"button\"\n onClick={() => setIndex(i())}\n class=\"k2b-content-lightbox__dot\"\n aria-current={index() === i() ? \"true\" : undefined}\n aria-label={messages().goToImage({ index: i() + 1 })}\n />\n )}\n </For>\n </div>\n </Show>\n </dialog>\n );\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["content/Lightbox.tsx"],"sourcesContent":["import { createEffect, createSignal, For, onCleanup, onMount, Show } from \"solid-js\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\nimport { useUiMessages } from \"../intl/messages\";\n\nexport type LightboxImage = {\n src: string;\n alt?: string;\n downloadUrl?: string;\n};\n\ntype LightboxProps = {\n images: LightboxImage[];\n initialIndex?: number;\n onClose: () => void;\n};\n\n/**\n * Minimal, accessible lightbox using native <dialog>.\n * Supports keyboard navigation, touch swipe gestures, and screen readers.\n */\nexport default function Lightbox(props: LightboxProps) {\n const messages = useUiMessages();\n const clampIndex = (value: number, images = props.images): number =>\n images.length === 0 ? 0 : Math.max(0, Math.min(value, images.length - 1));\n const [index, setIndex] = createSignal(clampIndex(props.initialIndex ?? 0));\n let dialogRef!: HTMLDialogElement;\n let opener: HTMLElement | null = null;\n let openerRing = true;\n\n createEffect(\n (previous: { images: LightboxImage[]; initialIndex: number | undefined }) => {\n const images = props.images;\n const initialIndex = props.initialIndex;\n setIndex((currentIndex) => {\n if (initialIndex !== previous.initialIndex) return clampIndex(initialIndex ?? 0, images);\n const previousImage = previous.images[currentIndex];\n const retained = previousImage ? images.findIndex((image) => image === previousImage || image.src === previousImage.src) : -1;\n return retained >= 0 ? retained : clampIndex(currentIndex, images);\n });\n return { images, initialIndex };\n },\n { images: props.images, initialIndex: props.initialIndex },\n );\n\n // Touch gesture tracking\n let touchStartX = 0;\n let touchStartY = 0;\n const SWIPE_THRESHOLD = 50;\n\n const current = () => props.images[index()];\n const isMultiple = () => props.images.length > 1;\n const prev = () => {\n if (!isMultiple()) return;\n setIndex((i) => (i - 1 + props.images.length) % props.images.length);\n };\n const next = () => {\n if (!isMultiple()) return;\n setIndex((i) => (i + 1) % props.images.length);\n };\n\n const close = () => {\n dialogRef.close();\n returnFocus(opener, openerRing);\n props.onClose();\n };\n\n // Keyboard navigation\n const handleKeyDown = (e: KeyboardEvent) => {\n switch (e.key) {\n case \"Escape\":\n // Handled here, so WebKit does not light the returned focus for this key.\n e.preventDefault();\n close();\n break;\n case \"ArrowLeft\":\n prev();\n break;\n case \"ArrowRight\":\n next();\n break;\n }\n };\n\n // Touch handlers for swipe gestures\n const handleTouchStart = (e: TouchEvent) => {\n const touch = e.touches[0];\n if (touch) {\n touchStartX = touch.clientX;\n touchStartY = touch.clientY;\n }\n };\n\n const handleTouchEnd = (e: TouchEvent) => {\n const touch = e.changedTouches[0];\n if (!touch) return;\n\n const deltaX = touch.clientX - touchStartX;\n const deltaY = touch.clientY - touchStartY;\n\n // Only trigger swipe if horizontal movement is dominant\n if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > SWIPE_THRESHOLD) {\n if (deltaX > 0) {\n prev();\n } else {\n next();\n }\n }\n };\n\n // Click on backdrop closes lightbox\n const handleBackdropClick = (e: MouseEvent) => {\n if (e.target === dialogRef) {\n close();\n }\n };\n\n // The browser cancels the dialog itself, as on the Android back gesture;\n // closing here still returns focus and tells the owner.\n const handleCancel = (e: Event) => {\n e.preventDefault();\n close();\n };\n\n // Registration and teardown both live in onMount: onCleanup also runs when an\n // SSR render is disposed, where `document` does not exist.\n onMount(() => {\n opener = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n openerRing = ringOnReturn(opener);\n // The native dialog would return focus with a ring of the browser's choosing.\n opener?.blur();\n dialogRef.showModal();\n document.addEventListener(\"keydown\", handleKeyDown);\n onCleanup(() => document.removeEventListener(\"keydown\", handleKeyDown));\n });\n\n return (\n <dialog\n ref={dialogRef}\n class=\"k2b-content-lightbox\"\n onMouseDown={handleBackdropClick}\n onCancel={handleCancel}\n onTouchStart={handleTouchStart}\n onTouchEnd={handleTouchEnd}\n aria-label={messages().imageLightbox}\n >\n {/* Top bar */}\n <div class=\"k2b-content-lightbox__bar\">\n <div class=\"k2b-content-lightbox__meta\">\n <Show when={isMultiple()}>\n <span class=\"k2b-content-lightbox__counter\" aria-live=\"polite\">\n {index() + 1} / {props.images.length}\n </span>\n </Show>\n <Show when={current()?.alt}>\n <div class=\"k2b-content-lightbox__caption\">\n <div class=\"k2b-content-lightbox__caption-text\">{current()?.alt}</div>\n </div>\n </Show>\n </div>\n\n <div class=\"k2b-content-lightbox__actions\">\n <Show when={current()?.downloadUrl}>\n <a href={current()!.downloadUrl} download=\"\" class=\"k2b-content-lightbox__button\" aria-label={messages().downloadImage}>\n <i class=\"ti ti-download\" aria-hidden=\"true\" />\n <span class=\"k2b-content-lightbox__button-label\">{messages().download}</span>\n </a>\n </Show>\n <button type=\"button\" onClick={close} class=\"k2b-content-lightbox__button\" aria-label={messages().closeLightbox}>\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n <span class=\"k2b-content-lightbox__button-label\">{messages().close}</span>\n </button>\n </div>\n </div>\n\n <div class=\"k2b-content-lightbox__stage\">\n <Show when={current()}>\n {(image) => <img src={image().src} alt={image().alt ?? \"\"} class=\"k2b-content-lightbox__image\" draggable={false} />}\n </Show>\n </div>\n\n <Show when={isMultiple()}>\n <button\n type=\"button\"\n onClick={prev}\n class=\"k2b-content-lightbox__nav\"\n data-direction=\"previous\"\n aria-label={messages().previousImage}\n >\n <i class=\"ti ti-chevron-left\" aria-hidden=\"true\" />\n </button>\n <button type=\"button\" onClick={next} class=\"k2b-content-lightbox__nav\" data-direction=\"next\" aria-label={messages().nextImage}>\n <i class=\"ti ti-chevron-right\" aria-hidden=\"true\" />\n </button>\n </Show>\n\n <Show when={isMultiple() && props.images.length <= 10}>\n <div class=\"k2b-content-lightbox__dots\" role=\"group\" aria-label={messages().imageNavigation}>\n <For each={props.images}>\n {(_, i) => (\n <button\n type=\"button\"\n onClick={() => setIndex(i())}\n class=\"k2b-content-lightbox__dot\"\n aria-current={index() === i() ? \"true\" : undefined}\n aria-label={messages().goToImage({ index: i() + 1 })}\n />\n )}\n </For>\n </div>\n </Show>\n </dialog>\n );\n}\n"],"mappings":"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","ignoreList":[]}
@@ -8,13 +8,13 @@ var _tmpl$ = ["<button type=\"button\" class=\"k2b-button\" data-variant=\"secon
8
8
  _tmpl$3 = ["<span role=\"alert\" class=\"k2b-content-pdf-preview__notice\">", "</span>"],
9
9
  _tmpl$4 = ["<div class=\"k2b-content-pdf-preview__actions\">", "", "", "", "</div>"],
10
10
  _tmpl$5 = ["<a class=\"k2b-button\" data-variant=\"secondary\" data-size=\"sm\"", " target=\"_blank\" rel=\"noopener\"><i class=\"ti ti-external-link\" aria-hidden=\"true\"></i>", "</a>"],
11
- _tmpl$6 = ["<div class=\"k2b-content-pdf-preview__empty\"><span", ">", "</span></div>"],
12
- _tmpl$7 = ["<iframe class=\"k2b-content-pdf-preview__frame\"", "></iframe>"],
13
- _tmpl$8 = ["<div role=\"alert\" class=\"k2b-content-pdf-preview__error\">", "</div>"],
14
- _tmpl$9 = ["<h2 class=\"k2b-content-pdf-preview__title\">", "</h2>"],
15
- _tmpl$0 = ["<section class=\"", "\"><div class=\"k2b-content-pdf-preview__toolbar\"><div class=\"k2b-content-pdf-preview__heading\">", "</div>", "</div>", "</section>"];
11
+ _tmpl$6 = ["<iframe class=\"k2b-content-pdf-preview__frame\"", "></iframe>"],
12
+ _tmpl$7 = ["<button type=\"button\" class=\"k2b-button\" data-variant=\"secondary\" data-size=\"sm\"", ">", "</button>"],
13
+ _tmpl$8 = ["<h2 class=\"k2b-content-pdf-preview__title\">", "</h2>"],
14
+ _tmpl$9 = ["<section class=\"", "\"><div class=\"k2b-content-pdf-preview__toolbar\"><div class=\"k2b-content-pdf-preview__heading\">", "</div>", "</div>", "</section>"];
16
15
  import { createSignal, onCleanup, onMount, Show } from "solid-js";
17
16
  import { resolveUiMessages, useUiMessages } from "../intl/messages";
17
+ import Placeholder from "../surfaces/Placeholder";
18
18
  const readErrorMessage = async response => {
19
19
  try {
20
20
  const data = await response.json();
@@ -40,6 +40,7 @@ export default function PdfPreview(props) {
40
40
  let shownBlob = null;
41
41
  let openButton;
42
42
  let renderButton;
43
+ let errorRetryButton;
43
44
  let disposed = false;
44
45
  let loadGeneration = 0;
45
46
  let openGeneration = 0;
@@ -64,7 +65,8 @@ export default function PdfPreview(props) {
64
65
  const load = async () => {
65
66
  if (loading() || opening() || props.disabled?.()) return;
66
67
  const generation = ++loadGeneration;
67
- const retryFocused = props.autoLoad && document.activeElement === renderButton;
68
+ // A retry the shown document or the loading state removes hands keyboard focus on instead of dropping it.
69
+ const retryFocused = props.autoLoad && document.activeElement === renderButton || errorRetryButton?.isConnected && document.activeElement === errorRetryButton;
68
70
  setLoading(true);
69
71
  setError(null);
70
72
  try {
@@ -87,6 +89,7 @@ export default function PdfPreview(props) {
87
89
  shownBlob = null;
88
90
  setFailed(true);
89
91
  setError(e instanceof Error ? e.message : "PDF preview failed");
92
+ if (retryFocused && document.activeElement === document.body) errorRetryButton?.focus();
90
93
  } finally {
91
94
  if (!disposed && generation === loadGeneration) setLoading(false);
92
95
  }
@@ -125,9 +128,9 @@ export default function PdfPreview(props) {
125
128
  }
126
129
  };
127
130
 
128
- // With autoLoad, rendering again would show the same document: offer it only until one is shown, e.g. to retry,
129
- // and keep it in place while a retry loads.
130
- const renderable = () => !props.autoLoad || failed() || !url() && !loading();
131
+ // With autoLoad, rendering again would show the same document: offer it only until one is shown. After a failure the
132
+ // default error state carries it as the retry; beside a caller's error content it stays in place while a retry loads.
133
+ const renderable = () => !props.autoLoad || (failed() ? Boolean(props.renderError) : !url() && !loading());
131
134
  const actions = () => _$ssr(_tmpl$4, _$escape(_$createComponent(Show, {
132
135
  get when() {
133
136
  return _$memo(() => !!!props.disabled?.())() && props.openHref;
@@ -159,6 +162,7 @@ export default function PdfPreview(props) {
159
162
  return _$ssr(_tmpl$3, _$escape(messages().pdfPreviewTabBlocked));
160
163
  }
161
164
  })));
165
+ // Every state before a document is shown uses one placeholder in the viewer's box, so loading changes no layout.
162
166
  const content = () => _$createComponent(Show, {
163
167
  get when() {
164
168
  return error();
@@ -169,12 +173,38 @@ export default function PdfPreview(props) {
169
173
  return url();
170
174
  },
171
175
  get fallback() {
172
- return _$ssr(_tmpl$6, _$ssrAttribute("role", loading() ? "status" : _$escape(undefined, true), false), loading() ? _$escape(messages().loading) : _$escape(props.emptyText ?? messages().renderPdfPreview));
176
+ return _$createComponent(Placeholder, {
177
+ "class": "k2b-content-pdf-preview__placeholder",
178
+ get state() {
179
+ return loading() ? "loading" : "empty";
180
+ },
181
+ get icon() {
182
+ return loading() ? undefined : "ti ti-file-type-pdf";
183
+ },
184
+ get title() {
185
+ return _$memo(() => !!loading())() ? messages().loading : undefined;
186
+ },
187
+ get description() {
188
+ return _$memo(() => !!loading())() ? undefined : props.emptyText ?? messages().renderPdfPreview;
189
+ }
190
+ });
173
191
  },
174
- children: currentUrl => _$ssr(_tmpl$7, _$ssrAttribute("src", _$escape(currentUrl(), true), false) + _$ssrAttribute("title", _$escape(props.title ?? messages().pdfPreview, true), false))
192
+ children: currentUrl => _$ssr(_tmpl$6, _$ssrAttribute("src", _$escape(currentUrl(), true), false) + _$ssrAttribute("title", _$escape(props.title ?? messages().pdfPreview, true), false))
175
193
  });
176
194
  },
177
- children: message => props.renderError?.(message()) ?? _$ssr(_tmpl$8, _$escape(message()))
195
+ children: message => props.renderError?.(message()) ?? _$createComponent(Placeholder, {
196
+ "class": "k2b-content-pdf-preview__placeholder",
197
+ state: "error",
198
+ get description() {
199
+ return message();
200
+ },
201
+ get action() {
202
+ return (
203
+ // One retry at a time: the render action moves here only where the toolbar no longer offers it.
204
+ _$memo(() => !!renderable())() ? undefined : _$ssr(_tmpl$7, _$ssrAttribute("disabled", opening() || props.disabled?.(), true), _$escape(props.buttonLabel ?? messages().retry))
205
+ );
206
+ }
207
+ })
178
208
  });
179
209
  if (props.children) return props.children({
180
210
  get actions() {
@@ -184,12 +214,12 @@ export default function PdfPreview(props) {
184
214
  return content();
185
215
  }
186
216
  });
187
- return _$ssr(_tmpl$0, `k2b-content-pdf-preview ${_$escape(props.class ?? "", true)}`, _$escape(_$createComponent(Show, {
217
+ return _$ssr(_tmpl$9, `k2b-content-pdf-preview ${_$escape(props.class ?? "", true)}`, _$escape(_$createComponent(Show, {
188
218
  get when() {
189
219
  return props.title;
190
220
  },
191
221
  get children() {
192
- return _$ssr(_tmpl$9, _$escape(props.title));
222
+ return _$ssr(_tmpl$8, _$escape(props.title));
193
223
  }
194
224
  })), _$escape(actions()), _$escape(content()));
195
225
  }
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["content/PdfPreview.tsx"],"sourcesContent":["import { createSignal, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { resolveUiMessages, useUiMessages } from \"../intl/messages\";\n\nexport type PdfPreviewRequest = () => Promise<Response | Blob>;\n\nexport type PdfPreviewProps = {\n request: PdfPreviewRequest;\n autoLoad?: boolean;\n disabled?: () => boolean;\n title?: string;\n buttonLabel?: string;\n openButtonLabel?: string;\n /**\n * Opens the document at this address in a new tab instead of a local copy. Pass a stable same-origin URL that\n * serves the PDF inline, so reloading and the viewer's file name keep working. Without it, the open action shows\n * a temporary copy of the requested document.\n */\n openHref?: string;\n /** Adds a Download action. The host owns the download, for example a fresh attachment URL. */\n onDownload?: () => void;\n emptyText?: string;\n class?: string;\n children?: (parts: { actions: JSX.Element; content: JSX.Element }) => JSX.Element;\n renderError?: (message: string) => JSX.Element;\n};\n\nconst readErrorMessage = async (response: Response): Promise<string> => {\n try {\n const data = (await response.json()) as unknown;\n if (data && typeof data === \"object\" && \"message\" in data && typeof data.message === \"string\") return data.message;\n } catch {\n // Fall through to the HTTP status fallback.\n }\n return resolveUiMessages().pdfPreviewHttpError({ status: response.status });\n};\n\nexport default function PdfPreview(props: PdfPreviewProps) {\n const messages = useUiMessages();\n const [url, setUrl] = createSignal<string | null>(null);\n // An automatic preview starts loading once mounted. The server and the page before hydration already show that\n // state, so they offer neither a retry nor an invitation to render while nothing has failed.\n const [loading, setLoading] = createSignal(Boolean(props.autoLoad) && !props.disabled?.());\n const [opening, setOpening] = createSignal(false);\n const [error, setError] = createSignal<string | null>(null);\n const [failed, setFailed] = createSignal(false);\n const [tabBlocked, setTabBlocked] = createSignal(false);\n // An automatic preview shows one fixed document; the open action reuses it instead of requesting it again.\n let shownBlob: Blob | null = null;\n let openButton: HTMLElement | undefined;\n let renderButton: HTMLButtonElement | undefined;\n let disposed = false;\n let loadGeneration = 0;\n let openGeneration = 0;\n\n const revokeCurrent = () => {\n const current = url();\n if (current) URL.revokeObjectURL(current);\n setUrl(null);\n };\n\n onCleanup(() => {\n disposed = true;\n loadGeneration += 1;\n openGeneration += 1;\n revokeCurrent();\n });\n\n const readPdfBlob = async () => {\n const response = await props.request();\n const blob = response instanceof Response ? (response.ok ? await response.blob() : null) : response;\n if (!blob) throw new Error(await readErrorMessage(response as Response));\n if (blob.type && blob.type !== \"application/pdf\") throw new Error(`PDF preview returned ${blob.type} instead of application/pdf`);\n return blob;\n };\n\n const load = async () => {\n if (loading() || opening() || props.disabled?.()) return;\n const generation = ++loadGeneration;\n const retryFocused = props.autoLoad && document.activeElement === renderButton;\n setLoading(true);\n setError(null);\n try {\n const blob = await readPdfBlob();\n const nextUrl = URL.createObjectURL(blob);\n if (disposed || generation !== loadGeneration) {\n URL.revokeObjectURL(nextUrl);\n return;\n }\n const previousUrl = url();\n shownBlob = blob;\n setFailed(false);\n setUrl(nextUrl);\n setLoading(false);\n if (previousUrl) URL.revokeObjectURL(previousUrl);\n // The shown document removes the retry action; keep keyboard focus in the actions instead of the page.\n if (retryFocused && document.activeElement === document.body) openButton?.focus();\n } catch (e) {\n if (disposed || generation !== loadGeneration) return;\n shownBlob = null;\n setFailed(true);\n setError(e instanceof Error ? e.message : \"PDF preview failed\");\n } finally {\n if (!disposed && generation === loadGeneration) setLoading(false);\n }\n };\n\n onMount(() => {\n // Hand the initial loading state to the request itself, which also covers a preview disabled by now.\n setLoading(false);\n if (props.autoLoad) void load();\n });\n\n const openInNewTab = async () => {\n if (loading() || opening() || props.disabled?.()) return;\n const generation = ++openGeneration;\n const tab = window.open(\"\", \"_blank\");\n // A blocked tab is not a document error: keep the shown document and report it beside the actions.\n setTabBlocked(!tab);\n if (!tab) return;\n tab.opener = null;\n tab.document.title = props.title ?? messages().pdfPreview;\n tab.document.body.textContent = messages().pdfPreviewRendering;\n setOpening(true);\n setError(null);\n try {\n const blob = (props.autoLoad ? shownBlob : null) ?? (await readPdfBlob());\n if (disposed || generation !== openGeneration) {\n tab.close();\n return;\n }\n const objectUrl = URL.createObjectURL(blob);\n tab.location.href = objectUrl;\n window.setTimeout(() => URL.revokeObjectURL(objectUrl), 60_000);\n } catch (e) {\n tab.close();\n if (!disposed && generation === openGeneration) setError(e instanceof Error ? e.message : \"PDF preview failed\");\n } finally {\n if (!disposed && generation === openGeneration) setOpening(false);\n }\n };\n\n // With autoLoad, rendering again would show the same document: offer it only until one is shown, e.g. to retry,\n // and keep it in place while a retry loads.\n const renderable = () => !props.autoLoad || failed() || (!url() && !loading());\n const actions = () => (\n <div class=\"k2b-content-pdf-preview__actions\">\n <Show\n when={!props.disabled?.() && props.openHref}\n fallback={\n <button\n ref={(element) => (openButton = element)}\n type=\"button\"\n class=\"k2b-button\"\n data-variant=\"secondary\"\n data-size=\"sm\"\n onClick={() => void openInNewTab()}\n disabled={loading() || opening() || props.disabled?.()}\n >\n <i class={opening() ? \"ti ti-loader-2 k2b-spin\" : \"ti ti-external-link\"} aria-hidden=\"true\" />\n {props.openButtonLabel ?? messages().openPreview}\n </button>\n }\n >\n {(href) => (\n // A plain link to a real address: the browser opens it on the user's own click, and the tab can reload it.\n <a\n ref={(element) => (openButton = element)}\n class=\"k2b-button\"\n data-variant=\"secondary\"\n data-size=\"sm\"\n href={href()}\n target=\"_blank\"\n rel=\"noopener\"\n >\n <i class=\"ti ti-external-link\" aria-hidden=\"true\" />\n {props.openButtonLabel ?? messages().openPreview}\n </a>\n )}\n </Show>\n <Show when={props.onDownload}>\n <button\n type=\"button\"\n class=\"k2b-button\"\n data-variant=\"secondary\"\n data-size=\"sm\"\n onClick={() => props.onDownload?.()}\n disabled={props.disabled?.()}\n >\n <i class=\"ti ti-download\" aria-hidden=\"true\" />\n {messages().download}\n </button>\n </Show>\n <Show when={renderable()}>\n <button\n ref={renderButton}\n type=\"button\"\n class=\"k2b-button\"\n data-variant=\"secondary\"\n data-size=\"sm\"\n onClick={() => void load()}\n disabled={loading() || opening() || props.disabled?.()}\n >\n <i class={loading() ? \"ti ti-loader-2 k2b-spin\" : \"ti ti-file-type-pdf\"} aria-hidden=\"true\" />\n {props.buttonLabel ?? messages().previewPdf}\n </button>\n </Show>\n <Show when={tabBlocked()}>\n <span role=\"alert\" class=\"k2b-content-pdf-preview__notice\">\n {messages().pdfPreviewTabBlocked}\n </span>\n </Show>\n </div>\n );\n const content = () => (\n <Show\n when={error()}\n fallback={\n <Show\n when={url()}\n fallback={\n <div class=\"k2b-content-pdf-preview__empty\">\n <span role={loading() ? \"status\" : undefined}>\n {loading() ? messages().loading : (props.emptyText ?? messages().renderPdfPreview)}\n </span>\n </div>\n }\n >\n {(currentUrl) => (\n <iframe class=\"k2b-content-pdf-preview__frame\" src={currentUrl()} title={props.title ?? messages().pdfPreview} />\n )}\n </Show>\n }\n >\n {(message) =>\n props.renderError?.(message()) ?? (\n <div role=\"alert\" class=\"k2b-content-pdf-preview__error\">\n {message()}\n </div>\n )\n }\n </Show>\n );\n\n if (props.children)\n return props.children({\n get actions() {\n return actions();\n },\n get content() {\n return content();\n },\n });\n return (\n <section class={`k2b-content-pdf-preview ${props.class ?? \"\"}`}>\n <div class=\"k2b-content-pdf-preview__toolbar\">\n <div class=\"k2b-content-pdf-preview__heading\">\n <Show when={props.title}>\n <h2 class=\"k2b-content-pdf-preview__title\">{props.title}</h2>\n </Show>\n </div>\n {actions()}\n </div>\n {content()}\n </section>\n );\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["content/PdfPreview.tsx"],"sourcesContent":["import { createSignal, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { resolveUiMessages, useUiMessages } from \"../intl/messages\";\nimport Placeholder from \"../surfaces/Placeholder\";\n\nexport type PdfPreviewRequest = () => Promise<Response | Blob>;\n\nexport type PdfPreviewProps = {\n request: PdfPreviewRequest;\n autoLoad?: boolean;\n disabled?: () => boolean;\n title?: string;\n buttonLabel?: string;\n openButtonLabel?: string;\n /**\n * Opens the document at this address in a new tab instead of a local copy. Pass a stable same-origin URL that\n * serves the PDF inline, so reloading and the viewer's file name keep working. Without it, the open action shows\n * a temporary copy of the requested document.\n */\n openHref?: string;\n /** Adds a Download action. The host owns the download, for example a fresh attachment URL. */\n onDownload?: () => void;\n emptyText?: string;\n class?: string;\n children?: (parts: { actions: JSX.Element; content: JSX.Element }) => JSX.Element;\n renderError?: (message: string) => JSX.Element;\n};\n\nconst readErrorMessage = async (response: Response): Promise<string> => {\n try {\n const data = (await response.json()) as unknown;\n if (data && typeof data === \"object\" && \"message\" in data && typeof data.message === \"string\") return data.message;\n } catch {\n // Fall through to the HTTP status fallback.\n }\n return resolveUiMessages().pdfPreviewHttpError({ status: response.status });\n};\n\nexport default function PdfPreview(props: PdfPreviewProps) {\n const messages = useUiMessages();\n const [url, setUrl] = createSignal<string | null>(null);\n // An automatic preview starts loading once mounted. The server and the page before hydration already show that\n // state, so they offer neither a retry nor an invitation to render while nothing has failed.\n const [loading, setLoading] = createSignal(Boolean(props.autoLoad) && !props.disabled?.());\n const [opening, setOpening] = createSignal(false);\n const [error, setError] = createSignal<string | null>(null);\n const [failed, setFailed] = createSignal(false);\n const [tabBlocked, setTabBlocked] = createSignal(false);\n // An automatic preview shows one fixed document; the open action reuses it instead of requesting it again.\n let shownBlob: Blob | null = null;\n let openButton: HTMLElement | undefined;\n let renderButton: HTMLButtonElement | undefined;\n let errorRetryButton: HTMLButtonElement | undefined;\n let disposed = false;\n let loadGeneration = 0;\n let openGeneration = 0;\n\n const revokeCurrent = () => {\n const current = url();\n if (current) URL.revokeObjectURL(current);\n setUrl(null);\n };\n\n onCleanup(() => {\n disposed = true;\n loadGeneration += 1;\n openGeneration += 1;\n revokeCurrent();\n });\n\n const readPdfBlob = async () => {\n const response = await props.request();\n const blob = response instanceof Response ? (response.ok ? await response.blob() : null) : response;\n if (!blob) throw new Error(await readErrorMessage(response as Response));\n if (blob.type && blob.type !== \"application/pdf\") throw new Error(`PDF preview returned ${blob.type} instead of application/pdf`);\n return blob;\n };\n\n const load = async () => {\n if (loading() || opening() || props.disabled?.()) return;\n const generation = ++loadGeneration;\n // A retry the shown document or the loading state removes hands keyboard focus on instead of dropping it.\n const retryFocused =\n (props.autoLoad && document.activeElement === renderButton) ||\n (errorRetryButton?.isConnected && document.activeElement === errorRetryButton);\n setLoading(true);\n setError(null);\n try {\n const blob = await readPdfBlob();\n const nextUrl = URL.createObjectURL(blob);\n if (disposed || generation !== loadGeneration) {\n URL.revokeObjectURL(nextUrl);\n return;\n }\n const previousUrl = url();\n shownBlob = blob;\n setFailed(false);\n setUrl(nextUrl);\n setLoading(false);\n if (previousUrl) URL.revokeObjectURL(previousUrl);\n // The shown document removes the retry action; keep keyboard focus in the actions instead of the page.\n if (retryFocused && document.activeElement === document.body) openButton?.focus();\n } catch (e) {\n if (disposed || generation !== loadGeneration) return;\n shownBlob = null;\n setFailed(true);\n setError(e instanceof Error ? e.message : \"PDF preview failed\");\n if (retryFocused && document.activeElement === document.body) errorRetryButton?.focus();\n } finally {\n if (!disposed && generation === loadGeneration) setLoading(false);\n }\n };\n\n onMount(() => {\n // Hand the initial loading state to the request itself, which also covers a preview disabled by now.\n setLoading(false);\n if (props.autoLoad) void load();\n });\n\n const openInNewTab = async () => {\n if (loading() || opening() || props.disabled?.()) return;\n const generation = ++openGeneration;\n const tab = window.open(\"\", \"_blank\");\n // A blocked tab is not a document error: keep the shown document and report it beside the actions.\n setTabBlocked(!tab);\n if (!tab) return;\n tab.opener = null;\n tab.document.title = props.title ?? messages().pdfPreview;\n tab.document.body.textContent = messages().pdfPreviewRendering;\n setOpening(true);\n setError(null);\n try {\n const blob = (props.autoLoad ? shownBlob : null) ?? (await readPdfBlob());\n if (disposed || generation !== openGeneration) {\n tab.close();\n return;\n }\n const objectUrl = URL.createObjectURL(blob);\n tab.location.href = objectUrl;\n window.setTimeout(() => URL.revokeObjectURL(objectUrl), 60_000);\n } catch (e) {\n tab.close();\n if (!disposed && generation === openGeneration) setError(e instanceof Error ? e.message : \"PDF preview failed\");\n } finally {\n if (!disposed && generation === openGeneration) setOpening(false);\n }\n };\n\n // With autoLoad, rendering again would show the same document: offer it only until one is shown. After a failure the\n // default error state carries it as the retry; beside a caller's error content it stays in place while a retry loads.\n const renderable = () => !props.autoLoad || (failed() ? Boolean(props.renderError) : !url() && !loading());\n const actions = () => (\n <div class=\"k2b-content-pdf-preview__actions\">\n <Show\n when={!props.disabled?.() && props.openHref}\n fallback={\n <button\n ref={(element) => (openButton = element)}\n type=\"button\"\n class=\"k2b-button\"\n data-variant=\"secondary\"\n data-size=\"sm\"\n onClick={() => void openInNewTab()}\n disabled={loading() || opening() || props.disabled?.()}\n >\n <i class={opening() ? \"ti ti-loader-2 k2b-spin\" : \"ti ti-external-link\"} aria-hidden=\"true\" />\n {props.openButtonLabel ?? messages().openPreview}\n </button>\n }\n >\n {(href) => (\n // A plain link to a real address: the browser opens it on the user's own click, and the tab can reload it.\n <a\n ref={(element) => (openButton = element)}\n class=\"k2b-button\"\n data-variant=\"secondary\"\n data-size=\"sm\"\n href={href()}\n target=\"_blank\"\n rel=\"noopener\"\n >\n <i class=\"ti ti-external-link\" aria-hidden=\"true\" />\n {props.openButtonLabel ?? messages().openPreview}\n </a>\n )}\n </Show>\n <Show when={props.onDownload}>\n <button\n type=\"button\"\n class=\"k2b-button\"\n data-variant=\"secondary\"\n data-size=\"sm\"\n onClick={() => props.onDownload?.()}\n disabled={props.disabled?.()}\n >\n <i class=\"ti ti-download\" aria-hidden=\"true\" />\n {messages().download}\n </button>\n </Show>\n <Show when={renderable()}>\n <button\n ref={renderButton}\n type=\"button\"\n class=\"k2b-button\"\n data-variant=\"secondary\"\n data-size=\"sm\"\n onClick={() => void load()}\n disabled={loading() || opening() || props.disabled?.()}\n >\n <i class={loading() ? \"ti ti-loader-2 k2b-spin\" : \"ti ti-file-type-pdf\"} aria-hidden=\"true\" />\n {props.buttonLabel ?? messages().previewPdf}\n </button>\n </Show>\n <Show when={tabBlocked()}>\n <span role=\"alert\" class=\"k2b-content-pdf-preview__notice\">\n {messages().pdfPreviewTabBlocked}\n </span>\n </Show>\n </div>\n );\n // Every state before a document is shown uses one placeholder in the viewer's box, so loading changes no layout.\n const content = () => (\n <Show\n when={error()}\n fallback={\n <Show\n when={url()}\n fallback={\n <Placeholder\n class=\"k2b-content-pdf-preview__placeholder\"\n state={loading() ? \"loading\" : \"empty\"}\n icon={loading() ? undefined : \"ti ti-file-type-pdf\"}\n title={loading() ? messages().loading : undefined}\n description={loading() ? undefined : (props.emptyText ?? messages().renderPdfPreview)}\n />\n }\n >\n {(currentUrl) => (\n <iframe class=\"k2b-content-pdf-preview__frame\" src={currentUrl()} title={props.title ?? messages().pdfPreview} />\n )}\n </Show>\n }\n >\n {(message) =>\n props.renderError?.(message()) ?? (\n <Placeholder\n class=\"k2b-content-pdf-preview__placeholder\"\n state=\"error\"\n description={message()}\n action={\n // One retry at a time: the render action moves here only where the toolbar no longer offers it.\n renderable() ? undefined : (\n <button\n ref={(element) => (errorRetryButton = element)}\n type=\"button\"\n class=\"k2b-button\"\n data-variant=\"secondary\"\n data-size=\"sm\"\n onClick={() => void load()}\n disabled={opening() || props.disabled?.()}\n >\n {props.buttonLabel ?? messages().retry}\n </button>\n )\n }\n />\n )\n }\n </Show>\n );\n\n if (props.children)\n return props.children({\n get actions() {\n return actions();\n },\n get content() {\n return content();\n },\n });\n return (\n <section class={`k2b-content-pdf-preview ${props.class ?? \"\"}`}>\n <div class=\"k2b-content-pdf-preview__toolbar\">\n <div class=\"k2b-content-pdf-preview__heading\">\n <Show when={props.title}>\n <h2 class=\"k2b-content-pdf-preview__title\">{props.title}</h2>\n </Show>\n </div>\n {actions()}\n </div>\n {content()}\n </section>\n );\n}\n"],"mappings":"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","ignoreList":[]}