@k2b/ui 0.8.0 → 0.9.1

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 (48) hide show
  1. package/dist/browser/content/Calendar.js +12 -5
  2. package/dist/browser/content/Calendar.js.map +1 -1
  3. package/dist/browser/content/MarkdownView.js +8 -1
  4. package/dist/browser/content/MarkdownView.js.map +1 -1
  5. package/dist/browser/content/PdfPreview.js +170 -72
  6. package/dist/browser/content/PdfPreview.js.map +1 -1
  7. package/dist/browser/feedback/dialog-core.js +2 -1
  8. package/dist/browser/feedback/dialog-core.js.map +1 -1
  9. package/dist/browser/feedback/prompts.js +20 -6
  10. package/dist/browser/feedback/prompts.js.map +1 -1
  11. package/dist/browser/feedback/toast.js +4 -2
  12. package/dist/browser/feedback/toast.js.map +1 -1
  13. package/dist/browser/intl/messages.js +48 -2
  14. package/dist/browser/intl/messages.js.map +1 -1
  15. package/dist/browser/layout/Navigation.js +8 -5
  16. package/dist/browser/layout/Navigation.js.map +1 -1
  17. package/dist/browser/layout/SettingsModal.js +32 -10
  18. package/dist/browser/layout/SettingsModal.js.map +1 -1
  19. package/dist/browser/layout/navigation-model.js +1 -0
  20. package/dist/browser/layout/navigation-model.js.map +1 -1
  21. package/dist/ssr/content/Calendar.js +13 -6
  22. package/dist/ssr/content/Calendar.js.map +1 -1
  23. package/dist/ssr/content/MarkdownView.js +8 -1
  24. package/dist/ssr/content/MarkdownView.js.map +1 -1
  25. package/dist/ssr/content/PdfPreview.js +79 -22
  26. package/dist/ssr/content/PdfPreview.js.map +1 -1
  27. package/dist/ssr/feedback/dialog-core.js +2 -1
  28. package/dist/ssr/feedback/dialog-core.js.map +1 -1
  29. package/dist/ssr/feedback/prompts.js +19 -5
  30. package/dist/ssr/feedback/prompts.js.map +1 -1
  31. package/dist/ssr/feedback/toast.js +4 -2
  32. package/dist/ssr/feedback/toast.js.map +1 -1
  33. package/dist/ssr/intl/messages.js +48 -2
  34. package/dist/ssr/intl/messages.js.map +1 -1
  35. package/dist/ssr/layout/Navigation.js +8 -5
  36. package/dist/ssr/layout/Navigation.js.map +1 -1
  37. package/dist/ssr/layout/SettingsModal.js +30 -5
  38. package/dist/ssr/layout/SettingsModal.js.map +1 -1
  39. package/dist/ssr/layout/navigation-model.js +1 -0
  40. package/dist/ssr/layout/navigation-model.js.map +1 -1
  41. package/dist/styles.css +1 -1
  42. package/dist/tabler-icons-15sezdfp.woff2 +0 -0
  43. package/dist/tabler.css +2 -2
  44. package/dist/types/content/PdfPreview.d.ts +8 -0
  45. package/dist/types/intl/messages.d.ts +23 -0
  46. package/dist/types/layout/navigation-model.d.ts +5 -0
  47. package/package.json +7 -6
  48. package/dist/tabler-icons-q30jt7jk.woff2 +0 -0
@@ -24,7 +24,14 @@ const isStandaloneInlineToken = (text, start, value) => {
24
24
  const createSafeRenderer = (options = {}) => {
25
25
  const renderer = new Renderer();
26
26
  const inlineTokens = normalizeInlineTokens(options.inlineTokens);
27
- const renderText = renderer.text.bind(renderer);
27
+ const baseText = renderer.text.bind(renderer);
28
+ // marked flags text that follows an inline <pre>, <code>, <kbd> or <script>
29
+ // tag as already escaped, because it expects that tag to reach the output as
30
+ // HTML. The tag is escaped here, so the text after it is escaped as well.
31
+ const renderText = token => baseText(token.type === "text" && token.escaped ? {
32
+ ...token,
33
+ escaped: false
34
+ } : token);
28
35
  const renderTable = renderer.table.bind(renderer);
29
36
  renderer.table = token => {
30
37
  const table = renderTable(token);
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["content/MarkdownView.tsx"],"sourcesContent":["import { marked, Renderer, type Tokens } from \"marked\";\n\ntype CommonProps = MarkdownRenderOptions & {\n /** Optional additional CSS classes */\n class?: string;\n /**\n * Visual heading scale. Markdown heading levels and document structure stay\n * unchanged.\n */\n headingScale?: \"compact\" | \"normal\" | \"large\";\n};\n\nexport type MarkdownViewProps = CommonProps &\n (\n | {\n /** Untrusted Markdown. Raw HTML and unsafe link protocols are escaped. */\n markdown: string;\n /** Exact standalone text tokens to emphasize without changing Markdown parsing or trusted-HTML boundaries. */\n inlineTokens?: readonly string[];\n trustedHtml?: never;\n }\n | {\n /** Explicitly trusted, already-rendered HTML. The caller owns sanitization. */\n trustedHtml: string;\n markdown?: never;\n inlineTokens?: never;\n }\n );\n\nexport type MarkdownRenderOptions = {\n inlineTokens?: readonly string[];\n /** Whether to render images. False renders alt text without resource requests. Defaults to true. */\n allowImages?: boolean;\n /** Optional protocol allowlist, including trailing colons. Relative URLs resolve as HTTPS. */\n linkProtocols?: readonly string[];\n linkTarget?: \"_blank\";\n};\n\nconst escapeHtml = (value: string): string =>\n value.replaceAll(\"&\", \"&amp;\").replaceAll(\"<\", \"&lt;\").replaceAll(\">\", \"&gt;\").replaceAll('\"', \"&quot;\").replaceAll(\"'\", \"&#39;\");\n\nconst safeUrl = (value: string): string | null => {\n const normalized = value.trim().replace(/[\\u0000-\\u001f\\u007f-\\u009f\\s]+/g, \"\");\n if (/^(?:javascript|vbscript|data):/i.test(normalized)) return null;\n return value;\n};\n\nconst normalizeInlineTokens = (tokens: readonly string[] | undefined): string[] =>\n [...new Set(tokens?.filter(Boolean) ?? [])].sort((left, right) => right.length - left.length);\n\nconst isStandaloneInlineToken = (text: string, start: number, value: string): boolean => {\n const before = text[start - 1];\n if (before && /[a-zA-Z0-9_.%+\\-]/.test(before)) return false;\n const end = start + value.length;\n const after = text[end];\n if (after && /[a-zA-Z0-9_@]/.test(after)) return false;\n return !(after === \".\" && /[a-zA-Z0-9_]/.test(text[end + 1] ?? \"\"));\n};\n\nconst createSafeRenderer = (options: MarkdownRenderOptions = {}): Renderer => {\n const renderer = new Renderer();\n const inlineTokens = normalizeInlineTokens(options.inlineTokens);\n const renderText = renderer.text.bind(renderer);\n const renderTable = renderer.table.bind(renderer);\n renderer.table = (token: Tokens.Table) => {\n const table = renderTable(token);\n const content = token.header.every((cell) => !cell.text.trim()) ? table.replace(/<thead>[\\s\\S]*?<\\/thead>\\n?/, \"\") : table;\n return `<div class=\"k2b-content-markdown__table\" tabindex=\"0\">${content}</div>`;\n };\n renderer.html = ({ text }: Tokens.HTML | Tokens.Tag) => escapeHtml(text);\n renderer.link = function ({ href, title, tokens }: Tokens.Link) {\n const body = this.parser.parseInline(tokens);\n const url = safeUrl(href);\n if (!url) return body;\n if (options.linkProtocols) {\n try {\n if (!options.linkProtocols.includes(new URL(url, \"https://markdown.invalid/\").protocol)) return body;\n } catch {\n return body;\n }\n }\n const titleAttribute = title ? ` title=\"${escapeHtml(title)}\"` : \"\";\n const target = options.linkTarget === \"_blank\" ? ' target=\"_blank\" rel=\"noopener noreferrer\"' : \"\";\n return `<a href=\"${escapeHtml(url)}\"${titleAttribute}${target}>${body}</a>`;\n };\n renderer.image = ({ href, title, text }: Tokens.Image) => {\n const url = safeUrl(href);\n if (!url || options.allowImages === false) return escapeHtml(text);\n const titleAttribute = title ? ` title=\"${escapeHtml(title)}\"` : \"\";\n return `<img src=\"${escapeHtml(url)}\" alt=\"${escapeHtml(text)}\"${titleAttribute}>`;\n };\n renderer.text = (token) => {\n if (inlineTokens.length === 0 || token.type === \"escape\" || (\"tokens\" in token && token.tokens)) return renderText(token);\n const parts: string[] = [];\n let plainStart = 0;\n let cursor = 0;\n while (cursor < token.text.length) {\n const inlineToken = inlineTokens.find(\n (candidate) => token.text.startsWith(candidate, cursor) && isStandaloneInlineToken(token.text, cursor, candidate),\n );\n if (!inlineToken) {\n cursor += 1;\n continue;\n }\n if (plainStart < cursor) {\n const text = token.text.slice(plainStart, cursor);\n parts.push(renderText({ ...token, raw: text, text }));\n }\n parts.push(\n `<span class=\"k2b-content-markdown__inline-token\">${renderText({ ...token, raw: inlineToken, text: inlineToken })}</span>`,\n );\n cursor += inlineToken.length;\n plainStart = cursor;\n }\n if (plainStart === 0) return renderText(token);\n if (plainStart < token.text.length) {\n const text = token.text.slice(plainStart);\n parts.push(renderText({ ...token, raw: text, text }));\n }\n return parts.join(\"\");\n };\n return renderer;\n};\n\nexport const renderSafeMarkdown = (markdown: string, options: MarkdownRenderOptions = {}): string =>\n marked.parse(markdown, {\n async: false,\n renderer: createSafeRenderer(options),\n }) as string;\n\n/**\n * Markdown View Component (SSR)\n *\n * Renders untrusted Markdown safely by default. Raw HTML and unsafe link\n * protocols are escaped. Already-rendered HTML requires the deliberately named\n * `trustedHtml` boundary; the caller owns sanitization in that mode.\n *\n * @example\n * ```tsx\n * import { MarkdownView } from \"@k2b/ui\";\n *\n * <MarkdownView markdown={source} />;\n * ```\n *\n * @example Compact headings, e.g. inside comments or file previews:\n * ```tsx\n * <MarkdownView markdown={source} headingScale=\"compact\" />;\n * ```\n */\nexport default function MarkdownView(props: MarkdownViewProps) {\n const html = () =>\n props.markdown !== undefined\n ? renderSafeMarkdown(props.markdown, {\n inlineTokens: props.inlineTokens,\n allowImages: props.allowImages,\n linkProtocols: props.linkProtocols,\n linkTarget: props.linkTarget,\n })\n : props.trustedHtml;\n return (\n <div\n class={`k2b-content-markdown ${props.class ?? \"\"}`}\n data-heading-scale={props.headingScale && props.headingScale !== \"normal\" ? props.headingScale : undefined}\n innerHTML={html()}\n />\n );\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["content/MarkdownView.tsx"],"sourcesContent":["import { marked, Renderer, type Tokens } from \"marked\";\n\ntype CommonProps = MarkdownRenderOptions & {\n /** Optional additional CSS classes */\n class?: string;\n /**\n * Visual heading scale. Markdown heading levels and document structure stay\n * unchanged.\n */\n headingScale?: \"compact\" | \"normal\" | \"large\";\n};\n\nexport type MarkdownViewProps = CommonProps &\n (\n | {\n /** Untrusted Markdown. Raw HTML and unsafe link protocols are escaped. */\n markdown: string;\n /** Exact standalone text tokens to emphasize without changing Markdown parsing or trusted-HTML boundaries. */\n inlineTokens?: readonly string[];\n trustedHtml?: never;\n }\n | {\n /** Explicitly trusted, already-rendered HTML. The caller owns sanitization. */\n trustedHtml: string;\n markdown?: never;\n inlineTokens?: never;\n }\n );\n\nexport type MarkdownRenderOptions = {\n inlineTokens?: readonly string[];\n /** Whether to render images. False renders alt text without resource requests. Defaults to true. */\n allowImages?: boolean;\n /** Optional protocol allowlist, including trailing colons. Relative URLs resolve as HTTPS. */\n linkProtocols?: readonly string[];\n linkTarget?: \"_blank\";\n};\n\nconst escapeHtml = (value: string): string =>\n value.replaceAll(\"&\", \"&amp;\").replaceAll(\"<\", \"&lt;\").replaceAll(\">\", \"&gt;\").replaceAll('\"', \"&quot;\").replaceAll(\"'\", \"&#39;\");\n\nconst safeUrl = (value: string): string | null => {\n const normalized = value.trim().replace(/[\\u0000-\\u001f\\u007f-\\u009f\\s]+/g, \"\");\n if (/^(?:javascript|vbscript|data):/i.test(normalized)) return null;\n return value;\n};\n\nconst normalizeInlineTokens = (tokens: readonly string[] | undefined): string[] =>\n [...new Set(tokens?.filter(Boolean) ?? [])].sort((left, right) => right.length - left.length);\n\nconst isStandaloneInlineToken = (text: string, start: number, value: string): boolean => {\n const before = text[start - 1];\n if (before && /[a-zA-Z0-9_.%+\\-]/.test(before)) return false;\n const end = start + value.length;\n const after = text[end];\n if (after && /[a-zA-Z0-9_@]/.test(after)) return false;\n return !(after === \".\" && /[a-zA-Z0-9_]/.test(text[end + 1] ?? \"\"));\n};\n\nconst createSafeRenderer = (options: MarkdownRenderOptions = {}): Renderer => {\n const renderer = new Renderer();\n const inlineTokens = normalizeInlineTokens(options.inlineTokens);\n const baseText = renderer.text.bind(renderer);\n // marked flags text that follows an inline <pre>, <code>, <kbd> or <script>\n // tag as already escaped, because it expects that tag to reach the output as\n // HTML. The tag is escaped here, so the text after it is escaped as well.\n const renderText: Renderer[\"text\"] = (token) => baseText(token.type === \"text\" && token.escaped ? { ...token, escaped: false } : token);\n const renderTable = renderer.table.bind(renderer);\n renderer.table = (token: Tokens.Table) => {\n const table = renderTable(token);\n const content = token.header.every((cell) => !cell.text.trim()) ? table.replace(/<thead>[\\s\\S]*?<\\/thead>\\n?/, \"\") : table;\n return `<div class=\"k2b-content-markdown__table\" tabindex=\"0\">${content}</div>`;\n };\n renderer.html = ({ text }: Tokens.HTML | Tokens.Tag) => escapeHtml(text);\n renderer.link = function ({ href, title, tokens }: Tokens.Link) {\n const body = this.parser.parseInline(tokens);\n const url = safeUrl(href);\n if (!url) return body;\n if (options.linkProtocols) {\n try {\n if (!options.linkProtocols.includes(new URL(url, \"https://markdown.invalid/\").protocol)) return body;\n } catch {\n return body;\n }\n }\n const titleAttribute = title ? ` title=\"${escapeHtml(title)}\"` : \"\";\n const target = options.linkTarget === \"_blank\" ? ' target=\"_blank\" rel=\"noopener noreferrer\"' : \"\";\n return `<a href=\"${escapeHtml(url)}\"${titleAttribute}${target}>${body}</a>`;\n };\n renderer.image = ({ href, title, text }: Tokens.Image) => {\n const url = safeUrl(href);\n if (!url || options.allowImages === false) return escapeHtml(text);\n const titleAttribute = title ? ` title=\"${escapeHtml(title)}\"` : \"\";\n return `<img src=\"${escapeHtml(url)}\" alt=\"${escapeHtml(text)}\"${titleAttribute}>`;\n };\n renderer.text = (token) => {\n if (inlineTokens.length === 0 || token.type === \"escape\" || (\"tokens\" in token && token.tokens)) return renderText(token);\n const parts: string[] = [];\n let plainStart = 0;\n let cursor = 0;\n while (cursor < token.text.length) {\n const inlineToken = inlineTokens.find(\n (candidate) => token.text.startsWith(candidate, cursor) && isStandaloneInlineToken(token.text, cursor, candidate),\n );\n if (!inlineToken) {\n cursor += 1;\n continue;\n }\n if (plainStart < cursor) {\n const text = token.text.slice(plainStart, cursor);\n parts.push(renderText({ ...token, raw: text, text }));\n }\n parts.push(\n `<span class=\"k2b-content-markdown__inline-token\">${renderText({ ...token, raw: inlineToken, text: inlineToken })}</span>`,\n );\n cursor += inlineToken.length;\n plainStart = cursor;\n }\n if (plainStart === 0) return renderText(token);\n if (plainStart < token.text.length) {\n const text = token.text.slice(plainStart);\n parts.push(renderText({ ...token, raw: text, text }));\n }\n return parts.join(\"\");\n };\n return renderer;\n};\n\nexport const renderSafeMarkdown = (markdown: string, options: MarkdownRenderOptions = {}): string =>\n marked.parse(markdown, {\n async: false,\n renderer: createSafeRenderer(options),\n }) as string;\n\n/**\n * Markdown View Component (SSR)\n *\n * Renders untrusted Markdown safely by default. Raw HTML and unsafe link\n * protocols are escaped. Already-rendered HTML requires the deliberately named\n * `trustedHtml` boundary; the caller owns sanitization in that mode.\n *\n * @example\n * ```tsx\n * import { MarkdownView } from \"@k2b/ui\";\n *\n * <MarkdownView markdown={source} />;\n * ```\n *\n * @example Compact headings, e.g. inside comments or file previews:\n * ```tsx\n * <MarkdownView markdown={source} headingScale=\"compact\" />;\n * ```\n */\nexport default function MarkdownView(props: MarkdownViewProps) {\n const html = () =>\n props.markdown !== undefined\n ? renderSafeMarkdown(props.markdown, {\n inlineTokens: props.inlineTokens,\n allowImages: props.allowImages,\n linkProtocols: props.linkProtocols,\n linkTarget: props.linkTarget,\n })\n : props.trustedHtml;\n return (\n <div\n class={`k2b-content-markdown ${props.class ?? \"\"}`}\n data-heading-scale={props.headingScale && props.headingScale !== \"normal\" ? props.headingScale : undefined}\n innerHTML={html()}\n />\n );\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,21 +1,26 @@
1
1
  import { template as _$template } from "solid-js/web";
2
2
  import { delegateEvents as _$delegateEvents } from "solid-js/web";
3
3
  import { setAttribute as _$setAttribute } from "solid-js/web";
4
- import { createComponent as _$createComponent } from "solid-js/web";
5
4
  import { className as _$className } from "solid-js/web";
5
+ import { use as _$use } from "solid-js/web";
6
6
  import { setProperty as _$setProperty } from "solid-js/web";
7
7
  import { effect as _$effect } from "solid-js/web";
8
8
  import { getNextElement as _$getNextElement } from "solid-js/web";
9
9
  import { runHydrationEvents as _$runHydrationEvents } from "solid-js/web";
10
10
  import { getNextMarker as _$getNextMarker } from "solid-js/web";
11
11
  import { insert as _$insert } from "solid-js/web";
12
+ import { createComponent as _$createComponent } from "solid-js/web";
12
13
  import { memo as _$memo } from "solid-js/web";
13
- var _tmpl$ = /*#__PURE__*/_$template(`<div class=k2b-content-pdf-preview__actions><button type=button class=k2b-button data-variant=secondary data-size=sm><i aria-hidden=true></i><!$><!/></button><button type=button class=k2b-button data-variant=secondary data-size=sm><i aria-hidden=true></i><!$><!/>`),
14
- _tmpl$2 = /*#__PURE__*/_$template(`<div class=k2b-content-pdf-preview__empty><span>`),
15
- _tmpl$3 = /*#__PURE__*/_$template(`<iframe class=k2b-content-pdf-preview__frame>`),
16
- _tmpl$4 = /*#__PURE__*/_$template(`<div role=alert class=k2b-content-pdf-preview__error>`),
17
- _tmpl$5 = /*#__PURE__*/_$template(`<h2 class=k2b-content-pdf-preview__title>`),
18
- _tmpl$6 = /*#__PURE__*/_$template(`<section><div class=k2b-content-pdf-preview__toolbar><div class=k2b-content-pdf-preview__heading></div><!$><!/></div><!$><!/>`);
14
+ var _tmpl$ = /*#__PURE__*/_$template(`<button type=button class=k2b-button data-variant=secondary data-size=sm><i class="ti ti-download"aria-hidden=true></i><!$><!/>`),
15
+ _tmpl$2 = /*#__PURE__*/_$template(`<button type=button class=k2b-button data-variant=secondary data-size=sm><i aria-hidden=true></i><!$><!/>`),
16
+ _tmpl$3 = /*#__PURE__*/_$template(`<span role=alert class=k2b-content-pdf-preview__notice>`),
17
+ _tmpl$4 = /*#__PURE__*/_$template(`<div class=k2b-content-pdf-preview__actions><!$><!/><!$><!/><!$><!/><!$><!/>`),
18
+ _tmpl$5 = /*#__PURE__*/_$template(`<a class=k2b-button data-variant=secondary data-size=sm target=_blank rel=noopener><i class="ti ti-external-link"aria-hidden=true></i><!$><!/>`),
19
+ _tmpl$6 = /*#__PURE__*/_$template(`<div class=k2b-content-pdf-preview__empty><span>`),
20
+ _tmpl$7 = /*#__PURE__*/_$template(`<iframe class=k2b-content-pdf-preview__frame>`),
21
+ _tmpl$8 = /*#__PURE__*/_$template(`<div role=alert class=k2b-content-pdf-preview__error>`),
22
+ _tmpl$9 = /*#__PURE__*/_$template(`<h2 class=k2b-content-pdf-preview__title>`),
23
+ _tmpl$0 = /*#__PURE__*/_$template(`<section><div class=k2b-content-pdf-preview__toolbar><div class=k2b-content-pdf-preview__heading></div><!$><!/></div><!$><!/>`);
19
24
  import { createSignal, onCleanup, onMount, Show } from "solid-js";
20
25
  import { resolveUiMessages, useUiMessages } from "../intl/messages";
21
26
  const readErrorMessage = async response => {
@@ -32,9 +37,17 @@ const readErrorMessage = async response => {
32
37
  export default function PdfPreview(props) {
33
38
  const messages = useUiMessages();
34
39
  const [url, setUrl] = createSignal(null);
35
- const [loading, setLoading] = createSignal(false);
40
+ // An automatic preview starts loading once mounted. The server and the page before hydration already show that
41
+ // state, so they offer neither a retry nor an invitation to render while nothing has failed.
42
+ const [loading, setLoading] = createSignal(Boolean(props.autoLoad) && !props.disabled?.());
36
43
  const [opening, setOpening] = createSignal(false);
37
44
  const [error, setError] = createSignal(null);
45
+ const [failed, setFailed] = createSignal(false);
46
+ const [tabBlocked, setTabBlocked] = createSignal(false);
47
+ // An automatic preview shows one fixed document; the open action reuses it instead of requesting it again.
48
+ let shownBlob = null;
49
+ let openButton;
50
+ let renderButton;
38
51
  let disposed = false;
39
52
  let loadGeneration = 0;
40
53
  let openGeneration = 0;
@@ -59,6 +72,7 @@ export default function PdfPreview(props) {
59
72
  const load = async () => {
60
73
  if (loading() || opening() || props.disabled?.()) return;
61
74
  const generation = ++loadGeneration;
75
+ const retryFocused = props.autoLoad && document.activeElement === renderButton;
62
76
  setLoading(true);
63
77
  setError(null);
64
78
  try {
@@ -69,32 +83,41 @@ export default function PdfPreview(props) {
69
83
  return;
70
84
  }
71
85
  const previousUrl = url();
86
+ shownBlob = blob;
87
+ setFailed(false);
72
88
  setUrl(nextUrl);
89
+ setLoading(false);
73
90
  if (previousUrl) URL.revokeObjectURL(previousUrl);
91
+ // The shown document removes the retry action; keep keyboard focus in the actions instead of the page.
92
+ if (retryFocused && document.activeElement === document.body) openButton?.focus();
74
93
  } catch (e) {
75
- if (!disposed && generation === loadGeneration) setError(e instanceof Error ? e.message : "PDF preview failed");
94
+ if (disposed || generation !== loadGeneration) return;
95
+ shownBlob = null;
96
+ setFailed(true);
97
+ setError(e instanceof Error ? e.message : "PDF preview failed");
76
98
  } finally {
77
99
  if (!disposed && generation === loadGeneration) setLoading(false);
78
100
  }
79
101
  };
80
102
  onMount(() => {
103
+ // Hand the initial loading state to the request itself, which also covers a preview disabled by now.
104
+ setLoading(false);
81
105
  if (props.autoLoad) void load();
82
106
  });
83
107
  const openInNewTab = async () => {
84
108
  if (loading() || opening() || props.disabled?.()) return;
85
109
  const generation = ++openGeneration;
86
110
  const tab = window.open("", "_blank");
87
- if (!tab) {
88
- setError("Browser blocked the preview tab");
89
- return;
90
- }
111
+ // A blocked tab is not a document error: keep the shown document and report it beside the actions.
112
+ setTabBlocked(!tab);
113
+ if (!tab) return;
91
114
  tab.opener = null;
92
115
  tab.document.title = props.title ?? messages().pdfPreview;
93
- tab.document.body.textContent = "Rendering PDF preview...";
116
+ tab.document.body.textContent = messages().pdfPreviewRendering;
94
117
  setOpening(true);
95
118
  setError(null);
96
119
  try {
97
- const blob = await readPdfBlob();
120
+ const blob = (props.autoLoad ? shownBlob : null) ?? (await readPdfBlob());
98
121
  if (disposed || generation !== openGeneration) {
99
122
  tab.close();
100
123
  return;
@@ -109,37 +132,112 @@ export default function PdfPreview(props) {
109
132
  if (!disposed && generation === openGeneration) setOpening(false);
110
133
  }
111
134
  };
135
+
136
+ // With autoLoad, rendering again would show the same document: offer it only until one is shown, e.g. to retry,
137
+ // and keep it in place while a retry loads.
138
+ const renderable = () => !props.autoLoad || failed() || !url() && !loading();
112
139
  const actions = () => (() => {
113
- var _el$ = _$getNextElement(_tmpl$),
114
- _el$2 = _el$.firstChild,
115
- _el$3 = _el$2.firstChild,
116
- _el$4 = _el$3.nextSibling,
117
- [_el$5, _co$] = _$getNextMarker(_el$4.nextSibling),
118
- _el$6 = _el$2.nextSibling,
119
- _el$7 = _el$6.firstChild,
120
- _el$8 = _el$7.nextSibling,
121
- [_el$9, _co$2] = _$getNextMarker(_el$8.nextSibling);
122
- _el$2.$$click = () => void openInNewTab();
123
- _$insert(_el$2, () => props.openButtonLabel ?? messages().openPreview, _el$5, _co$);
124
- _el$6.$$click = () => void load();
125
- _$insert(_el$6, () => props.buttonLabel ?? messages().previewPdf, _el$9, _co$2);
126
- _$effect(_p$ => {
127
- var _v$ = loading() || opening() || props.disabled?.(),
128
- _v$2 = opening() ? "ti ti-loader-2 k2b-spin" : "ti ti-external-link",
129
- _v$3 = loading() || opening() || props.disabled?.(),
130
- _v$4 = loading() ? "ti ti-loader-2 k2b-spin" : "ti ti-file-type-pdf";
131
- _v$ !== _p$.e && _$setProperty(_el$2, "disabled", _p$.e = _v$);
132
- _v$2 !== _p$.t && _$className(_el$3, _p$.t = _v$2);
133
- _v$3 !== _p$.a && _$setProperty(_el$6, "disabled", _p$.a = _v$3);
134
- _v$4 !== _p$.o && _$className(_el$7, _p$.o = _v$4);
135
- return _p$;
136
- }, {
137
- e: undefined,
138
- t: undefined,
139
- a: undefined,
140
- o: undefined
141
- });
142
- _$runHydrationEvents();
140
+ var _el$ = _$getNextElement(_tmpl$4),
141
+ _el$1 = _el$.firstChild,
142
+ [_el$10, _co$3] = _$getNextMarker(_el$1.nextSibling),
143
+ _el$11 = _el$10.nextSibling,
144
+ [_el$12, _co$4] = _$getNextMarker(_el$11.nextSibling),
145
+ _el$13 = _el$12.nextSibling,
146
+ [_el$14, _co$5] = _$getNextMarker(_el$13.nextSibling),
147
+ _el$15 = _el$14.nextSibling,
148
+ [_el$16, _co$6] = _$getNextMarker(_el$15.nextSibling);
149
+ _$insert(_el$, _$createComponent(Show, {
150
+ get when() {
151
+ return _$memo(() => !!!props.disabled?.())() && props.openHref;
152
+ },
153
+ get fallback() {
154
+ return (() => {
155
+ var _el$17 = _$getNextElement(_tmpl$2),
156
+ _el$18 = _el$17.firstChild,
157
+ _el$19 = _el$18.nextSibling,
158
+ [_el$20, _co$7] = _$getNextMarker(_el$19.nextSibling);
159
+ _el$17.$$click = () => void openInNewTab();
160
+ _$use(element => openButton = element, _el$17);
161
+ _$insert(_el$17, () => props.openButtonLabel ?? messages().openPreview, _el$20, _co$7);
162
+ _$effect(_p$ => {
163
+ var _v$3 = loading() || opening() || props.disabled?.(),
164
+ _v$4 = opening() ? "ti ti-loader-2 k2b-spin" : "ti ti-external-link";
165
+ _v$3 !== _p$.e && _$setProperty(_el$17, "disabled", _p$.e = _v$3);
166
+ _v$4 !== _p$.t && _$className(_el$18, _p$.t = _v$4);
167
+ return _p$;
168
+ }, {
169
+ e: undefined,
170
+ t: undefined
171
+ });
172
+ _$runHydrationEvents();
173
+ return _el$17;
174
+ })();
175
+ },
176
+ children: href => // A plain link to a real address: the browser opens it on the user's own click, and the tab can reload it.
177
+ (() => {
178
+ var _el$21 = _$getNextElement(_tmpl$5),
179
+ _el$22 = _el$21.firstChild,
180
+ _el$23 = _el$22.nextSibling,
181
+ [_el$24, _co$8] = _$getNextMarker(_el$23.nextSibling);
182
+ _$use(element => openButton = element, _el$21);
183
+ _$insert(_el$21, () => props.openButtonLabel ?? messages().openPreview, _el$24, _co$8);
184
+ _$effect(() => _$setAttribute(_el$21, "href", href()));
185
+ return _el$21;
186
+ })()
187
+ }), _el$10, _co$3);
188
+ _$insert(_el$, _$createComponent(Show, {
189
+ get when() {
190
+ return props.onDownload;
191
+ },
192
+ get children() {
193
+ var _el$2 = _$getNextElement(_tmpl$),
194
+ _el$3 = _el$2.firstChild,
195
+ _el$4 = _el$3.nextSibling,
196
+ [_el$5, _co$] = _$getNextMarker(_el$4.nextSibling);
197
+ _el$2.$$click = () => props.onDownload?.();
198
+ _$insert(_el$2, () => messages().download, _el$5, _co$);
199
+ _$effect(() => _$setProperty(_el$2, "disabled", props.disabled?.()));
200
+ _$runHydrationEvents();
201
+ return _el$2;
202
+ }
203
+ }), _el$12, _co$4);
204
+ _$insert(_el$, _$createComponent(Show, {
205
+ get when() {
206
+ return renderable();
207
+ },
208
+ get children() {
209
+ var _el$6 = _$getNextElement(_tmpl$2),
210
+ _el$7 = _el$6.firstChild,
211
+ _el$8 = _el$7.nextSibling,
212
+ [_el$9, _co$2] = _$getNextMarker(_el$8.nextSibling);
213
+ _el$6.$$click = () => void load();
214
+ var _ref$ = renderButton;
215
+ typeof _ref$ === "function" ? _$use(_ref$, _el$6) : renderButton = _el$6;
216
+ _$insert(_el$6, () => props.buttonLabel ?? messages().previewPdf, _el$9, _co$2);
217
+ _$effect(_p$ => {
218
+ var _v$ = loading() || opening() || props.disabled?.(),
219
+ _v$2 = loading() ? "ti ti-loader-2 k2b-spin" : "ti ti-file-type-pdf";
220
+ _v$ !== _p$.e && _$setProperty(_el$6, "disabled", _p$.e = _v$);
221
+ _v$2 !== _p$.t && _$className(_el$7, _p$.t = _v$2);
222
+ return _p$;
223
+ }, {
224
+ e: undefined,
225
+ t: undefined
226
+ });
227
+ _$runHydrationEvents();
228
+ return _el$6;
229
+ }
230
+ }), _el$14, _co$5);
231
+ _$insert(_el$, _$createComponent(Show, {
232
+ get when() {
233
+ return tabBlocked();
234
+ },
235
+ get children() {
236
+ var _el$0 = _$getNextElement(_tmpl$3);
237
+ _$insert(_el$0, () => messages().pdfPreviewTabBlocked);
238
+ return _el$0;
239
+ }
240
+ }), _el$16, _co$6);
143
241
  return _el$;
144
242
  })();
145
243
  const content = () => _$createComponent(Show, {
@@ -153,36 +251,36 @@ export default function PdfPreview(props) {
153
251
  },
154
252
  get fallback() {
155
253
  return (() => {
156
- var _el$0 = _$getNextElement(_tmpl$2),
157
- _el$1 = _el$0.firstChild;
158
- _$insert(_el$1, (() => {
254
+ var _el$25 = _$getNextElement(_tmpl$6),
255
+ _el$26 = _el$25.firstChild;
256
+ _$insert(_el$26, (() => {
159
257
  var _c$ = _$memo(() => !!loading());
160
258
  return () => _c$() ? messages().loading : props.emptyText ?? messages().renderPdfPreview;
161
259
  })());
162
- _$effect(() => _$setAttribute(_el$1, "role", loading() ? "status" : undefined));
163
- return _el$0;
260
+ _$effect(() => _$setAttribute(_el$26, "role", loading() ? "status" : undefined));
261
+ return _el$25;
164
262
  })();
165
263
  },
166
264
  children: currentUrl => (() => {
167
- var _el$10 = _$getNextElement(_tmpl$3);
265
+ var _el$27 = _$getNextElement(_tmpl$7);
168
266
  _$effect(_p$ => {
169
267
  var _v$5 = currentUrl(),
170
268
  _v$6 = props.title ?? messages().pdfPreview;
171
- _v$5 !== _p$.e && _$setAttribute(_el$10, "src", _p$.e = _v$5);
172
- _v$6 !== _p$.t && _$setAttribute(_el$10, "title", _p$.t = _v$6);
269
+ _v$5 !== _p$.e && _$setAttribute(_el$27, "src", _p$.e = _v$5);
270
+ _v$6 !== _p$.t && _$setAttribute(_el$27, "title", _p$.t = _v$6);
173
271
  return _p$;
174
272
  }, {
175
273
  e: undefined,
176
274
  t: undefined
177
275
  });
178
- return _el$10;
276
+ return _el$27;
179
277
  })()
180
278
  });
181
279
  },
182
280
  children: message => props.renderError?.(message()) ?? (() => {
183
- var _el$11 = _$getNextElement(_tmpl$4);
184
- _$insert(_el$11, message);
185
- return _el$11;
281
+ var _el$28 = _$getNextElement(_tmpl$8);
282
+ _$insert(_el$28, message);
283
+ return _el$28;
186
284
  })()
187
285
  });
188
286
  if (props.children) return props.children({
@@ -194,27 +292,27 @@ export default function PdfPreview(props) {
194
292
  }
195
293
  });
196
294
  return (() => {
197
- var _el$12 = _$getNextElement(_tmpl$6),
198
- _el$13 = _el$12.firstChild,
199
- _el$14 = _el$13.firstChild,
200
- _el$16 = _el$14.nextSibling,
201
- [_el$17, _co$3] = _$getNextMarker(_el$16.nextSibling),
202
- _el$18 = _el$13.nextSibling,
203
- [_el$19, _co$4] = _$getNextMarker(_el$18.nextSibling);
204
- _$insert(_el$14, _$createComponent(Show, {
295
+ var _el$29 = _$getNextElement(_tmpl$0),
296
+ _el$30 = _el$29.firstChild,
297
+ _el$31 = _el$30.firstChild,
298
+ _el$33 = _el$31.nextSibling,
299
+ [_el$34, _co$9] = _$getNextMarker(_el$33.nextSibling),
300
+ _el$35 = _el$30.nextSibling,
301
+ [_el$36, _co$0] = _$getNextMarker(_el$35.nextSibling);
302
+ _$insert(_el$31, _$createComponent(Show, {
205
303
  get when() {
206
304
  return props.title;
207
305
  },
208
306
  get children() {
209
- var _el$15 = _$getNextElement(_tmpl$5);
210
- _$insert(_el$15, () => props.title);
211
- return _el$15;
307
+ var _el$32 = _$getNextElement(_tmpl$9);
308
+ _$insert(_el$32, () => props.title);
309
+ return _el$32;
212
310
  }
213
311
  }));
214
- _$insert(_el$13, actions, _el$17, _co$3);
215
- _$insert(_el$12, content, _el$19, _co$4);
216
- _$effect(() => _$className(_el$12, `k2b-content-pdf-preview ${props.class ?? ""}`));
217
- return _el$12;
312
+ _$insert(_el$30, actions, _el$34, _co$9);
313
+ _$insert(_el$29, content, _el$36, _co$0);
314
+ _$effect(() => _$className(_el$29, `k2b-content-pdf-preview ${props.class ?? ""}`));
315
+ return _el$29;
218
316
  })();
219
317
  }
220
318
  _$delegateEvents(["click"]);
@@ -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 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 const [loading, setLoading] = createSignal(false);\n const [opening, setOpening] = createSignal(false);\n const [error, setError] = createSignal<string | null>(null);\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 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 setUrl(nextUrl);\n if (previousUrl) URL.revokeObjectURL(previousUrl);\n } catch (e) {\n if (!disposed && generation === loadGeneration) setError(e instanceof Error ? e.message : \"PDF preview failed\");\n } finally {\n if (!disposed && generation === loadGeneration) setLoading(false);\n }\n };\n\n onMount(() => {\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 if (!tab) {\n setError(\"Browser blocked the preview tab\");\n return;\n }\n tab.opener = null;\n tab.document.title = props.title ?? messages().pdfPreview;\n tab.document.body.textContent = \"Rendering PDF preview...\";\n setOpening(true);\n setError(null);\n try {\n const blob = 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 const actions = () => (\n <div class=\"k2b-content-pdf-preview__actions\">\n <button\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 <button\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 </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\";\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,5 +1,6 @@
1
1
  import { render } from "solid-js/web";
2
2
  import { getK2bPortalRoot } from "../internal/portal";
3
+ import { resolveUiMessages } from "../intl/messages";
3
4
  import { isPointInsideToast } from "./toast";
4
5
  const DEFAULT_PANEL_CLASS = "k2b-dialog";
5
6
  const DEFAULT_CONTENT_CLASS = "k2b-dialog__viewport";
@@ -22,7 +23,7 @@ const applyAccessibleName = (dialog, entry) => {
22
23
  }
23
24
  const heading = entry.container.querySelector("h1, h2, h3");
24
25
  if (!heading) {
25
- dialog.setAttribute("aria-label", "Dialog");
26
+ dialog.setAttribute("aria-label", resolveUiMessages().dialog);
26
27
  return;
27
28
  }
28
29
  heading.id ||= `k2b-dialog-title-${++nextDialogTitleId}`;