@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
@@ -21,7 +21,14 @@ const isStandaloneInlineToken = (text, start, value) => {
21
21
  const createSafeRenderer = (options = {}) => {
22
22
  const renderer = new Renderer();
23
23
  const inlineTokens = normalizeInlineTokens(options.inlineTokens);
24
- const renderText = renderer.text.bind(renderer);
24
+ const baseText = renderer.text.bind(renderer);
25
+ // marked flags text that follows an inline <pre>, <code>, <kbd> or <script>
26
+ // tag as already escaped, because it expects that tag to reach the output as
27
+ // HTML. The tag is escaped here, so the text after it is escaped as well.
28
+ const renderText = token => baseText(token.type === "text" && token.escaped ? {
29
+ ...token,
30
+ escaped: false
31
+ } : token);
25
32
  const renderTable = renderer.table.bind(renderer);
26
33
  renderer.table = token => {
27
34
  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":";;;;AAAA,SAAS,MAAM,EAAE,QAAQ,QAAqB,QAAQ;AAsCtD,MAAM,UAAU,GAAI,KAAa,IAC/B,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;AAEnI,MAAM,OAAO,GAAI,KAAa,IAAoB;EAChD,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,kCAAkC,EAAE,EAAE,CAAC;EAC/E,IAAI,iCAAiC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,OAAO,IAAI;EACnE,OAAO,KAAK;AACd,CAAC;AAED,MAAM,qBAAqB,GAAI,MAAqC,IAClE,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,KAAK,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;AAE/F,MAAM,uBAAuB,GAAG,CAAC,IAAY,EAAE,KAAa,EAAE,KAAa,KAAc;EACvF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;EAC9B,IAAI,MAAM,IAAI,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK;EAC5D,MAAM,GAAG,GAAG,KAAK,GAAG,KAAK,CAAC,MAAM;EAChC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC;EACvB,IAAI,KAAK,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK;EACtD,OAAO,EAAE,KAAK,KAAK,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,kBAAkB,GAAG,CAAC,OAA8B,GAAG,CAAC,CAAC,KAAe;EAC5E,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,CAAC;EAC/B,MAAM,YAAY,GAAG,qBAAqB,CAAC,OAAO,CAAC,YAAY,CAAC;EAChE,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;EAC7C;EACA;EACA;EACA,MAAM,UAA4B,GAAI,KAAK,IAAK,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,OAAO,GAAG;IAAE,GAAG,KAAK;IAAE,OAAO,EAAE;EAAM,CAAC,GAAG,KAAK,CAAC;EACvI,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;EACjD,QAAQ,CAAC,KAAK,GAAI,KAAmB,IAAK;IACxC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC;IAChC,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAE,IAAI,IAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,6BAA6B,EAAE,EAAE,CAAC,GAAG,KAAK;IAC1H,OAAO,yDAAyD,OAAO,QAAQ;EACjF,CAAC;EACD,QAAQ,CAAC,IAAI,GAAG,CAAC;IAAE;EAA+B,CAAC,KAAK,UAAU,CAAC,IAAI,CAAC;EACxE,QAAQ,CAAC,IAAI,GAAG,UAAU;IAAE,IAAI;IAAE,KAAK;IAAE;EAAoB,CAAC,EAAE;IAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC;IAC5C,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IACzB,IAAI,CAAC,GAAG,EAAE,OAAO,IAAI;IACrB,IAAI,OAAO,CAAC,aAAa,EAAE;MACzB,IAAI;QACF,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,2BAA2B,CAAC,CAAC,QAAQ,CAAC,EAAE,OAAO,IAAI;MACtG,CAAC,CAAC,MAAM;QACN,OAAO,IAAI;MACb;IACF;IACA,MAAM,cAAc,GAAG,KAAK,GAAG,WAAW,UAAU,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE;IACnE,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,KAAK,QAAQ,GAAG,4CAA4C,GAAG,EAAE;IAClG,OAAO,YAAY,UAAU,CAAC,GAAG,CAAC,IAAI,cAAc,GAAG,MAAM,IAAI,IAAI,MAAM;EAC7E,CAAC;EACD,QAAQ,CAAC,KAAK,GAAG,CAAC;IAAE,IAAI;IAAE,KAAK;IAAE;EAAmB,CAAC,KAAK;IACxD,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IACzB,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,WAAW,KAAK,KAAK,EAAE,OAAO,UAAU,CAAC,IAAI,CAAC;IAClE,MAAM,cAAc,GAAG,KAAK,GAAG,WAAW,UAAU,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE;IACnE,OAAO,aAAa,UAAU,CAAC,GAAG,CAAC,UAAU,UAAU,CAAC,IAAI,CAAC,IAAI,cAAc,GAAG;EACpF,CAAC;EACD,QAAQ,CAAC,IAAI,GAAI,KAAK,IAAK;IACzB,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAK,QAAQ,IAAI,KAAK,IAAI,KAAK,CAAC,MAAO,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACzH,MAAM,KAAe,GAAG,EAAE;IAC1B,IAAI,UAAU,GAAG,CAAC;IAClB,IAAI,MAAM,GAAG,CAAC;IACd,OAAO,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE;MACjC,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAClC,SAAS,IAAK,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,uBAAuB,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAClH,CAAC;MACD,IAAI,CAAC,WAAW,EAAE;QAChB,MAAM,IAAI,CAAC;QACX;MACF;MACA,IAAI,UAAU,GAAG,MAAM,EAAE;QACvB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC;QACjD,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;UAAE,GAAG,KAAK;UAAE,GAAG,EAAE,IAAI;UAAE;QAAK,CAAC,CAAC,CAAC;MACvD;MACA,KAAK,CAAC,IAAI,CACR,oDAAoD,UAAU,CAAC;QAAE,GAAG,KAAK;QAAE,GAAG,EAAE,WAAW;QAAE,IAAI,EAAE;MAAY,CAAC,CAAC,SACnH,CAAC;MACD,MAAM,IAAI,WAAW,CAAC,MAAM;MAC5B,UAAU,GAAG,MAAM;IACrB;IACA,IAAI,UAAU,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAC9C,IAAI,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE;MAClC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;MACzC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;QAAE,GAAG,KAAK;QAAE,GAAG,EAAE,IAAI;QAAE;MAAK,CAAC,CAAC,CAAC;IACvD;IACA,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;EACvB,CAAC;EACD,OAAO,QAAQ;AACjB,CAAC;AAED,OAAO,MAAM,kBAAkB,GAAG,CAAC,QAAgB,EAAE,OAA8B,GAAG,CAAC,CAAC,KACtF,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE;EACrB,KAAK,EAAE,KAAK;EACZ,QAAQ,EAAE,kBAAkB,CAAC,OAAO;AACtC,CAAC,CAAW;;AAEd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,SAAS,YAAY,CAAC,KAAwB,EAAE;EAC7D,MAAM,IAAI,GAAG,MACX,KAAK,CAAC,QAAQ,KAAK,SAAS,GACxB,kBAAkB,CAAC,KAAK,CAAC,QAAQ,EAAE;IACjC,YAAY,EAAE,KAAK,CAAC,YAAY;IAChC,WAAW,EAAE,KAAK,CAAC,WAAW;IAC9B,aAAa,EAAE,KAAK,CAAC,aAAa;IAClC,UAAU,EAAE,KAAK,CAAC;EACpB,CAAC,CAAC,GACF,KAAK,CAAC,WAAW;EACvB,qBAEW,iCAAwB,KAAK,CAAC,KAAK,IAAI,EAAE,SAAE,uCAC9B,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,KAAK,QAAQ,YAAG,KAAK,CAAC,YAAY,mBAAG,SAAS,iBAC/F,IAAI,CAAC,CAAC;AAGvB","ignoreList":[]}
@@ -1,13 +1,18 @@
1
- import { createComponent as _$createComponent } from "solid-js/web";
2
1
  import { ssr as _$ssr } from "solid-js/web";
3
- import { escape as _$escape } from "solid-js/web";
4
2
  import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
5
- var _tmpl$ = ["<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>", "</button></div>"],
6
- _tmpl$2 = ["<div class=\"k2b-content-pdf-preview__empty\"><span", ">", "</span></div>"],
7
- _tmpl$3 = ["<iframe class=\"k2b-content-pdf-preview__frame\"", "></iframe>"],
8
- _tmpl$4 = ["<div role=\"alert\" class=\"k2b-content-pdf-preview__error\">", "</div>"],
9
- _tmpl$5 = ["<h2 class=\"k2b-content-pdf-preview__title\">", "</h2>"],
10
- _tmpl$6 = ["<section class=\"", "\"><div class=\"k2b-content-pdf-preview__toolbar\"><div class=\"k2b-content-pdf-preview__heading\">", "</div>", "</div>", "</section>"];
3
+ import { escape as _$escape } from "solid-js/web";
4
+ import { createComponent as _$createComponent } from "solid-js/web";
5
+ import { memo as _$memo } from "solid-js/web";
6
+ var _tmpl$ = ["<button type=\"button\" class=\"k2b-button\" data-variant=\"secondary\" data-size=\"sm\"", "><i class=\"ti ti-download\" aria-hidden=\"true\"></i>", "</button>"],
7
+ _tmpl$2 = ["<button type=\"button\" class=\"k2b-button\" data-variant=\"secondary\" data-size=\"sm\"", "><i", " aria-hidden=\"true\"></i>", "</button>"],
8
+ _tmpl$3 = ["<span role=\"alert\" class=\"k2b-content-pdf-preview__notice\">", "</span>"],
9
+ _tmpl$4 = ["<div class=\"k2b-content-pdf-preview__actions\">", "", "", "", "</div>"],
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
16
  import { createSignal, onCleanup, onMount, Show } from "solid-js";
12
17
  import { resolveUiMessages, useUiMessages } from "../intl/messages";
13
18
  const readErrorMessage = async response => {
@@ -24,9 +29,17 @@ const readErrorMessage = async response => {
24
29
  export default function PdfPreview(props) {
25
30
  const messages = useUiMessages();
26
31
  const [url, setUrl] = createSignal(null);
27
- const [loading, setLoading] = createSignal(false);
32
+ // An automatic preview starts loading once mounted. The server and the page before hydration already show that
33
+ // state, so they offer neither a retry nor an invitation to render while nothing has failed.
34
+ const [loading, setLoading] = createSignal(Boolean(props.autoLoad) && !props.disabled?.());
28
35
  const [opening, setOpening] = createSignal(false);
29
36
  const [error, setError] = createSignal(null);
37
+ const [failed, setFailed] = createSignal(false);
38
+ const [tabBlocked, setTabBlocked] = createSignal(false);
39
+ // An automatic preview shows one fixed document; the open action reuses it instead of requesting it again.
40
+ let shownBlob = null;
41
+ let openButton;
42
+ let renderButton;
30
43
  let disposed = false;
31
44
  let loadGeneration = 0;
32
45
  let openGeneration = 0;
@@ -51,6 +64,7 @@ export default function PdfPreview(props) {
51
64
  const load = async () => {
52
65
  if (loading() || opening() || props.disabled?.()) return;
53
66
  const generation = ++loadGeneration;
67
+ const retryFocused = props.autoLoad && document.activeElement === renderButton;
54
68
  setLoading(true);
55
69
  setError(null);
56
70
  try {
@@ -61,32 +75,41 @@ export default function PdfPreview(props) {
61
75
  return;
62
76
  }
63
77
  const previousUrl = url();
78
+ shownBlob = blob;
79
+ setFailed(false);
64
80
  setUrl(nextUrl);
81
+ setLoading(false);
65
82
  if (previousUrl) URL.revokeObjectURL(previousUrl);
83
+ // The shown document removes the retry action; keep keyboard focus in the actions instead of the page.
84
+ if (retryFocused && document.activeElement === document.body) openButton?.focus();
66
85
  } catch (e) {
67
- if (!disposed && generation === loadGeneration) setError(e instanceof Error ? e.message : "PDF preview failed");
86
+ if (disposed || generation !== loadGeneration) return;
87
+ shownBlob = null;
88
+ setFailed(true);
89
+ setError(e instanceof Error ? e.message : "PDF preview failed");
68
90
  } finally {
69
91
  if (!disposed && generation === loadGeneration) setLoading(false);
70
92
  }
71
93
  };
72
94
  onMount(() => {
95
+ // Hand the initial loading state to the request itself, which also covers a preview disabled by now.
96
+ setLoading(false);
73
97
  if (props.autoLoad) void load();
74
98
  });
75
99
  const openInNewTab = async () => {
76
100
  if (loading() || opening() || props.disabled?.()) return;
77
101
  const generation = ++openGeneration;
78
102
  const tab = window.open("", "_blank");
79
- if (!tab) {
80
- setError("Browser blocked the preview tab");
81
- return;
82
- }
103
+ // A blocked tab is not a document error: keep the shown document and report it beside the actions.
104
+ setTabBlocked(!tab);
105
+ if (!tab) return;
83
106
  tab.opener = null;
84
107
  tab.document.title = props.title ?? messages().pdfPreview;
85
- tab.document.body.textContent = "Rendering PDF preview...";
108
+ tab.document.body.textContent = messages().pdfPreviewRendering;
86
109
  setOpening(true);
87
110
  setError(null);
88
111
  try {
89
- const blob = await readPdfBlob();
112
+ const blob = (props.autoLoad ? shownBlob : null) ?? (await readPdfBlob());
90
113
  if (disposed || generation !== openGeneration) {
91
114
  tab.close();
92
115
  return;
@@ -101,7 +124,41 @@ export default function PdfPreview(props) {
101
124
  if (!disposed && generation === openGeneration) setOpening(false);
102
125
  }
103
126
  };
104
- const actions = () => _$ssr(_tmpl$, _$ssrAttribute("disabled", loading() || opening() || props.disabled?.(), true), _$ssrAttribute("class", opening() ? "ti ti-loader-2 k2b-spin" : "ti ti-external-link", false), _$escape(props.openButtonLabel ?? messages().openPreview), _$ssrAttribute("disabled", loading() || opening() || props.disabled?.(), true), _$ssrAttribute("class", loading() ? "ti ti-loader-2 k2b-spin" : "ti ti-file-type-pdf", false), _$escape(props.buttonLabel ?? messages().previewPdf));
127
+
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
+ const actions = () => _$ssr(_tmpl$4, _$escape(_$createComponent(Show, {
132
+ get when() {
133
+ return _$memo(() => !!!props.disabled?.())() && props.openHref;
134
+ },
135
+ get fallback() {
136
+ return _$ssr(_tmpl$2, _$ssrAttribute("disabled", loading() || opening() || props.disabled?.(), true), _$ssrAttribute("class", opening() ? "ti ti-loader-2 k2b-spin" : "ti ti-external-link", false), _$escape(props.openButtonLabel ?? messages().openPreview));
137
+ },
138
+ 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.
139
+ _$ssr(_tmpl$5, _$ssrAttribute("href", _$escape(href(), true), false), _$escape(props.openButtonLabel ?? messages().openPreview))
140
+ })), _$escape(_$createComponent(Show, {
141
+ get when() {
142
+ return props.onDownload;
143
+ },
144
+ get children() {
145
+ return _$ssr(_tmpl$, _$ssrAttribute("disabled", props.disabled?.(), true), _$escape(messages().download));
146
+ }
147
+ })), _$escape(_$createComponent(Show, {
148
+ get when() {
149
+ return renderable();
150
+ },
151
+ get children() {
152
+ return _$ssr(_tmpl$2, _$ssrAttribute("disabled", loading() || opening() || props.disabled?.(), true), _$ssrAttribute("class", loading() ? "ti ti-loader-2 k2b-spin" : "ti ti-file-type-pdf", false), _$escape(props.buttonLabel ?? messages().previewPdf));
153
+ }
154
+ })), _$escape(_$createComponent(Show, {
155
+ get when() {
156
+ return tabBlocked();
157
+ },
158
+ get children() {
159
+ return _$ssr(_tmpl$3, _$escape(messages().pdfPreviewTabBlocked));
160
+ }
161
+ })));
105
162
  const content = () => _$createComponent(Show, {
106
163
  get when() {
107
164
  return error();
@@ -112,12 +169,12 @@ export default function PdfPreview(props) {
112
169
  return url();
113
170
  },
114
171
  get fallback() {
115
- return _$ssr(_tmpl$2, _$ssrAttribute("role", loading() ? "status" : _$escape(undefined, true), false), loading() ? _$escape(messages().loading) : _$escape(props.emptyText ?? messages().renderPdfPreview));
172
+ return _$ssr(_tmpl$6, _$ssrAttribute("role", loading() ? "status" : _$escape(undefined, true), false), loading() ? _$escape(messages().loading) : _$escape(props.emptyText ?? messages().renderPdfPreview));
116
173
  },
117
- children: currentUrl => _$ssr(_tmpl$3, _$ssrAttribute("src", _$escape(currentUrl(), true), false) + _$ssrAttribute("title", _$escape(props.title ?? messages().pdfPreview, true), false))
174
+ children: currentUrl => _$ssr(_tmpl$7, _$ssrAttribute("src", _$escape(currentUrl(), true), false) + _$ssrAttribute("title", _$escape(props.title ?? messages().pdfPreview, true), false))
118
175
  });
119
176
  },
120
- children: message => props.renderError?.(message()) ?? _$ssr(_tmpl$4, _$escape(message()))
177
+ children: message => props.renderError?.(message()) ?? _$ssr(_tmpl$8, _$escape(message()))
121
178
  });
122
179
  if (props.children) return props.children({
123
180
  get actions() {
@@ -127,12 +184,12 @@ export default function PdfPreview(props) {
127
184
  return content();
128
185
  }
129
186
  });
130
- return _$ssr(_tmpl$6, `k2b-content-pdf-preview ${_$escape(props.class ?? "", true)}`, _$escape(_$createComponent(Show, {
187
+ return _$ssr(_tmpl$0, `k2b-content-pdf-preview ${_$escape(props.class ?? "", true)}`, _$escape(_$createComponent(Show, {
131
188
  get when() {
132
189
  return props.title;
133
190
  },
134
191
  get children() {
135
- return _$ssr(_tmpl$5, _$escape(props.title));
192
+ return _$ssr(_tmpl$9, _$escape(props.title));
136
193
  }
137
194
  })), _$escape(actions()), _$escape(content()));
138
195
  }
@@ -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}`;
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["feedback/dialog-core.ts"],"sourcesContent":["import type { JSX } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport { getK2bPortalRoot } from \"../internal/portal\";\nimport { isPointInsideToast } from \"./toast\";\n\nexport type DialogClose<T> = (result?: T) => void;\n\nexport type OpenDialogOptions = {\n /** Close only this dialog when its owning operation is cancelled. */\n signal?: AbortSignal;\n panelClassName?: string;\n contentClassName?: string;\n initialFocus?: \"first-input\" | \"none\" | ((dialog: HTMLDialogElement) => HTMLElement | null);\n cancelBehavior?: \"resolve-undefined\" | \"ignore\";\n ariaLabel?: string;\n};\n\nexport type DialogRender<T> = (\n close: DialogClose<T>,\n context: {\n dialog: HTMLDialogElement;\n /** Switch this entry between a modal and a modeless window without remounting. */\n setModal: (modal: boolean) => void;\n /** Set viewport coordinates, or restore the panel stylesheet position with null. */\n setPosition: (position: { x: number; y: number } | null) => void;\n /** Route Escape/backdrop through the same guarded handler as Cancel and X. */\n setDismissHandler: (handler: () => void | Promise<void>) => void;\n /** Request dismissal through this entry's cancellation policy and guard. */\n requestDismiss: () => Promise<void>;\n },\n) => JSX.Element;\n\nexport type DialogCore = {\n open: <T>(view: DialogRender<T>, options?: OpenDialogOptions) => Promise<T | undefined>;\n close: (result?: unknown) => void;\n isOpen: () => boolean;\n};\n\ntype DialogStackEntry = {\n container: HTMLDivElement;\n dispose?: () => void;\n resolve?: (value: unknown) => void;\n panelClassName: string;\n cancelBehavior: NonNullable<OpenDialogOptions[\"cancelBehavior\"]>;\n initialFocus: NonNullable<OpenDialogOptions[\"initialFocus\"]>;\n opener?: HTMLElement;\n ariaLabel?: string;\n dismissHandler?: () => void | Promise<void>;\n dismissPending?: boolean;\n modal: boolean;\n position?: { x: number; y: number } | null;\n};\n\ntype DialogState = {\n element?: HTMLDialogElement;\n modal?: boolean;\n stack: DialogStackEntry[];\n scrollLocked?: boolean;\n previousBodyOverflow?: string;\n previousHtmlOverflow?: string;\n mouseDownOnDialog?: boolean;\n connectionObserver?: MutationObserver;\n};\n\nconst DEFAULT_PANEL_CLASS = \"k2b-dialog\";\nconst DEFAULT_CONTENT_CLASS = \"k2b-dialog__viewport\";\nlet nextDialogTitleId = 0;\n\nconst resolveInitialFocusTarget = (entry: DialogStackEntry, dialog: HTMLDialogElement): HTMLElement | null => {\n const { initialFocus } = entry;\n if (initialFocus === \"none\") return null;\n if (typeof initialFocus === \"function\") return initialFocus(dialog);\n const input = entry.container.querySelector<HTMLElement>(\n \"input:not([type='hidden']):not([disabled]), textarea:not([disabled]), select:not([disabled]), [role='combobox']:not([disabled]):not([aria-disabled='true'])\",\n );\n return (\n input ??\n entry.container.querySelector<HTMLElement>(\n \"input:not([type='hidden']):not([disabled]), textarea:not([disabled]), select:not([disabled]), button:not([disabled]), a[href], [tabindex]:not([tabindex='-1'])\",\n )\n );\n};\n\nconst applyAccessibleName = (dialog: HTMLDialogElement, entry: DialogStackEntry): void => {\n dialog.removeAttribute(\"aria-label\");\n dialog.removeAttribute(\"aria-labelledby\");\n if (entry.ariaLabel) {\n dialog.setAttribute(\"aria-label\", entry.ariaLabel);\n return;\n }\n const heading = entry.container.querySelector<HTMLElement>(\"h1, h2, h3\");\n if (!heading) {\n dialog.setAttribute(\"aria-label\", \"Dialog\");\n return;\n }\n heading.id ||= `k2b-dialog-title-${++nextDialogTitleId}`;\n dialog.setAttribute(\"aria-labelledby\", heading.id);\n};\n\nconst schedule = (callback: () => void): void => {\n if (typeof requestAnimationFrame === \"function\") requestAnimationFrame(callback);\n else queueMicrotask(callback);\n};\n\nexport const createDialogCore = (): DialogCore => {\n const state: DialogState = { stack: [] };\n\n const ensureDialogElement = () => {\n if (typeof document === \"undefined\") throw new Error(\"@k2b/ui dialogs can only be opened in the browser\");\n // Reuse the shared element whenever it is still in the document. Resolving\n // the portal root first would create a second <dialog> when focus has moved\n // into another `.k2b-ui` scope, orphaning the levels already on the stack.\n if (state.element?.isConnected) return state.element;\n\n const element = document.createElement(\"dialog\");\n element.onclose = () => {\n // Repeated Escape can force a non-cancelable native close. A retained\n // entry (ignore, an async guard, or a parent) still owns the modal.\n const top = state.stack[state.stack.length - 1];\n if (state.element !== element || element.open || !top) return;\n if (top.modal) element.showModal();\n else element.show();\n resolveInitialFocusTarget(top, element)?.focus();\n };\n getK2bPortalRoot().appendChild(element);\n state.element = element;\n return element;\n };\n\n const lockPageScroll = () => {\n if (typeof document === \"undefined\" || state.scrollLocked) return;\n state.previousBodyOverflow = document.body.style.overflow;\n state.previousHtmlOverflow = document.documentElement.style.overflow;\n document.body.style.overflow = \"hidden\";\n document.documentElement.style.overflow = \"hidden\";\n state.scrollLocked = true;\n };\n\n const unlockPageScroll = () => {\n if (typeof document === \"undefined\" || !state.scrollLocked) return;\n document.body.style.overflow = state.previousBodyOverflow ?? \"\";\n document.documentElement.style.overflow = state.previousHtmlOverflow ?? \"\";\n state.scrollLocked = false;\n state.previousBodyOverflow = undefined;\n state.previousHtmlOverflow = undefined;\n };\n\n const applyPresentation = (entry: DialogStackEntry) => {\n const dialog = state.element;\n if (!dialog || state.stack[state.stack.length - 1] !== entry) return;\n const position = entry.position;\n dialog.style.position = position ? \"fixed\" : \"\";\n dialog.style.inset = position ? `${position.y}px auto auto ${position.x}px` : \"\";\n dialog.style.margin = position ? \"0\" : \"\";\n dialog.style.transform = position ? \"none\" : \"\";\n dialog.dataset.modeless = String(!entry.modal);\n dialog.setAttribute(\"aria-modal\", String(entry.modal));\n if (dialog.open && state.modal !== entry.modal) {\n const active = document.activeElement;\n dialog.close();\n if (entry.modal) dialog.showModal();\n else dialog.show();\n if (active instanceof HTMLElement && active.isConnected && (!entry.modal || dialog.contains(active))) {\n active.focus({ preventScroll: true });\n } else resolveInitialFocusTarget(entry, dialog)?.focus({ preventScroll: true });\n }\n state.modal = entry.modal;\n if (entry.modal) lockPageScroll();\n else unlockPageScroll();\n };\n\n const modelessEscape = (event: KeyboardEvent) => {\n const top = state.stack[state.stack.length - 1];\n if (!top || top.modal || event.key !== \"Escape\" || event.defaultPrevented || event.isComposing) return;\n event.preventDefault();\n void requestDismiss(top);\n };\n\n const stopConnectionObserver = () => {\n document.removeEventListener(\"keydown\", modelessEscape);\n state.connectionObserver?.disconnect();\n state.connectionObserver = undefined;\n };\n\n const applyCancelBehavior = (\n dialog: HTMLDialogElement,\n close: () => void,\n behavior: NonNullable<OpenDialogOptions[\"cancelBehavior\"]>,\n ) => {\n dialog.oncancel = (event) => {\n if (behavior === \"ignore\") {\n event.preventDefault();\n return;\n }\n event.preventDefault();\n close();\n };\n dialog.onmousedown = (event) => {\n state.mouseDownOnDialog = event.target === dialog;\n };\n dialog.onclick = (event) => {\n const realBackdropClick = state.mouseDownOnDialog === true;\n state.mouseDownOnDialog = false;\n if (event.target !== dialog || !state.modal) return;\n if (!realBackdropClick) return;\n if (behavior === \"ignore\") return;\n if (isPointInsideToast(event.clientX, event.clientY)) return;\n close();\n };\n };\n\n const requestDismiss = async (entry: DialogStackEntry) => {\n if (state.stack[state.stack.length - 1] !== entry || entry.dismissPending || entry.cancelBehavior === \"ignore\") return;\n if (!entry.dismissHandler) {\n popTop(undefined);\n return;\n }\n entry.dismissPending = true;\n try {\n await entry.dismissHandler();\n } catch (error) {\n // A failed guard must never discard the dialog's state.\n console.error(\"Dialog dismissal failed\", error);\n } finally {\n entry.dismissPending = false;\n }\n };\n\n const popTop = (result?: unknown) => {\n const top = state.stack.pop();\n if (!top) return;\n top.dispose?.();\n top.container.remove();\n\n const dialog = state.element;\n const previous = state.stack[state.stack.length - 1];\n if (previous && dialog) {\n previous.container.style.display = \"\";\n dialog.className = previous.panelClassName;\n applyPresentation(previous);\n applyAccessibleName(dialog, previous);\n applyCancelBehavior(dialog, () => void requestDismiss(previous), previous.cancelBehavior);\n schedule(() => {\n const target = top.opener?.isConnected ? top.opener : resolveInitialFocusTarget(previous, dialog);\n target?.focus();\n });\n } else if (dialog) {\n dialog.oncancel = null;\n dialog.onmousedown = null;\n dialog.onclick = null;\n dialog.removeAttribute(\"aria-label\");\n dialog.removeAttribute(\"aria-labelledby\");\n if (dialog.open && typeof dialog.close === \"function\") dialog.close();\n else dialog.removeAttribute(\"open\");\n dialog.remove();\n state.element = undefined;\n stopConnectionObserver();\n unlockPageScroll();\n schedule(() => {\n if (top.opener?.isConnected) top.opener.focus();\n });\n }\n\n top.resolve?.(result);\n };\n\n const resetDisconnectedDialog = () => {\n if (state.stack.length === 0 || state.element?.isConnected) return;\n const entries = state.stack.splice(0);\n const dialog = state.element;\n state.element = undefined;\n stopConnectionObserver();\n dialog?.remove();\n unlockPageScroll();\n for (const entry of entries.reverse()) {\n entry.dispose?.();\n entry.container.remove();\n entry.resolve?.(undefined);\n }\n };\n\n const observeConnection = () => {\n if (state.connectionObserver || typeof MutationObserver === \"undefined\") return;\n document.addEventListener(\"keydown\", modelessEscape);\n state.connectionObserver = new MutationObserver(resetDisconnectedDialog);\n state.connectionObserver.observe(document.documentElement, { childList: true, subtree: true });\n };\n\n const open = <T>(view: DialogRender<T>, options: OpenDialogOptions = {}): Promise<T | undefined> => {\n if (options.signal?.aborted) return Promise.resolve(undefined);\n const dialog = ensureDialogElement();\n const previousTop = state.stack[state.stack.length - 1];\n if (previousTop) previousTop.container.style.display = \"none\";\n const activeElement = document.activeElement;\n\n const panelClassName = options.panelClassName ?? DEFAULT_PANEL_CLASS;\n const cancelBehavior = options.cancelBehavior ?? \"resolve-undefined\";\n const initialFocus = options.initialFocus ?? \"first-input\";\n dialog.className = panelClassName;\n\n const container = document.createElement(\"div\");\n container.className = options.contentClassName ?? DEFAULT_CONTENT_CLASS;\n dialog.appendChild(container);\n\n const entry: DialogStackEntry = {\n container,\n panelClassName,\n cancelBehavior,\n initialFocus,\n opener: activeElement instanceof HTMLElement ? activeElement : undefined,\n ariaLabel: options.ariaLabel,\n modal: true,\n };\n\n return new Promise((resolve, reject) => {\n const abort = () => {\n const index = state.stack.indexOf(entry);\n if (index < 0) return;\n if (index === state.stack.length - 1) popTop(undefined);\n else {\n state.stack.splice(index, 1);\n entry.dispose?.();\n entry.container.remove();\n entry.resolve?.(undefined);\n }\n };\n entry.resolve = (value) => {\n options.signal?.removeEventListener(\"abort\", abort);\n resolve(value as T | undefined);\n };\n const closeTyped: DialogClose<T> = (result) => {\n if (state.stack[state.stack.length - 1] !== entry) return;\n popTop(result);\n };\n\n state.stack.push(entry);\n try {\n entry.dispose = render(\n () =>\n view(closeTyped, {\n dialog,\n setModal: (modal) => {\n entry.modal = modal;\n applyPresentation(entry);\n },\n setPosition: (position) => {\n if (position && (!Number.isFinite(position.x) || !Number.isFinite(position.y))) return;\n entry.position = position;\n applyPresentation(entry);\n },\n requestDismiss: () => requestDismiss(entry),\n setDismissHandler: (handler) => {\n entry.dismissHandler = handler;\n },\n }),\n container,\n );\n applyPresentation(entry);\n applyAccessibleName(dialog, entry);\n applyCancelBehavior(dialog, () => void requestDismiss(entry), cancelBehavior);\n\n if (state.stack.length === 1) {\n if (typeof dialog.showModal === \"function\") {\n if (entry.modal) dialog.showModal();\n else dialog.show();\n } else dialog.setAttribute(\"open\", \"\");\n observeConnection();\n }\n options.signal?.addEventListener(\"abort\", abort, { once: true });\n if (options.signal?.aborted) abort();\n schedule(() => {\n if (state.stack[state.stack.length - 1] === entry) resolveInitialFocusTarget(entry, dialog)?.focus();\n });\n } catch (error) {\n entry.resolve = undefined;\n if (state.stack[state.stack.length - 1] === entry) popTop(undefined);\n reject(error);\n }\n });\n };\n\n const close: DialogCore[\"close\"] = (result) => {\n let first = true;\n while (state.stack.length > 0) {\n popTop(first ? result : undefined);\n first = false;\n }\n };\n\n return {\n open,\n close,\n isOpen: () => state.stack.length > 0,\n };\n};\n\nexport const dialogCore = createDialogCore();\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["feedback/dialog-core.ts"],"sourcesContent":["import type { JSX } from \"solid-js\";\nimport { render } from \"solid-js/web\";\nimport { getK2bPortalRoot } from \"../internal/portal\";\nimport { resolveUiMessages } from \"../intl/messages\";\nimport { isPointInsideToast } from \"./toast\";\n\nexport type DialogClose<T> = (result?: T) => void;\n\nexport type OpenDialogOptions = {\n /** Close only this dialog when its owning operation is cancelled. */\n signal?: AbortSignal;\n panelClassName?: string;\n contentClassName?: string;\n initialFocus?: \"first-input\" | \"none\" | ((dialog: HTMLDialogElement) => HTMLElement | null);\n cancelBehavior?: \"resolve-undefined\" | \"ignore\";\n ariaLabel?: string;\n};\n\nexport type DialogRender<T> = (\n close: DialogClose<T>,\n context: {\n dialog: HTMLDialogElement;\n /** Switch this entry between a modal and a modeless window without remounting. */\n setModal: (modal: boolean) => void;\n /** Set viewport coordinates, or restore the panel stylesheet position with null. */\n setPosition: (position: { x: number; y: number } | null) => void;\n /** Route Escape/backdrop through the same guarded handler as Cancel and X. */\n setDismissHandler: (handler: () => void | Promise<void>) => void;\n /** Request dismissal through this entry's cancellation policy and guard. */\n requestDismiss: () => Promise<void>;\n },\n) => JSX.Element;\n\nexport type DialogCore = {\n open: <T>(view: DialogRender<T>, options?: OpenDialogOptions) => Promise<T | undefined>;\n close: (result?: unknown) => void;\n isOpen: () => boolean;\n};\n\ntype DialogStackEntry = {\n container: HTMLDivElement;\n dispose?: () => void;\n resolve?: (value: unknown) => void;\n panelClassName: string;\n cancelBehavior: NonNullable<OpenDialogOptions[\"cancelBehavior\"]>;\n initialFocus: NonNullable<OpenDialogOptions[\"initialFocus\"]>;\n opener?: HTMLElement;\n ariaLabel?: string;\n dismissHandler?: () => void | Promise<void>;\n dismissPending?: boolean;\n modal: boolean;\n position?: { x: number; y: number } | null;\n};\n\ntype DialogState = {\n element?: HTMLDialogElement;\n modal?: boolean;\n stack: DialogStackEntry[];\n scrollLocked?: boolean;\n previousBodyOverflow?: string;\n previousHtmlOverflow?: string;\n mouseDownOnDialog?: boolean;\n connectionObserver?: MutationObserver;\n};\n\nconst DEFAULT_PANEL_CLASS = \"k2b-dialog\";\nconst DEFAULT_CONTENT_CLASS = \"k2b-dialog__viewport\";\nlet nextDialogTitleId = 0;\n\nconst resolveInitialFocusTarget = (entry: DialogStackEntry, dialog: HTMLDialogElement): HTMLElement | null => {\n const { initialFocus } = entry;\n if (initialFocus === \"none\") return null;\n if (typeof initialFocus === \"function\") return initialFocus(dialog);\n const input = entry.container.querySelector<HTMLElement>(\n \"input:not([type='hidden']):not([disabled]), textarea:not([disabled]), select:not([disabled]), [role='combobox']:not([disabled]):not([aria-disabled='true'])\",\n );\n return (\n input ??\n entry.container.querySelector<HTMLElement>(\n \"input:not([type='hidden']):not([disabled]), textarea:not([disabled]), select:not([disabled]), button:not([disabled]), a[href], [tabindex]:not([tabindex='-1'])\",\n )\n );\n};\n\nconst applyAccessibleName = (dialog: HTMLDialogElement, entry: DialogStackEntry): void => {\n dialog.removeAttribute(\"aria-label\");\n dialog.removeAttribute(\"aria-labelledby\");\n if (entry.ariaLabel) {\n dialog.setAttribute(\"aria-label\", entry.ariaLabel);\n return;\n }\n const heading = entry.container.querySelector<HTMLElement>(\"h1, h2, h3\");\n if (!heading) {\n dialog.setAttribute(\"aria-label\", resolveUiMessages().dialog);\n return;\n }\n heading.id ||= `k2b-dialog-title-${++nextDialogTitleId}`;\n dialog.setAttribute(\"aria-labelledby\", heading.id);\n};\n\nconst schedule = (callback: () => void): void => {\n if (typeof requestAnimationFrame === \"function\") requestAnimationFrame(callback);\n else queueMicrotask(callback);\n};\n\nexport const createDialogCore = (): DialogCore => {\n const state: DialogState = { stack: [] };\n\n const ensureDialogElement = () => {\n if (typeof document === \"undefined\") throw new Error(\"@k2b/ui dialogs can only be opened in the browser\");\n // Reuse the shared element whenever it is still in the document. Resolving\n // the portal root first would create a second <dialog> when focus has moved\n // into another `.k2b-ui` scope, orphaning the levels already on the stack.\n if (state.element?.isConnected) return state.element;\n\n const element = document.createElement(\"dialog\");\n element.onclose = () => {\n // Repeated Escape can force a non-cancelable native close. A retained\n // entry (ignore, an async guard, or a parent) still owns the modal.\n const top = state.stack[state.stack.length - 1];\n if (state.element !== element || element.open || !top) return;\n if (top.modal) element.showModal();\n else element.show();\n resolveInitialFocusTarget(top, element)?.focus();\n };\n getK2bPortalRoot().appendChild(element);\n state.element = element;\n return element;\n };\n\n const lockPageScroll = () => {\n if (typeof document === \"undefined\" || state.scrollLocked) return;\n state.previousBodyOverflow = document.body.style.overflow;\n state.previousHtmlOverflow = document.documentElement.style.overflow;\n document.body.style.overflow = \"hidden\";\n document.documentElement.style.overflow = \"hidden\";\n state.scrollLocked = true;\n };\n\n const unlockPageScroll = () => {\n if (typeof document === \"undefined\" || !state.scrollLocked) return;\n document.body.style.overflow = state.previousBodyOverflow ?? \"\";\n document.documentElement.style.overflow = state.previousHtmlOverflow ?? \"\";\n state.scrollLocked = false;\n state.previousBodyOverflow = undefined;\n state.previousHtmlOverflow = undefined;\n };\n\n const applyPresentation = (entry: DialogStackEntry) => {\n const dialog = state.element;\n if (!dialog || state.stack[state.stack.length - 1] !== entry) return;\n const position = entry.position;\n dialog.style.position = position ? \"fixed\" : \"\";\n dialog.style.inset = position ? `${position.y}px auto auto ${position.x}px` : \"\";\n dialog.style.margin = position ? \"0\" : \"\";\n dialog.style.transform = position ? \"none\" : \"\";\n dialog.dataset.modeless = String(!entry.modal);\n dialog.setAttribute(\"aria-modal\", String(entry.modal));\n if (dialog.open && state.modal !== entry.modal) {\n const active = document.activeElement;\n dialog.close();\n if (entry.modal) dialog.showModal();\n else dialog.show();\n if (active instanceof HTMLElement && active.isConnected && (!entry.modal || dialog.contains(active))) {\n active.focus({ preventScroll: true });\n } else resolveInitialFocusTarget(entry, dialog)?.focus({ preventScroll: true });\n }\n state.modal = entry.modal;\n if (entry.modal) lockPageScroll();\n else unlockPageScroll();\n };\n\n const modelessEscape = (event: KeyboardEvent) => {\n const top = state.stack[state.stack.length - 1];\n if (!top || top.modal || event.key !== \"Escape\" || event.defaultPrevented || event.isComposing) return;\n event.preventDefault();\n void requestDismiss(top);\n };\n\n const stopConnectionObserver = () => {\n document.removeEventListener(\"keydown\", modelessEscape);\n state.connectionObserver?.disconnect();\n state.connectionObserver = undefined;\n };\n\n const applyCancelBehavior = (\n dialog: HTMLDialogElement,\n close: () => void,\n behavior: NonNullable<OpenDialogOptions[\"cancelBehavior\"]>,\n ) => {\n dialog.oncancel = (event) => {\n if (behavior === \"ignore\") {\n event.preventDefault();\n return;\n }\n event.preventDefault();\n close();\n };\n dialog.onmousedown = (event) => {\n state.mouseDownOnDialog = event.target === dialog;\n };\n dialog.onclick = (event) => {\n const realBackdropClick = state.mouseDownOnDialog === true;\n state.mouseDownOnDialog = false;\n if (event.target !== dialog || !state.modal) return;\n if (!realBackdropClick) return;\n if (behavior === \"ignore\") return;\n if (isPointInsideToast(event.clientX, event.clientY)) return;\n close();\n };\n };\n\n const requestDismiss = async (entry: DialogStackEntry) => {\n if (state.stack[state.stack.length - 1] !== entry || entry.dismissPending || entry.cancelBehavior === \"ignore\") return;\n if (!entry.dismissHandler) {\n popTop(undefined);\n return;\n }\n entry.dismissPending = true;\n try {\n await entry.dismissHandler();\n } catch (error) {\n // A failed guard must never discard the dialog's state.\n console.error(\"Dialog dismissal failed\", error);\n } finally {\n entry.dismissPending = false;\n }\n };\n\n const popTop = (result?: unknown) => {\n const top = state.stack.pop();\n if (!top) return;\n top.dispose?.();\n top.container.remove();\n\n const dialog = state.element;\n const previous = state.stack[state.stack.length - 1];\n if (previous && dialog) {\n previous.container.style.display = \"\";\n dialog.className = previous.panelClassName;\n applyPresentation(previous);\n applyAccessibleName(dialog, previous);\n applyCancelBehavior(dialog, () => void requestDismiss(previous), previous.cancelBehavior);\n schedule(() => {\n const target = top.opener?.isConnected ? top.opener : resolveInitialFocusTarget(previous, dialog);\n target?.focus();\n });\n } else if (dialog) {\n dialog.oncancel = null;\n dialog.onmousedown = null;\n dialog.onclick = null;\n dialog.removeAttribute(\"aria-label\");\n dialog.removeAttribute(\"aria-labelledby\");\n if (dialog.open && typeof dialog.close === \"function\") dialog.close();\n else dialog.removeAttribute(\"open\");\n dialog.remove();\n state.element = undefined;\n stopConnectionObserver();\n unlockPageScroll();\n schedule(() => {\n if (top.opener?.isConnected) top.opener.focus();\n });\n }\n\n top.resolve?.(result);\n };\n\n const resetDisconnectedDialog = () => {\n if (state.stack.length === 0 || state.element?.isConnected) return;\n const entries = state.stack.splice(0);\n const dialog = state.element;\n state.element = undefined;\n stopConnectionObserver();\n dialog?.remove();\n unlockPageScroll();\n for (const entry of entries.reverse()) {\n entry.dispose?.();\n entry.container.remove();\n entry.resolve?.(undefined);\n }\n };\n\n const observeConnection = () => {\n if (state.connectionObserver || typeof MutationObserver === \"undefined\") return;\n document.addEventListener(\"keydown\", modelessEscape);\n state.connectionObserver = new MutationObserver(resetDisconnectedDialog);\n state.connectionObserver.observe(document.documentElement, { childList: true, subtree: true });\n };\n\n const open = <T>(view: DialogRender<T>, options: OpenDialogOptions = {}): Promise<T | undefined> => {\n if (options.signal?.aborted) return Promise.resolve(undefined);\n const dialog = ensureDialogElement();\n const previousTop = state.stack[state.stack.length - 1];\n if (previousTop) previousTop.container.style.display = \"none\";\n const activeElement = document.activeElement;\n\n const panelClassName = options.panelClassName ?? DEFAULT_PANEL_CLASS;\n const cancelBehavior = options.cancelBehavior ?? \"resolve-undefined\";\n const initialFocus = options.initialFocus ?? \"first-input\";\n dialog.className = panelClassName;\n\n const container = document.createElement(\"div\");\n container.className = options.contentClassName ?? DEFAULT_CONTENT_CLASS;\n dialog.appendChild(container);\n\n const entry: DialogStackEntry = {\n container,\n panelClassName,\n cancelBehavior,\n initialFocus,\n opener: activeElement instanceof HTMLElement ? activeElement : undefined,\n ariaLabel: options.ariaLabel,\n modal: true,\n };\n\n return new Promise((resolve, reject) => {\n const abort = () => {\n const index = state.stack.indexOf(entry);\n if (index < 0) return;\n if (index === state.stack.length - 1) popTop(undefined);\n else {\n state.stack.splice(index, 1);\n entry.dispose?.();\n entry.container.remove();\n entry.resolve?.(undefined);\n }\n };\n entry.resolve = (value) => {\n options.signal?.removeEventListener(\"abort\", abort);\n resolve(value as T | undefined);\n };\n const closeTyped: DialogClose<T> = (result) => {\n if (state.stack[state.stack.length - 1] !== entry) return;\n popTop(result);\n };\n\n state.stack.push(entry);\n try {\n entry.dispose = render(\n () =>\n view(closeTyped, {\n dialog,\n setModal: (modal) => {\n entry.modal = modal;\n applyPresentation(entry);\n },\n setPosition: (position) => {\n if (position && (!Number.isFinite(position.x) || !Number.isFinite(position.y))) return;\n entry.position = position;\n applyPresentation(entry);\n },\n requestDismiss: () => requestDismiss(entry),\n setDismissHandler: (handler) => {\n entry.dismissHandler = handler;\n },\n }),\n container,\n );\n applyPresentation(entry);\n applyAccessibleName(dialog, entry);\n applyCancelBehavior(dialog, () => void requestDismiss(entry), cancelBehavior);\n\n if (state.stack.length === 1) {\n if (typeof dialog.showModal === \"function\") {\n if (entry.modal) dialog.showModal();\n else dialog.show();\n } else dialog.setAttribute(\"open\", \"\");\n observeConnection();\n }\n options.signal?.addEventListener(\"abort\", abort, { once: true });\n if (options.signal?.aborted) abort();\n schedule(() => {\n if (state.stack[state.stack.length - 1] === entry) resolveInitialFocusTarget(entry, dialog)?.focus();\n });\n } catch (error) {\n entry.resolve = undefined;\n if (state.stack[state.stack.length - 1] === entry) popTop(undefined);\n reject(error);\n }\n });\n };\n\n const close: DialogCore[\"close\"] = (result) => {\n let first = true;\n while (state.stack.length > 0) {\n popTop(first ? result : undefined);\n first = false;\n }\n };\n\n return {\n open,\n close,\n isOpen: () => state.stack.length > 0,\n };\n};\n\nexport const dialogCore = createDialogCore();\n"],"mappings":"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","ignoreList":[]}
@@ -42,6 +42,7 @@ import { TagsInput } from "../inputs/TagsInput";
42
42
  import { TextInput } from "../inputs/TextInput";
43
43
  import { resolveUiMessages } from "../intl/messages";
44
44
  import { dialogCore } from "./dialog-core";
45
+ const PHRASE_SLOT = "\u0000";
45
46
  const isEmpty = value => value === undefined || value === null || value === "" || Array.isArray(value) && value.length === 0;
46
47
  export const createFormState = schema => {
47
48
  const messages = resolveUiMessages();
@@ -60,12 +61,20 @@ export const createFormState = schema => {
60
61
  if (customError) return customError;
61
62
  }
62
63
  if (field.type === "text" && typeof value === "string" && value.length > 0) {
63
- if (field.minLength !== undefined && value.length < field.minLength) return `minimum ${field.minLength} characters`;
64
- if (field.maxLength !== undefined && value.length > field.maxLength) return `maximum ${field.maxLength} characters`;
64
+ if (field.minLength !== undefined && value.length < field.minLength) return messages.minCharacters({
65
+ count: field.minLength
66
+ });
67
+ if (field.maxLength !== undefined && value.length > field.maxLength) return messages.maxCharacters({
68
+ count: field.maxLength
69
+ });
65
70
  }
66
71
  if (field.type === "tags" && Array.isArray(value) && value.length > 0) {
67
- if (field.minTags !== undefined && value.length < field.minTags) return `minimum ${field.minTags} tags`;
68
- if (field.maxTags !== undefined && value.length > field.maxTags) return `maximum ${field.maxTags} tags`;
72
+ if (field.minTags !== undefined && value.length < field.minTags) return messages.minTags({
73
+ count: field.minTags
74
+ });
75
+ if (field.maxTags !== undefined && value.length > field.maxTags) return messages.maxTags({
76
+ count: field.maxTags
77
+ });
69
78
  }
70
79
  return null;
71
80
  };
@@ -614,6 +623,11 @@ export const prompts = {
614
623
  close: () => close(false)
615
624
  })), _$escape(content), _$escape(options?.cancelText || resolveUiMessages().cancel), _$ssrAttribute("data-variant", _$escape(options?.variant ?? "primary", true), false), _$escape(options?.confirmText || resolveUiMessages().confirm));
616
625
  }
626
+
627
+ // The catalog owns word order; the slot marks where the verbatim phrase is rendered as code.
628
+ const [labelBefore, labelAfter] = resolveUiMessages().typeToConfirm({
629
+ phrase: PHRASE_SLOT
630
+ }).split(PHRASE_SLOT);
617
631
  const [confirmationValue, setConfirmationValue] = createSignal("");
618
632
  const canConfirm = () => confirmationValue() === confirmationPhrase;
619
633
  const submit = event => {
@@ -630,7 +644,7 @@ export const prompts = {
630
644
  close: () => close(false)
631
645
  })), _$escape(content), _$escape(_$createComponent(TextInput, {
632
646
  get label() {
633
- return ["Type ", _$ssr(_tmpl$21, _$escape(confirmationPhrase)), " to confirm"];
647
+ return [labelBefore, _$ssr(_tmpl$21, _$escape(confirmationPhrase)), labelAfter];
634
648
  },
635
649
  value: confirmationValue,
636
650
  onValueChange: setConfirmationValue,