@templatical/editor 0.16.4 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/dist/{AiChatSidebar-CYAbVB2G.js → AiChatSidebar-LxCHMdcj.js} +1 -1
  2. package/dist/{AiFeatureMenu-BPCkrHAS.js → AiFeatureMenu-zwSmx9ZW.js} +3 -3
  3. package/dist/{BlockIssueBadge-BLytBabN.js → BlockIssueBadge-BQ1yB1me.js} +2 -2
  4. package/dist/{CloudEditor-v8ARYaFW.js → CloudEditor-5ahgKRX8.js} +11 -10
  5. package/dist/{CollaboratorBar-BQzKZ2zo.js → CollaboratorBar-6PtX-1AS.js} +2 -2
  6. package/dist/{ColorPicker-Cab6U2sH.js → ColorPicker-DfzDyNKe.js} +57 -58
  7. package/dist/{CommentsSidebar-C_XLBbo3.js → CommentsSidebar-Cl93TN96.js} +3 -3
  8. package/dist/{CountdownBlock-173fiO5Z.js → CountdownBlock-DbXfzwae.js} +1 -1
  9. package/dist/{CountdownToolbar-q3umZ7TZ.js → CountdownToolbar-BqaMWRyB.js} +3 -3
  10. package/dist/{DesignReferenceSidebar-Bh9uAZ4B.js → DesignReferenceSidebar-jVrdS8wW.js} +2 -2
  11. package/dist/{IssuesPanel-DltSuU6H.js → IssuesPanel-Bq3yXg6M.js} +2 -2
  12. package/dist/{MergeTagSuggestion-DrT3LiZ4.js → MergeTagSuggestion-jIpT_jmz.js} +7 -5
  13. package/dist/{ModuleBrowserModal-CzzChPmN.js → ModuleBrowserModal-B5IH3-1I.js} +7 -7
  14. package/dist/{ModulePreviewCanvas-C0Q2n3FL.js → ModulePreviewCanvas-CYOLWoZ9.js} +2 -2
  15. package/dist/{NumberWithSuffix-Bhm2ByHs.js → NumberWithSuffix-9FG7mNnn.js} +1 -1
  16. package/dist/{ParagraphEditor-BhsBi8p8.js → ParagraphEditor-duWYA6Vv.js} +38 -39
  17. package/dist/{RichTextEditorContent-ef0fdj6e.js → RichTextEditorContent-DCzmVeyb.js} +13 -13
  18. package/dist/{SaveModuleDialog-BNN3dcxD.js → SaveModuleDialog-BPUly5h3.js} +6 -6
  19. package/dist/{SnapshotHistory-tWvgMCe6.js → SnapshotHistory-CmwU3nlN.js} +4 -4
  20. package/dist/{TemplateScoringPanel-ZhObHWeb.js → TemplateScoringPanel-CMrfa9Rd.js} +3 -3
  21. package/dist/{TestEmailModal-EdwEcsrD.js → TestEmailModal-zfomMz9i.js} +3 -3
  22. package/dist/{TitleEditor-DdvRepBq.js → TitleEditor-v0gtezZE.js} +18 -18
  23. package/dist/{TplModal-Niu4Y96-.js → TplModal-eGFG7k-y.js} +4 -4
  24. package/dist/{blockTypeIcons-DHcYPMB8.js → blockTypeIcons-Dd0w4T0I.js} +1 -1
  25. package/dist/bundle-stats.json +7 -7
  26. package/dist/{ca-DI1ViqMa.js → ca-CSl--oWR.js} +1 -1
  27. package/dist/cdn/chunks/{AiFeatureMenu-AoUwsqor.js → AiFeatureMenu-CtXsam7G.js} +6 -6
  28. package/dist/cdn/chunks/{AiFeatureMenu-AoUwsqor.js.map → AiFeatureMenu-CtXsam7G.js.map} +1 -1
  29. package/dist/cdn/chunks/{BlockIssueBadge-DZU3CfEN.js → BlockIssueBadge-DR7cpDfQ.js} +4 -4
  30. package/dist/cdn/chunks/{BlockIssueBadge-DZU3CfEN.js.map → BlockIssueBadge-DR7cpDfQ.js.map} +1 -1
  31. package/dist/cdn/chunks/{CloudEditor-BrZLF_m1.js → CloudEditor-YC5y3AwC.js} +131 -130
  32. package/dist/cdn/chunks/CloudEditor-YC5y3AwC.js.map +1 -0
  33. package/dist/cdn/chunks/{CollaboratorBar-BAC56ez6.js → CollaboratorBar-BOD2j8Kl.js} +3 -3
  34. package/dist/cdn/chunks/{CollaboratorBar-BAC56ez6.js.map → CollaboratorBar-BOD2j8Kl.js.map} +1 -1
  35. package/dist/cdn/chunks/{ColorPicker-DLEoT419.js → ColorPicker-CPMWLHpa.js} +144 -144
  36. package/dist/cdn/chunks/ColorPicker-CPMWLHpa.js.map +1 -0
  37. package/dist/cdn/chunks/{CountdownBlock-BOF9aTXF.js → CountdownBlock-BmGqb7Zi.js} +4 -4
  38. package/dist/cdn/chunks/{CountdownBlock-BOF9aTXF.js.map → CountdownBlock-BmGqb7Zi.js.map} +1 -1
  39. package/dist/cdn/chunks/{CountdownToolbar-C9bQ5k4E.js → CountdownToolbar-BBwsdGbV.js} +4 -4
  40. package/dist/cdn/chunks/{CountdownToolbar-C9bQ5k4E.js.map → CountdownToolbar-BBwsdGbV.js.map} +1 -1
  41. package/dist/cdn/chunks/{IssuesPanel-CHwYahKK.js → IssuesPanel-G0z-j3JS.js} +7 -7
  42. package/dist/cdn/chunks/{IssuesPanel-CHwYahKK.js.map → IssuesPanel-G0z-j3JS.js.map} +1 -1
  43. package/dist/cdn/chunks/{MergeTagSuggestion-jesxS7An.js → MergeTagSuggestion-rpZ6Ol-i.js} +8 -6
  44. package/dist/cdn/chunks/MergeTagSuggestion-rpZ6Ol-i.js.map +1 -0
  45. package/dist/cdn/chunks/{ModuleBrowserModal-iSXXpAUk.js → ModuleBrowserModal-DiLTY0ec.js} +8 -8
  46. package/dist/cdn/chunks/{ModuleBrowserModal-iSXXpAUk.js.map → ModuleBrowserModal-DiLTY0ec.js.map} +1 -1
  47. package/dist/cdn/chunks/{ModulePreviewCanvas-DIy0MZj2.js → ModulePreviewCanvas-CdV5mEQ6.js} +32 -32
  48. package/dist/cdn/chunks/{ModulePreviewCanvas-DIy0MZj2.js.map → ModulePreviewCanvas-CdV5mEQ6.js.map} +1 -1
  49. package/dist/cdn/chunks/{NumberWithSuffix-vPdOG2lO.js → NumberWithSuffix-lqQlf0Uk.js} +2 -2
  50. package/dist/cdn/chunks/{NumberWithSuffix-vPdOG2lO.js.map → NumberWithSuffix-lqQlf0Uk.js.map} +1 -1
  51. package/dist/cdn/chunks/{ParagraphEditor-D7znI_X1.js → ParagraphEditor-BYoZfURd.js} +75 -75
  52. package/dist/cdn/chunks/ParagraphEditor-BYoZfURd.js.map +1 -0
  53. package/dist/cdn/chunks/{RichTextEditorContent-DVwGHbO6.js → RichTextEditorContent-BnPRnXxy.js} +6 -6
  54. package/dist/cdn/chunks/{RichTextEditorContent-DVwGHbO6.js.map → RichTextEditorContent-BnPRnXxy.js.map} +1 -1
  55. package/dist/cdn/chunks/{SaveModuleDialog-D2_qPtE9.js → SaveModuleDialog-C9hUeWyG.js} +20 -20
  56. package/dist/cdn/chunks/{SaveModuleDialog-D2_qPtE9.js.map → SaveModuleDialog-C9hUeWyG.js.map} +1 -1
  57. package/dist/cdn/chunks/{TitleEditor-CKjZ6Cgp.js → TitleEditor-wFvnU3Jr.js} +9 -9
  58. package/dist/cdn/chunks/TitleEditor-wFvnU3Jr.js.map +1 -0
  59. package/dist/cdn/chunks/{blockTypeIcons-BKecgdgr.js → blockTypeIcons-DNMvDz5B.js} +7 -7
  60. package/dist/cdn/chunks/{blockTypeIcons-BKecgdgr.js.map → blockTypeIcons-DNMvDz5B.js.map} +1 -1
  61. package/dist/cdn/chunks/{ca-DI1ViqMa.js → ca-CSl--oWR.js} +2 -2
  62. package/dist/cdn/chunks/ca-CSl--oWR.js.map +1 -0
  63. package/dist/cdn/chunks/{de-q9lTCMre.js → de-ZaffrKDP.js} +2 -2
  64. package/dist/cdn/chunks/de-ZaffrKDP.js.map +1 -0
  65. package/dist/cdn/chunks/{en-CR4LItrX.js → en-CHuXeJDt.js} +2 -2
  66. package/dist/cdn/chunks/en-CHuXeJDt.js.map +1 -0
  67. package/dist/cdn/chunks/{es-CEt-lrGd.js → es-CaC8VQjO.js} +2 -2
  68. package/dist/cdn/chunks/es-CaC8VQjO.js.map +1 -0
  69. package/dist/cdn/chunks/{extensions-OZTN_skA.js → extensions-DxcxIlwT.js} +29 -29
  70. package/dist/cdn/chunks/{extensions-OZTN_skA.js.map → extensions-DxcxIlwT.js.map} +1 -1
  71. package/dist/cdn/chunks/{features-Bo7H8WNI.js → features-B3qgDBHf.js} +727 -677
  72. package/dist/cdn/chunks/features-B3qgDBHf.js.map +1 -0
  73. package/dist/cdn/chunks/{icons-BrNSrnyT.js → icons-kiMqh99T.js} +2 -2
  74. package/dist/cdn/chunks/{icons-BrNSrnyT.js.map → icons-kiMqh99T.js.map} +1 -1
  75. package/dist/cdn/chunks/{media-library-Cec5DMR3.js → media-library-C5ogiZ4f.js} +451 -451
  76. package/dist/cdn/chunks/{media-library-Cec5DMR3.js.map → media-library-C5ogiZ4f.js.map} +1 -1
  77. package/dist/cdn/chunks/{pt-BR-DvBHY0AA.js → pt-BR-C74zfEWH.js} +2 -2
  78. package/dist/cdn/chunks/pt-BR-C74zfEWH.js.map +1 -0
  79. package/dist/cdn/chunks/{quality-Dd2iYgRf.js → quality-BftAn_AJ.js} +512 -512
  80. package/dist/cdn/chunks/{quality-Dd2iYgRf.js.map → quality-BftAn_AJ.js.map} +1 -1
  81. package/dist/cdn/chunks/{renderer-Br-qXdnQ.js → renderer-Cdlo4MVX.js} +16 -16
  82. package/dist/cdn/chunks/{renderer-Br-qXdnQ.js.map → renderer-Cdlo4MVX.js.map} +1 -1
  83. package/dist/cdn/chunks/{src-BH8PABpF.js → src-GBA8oUL2.js} +6 -6
  84. package/dist/cdn/chunks/{src-BH8PABpF.js.map → src-GBA8oUL2.js.map} +1 -1
  85. package/dist/cdn/chunks/{styles-nqo5BynI.js → styles-B6rdq9JB.js} +219 -219
  86. package/dist/cdn/chunks/styles-B6rdq9JB.js.map +1 -0
  87. package/dist/cdn/editor.css +1 -1
  88. package/dist/cdn/editor.js +53 -52
  89. package/dist/cdn/editor.js.map +1 -1
  90. package/dist/{de-q9lTCMre.js → de-ZaffrKDP.js} +1 -1
  91. package/dist/{en-CR4LItrX.js → en-CHuXeJDt.js} +1 -1
  92. package/dist/{es-CEt-lrGd.js → es-CaC8VQjO.js} +1 -1
  93. package/dist/{extensions-B2poxDIo.js → extensions-B4lu0KkE.js} +3 -3
  94. package/dist/index.d.ts +56 -0
  95. package/dist/keys-WVNarXg8.js +10 -0
  96. package/dist/{pt-BR-DvBHY0AA.js → pt-BR-C74zfEWH.js} +1 -1
  97. package/dist/style.css +1 -1
  98. package/dist/{styles-DN4J7w-C.js → styles-mBSbDYeX.js} +98 -98
  99. package/dist/templatical-editor.js +11 -10
  100. package/dist/{useCloudI18n-WbfVWq5k.js → useCloudI18n-CIKI0hCd.js} +1 -1
  101. package/dist/{useEditorCore-DBq2689h.js → useEditorCore-CaaHPKjm.js} +715 -684
  102. package/dist/{useI18n-eR1yVW0v.js → useI18n-0EU_JVe7.js} +1 -1
  103. package/dist/{useMergeTag-C3GfSktg.js → useMergeTag-C7v6MVah.js} +2 -2
  104. package/dist/usePopoverPosition-BDqqnMeo.js +281 -0
  105. package/package.json +7 -7
  106. package/dist/cdn/chunks/CloudEditor-BrZLF_m1.js.map +0 -1
  107. package/dist/cdn/chunks/ColorPicker-DLEoT419.js.map +0 -1
  108. package/dist/cdn/chunks/MergeTagSuggestion-jesxS7An.js.map +0 -1
  109. package/dist/cdn/chunks/ParagraphEditor-D7znI_X1.js.map +0 -1
  110. package/dist/cdn/chunks/TitleEditor-CKjZ6Cgp.js.map +0 -1
  111. package/dist/cdn/chunks/ca-DI1ViqMa.js.map +0 -1
  112. package/dist/cdn/chunks/de-q9lTCMre.js.map +0 -1
  113. package/dist/cdn/chunks/en-CR4LItrX.js.map +0 -1
  114. package/dist/cdn/chunks/es-CEt-lrGd.js.map +0 -1
  115. package/dist/cdn/chunks/features-Bo7H8WNI.js.map +0 -1
  116. package/dist/cdn/chunks/pt-BR-DvBHY0AA.js.map +0 -1
  117. package/dist/cdn/chunks/styles-nqo5BynI.js.map +0 -1
  118. package/dist/color-DhoxCSMv.js +0 -259
  119. package/dist/keys-BbDgCU6K.js +0 -10
  120. package/dist/usePopoverRoot-C1j0D7cc.js +0 -8
@@ -1 +0,0 @@
1
- {"version":3,"file":"MergeTagSuggestion-jesxS7An.js","names":["$emit"],"sources":["../../../src/components/MergeTagSuggestionList.vue","../../../src/components/MergeTagSuggestionList.vue","../../../src/extensions/MergeTagSuggestion.ts"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { MergeTag } from \"@templatical/types\";\n\nconst props = defineProps<{\n items: MergeTag[];\n selectedIndex: number;\n emptyText: string;\n /** Stable id used for aria-controls + per-option id derivation. */\n listId?: string;\n}>();\n\ndefineEmits<{\n (e: \"select\", item: MergeTag): void;\n (e: \"hover\", index: number): void;\n}>();\n\nfunction optionId(index: number): string | undefined {\n return props.listId ? `${props.listId}-opt-${index}` : undefined;\n}\n</script>\n\n<template>\n <div\n :id=\"listId\"\n class=\"tpl:min-w-[200px] tpl:max-w-[320px] tpl:max-h-[50vh] tpl:overflow-y-auto tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)] tpl:py-1 tpl:shadow-lg\"\n role=\"listbox\"\n data-testid=\"merge-tag-suggestion-list\"\n >\n <div\n v-if=\"items.length === 0\"\n class=\"tpl:px-3 tpl:py-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n data-testid=\"merge-tag-suggestion-empty\"\n >\n {{ emptyText }}\n </div>\n <button\n v-for=\"(item, index) in items\"\n :key=\"item.value\"\n :id=\"optionId(index)\"\n type=\"button\"\n role=\"option\"\n :aria-selected=\"index === selectedIndex\"\n :data-selected=\"index === selectedIndex ? 'true' : 'false'\"\n :data-merge-tag-value=\"item.value\"\n class=\"tpl:flex tpl:w-full tpl:flex-col tpl:items-start tpl:gap-0.5 tpl:px-3 tpl:py-1.5 tpl:text-left tpl:text-xs tpl:transition-colors\"\n :class=\"\n index === selectedIndex\n ? 'tpl:bg-[var(--tpl-primary-light)] tpl:text-[var(--tpl-primary)]'\n : 'tpl:text-[var(--tpl-text)] hover:tpl:bg-[var(--tpl-bg-hover)]'\n \"\n @mousedown.prevent.stop=\"$emit('select', item)\"\n @mousemove=\"index !== selectedIndex && $emit('hover', index)\"\n >\n <span class=\"tpl:font-medium\">{{ item.label }}</span>\n <span class=\"tpl:text-[var(--tpl-text-dim)] tpl:font-mono\">{{\n item.value\n }}</span>\n </button>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { MergeTag } from \"@templatical/types\";\n\nconst props = defineProps<{\n items: MergeTag[];\n selectedIndex: number;\n emptyText: string;\n /** Stable id used for aria-controls + per-option id derivation. */\n listId?: string;\n}>();\n\ndefineEmits<{\n (e: \"select\", item: MergeTag): void;\n (e: \"hover\", index: number): void;\n}>();\n\nfunction optionId(index: number): string | undefined {\n return props.listId ? `${props.listId}-opt-${index}` : undefined;\n}\n</script>\n\n<template>\n <div\n :id=\"listId\"\n class=\"tpl:min-w-[200px] tpl:max-w-[320px] tpl:max-h-[50vh] tpl:overflow-y-auto tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)] tpl:py-1 tpl:shadow-lg\"\n role=\"listbox\"\n data-testid=\"merge-tag-suggestion-list\"\n >\n <div\n v-if=\"items.length === 0\"\n class=\"tpl:px-3 tpl:py-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n data-testid=\"merge-tag-suggestion-empty\"\n >\n {{ emptyText }}\n </div>\n <button\n v-for=\"(item, index) in items\"\n :key=\"item.value\"\n :id=\"optionId(index)\"\n type=\"button\"\n role=\"option\"\n :aria-selected=\"index === selectedIndex\"\n :data-selected=\"index === selectedIndex ? 'true' : 'false'\"\n :data-merge-tag-value=\"item.value\"\n class=\"tpl:flex tpl:w-full tpl:flex-col tpl:items-start tpl:gap-0.5 tpl:px-3 tpl:py-1.5 tpl:text-left tpl:text-xs tpl:transition-colors\"\n :class=\"\n index === selectedIndex\n ? 'tpl:bg-[var(--tpl-primary-light)] tpl:text-[var(--tpl-primary)]'\n : 'tpl:text-[var(--tpl-text)] hover:tpl:bg-[var(--tpl-bg-hover)]'\n \"\n @mousedown.prevent.stop=\"$emit('select', item)\"\n @mousemove=\"index !== selectedIndex && $emit('hover', index)\"\n >\n <span class=\"tpl:font-medium\">{{ item.label }}</span>\n <span class=\"tpl:text-[var(--tpl-text-dim)] tpl:font-mono\">{{\n item.value\n }}</span>\n </button>\n </div>\n</template>\n","import type { MergeTag } from \"@templatical/types\";\nimport { Extension } from \"@tiptap/core\";\nimport Suggestion, {\n type SuggestionOptions,\n type SuggestionProps,\n type SuggestionKeyDownProps,\n} from \"@tiptap/suggestion\";\nimport { type App, createApp, h, ref, type Ref } from \"vue\";\nimport MergeTagSuggestionList from \"../components/MergeTagSuggestionList.vue\";\n\nconst MAX_RESULTS = 10;\n\n// Monotonic counter for unique listbox IDs across multiple popup instances.\nlet POPUP_ID_SEQ = 0;\n\nexport interface MergeTagSuggestionOptions {\n /** Available merge tags */\n mergeTags: MergeTag[];\n /** Trigger string (e.g. \"{{\", \"*|\", \"%%=\") */\n char: string;\n /** Localized empty-state label */\n emptyText: string;\n /**\n * Mount target for the suggestion popup. When provided with a non-null\n * `.value`, the popup attaches into that element instead of\n * `document.body` — keeping it inside the editor's effective DOM root\n * (shadow-aware). Pass the ref returned by `usePopoverRoot()`.\n *\n * Falls back to `document.body` when omitted or when the ref's value is\n * null at popup-open time (e.g. headless/test editors without an editor\n * shell). Preserves pre-Phase-3 behavior for callers that don't migrate.\n */\n popoverRoot?: Ref<HTMLElement | null> | null;\n}\n\n/**\n * Filter merge tags by query against label and value (case-insensitive).\n * Capped at MAX_RESULTS. Exported for testing.\n */\nexport function filterMergeTags(tags: MergeTag[], query: string): MergeTag[] {\n const trimmed = query.trim().toLowerCase();\n if (trimmed === \"\") {\n return tags.slice(0, MAX_RESULTS);\n }\n return tags\n .filter((tag) => {\n const label = tag.label.toLowerCase();\n const value = tag.value.toLowerCase();\n return label.includes(trimmed) || value.includes(trimmed);\n })\n .slice(0, MAX_RESULTS);\n}\n\n/**\n * Handle a keydown event against a list of items. Returns whether the\n * event was handled (so the suggestion plugin can stop propagation).\n * Exported for testing.\n */\nexport function handleSuggestionKeyDown(\n event: KeyboardEvent,\n items: MergeTag[],\n selectedIndex: Ref<number>,\n onSelect: (item: MergeTag) => void,\n): boolean {\n if (items.length === 0) {\n if (event.key === \"Enter\" || event.key === \"Tab\") return true;\n return false;\n }\n\n if (event.key === \"ArrowDown\") {\n selectedIndex.value = (selectedIndex.value + 1) % items.length;\n return true;\n }\n if (event.key === \"ArrowUp\") {\n selectedIndex.value =\n (selectedIndex.value - 1 + items.length) % items.length;\n return true;\n }\n if (event.key === \"Enter\" || event.key === \"Tab\") {\n onSelect(items[selectedIndex.value]);\n return true;\n }\n return false;\n}\n\n/** Options for opening the merge-tag popup. */\nexport interface MergeTagPopupOpenOptions {\n /** Filtered tags to render. */\n items: MergeTag[];\n /**\n * Anchor rect getter (the caret rect). Same contract as\n * `@tiptap/suggestion`'s `clientRect`: viewport coordinates, re-read on\n * every reposition so the popup tracks the caret through scroll.\n */\n getRect: (() => DOMRect | null) | null;\n /**\n * Element that owns the ARIA combobox state and serves as the theme +\n * scroll-ancestor anchor — the ProseMirror `view.dom` in rich text, the\n * `<input>`/`<textarea>` in a field.\n */\n anchorEl: HTMLElement | null;\n /** Called with the item the user picks. */\n onCommand: (item: MergeTag) => void;\n}\n\n/** Options for updating the popup after the query changed. */\nexport interface MergeTagPopupUpdateOptions {\n items: MergeTag[];\n getRect: (() => DOMRect | null) | null;\n onCommand: (item: MergeTag) => void;\n}\n\n/**\n * Imperative handle over a single merge-tag suggestion popup.\n * Both the TipTap suggestion renderer and the input/textarea autocomplete\n * driver drive the SAME controller, so the popup's rendering, positioning,\n * scroll-tracking, ARIA wiring, and keyboard behavior are identical across\n * rich-text and plain-field surfaces by construction.\n */\nexport interface MergeTagPopupController {\n /** Mount the popup and start tracking the caret. */\n open(options: MergeTagPopupOpenOptions): void;\n /** Refresh items + anchor after the query changed. */\n update(options: MergeTagPopupUpdateOptions): void;\n /**\n * Handle a navigation/selection key (Arrow/Enter/Tab). Returns whether it\n * was handled. Does NOT handle Escape — each caller owns Escape (TipTap's\n * plugin closes via `onExit`; the field driver calls `close()`).\n */\n handleKeyDown(event: KeyboardEvent): boolean;\n /** Unmount the popup, clear ARIA, and detach listeners. Idempotent. */\n close(): void;\n /** Whether the popup is currently mounted. */\n isOpen(): boolean;\n}\n\n/**\n * Creates a merge-tag suggestion popup controller: mount, ARIA wiring,\n * caret-tracking position (flip-above + off-screen freeze), scroll/resize\n * repositioning, and cleanup. Framework-agnostic — it takes a plain caret\n * rect getter and an anchor element, so it serves both the ProseMirror\n * suggestion plugin and native text fields.\n */\nexport function createMergeTagPopup(\n emptyText: string,\n popoverRootRef?: Ref<HTMLElement | null> | null,\n): MergeTagPopupController {\n let app: App | null = null;\n let container: HTMLElement | null = null;\n let editableEl: HTMLElement | null = null;\n const itemsRef = ref<MergeTag[]>([]);\n const selectedIndex = ref(0);\n let currentCommand: ((item: MergeTag) => void) | null = null;\n const listId = `tpl-merge-tag-suggestion-${++POPUP_ID_SEQ}`;\n let latestClientRect: (() => DOMRect | null) | null = null;\n let scrollTargets: Array<EventTarget> = [];\n let pendingRaf: number | null = null;\n\n function reposition(): void {\n position(latestClientRect?.() ?? null);\n }\n\n /**\n * Reposition immediately and on the next animation frame.\n * After a keystroke triggers the suggestion, TipTap may run its\n * own `scrollIntoView` to keep the caret visible. That scroll\n * lands AFTER the current task's `position()` call but BEFORE\n * the browser's next paint, so we re-measure on rAF to catch\n * the post-scroll caret rect. Without this, the popup pins to\n * the pre-scroll caret position and ends up offset on slower\n * runners.\n */\n function repositionAfterPaint(): void {\n reposition();\n if (pendingRaf !== null) cancelAnimationFrame(pendingRaf);\n pendingRaf = requestAnimationFrame(() => {\n pendingRaf = null;\n reposition();\n });\n }\n\n function collectScrollAncestors(el: HTMLElement | null): HTMLElement[] {\n // Walk up the DOM finding scrollable ancestors. ProseMirror's\n // scrollIntoView fires on whichever ancestor scrolls — listening\n // to all of them ensures we reposition regardless of which one\n // moves.\n const result: HTMLElement[] = [];\n let node: HTMLElement | null = el?.parentElement ?? null;\n while (\n node &&\n // shadow-ok: ancestor walk terminator; not a mount target\n node !== document.body &&\n node !== document.documentElement\n ) {\n const style = window.getComputedStyle(node);\n const overflow = style.overflow + style.overflowX + style.overflowY;\n if (/(auto|scroll|overlay)/.test(overflow)) {\n result.push(node);\n }\n node = node.parentElement;\n }\n return result;\n }\n\n function attachScrollListeners(viewDom: HTMLElement | null): void {\n scrollTargets = [window, ...collectScrollAncestors(viewDom)];\n for (const target of scrollTargets) {\n target.addEventListener(\"scroll\", reposition, {\n passive: true,\n capture: true,\n });\n }\n window.addEventListener(\"resize\", reposition, { passive: true });\n }\n\n function detachScrollListeners(): void {\n for (const target of scrollTargets) {\n target.removeEventListener(\"scroll\", reposition, {\n capture: true,\n } as EventListenerOptions);\n }\n window.removeEventListener(\"resize\", reposition);\n scrollTargets = [];\n }\n\n function position(rect: DOMRect | null): void {\n if (!container || !rect) return;\n // If the caret has scrolled out of the viewport, freeze the\n // popup at its last on-screen position. Following the caret\n // off-screen produces an invisible popup the user can't reach,\n // and lets pathological scroll loops drag the popup further\n // each tick.\n if (rect.bottom < 0 || rect.top > window.innerHeight) return;\n container.style.position = \"fixed\";\n container.style.left = `${rect.left}px`;\n container.style.zIndex = \"9999\";\n // Place below caret first; offsetHeight is sync-readable after\n // the Vue app has mounted (or after onUpdate's reactive flush).\n container.style.top = `${rect.bottom}px`;\n const popupHeight = container.offsetHeight;\n if (popupHeight === 0) return;\n const spaceBelow = window.innerHeight - rect.bottom;\n if (spaceBelow < popupHeight) {\n // Not enough room below — flip above. Clamp to 0 so the\n // popup never positions off the top of the viewport.\n const flippedTop = Math.max(0, rect.top - popupHeight);\n container.style.top = `${flippedTop}px`;\n }\n }\n\n function applyThemeContext(\n target: HTMLElement,\n editorEl: HTMLElement | null | undefined,\n ): void {\n // When the popup mounts to document.body its `position: fixed`\n // resolves against the viewport — any transform/filter on a\n // consumer-page ancestor (route transitions, reveal animations,\n // dark canvas inversion) creates a containing block and moves\n // fixed descendants with it. Body ancestors don't transform.\n //\n // When mounting inside the editor's popover root, the popup is a\n // descendant of the `.tpl[data-tpl-theme]` root so CSS vars + font\n // would inherit — but the snapshot below is still emitted inline\n // because inline declarations win and the cost is negligible. This\n // keeps a single behavior across both mount paths.\n //\n // CSS vars (--tpl-bg-elevated, --tpl-border, etc.) are scoped to\n // `.tpl` and `.tpl[data-tpl-theme=\"dark\"]` in the editor's\n // stylesheet, so the popup wouldn't inherit them at body root.\n // Adding `class=\"tpl\"` would also pull base rules (min-height,\n // flex, full-page bg) we don't want on a popup. Instead, snapshot\n // every --tpl-* custom property from the editor's theme root and\n // re-emit them inline on the popup wrapper.\n const themeRoot = editorEl?.closest<HTMLElement>(\"[data-tpl-theme]\");\n if (!themeRoot) return;\n const themeValue = themeRoot.getAttribute(\"data-tpl-theme\");\n if (themeValue) target.setAttribute(\"data-tpl-theme\", themeValue);\n const computed = window.getComputedStyle(themeRoot);\n for (let i = 0; i < computed.length; i++) {\n const prop = computed[i];\n if (prop.startsWith(\"--tpl-\")) {\n target.style.setProperty(prop, computed.getPropertyValue(prop));\n }\n }\n // The popup no longer inherits font from the editor wrapper, so\n // its content would render in the page's default font and end up\n // at a different height — which changes the flip-above decision\n // and shifts the popup off the caret. Copy typography too.\n target.style.fontFamily = computed.fontFamily;\n target.style.fontSize = computed.fontSize;\n target.style.lineHeight = computed.lineHeight;\n }\n\n function setEditableAria(active: boolean): void {\n if (!editableEl) return;\n if (active) {\n editableEl.setAttribute(\"role\", \"combobox\");\n editableEl.setAttribute(\"aria-haspopup\", \"listbox\");\n editableEl.setAttribute(\"aria-expanded\", \"true\");\n editableEl.setAttribute(\"aria-controls\", listId);\n } else {\n editableEl.removeAttribute(\"aria-expanded\");\n editableEl.removeAttribute(\"aria-controls\");\n editableEl.removeAttribute(\"aria-activedescendant\");\n editableEl.removeAttribute(\"aria-haspopup\");\n editableEl.removeAttribute(\"role\");\n }\n }\n\n function setActiveDescendant(): void {\n if (!editableEl) return;\n if (itemsRef.value.length === 0) {\n editableEl.removeAttribute(\"aria-activedescendant\");\n return;\n }\n editableEl.setAttribute(\n \"aria-activedescendant\",\n `${listId}-opt-${selectedIndex.value}`,\n );\n }\n\n function select(item: MergeTag): void {\n currentCommand?.(item);\n }\n\n return {\n open: ({ items, getRect, anchorEl, onCommand }) => {\n itemsRef.value = items;\n selectedIndex.value = 0;\n currentCommand = onCommand;\n\n container = document.createElement(\"div\");\n container.setAttribute(\"data-testid\", \"merge-tag-suggestion-popup\");\n editableEl = anchorEl;\n applyThemeContext(container, anchorEl);\n // Prefer the editor's popover root (shadow-aware) when wired by\n // the consumer. Falls back to document.body for headless callers\n // that don't pass `popoverRoot` to configure().\n // shadow-ok: fallback when popoverRoot wasn't provided (e.g., headless caller); editor mounts pass the shadow-aware root\n const mountTarget = popoverRootRef?.value ?? document.body;\n mountTarget.appendChild(container);\n\n app = createApp({\n render() {\n return h(MergeTagSuggestionList, {\n items: itemsRef.value,\n selectedIndex: selectedIndex.value,\n emptyText,\n listId,\n onSelect: (item: MergeTag) => select(item),\n onHover: (index: number) => {\n selectedIndex.value = index;\n setActiveDescendant();\n },\n });\n },\n });\n app.mount(container);\n setEditableAria(true);\n setActiveDescendant();\n latestClientRect = getRect;\n repositionAfterPaint();\n attachScrollListeners(anchorEl);\n },\n update: ({ items, getRect, onCommand }) => {\n itemsRef.value = items;\n // Reset selection when item set changes (query changed).\n if (selectedIndex.value >= items.length) {\n selectedIndex.value = 0;\n }\n currentCommand = onCommand;\n setActiveDescendant();\n latestClientRect = getRect;\n repositionAfterPaint();\n },\n handleKeyDown: (event: KeyboardEvent): boolean => {\n const handled = handleSuggestionKeyDown(\n event,\n itemsRef.value,\n selectedIndex,\n select,\n );\n if (handled) setActiveDescendant();\n return handled;\n },\n close: () => {\n // Idempotent: nothing to tear down (and no window listeners to detach)\n // when the popup was never opened. Keeps repeated close() / close-before-\n // open cheap and side-effect-free.\n if (container === null) return;\n if (pendingRaf !== null) {\n cancelAnimationFrame(pendingRaf);\n pendingRaf = null;\n }\n detachScrollListeners();\n setEditableAria(false);\n app?.unmount();\n container.remove();\n app = null;\n container = null;\n editableEl = null;\n currentCommand = null;\n latestClientRect = null;\n },\n isOpen: () => container !== null,\n };\n}\n\n/**\n * Builds the `@tiptap/suggestion` `render` factory for the merge-tag popup.\n * A thin adapter over {@link createMergeTagPopup}: it maps ProseMirror's\n * `SuggestionProps` (items, `clientRect`, `view.dom`, `command`) onto the\n * controller. Exported as a standalone function so that mapping can be\n * unit-tested with mocked `SuggestionProps` instead of a full editor.\n */\nexport function createMergeTagSuggestionRenderer(\n emptyText: string,\n popoverRootRef?: Ref<HTMLElement | null> | null,\n): NonNullable<SuggestionOptions<MergeTag>[\"render\"]> {\n return () => {\n const popup = createMergeTagPopup(emptyText, popoverRootRef);\n\n return {\n onStart: (props: SuggestionProps<MergeTag>) => {\n // Use view.dom (ProseMirror contenteditable, actually\n // attached to the DOM) rather than options.element, which may\n // be a detached div when no `element` is passed to the editor\n // constructor (as is the case with @tiptap/vue-3 EditorContent).\n const viewDom = props.editor.view?.dom as HTMLElement | undefined;\n popup.open({\n items: props.items,\n getRect: props.clientRect ?? null,\n anchorEl: viewDom ?? null,\n onCommand: (item) => props.command(item),\n });\n },\n onUpdate: (props: SuggestionProps<MergeTag>) => {\n popup.update({\n items: props.items,\n getRect: props.clientRect ?? null,\n onCommand: (item) => props.command(item),\n });\n },\n onKeyDown: (props: SuggestionKeyDownProps): boolean => {\n // Escape closes via TipTap's suggestion plugin (→ onExit); report it\n // handled without selecting.\n if (props.event.key === \"Escape\") {\n return true;\n }\n return popup.handleKeyDown(props.event);\n },\n onExit: () => popup.close(),\n };\n };\n}\n\nexport const MergeTagSuggestion = Extension.create<MergeTagSuggestionOptions>({\n name: \"mergeTagSuggestion\",\n\n addOptions() {\n return {\n mergeTags: [],\n char: \"{{\",\n emptyText: \"No matching merge tags\",\n popoverRoot: null,\n };\n },\n\n addProseMirrorPlugins() {\n const tags = this.options.mergeTags;\n const emptyText = this.options.emptyText;\n const popoverRootRef = this.options.popoverRoot;\n\n const config: Omit<SuggestionOptions<MergeTag>, \"editor\"> = {\n char: this.options.char,\n allowSpaces: false,\n startOfLine: false,\n // Default is [\" \"] which requires whitespace/line-start before the\n // trigger char — so `.{{` would not fire. Allow any preceding char.\n allowedPrefixes: null,\n items: ({ query }: { query: string }) => filterMergeTags(tags, query),\n command: ({\n editor,\n range,\n props,\n }: {\n editor: SuggestionProps<MergeTag>[\"editor\"];\n range: { from: number; to: number };\n props: MergeTag;\n }) => {\n // Use insertContentAt for atomic replace (matches the canonical\n // @tiptap/suggestion + Mention pattern). Avoids edge cases where\n // chained deleteRange + insertMergeTag fails to insert when the\n // selection state shifts mid-chain.\n editor\n .chain()\n .focus()\n .insertContentAt(range, {\n type: \"mergeTagNode\",\n attrs: { label: props.label, value: props.value },\n })\n .run();\n },\n render: createMergeTagSuggestionRenderer(emptyText, popoverRootRef),\n };\n\n return [\n Suggestion({\n editor: this.editor,\n ...config,\n }),\n ];\n },\n});\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ParagraphEditor-D7znI_X1.js","names":[],"sources":["../../../src/components/blocks/EmojiPickerDropdown.vue","../../../src/components/blocks/EmojiPickerDropdown.vue","../../../src/components/toolbar/ToolbarIconButton.vue","../../../src/components/toolbar/ToolbarIconButton.vue","../../../src/components/toolbar/ToolbarSeparator.vue","../../../src/components/toolbar/ToolbarSelect.vue","../../../src/components/toolbar/ToolbarSelect.vue","../../../src/utils/richTextColor.ts","../../../src/components/blocks/ParagraphToolbar.vue","../../../src/components/blocks/ParagraphToolbar.vue","../../../src/components/blocks/ParagraphEditor.vue","../../../src/components/blocks/ParagraphEditor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useEmoji, useI18n } from \"../../composables\";\nimport { useFocusTrap } from \"../../composables/useFocusTrap\";\nimport { onClickOutside } from \"@vueuse/core\";\nimport { Smile } from \"@lucide/vue\";\nimport { computed, ref } from \"vue\";\n\nconst emit = defineEmits<{\n (e: \"insert\", emoji: string): void;\n}>();\n\nconst {\n categories: emojiCategories,\n isOpen: showEmojiPicker,\n toggle: toggleEmojiPicker,\n close: closeEmojiPicker,\n} = useEmoji();\n\nconst { t, format } = useI18n();\n\nconst pickerRef = ref<HTMLElement | null>(null);\nconst rootRef = ref<HTMLElement | null>(null);\n\nconst isOpenRef = computed(() => showEmojiPicker.value);\nuseFocusTrap(pickerRef, isOpenRef);\n\nonClickOutside(rootRef, () => {\n if (showEmojiPicker.value) {\n closeEmojiPicker();\n }\n});\n\nfunction handleInsert(emoji: string): void {\n emit(\"insert\", emoji);\n closeEmojiPicker();\n}\n</script>\n\n<template>\n <div ref=\"rootRef\" class=\"tpl:relative\">\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': showEmojiPicker,\n }\"\n :aria-label=\"t.paragraphEditor.insertEmoji\"\n :title=\"t.paragraphEditor.insertEmoji\"\n :aria-expanded=\"showEmojiPicker\"\n aria-haspopup=\"dialog\"\n aria-controls=\"tpl-emoji-picker\"\n @click=\"toggleEmojiPicker\"\n >\n <Smile :size=\"16\" :stroke-width=\"2\" />\n </button>\n <div\n v-if=\"showEmojiPicker\"\n id=\"tpl-emoji-picker\"\n ref=\"pickerRef\"\n role=\"dialog\"\n aria-modal=\"false\"\n :aria-label=\"t.paragraphEditor.insertEmoji\"\n tabindex=\"-1\"\n class=\"tpl-emoji-picker tpl:absolute tpl:top-full tpl:left-0 tpl:z-10 tpl:mt-2 tpl:w-72 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:p-2 tpl:shadow-lg\"\n @keydown.esc.stop.prevent=\"closeEmojiPicker\"\n >\n <div\n v-for=\"category in emojiCategories\"\n :key=\"category.key\"\n class=\"tpl:mb-2 tpl:last:mb-0\"\n >\n <div\n class=\"tpl:mb-1.5 tpl:text-[10px] tpl:font-medium tpl:tracking-wide tpl:text-[var(--tpl-text-muted)] tpl:uppercase\"\n >\n {{ t.emoji[category.key] }}\n </div>\n <div class=\"tpl:grid tpl:grid-cols-10 tpl:gap-0.5\">\n <button\n v-for=\"emoji in category.emojis\"\n :key=\"emoji\"\n type=\"button\"\n :aria-label=\"format(t.paragraphEditor.emojiItemLabel, { emoji })\"\n class=\"tpl:flex tpl:size-6 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded tpl:border-none tpl:bg-transparent tpl:text-base tpl:transition-all tpl:duration-100 tpl:hover:scale-125 tpl:hover:bg-[var(--tpl-bg-active)]\"\n @click=\"handleInsert(emoji)\"\n >\n {{ emoji }}\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { useEmoji, useI18n } from \"../../composables\";\nimport { useFocusTrap } from \"../../composables/useFocusTrap\";\nimport { onClickOutside } from \"@vueuse/core\";\nimport { Smile } from \"@lucide/vue\";\nimport { computed, ref } from \"vue\";\n\nconst emit = defineEmits<{\n (e: \"insert\", emoji: string): void;\n}>();\n\nconst {\n categories: emojiCategories,\n isOpen: showEmojiPicker,\n toggle: toggleEmojiPicker,\n close: closeEmojiPicker,\n} = useEmoji();\n\nconst { t, format } = useI18n();\n\nconst pickerRef = ref<HTMLElement | null>(null);\nconst rootRef = ref<HTMLElement | null>(null);\n\nconst isOpenRef = computed(() => showEmojiPicker.value);\nuseFocusTrap(pickerRef, isOpenRef);\n\nonClickOutside(rootRef, () => {\n if (showEmojiPicker.value) {\n closeEmojiPicker();\n }\n});\n\nfunction handleInsert(emoji: string): void {\n emit(\"insert\", emoji);\n closeEmojiPicker();\n}\n</script>\n\n<template>\n <div ref=\"rootRef\" class=\"tpl:relative\">\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': showEmojiPicker,\n }\"\n :aria-label=\"t.paragraphEditor.insertEmoji\"\n :title=\"t.paragraphEditor.insertEmoji\"\n :aria-expanded=\"showEmojiPicker\"\n aria-haspopup=\"dialog\"\n aria-controls=\"tpl-emoji-picker\"\n @click=\"toggleEmojiPicker\"\n >\n <Smile :size=\"16\" :stroke-width=\"2\" />\n </button>\n <div\n v-if=\"showEmojiPicker\"\n id=\"tpl-emoji-picker\"\n ref=\"pickerRef\"\n role=\"dialog\"\n aria-modal=\"false\"\n :aria-label=\"t.paragraphEditor.insertEmoji\"\n tabindex=\"-1\"\n class=\"tpl-emoji-picker tpl:absolute tpl:top-full tpl:left-0 tpl:z-10 tpl:mt-2 tpl:w-72 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:p-2 tpl:shadow-lg\"\n @keydown.esc.stop.prevent=\"closeEmojiPicker\"\n >\n <div\n v-for=\"category in emojiCategories\"\n :key=\"category.key\"\n class=\"tpl:mb-2 tpl:last:mb-0\"\n >\n <div\n class=\"tpl:mb-1.5 tpl:text-[10px] tpl:font-medium tpl:tracking-wide tpl:text-[var(--tpl-text-muted)] tpl:uppercase\"\n >\n {{ t.emoji[category.key] }}\n </div>\n <div class=\"tpl:grid tpl:grid-cols-10 tpl:gap-0.5\">\n <button\n v-for=\"emoji in category.emojis\"\n :key=\"emoji\"\n type=\"button\"\n :aria-label=\"format(t.paragraphEditor.emojiItemLabel, { emoji })\"\n class=\"tpl:flex tpl:size-6 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:rounded tpl:border-none tpl:bg-transparent tpl:text-base tpl:transition-all tpl:duration-100 tpl:hover:scale-125 tpl:hover:bg-[var(--tpl-bg-active)]\"\n @click=\"handleInsert(emoji)\"\n >\n {{ emoji }}\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { Component } from \"vue\";\n\ndefineProps<{\n icon: Component;\n label: string;\n active?: boolean;\n strokeWidth?: number;\n size?: number;\n}>();\n</script>\n\n<template>\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{ 'tpl-text-toolbar-btn--active': active }\"\n :aria-label=\"label\"\n :title=\"label\"\n :aria-pressed=\"active ? 'true' : 'false'\"\n >\n <component :is=\"icon\" :size=\"size ?? 16\" :stroke-width=\"strokeWidth ?? 2\" />\n </button>\n</template>\n","<script setup lang=\"ts\">\nimport type { Component } from \"vue\";\n\ndefineProps<{\n icon: Component;\n label: string;\n active?: boolean;\n strokeWidth?: number;\n size?: number;\n}>();\n</script>\n\n<template>\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{ 'tpl-text-toolbar-btn--active': active }\"\n :aria-label=\"label\"\n :title=\"label\"\n :aria-pressed=\"active ? 'true' : 'false'\"\n >\n <component :is=\"icon\" :size=\"size ?? 16\" :stroke-width=\"strokeWidth ?? 2\" />\n </button>\n</template>\n","<template>\n <span\n class=\"tpl:mx-1 tpl:h-6 tpl:w-px tpl:bg-[var(--tpl-border)]\"\n aria-hidden=\"true\"\n ></span>\n</template>\n","<script setup lang=\"ts\">\ninterface OptionItem {\n value: string;\n label: string;\n}\n\ndefineProps<{\n modelValue: string;\n options: readonly (string | OptionItem)[];\n label: string;\n placeholder?: string;\n widthClass?: string;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update:modelValue\", value: string): void;\n}>();\n\nfunction onChange(e: Event): void {\n emit(\"update:modelValue\", (e.target as HTMLSelectElement).value);\n}\n\nfunction optionValue(opt: string | OptionItem): string {\n return typeof opt === \"string\" ? opt : opt.value;\n}\n\nfunction optionLabel(opt: string | OptionItem): string {\n return typeof opt === \"string\" ? opt : opt.label;\n}\n</script>\n\n<template>\n <select\n :class=\"[\n 'tpl:h-8 tpl:cursor-pointer tpl:rounded tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text)] tpl:outline-none',\n widthClass ?? 'tpl:w-20',\n ]\"\n :value=\"modelValue\"\n :aria-label=\"label\"\n :title=\"label\"\n @change=\"onChange\"\n >\n <option value=\"\">{{ placeholder ?? \"\" }}</option>\n <option\n v-for=\"opt in options\"\n :key=\"optionValue(opt)\"\n :value=\"optionValue(opt)\"\n >\n {{ optionLabel(opt) }}\n </option>\n </select>\n</template>\n","<script setup lang=\"ts\">\ninterface OptionItem {\n value: string;\n label: string;\n}\n\ndefineProps<{\n modelValue: string;\n options: readonly (string | OptionItem)[];\n label: string;\n placeholder?: string;\n widthClass?: string;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update:modelValue\", value: string): void;\n}>();\n\nfunction onChange(e: Event): void {\n emit(\"update:modelValue\", (e.target as HTMLSelectElement).value);\n}\n\nfunction optionValue(opt: string | OptionItem): string {\n return typeof opt === \"string\" ? opt : opt.value;\n}\n\nfunction optionLabel(opt: string | OptionItem): string {\n return typeof opt === \"string\" ? opt : opt.label;\n}\n</script>\n\n<template>\n <select\n :class=\"[\n 'tpl:h-8 tpl:cursor-pointer tpl:rounded tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text)] tpl:outline-none',\n widthClass ?? 'tpl:w-20',\n ]\"\n :value=\"modelValue\"\n :aria-label=\"label\"\n :title=\"label\"\n @change=\"onChange\"\n >\n <option value=\"\">{{ placeholder ?? \"\" }}</option>\n <option\n v-for=\"opt in options\"\n :key=\"optionValue(opt)\"\n :value=\"optionValue(opt)\"\n >\n {{ optionLabel(opt) }}\n </option>\n </select>\n</template>\n","import { DEFAULT_TEXT_COLOR } from \"../constants/styleConstants\";\n\n/**\n * The color a rich-text selection actually renders as, for display in the\n * text-color control (issue #373).\n *\n * Priority: an explicit inline text-color mark on the selection wins; otherwise\n * the text inherits the document-level `textColor`; if that too is unset (older\n * content predating document text color), fall back to the built-in default.\n *\n * A native `<input type=\"color\">` can't represent \"no color\", so before this it\n * always painted a hard-coded `#000000` when no inline mark existed — which both\n * looked like an explicit choice and didn't even match the real inherited color\n * (`#1a1a1a`). Resolving the effective color keeps the swatch truthful: it shows\n * the color the text is actually rendered in, whatever level it comes from.\n */\nexport function resolveEffectiveTextColor(\n explicitColor: string,\n documentTextColor: string | undefined,\n): string {\n return explicitColor || documentTextColor || DEFAULT_TEXT_COLOR;\n}\n","<script setup lang=\"ts\">\nimport ColorPicker from \"../ColorPicker.vue\";\nimport EmojiPickerDropdown from \"./EmojiPickerDropdown.vue\";\nimport ToolbarIconButton from \"../toolbar/ToolbarIconButton.vue\";\nimport ToolbarSeparator from \"../toolbar/ToolbarSeparator.vue\";\nimport ToolbarSelect from \"../toolbar/ToolbarSelect.vue\";\nimport { useI18n } from \"../../composables\";\nimport { usePopoverRoot } from \"../../composables/usePopoverRoot\";\nimport type { Editor } from \"@tiptap/core\";\nimport {\n AlignCenter,\n AlignLeft,\n AlignRight,\n Bold,\n Italic,\n Braces,\n Link,\n List,\n ListOrdered,\n LoaderCircle,\n RemoveFormatting,\n ScanLine,\n Strikethrough,\n Subscript,\n Superscript,\n Underline,\n} from \"@lucide/vue\";\nimport { computed, inject } from \"vue\";\nimport {\n EDITOR_KEY,\n THEME_STYLES_KEY,\n UI_THEME_KEY,\n FONTS_MANAGER_KEY,\n MERGE_TAG_PICKER_KEY,\n LOGIC_TAG_PICKER_KEY,\n requireInject,\n} from \"../../keys\";\nimport {\n DEFAULT_HIGHLIGHT_COLOR,\n FONT_SIZE_OPTIONS,\n LINE_HEIGHT_OPTIONS,\n LETTER_SPACING_OPTIONS,\n} from \"../../constants/styleConstants\";\nimport { resolveEffectiveTextColor } from \"../../utils/richTextColor\";\n\nconst props = defineProps<{\n editor: Editor | null;\n toolbarPosition: { top: number; left: number };\n isLoading: boolean;\n canRequestMergeTag: boolean;\n canInsertLogicTag: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"open-link-dialog\"): void;\n (e: \"add-merge-tag\"): void;\n (e: \"add-logic-tag\"): void;\n}>();\n\nconst themeStyles = inject(THEME_STYLES_KEY, null);\nconst tplUiTheme = inject(UI_THEME_KEY, null);\nconst fontsManager = requireInject(FONTS_MANAGER_KEY, \"ParagraphToolbar\");\nconst popoverRoot = usePopoverRoot();\n// Picker may be null in non-editor contexts (e.g. isolated component tests).\n// When it's provided AND open, hide the floating toolbar — leaving it\n// visible behind the modal is visually noisy and the toolbar's Tailwind\n// z-index utility doesn't compile reliably, so it can sometimes paint\n// over the modal backdrop.\nconst picker = inject(MERGE_TAG_PICKER_KEY, null);\nconst logicPicker = inject(LOGIC_TAG_PICKER_KEY, null);\n// Editor may be absent in isolated tests; used only to resolve the inherited\n// document text color for the text-color swatch.\nconst editorReturn = inject(EDITOR_KEY, null);\n// Hide the floating toolbar while either built-in picker modal is open, so it\n// doesn't overlap the dialog.\nconst pickerIsOpen = computed(\n () => (picker?.isOpen.value ?? false) || (logicPicker?.isOpen.value ?? false),\n);\n\nconst { t } = useI18n();\n\nconst fontFamilies = fontsManager.fonts;\n\nfunction insertEmoji(emoji: string): void {\n props.editor?.chain().focus().insertContent(emoji).run();\n}\n\nfunction textStyleAttr(attr: string): string {\n return (props.editor?.getAttributes(\"textStyle\")[attr] as string) || \"\";\n}\n\nfunction setFontFamily(family: string): void {\n const chain = props.editor?.chain().focus();\n if (family) chain?.setFontFamily(family).run();\n else chain?.unsetFontFamily().run();\n}\n\nfunction setFontSize(size: string): void {\n const chain = props.editor?.chain().focus();\n if (size) chain?.setFontSize(size).run();\n else chain?.unsetFontSize().run();\n}\n\n// When the selection is a link, the color control operates on the link itself\n// (its `color` attribute → inline on the `<a>`) so the link's text and underline\n// stay in sync; otherwise it applies a plain inline text-color mark.\nfunction isLinkSelection(): boolean {\n return props.editor?.isActive(\"link\") ?? false;\n}\n\nfunction linkColorAttr(): string {\n return (props.editor?.getAttributes(\"link\").color as string) || \"\";\n}\n\n// Set (or clear, when empty) the color of the current selection. On a link the\n// whole link is recolored (extendMarkRange) so it doesn't split into segments.\nfunction setColor(color: string): void {\n const chain = props.editor?.chain().focus();\n if (!chain) return;\n if (isLinkSelection()) {\n chain.extendMarkRange(\"link\").updateAttributes(\"link\", {\n color: color || null,\n });\n // A per-link color takes absolute priority over any inner text-color: strip\n // the inline text color on the link range so the `<a>` color alone drives\n // the glyphs and the underline (mirrors useRichTextLinkDialog.insertLink).\n // Only when setting a color — clearing leaves the text color untouched.\n if (color) chain.unsetColor();\n chain.run();\n } else if (color) {\n // A text color applied over a selection that includes a link unifies the\n // link with it: update the link's own color so the `<a>` (which paints the\n // underline and is what the dialog/toolbar read) matches the recolored\n // glyphs. A no-op on a selection with no link. Mirror of the link branch\n // above — either way a link never ends up with a text color fighting its\n // own color.\n chain.setColor(color).updateAttributes(\"link\", { color }).run();\n } else {\n chain.unsetColor().run();\n }\n}\n\n// The color the current selection actually renders in — a link's own color (else\n// the effective document link color: link color, then text color), or for plain\n// text the inline mark else the document text color. Keeps the swatch truthful\n// rather than showing a hard-coded default (issue #373 / per-link color).\nfunction effectiveTextColor(): string {\n const settings = editorReturn?.content.value.settings;\n if (isLinkSelection()) {\n return resolveEffectiveTextColor(\n linkColorAttr(),\n settings?.linkColor || settings?.textColor,\n );\n }\n return resolveEffectiveTextColor(textStyleAttr(\"color\"), settings?.textColor);\n}\n\n// The selection's own explicit color: a link's color when on a link, else the\n// inline text-color mark. May be \"\" when the selection only inherits its color\n// — that drives the swatch's set/unset state, while `effectiveTextColor()`\n// seeds the wheel so it still opens on the real rendered color.\nfunction explicitTextColor(): string {\n return isLinkSelection() ? linkColorAttr() : textStyleAttr(\"color\");\n}\n\nfunction getCurrentLineHeight(): string {\n return (props.editor?.getAttributes(\"paragraph\").lineHeight as string) || \"\";\n}\n\nfunction setLineHeight(value: string): void {\n const chain = props.editor?.chain().focus();\n if (value) chain?.setLineHeight(value).run();\n else chain?.unsetLineHeight().run();\n}\n\nfunction setLetterSpacing(value: string): void {\n const chain = props.editor?.chain().focus();\n if (value && value !== \"normal\") chain?.setLetterSpacing(value).run();\n else chain?.unsetLetterSpacing().run();\n}\n\nfunction getCurrentHighlight(): string {\n return (props.editor?.getAttributes(\"highlight\").color as string) || \"\";\n}\n\nfunction setHighlight(color: string): void {\n const chain = props.editor?.chain().focus();\n if (color) chain?.setHighlight({ color }).run();\n else chain?.unsetHighlight().run();\n}\n</script>\n\n<template>\n <Teleport v-if=\"popoverRoot && !pickerIsOpen\" :to=\"popoverRoot\">\n <div\n :data-tpl-theme=\"tplUiTheme\"\n role=\"toolbar\"\n :aria-label=\"t.paragraphEditor.toolbar\"\n class=\"tpl tpl-text-toolbar tpl:fixed tpl:z-popover tpl:flex tpl:gap-1 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-3 tpl:py-2 tpl:shadow-lg\"\n :style=\"{\n ...themeStyles,\n top: `${toolbarPosition.top}px`,\n left: `${toolbarPosition.left}px`,\n transform: 'translateY(-100%)',\n flexDirection: 'column',\n }\"\n >\n <template v-if=\"!isLoading && editor\">\n <!-- Row 1: Font family, Font size, Text color, Bold/Italic/Underline/Strikethrough -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <ToolbarSelect\n :model-value=\"textStyleAttr('fontFamily')\"\n :options=\"fontFamilies\"\n :label=\"t.paragraphEditor.fontFamily\"\n :placeholder=\"t.paragraphEditor.defaultFont\"\n width-class=\"tpl:w-32\"\n @update:model-value=\"setFontFamily\"\n />\n <ToolbarSelect\n :model-value=\"textStyleAttr('fontSize')\"\n :options=\"FONT_SIZE_OPTIONS\"\n :label=\"t.paragraphEditor.fontSize\"\n :placeholder=\"t.paragraphEditor.defaultSize\"\n width-class=\"tpl:w-20\"\n @update:model-value=\"setFontSize\"\n />\n <ToolbarSeparator />\n <ColorPicker\n swatch-only\n size=\"sm\"\n data-testid=\"text-color-picker\"\n :model-value=\"explicitTextColor()\"\n :seed-color=\"effectiveTextColor()\"\n :aria-label=\"t.paragraphEditor.textColor\"\n @update:model-value=\"setColor\"\n />\n <ColorPicker\n swatch-only\n size=\"sm\"\n data-testid=\"highlight-color-picker\"\n :model-value=\"getCurrentHighlight()\"\n :seed-color=\"DEFAULT_HIGHLIGHT_COLOR\"\n :aria-label=\"t.paragraphEditor.highlightColor\"\n @update:model-value=\"setHighlight\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Bold\"\n :label=\"t.paragraphEditor.bold\"\n :active=\"editor.isActive('bold')\"\n :stroke-width=\"2.5\"\n @click=\"editor.chain().focus().toggleBold().run()\"\n />\n <ToolbarIconButton\n :icon=\"Italic\"\n :label=\"t.paragraphEditor.italic\"\n :active=\"editor.isActive('italic')\"\n @click=\"editor.chain().focus().toggleItalic().run()\"\n />\n <ToolbarIconButton\n :icon=\"Underline\"\n :label=\"t.paragraphEditor.underline\"\n :active=\"editor.isActive('underline')\"\n @click=\"editor.chain().focus().toggleUnderline().run()\"\n />\n <ToolbarIconButton\n :icon=\"Strikethrough\"\n :label=\"t.paragraphEditor.strikethrough\"\n :active=\"editor.isActive('strike')\"\n @click=\"editor.chain().focus().toggleStrike().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Subscript\"\n :label=\"t.paragraphEditor.subscript\"\n :active=\"editor.isActive('subscript')\"\n @click=\"editor.chain().focus().toggleSubscript().run()\"\n />\n <ToolbarIconButton\n :icon=\"Superscript\"\n :label=\"t.paragraphEditor.superscript\"\n :active=\"editor.isActive('superscript')\"\n @click=\"editor.chain().focus().toggleSuperscript().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Link\"\n :label=\"t.paragraphEditor.addLink\"\n :active=\"editor.isActive('link')\"\n @click=\"emit('open-link-dialog')\"\n />\n </div>\n <!-- Row 2: Lists, Alignment, LH, LS, Clear, Emoji, Merge tags -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <ToolbarIconButton\n :icon=\"List\"\n :label=\"t.paragraphEditor.bulletList\"\n :active=\"editor.isActive('bulletList')\"\n @click=\"editor.chain().focus().toggleBulletList().run()\"\n />\n <ToolbarIconButton\n :icon=\"ListOrdered\"\n :label=\"t.paragraphEditor.numberedList\"\n :active=\"editor.isActive('orderedList')\"\n @click=\"editor.chain().focus().toggleOrderedList().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"AlignLeft\"\n :label=\"t.paragraphEditor.alignLeft\"\n :active=\"editor.isActive({ textAlign: 'left' })\"\n @click=\"editor.chain().focus().setTextAlign('left').run()\"\n />\n <ToolbarIconButton\n :icon=\"AlignCenter\"\n :label=\"t.paragraphEditor.alignCenter\"\n :active=\"editor.isActive({ textAlign: 'center' })\"\n @click=\"editor.chain().focus().setTextAlign('center').run()\"\n />\n <ToolbarIconButton\n :icon=\"AlignRight\"\n :label=\"t.paragraphEditor.alignRight\"\n :active=\"editor.isActive({ textAlign: 'right' })\"\n @click=\"editor.chain().focus().setTextAlign('right').run()\"\n />\n <ToolbarSeparator />\n <ToolbarSelect\n :model-value=\"getCurrentLineHeight()\"\n :options=\"LINE_HEIGHT_OPTIONS\"\n :label=\"t.paragraphEditor.lineHeight\"\n placeholder=\"LH\"\n width-class=\"tpl:w-16\"\n @update:model-value=\"setLineHeight\"\n />\n <ToolbarSelect\n :model-value=\"textStyleAttr('letterSpacing')\"\n :options=\"LETTER_SPACING_OPTIONS\"\n :label=\"t.paragraphEditor.letterSpacing\"\n placeholder=\"LS\"\n width-class=\"tpl:w-20\"\n @update:model-value=\"setLetterSpacing\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"RemoveFormatting\"\n :label=\"t.paragraphEditor.clearFormatting\"\n @click=\"editor.chain().focus().clearNodes().unsetAllMarks().run()\"\n />\n <ToolbarSeparator />\n <EmojiPickerDropdown @insert=\"insertEmoji\" />\n <template v-if=\"canRequestMergeTag\">\n <ToolbarSeparator />\n <button\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.mergeTag.insert\"\n :title=\"t.mergeTag.insert\"\n @click=\"emit('add-merge-tag')\"\n >\n <ScanLine :size=\"16\" :stroke-width=\"2\" />\n {{ t.mergeTag.insertShort }}\n </button>\n </template>\n <template v-if=\"canInsertLogicTag\">\n <ToolbarSeparator />\n <button\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.logicTag.insert\"\n :title=\"t.logicTag.insert\"\n data-testid=\"insert-logic-button\"\n @click=\"emit('add-logic-tag')\"\n >\n <Braces :size=\"16\" :stroke-width=\"2\" />\n {{ t.logicTag.insertShort }}\n </button>\n </template>\n </div>\n </template>\n <template v-else>\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n <LoaderCircle class=\"tpl-spinner\" :size=\"14\" :stroke-width=\"2\" />\n {{ t.errors.editorLoading }}\n </div>\n </template>\n </div>\n </Teleport>\n</template>\n","<script setup lang=\"ts\">\nimport ColorPicker from \"../ColorPicker.vue\";\nimport EmojiPickerDropdown from \"./EmojiPickerDropdown.vue\";\nimport ToolbarIconButton from \"../toolbar/ToolbarIconButton.vue\";\nimport ToolbarSeparator from \"../toolbar/ToolbarSeparator.vue\";\nimport ToolbarSelect from \"../toolbar/ToolbarSelect.vue\";\nimport { useI18n } from \"../../composables\";\nimport { usePopoverRoot } from \"../../composables/usePopoverRoot\";\nimport type { Editor } from \"@tiptap/core\";\nimport {\n AlignCenter,\n AlignLeft,\n AlignRight,\n Bold,\n Italic,\n Braces,\n Link,\n List,\n ListOrdered,\n LoaderCircle,\n RemoveFormatting,\n ScanLine,\n Strikethrough,\n Subscript,\n Superscript,\n Underline,\n} from \"@lucide/vue\";\nimport { computed, inject } from \"vue\";\nimport {\n EDITOR_KEY,\n THEME_STYLES_KEY,\n UI_THEME_KEY,\n FONTS_MANAGER_KEY,\n MERGE_TAG_PICKER_KEY,\n LOGIC_TAG_PICKER_KEY,\n requireInject,\n} from \"../../keys\";\nimport {\n DEFAULT_HIGHLIGHT_COLOR,\n FONT_SIZE_OPTIONS,\n LINE_HEIGHT_OPTIONS,\n LETTER_SPACING_OPTIONS,\n} from \"../../constants/styleConstants\";\nimport { resolveEffectiveTextColor } from \"../../utils/richTextColor\";\n\nconst props = defineProps<{\n editor: Editor | null;\n toolbarPosition: { top: number; left: number };\n isLoading: boolean;\n canRequestMergeTag: boolean;\n canInsertLogicTag: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"open-link-dialog\"): void;\n (e: \"add-merge-tag\"): void;\n (e: \"add-logic-tag\"): void;\n}>();\n\nconst themeStyles = inject(THEME_STYLES_KEY, null);\nconst tplUiTheme = inject(UI_THEME_KEY, null);\nconst fontsManager = requireInject(FONTS_MANAGER_KEY, \"ParagraphToolbar\");\nconst popoverRoot = usePopoverRoot();\n// Picker may be null in non-editor contexts (e.g. isolated component tests).\n// When it's provided AND open, hide the floating toolbar — leaving it\n// visible behind the modal is visually noisy and the toolbar's Tailwind\n// z-index utility doesn't compile reliably, so it can sometimes paint\n// over the modal backdrop.\nconst picker = inject(MERGE_TAG_PICKER_KEY, null);\nconst logicPicker = inject(LOGIC_TAG_PICKER_KEY, null);\n// Editor may be absent in isolated tests; used only to resolve the inherited\n// document text color for the text-color swatch.\nconst editorReturn = inject(EDITOR_KEY, null);\n// Hide the floating toolbar while either built-in picker modal is open, so it\n// doesn't overlap the dialog.\nconst pickerIsOpen = computed(\n () => (picker?.isOpen.value ?? false) || (logicPicker?.isOpen.value ?? false),\n);\n\nconst { t } = useI18n();\n\nconst fontFamilies = fontsManager.fonts;\n\nfunction insertEmoji(emoji: string): void {\n props.editor?.chain().focus().insertContent(emoji).run();\n}\n\nfunction textStyleAttr(attr: string): string {\n return (props.editor?.getAttributes(\"textStyle\")[attr] as string) || \"\";\n}\n\nfunction setFontFamily(family: string): void {\n const chain = props.editor?.chain().focus();\n if (family) chain?.setFontFamily(family).run();\n else chain?.unsetFontFamily().run();\n}\n\nfunction setFontSize(size: string): void {\n const chain = props.editor?.chain().focus();\n if (size) chain?.setFontSize(size).run();\n else chain?.unsetFontSize().run();\n}\n\n// When the selection is a link, the color control operates on the link itself\n// (its `color` attribute → inline on the `<a>`) so the link's text and underline\n// stay in sync; otherwise it applies a plain inline text-color mark.\nfunction isLinkSelection(): boolean {\n return props.editor?.isActive(\"link\") ?? false;\n}\n\nfunction linkColorAttr(): string {\n return (props.editor?.getAttributes(\"link\").color as string) || \"\";\n}\n\n// Set (or clear, when empty) the color of the current selection. On a link the\n// whole link is recolored (extendMarkRange) so it doesn't split into segments.\nfunction setColor(color: string): void {\n const chain = props.editor?.chain().focus();\n if (!chain) return;\n if (isLinkSelection()) {\n chain.extendMarkRange(\"link\").updateAttributes(\"link\", {\n color: color || null,\n });\n // A per-link color takes absolute priority over any inner text-color: strip\n // the inline text color on the link range so the `<a>` color alone drives\n // the glyphs and the underline (mirrors useRichTextLinkDialog.insertLink).\n // Only when setting a color — clearing leaves the text color untouched.\n if (color) chain.unsetColor();\n chain.run();\n } else if (color) {\n // A text color applied over a selection that includes a link unifies the\n // link with it: update the link's own color so the `<a>` (which paints the\n // underline and is what the dialog/toolbar read) matches the recolored\n // glyphs. A no-op on a selection with no link. Mirror of the link branch\n // above — either way a link never ends up with a text color fighting its\n // own color.\n chain.setColor(color).updateAttributes(\"link\", { color }).run();\n } else {\n chain.unsetColor().run();\n }\n}\n\n// The color the current selection actually renders in — a link's own color (else\n// the effective document link color: link color, then text color), or for plain\n// text the inline mark else the document text color. Keeps the swatch truthful\n// rather than showing a hard-coded default (issue #373 / per-link color).\nfunction effectiveTextColor(): string {\n const settings = editorReturn?.content.value.settings;\n if (isLinkSelection()) {\n return resolveEffectiveTextColor(\n linkColorAttr(),\n settings?.linkColor || settings?.textColor,\n );\n }\n return resolveEffectiveTextColor(textStyleAttr(\"color\"), settings?.textColor);\n}\n\n// The selection's own explicit color: a link's color when on a link, else the\n// inline text-color mark. May be \"\" when the selection only inherits its color\n// — that drives the swatch's set/unset state, while `effectiveTextColor()`\n// seeds the wheel so it still opens on the real rendered color.\nfunction explicitTextColor(): string {\n return isLinkSelection() ? linkColorAttr() : textStyleAttr(\"color\");\n}\n\nfunction getCurrentLineHeight(): string {\n return (props.editor?.getAttributes(\"paragraph\").lineHeight as string) || \"\";\n}\n\nfunction setLineHeight(value: string): void {\n const chain = props.editor?.chain().focus();\n if (value) chain?.setLineHeight(value).run();\n else chain?.unsetLineHeight().run();\n}\n\nfunction setLetterSpacing(value: string): void {\n const chain = props.editor?.chain().focus();\n if (value && value !== \"normal\") chain?.setLetterSpacing(value).run();\n else chain?.unsetLetterSpacing().run();\n}\n\nfunction getCurrentHighlight(): string {\n return (props.editor?.getAttributes(\"highlight\").color as string) || \"\";\n}\n\nfunction setHighlight(color: string): void {\n const chain = props.editor?.chain().focus();\n if (color) chain?.setHighlight({ color }).run();\n else chain?.unsetHighlight().run();\n}\n</script>\n\n<template>\n <Teleport v-if=\"popoverRoot && !pickerIsOpen\" :to=\"popoverRoot\">\n <div\n :data-tpl-theme=\"tplUiTheme\"\n role=\"toolbar\"\n :aria-label=\"t.paragraphEditor.toolbar\"\n class=\"tpl tpl-text-toolbar tpl:fixed tpl:z-popover tpl:flex tpl:gap-1 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-3 tpl:py-2 tpl:shadow-lg\"\n :style=\"{\n ...themeStyles,\n top: `${toolbarPosition.top}px`,\n left: `${toolbarPosition.left}px`,\n transform: 'translateY(-100%)',\n flexDirection: 'column',\n }\"\n >\n <template v-if=\"!isLoading && editor\">\n <!-- Row 1: Font family, Font size, Text color, Bold/Italic/Underline/Strikethrough -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <ToolbarSelect\n :model-value=\"textStyleAttr('fontFamily')\"\n :options=\"fontFamilies\"\n :label=\"t.paragraphEditor.fontFamily\"\n :placeholder=\"t.paragraphEditor.defaultFont\"\n width-class=\"tpl:w-32\"\n @update:model-value=\"setFontFamily\"\n />\n <ToolbarSelect\n :model-value=\"textStyleAttr('fontSize')\"\n :options=\"FONT_SIZE_OPTIONS\"\n :label=\"t.paragraphEditor.fontSize\"\n :placeholder=\"t.paragraphEditor.defaultSize\"\n width-class=\"tpl:w-20\"\n @update:model-value=\"setFontSize\"\n />\n <ToolbarSeparator />\n <ColorPicker\n swatch-only\n size=\"sm\"\n data-testid=\"text-color-picker\"\n :model-value=\"explicitTextColor()\"\n :seed-color=\"effectiveTextColor()\"\n :aria-label=\"t.paragraphEditor.textColor\"\n @update:model-value=\"setColor\"\n />\n <ColorPicker\n swatch-only\n size=\"sm\"\n data-testid=\"highlight-color-picker\"\n :model-value=\"getCurrentHighlight()\"\n :seed-color=\"DEFAULT_HIGHLIGHT_COLOR\"\n :aria-label=\"t.paragraphEditor.highlightColor\"\n @update:model-value=\"setHighlight\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Bold\"\n :label=\"t.paragraphEditor.bold\"\n :active=\"editor.isActive('bold')\"\n :stroke-width=\"2.5\"\n @click=\"editor.chain().focus().toggleBold().run()\"\n />\n <ToolbarIconButton\n :icon=\"Italic\"\n :label=\"t.paragraphEditor.italic\"\n :active=\"editor.isActive('italic')\"\n @click=\"editor.chain().focus().toggleItalic().run()\"\n />\n <ToolbarIconButton\n :icon=\"Underline\"\n :label=\"t.paragraphEditor.underline\"\n :active=\"editor.isActive('underline')\"\n @click=\"editor.chain().focus().toggleUnderline().run()\"\n />\n <ToolbarIconButton\n :icon=\"Strikethrough\"\n :label=\"t.paragraphEditor.strikethrough\"\n :active=\"editor.isActive('strike')\"\n @click=\"editor.chain().focus().toggleStrike().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Subscript\"\n :label=\"t.paragraphEditor.subscript\"\n :active=\"editor.isActive('subscript')\"\n @click=\"editor.chain().focus().toggleSubscript().run()\"\n />\n <ToolbarIconButton\n :icon=\"Superscript\"\n :label=\"t.paragraphEditor.superscript\"\n :active=\"editor.isActive('superscript')\"\n @click=\"editor.chain().focus().toggleSuperscript().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"Link\"\n :label=\"t.paragraphEditor.addLink\"\n :active=\"editor.isActive('link')\"\n @click=\"emit('open-link-dialog')\"\n />\n </div>\n <!-- Row 2: Lists, Alignment, LH, LS, Clear, Emoji, Merge tags -->\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <ToolbarIconButton\n :icon=\"List\"\n :label=\"t.paragraphEditor.bulletList\"\n :active=\"editor.isActive('bulletList')\"\n @click=\"editor.chain().focus().toggleBulletList().run()\"\n />\n <ToolbarIconButton\n :icon=\"ListOrdered\"\n :label=\"t.paragraphEditor.numberedList\"\n :active=\"editor.isActive('orderedList')\"\n @click=\"editor.chain().focus().toggleOrderedList().run()\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"AlignLeft\"\n :label=\"t.paragraphEditor.alignLeft\"\n :active=\"editor.isActive({ textAlign: 'left' })\"\n @click=\"editor.chain().focus().setTextAlign('left').run()\"\n />\n <ToolbarIconButton\n :icon=\"AlignCenter\"\n :label=\"t.paragraphEditor.alignCenter\"\n :active=\"editor.isActive({ textAlign: 'center' })\"\n @click=\"editor.chain().focus().setTextAlign('center').run()\"\n />\n <ToolbarIconButton\n :icon=\"AlignRight\"\n :label=\"t.paragraphEditor.alignRight\"\n :active=\"editor.isActive({ textAlign: 'right' })\"\n @click=\"editor.chain().focus().setTextAlign('right').run()\"\n />\n <ToolbarSeparator />\n <ToolbarSelect\n :model-value=\"getCurrentLineHeight()\"\n :options=\"LINE_HEIGHT_OPTIONS\"\n :label=\"t.paragraphEditor.lineHeight\"\n placeholder=\"LH\"\n width-class=\"tpl:w-16\"\n @update:model-value=\"setLineHeight\"\n />\n <ToolbarSelect\n :model-value=\"textStyleAttr('letterSpacing')\"\n :options=\"LETTER_SPACING_OPTIONS\"\n :label=\"t.paragraphEditor.letterSpacing\"\n placeholder=\"LS\"\n width-class=\"tpl:w-20\"\n @update:model-value=\"setLetterSpacing\"\n />\n <ToolbarSeparator />\n <ToolbarIconButton\n :icon=\"RemoveFormatting\"\n :label=\"t.paragraphEditor.clearFormatting\"\n @click=\"editor.chain().focus().clearNodes().unsetAllMarks().run()\"\n />\n <ToolbarSeparator />\n <EmojiPickerDropdown @insert=\"insertEmoji\" />\n <template v-if=\"canRequestMergeTag\">\n <ToolbarSeparator />\n <button\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.mergeTag.insert\"\n :title=\"t.mergeTag.insert\"\n @click=\"emit('add-merge-tag')\"\n >\n <ScanLine :size=\"16\" :stroke-width=\"2\" />\n {{ t.mergeTag.insertShort }}\n </button>\n </template>\n <template v-if=\"canInsertLogicTag\">\n <ToolbarSeparator />\n <button\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.logicTag.insert\"\n :title=\"t.logicTag.insert\"\n data-testid=\"insert-logic-button\"\n @click=\"emit('add-logic-tag')\"\n >\n <Braces :size=\"16\" :stroke-width=\"2\" />\n {{ t.logicTag.insertShort }}\n </button>\n </template>\n </div>\n </template>\n <template v-else>\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n <LoaderCircle class=\"tpl-spinner\" :size=\"14\" :stroke-width=\"2\" />\n {{ t.errors.editorLoading }}\n </div>\n </template>\n </div>\n </Teleport>\n</template>\n","<script setup lang=\"ts\">\nimport { useRichTextEditor } from \"../../composables/useRichTextEditor\";\nimport { usePopoverRoot } from \"../../composables/usePopoverRoot\";\nimport type { ParagraphBlock as ParagraphBlockType } from \"@templatical/types\";\nimport ParagraphToolbar from \"./ParagraphToolbar.vue\";\nimport RichTextLinkDialog from \"./RichTextLinkDialog.vue\";\nimport RichTextEditorContent from \"./RichTextEditorContent.vue\";\nimport { withLinkColor } from \"../../utils/linkColorExtension\";\n\nconst props = defineProps<{\n block: ParagraphBlockType;\n toolbarPosition: { top: number; left: number };\n}>();\n\nconst emit = defineEmits<{\n (e: \"done\"): void;\n}>();\n\nconst popoverRoot = usePopoverRoot();\n\nconst {\n editor,\n EditorContent,\n isLoading,\n initError,\n retry,\n showLinkDialog,\n linkUrl,\n linkColor,\n linkDialogRef,\n canRequestMergeTag,\n canInsertLogicTag,\n openLinkDialog,\n insertLink,\n removeLink,\n closeLinkDialog,\n handleLinkKeydown,\n handleAddMergeTag,\n handleAddLogicTag,\n} = useRichTextEditor({\n blockId: () => props.block.id,\n blockContent: () => props.block.content,\n onDone: () => emit(\"done\"),\n editorName: \"ParagraphEditor\",\n async loadExtensions({\n mergeTags,\n syntax,\n triggerChar,\n autocompleteEnabled,\n suggestionEmptyText,\n }) {\n const [\n { Editor: TiptapEditor, EditorContent: EC },\n { default: StarterKit },\n { default: LinkExt },\n { default: UnderlineExt },\n { default: SubscriptExt },\n { default: SuperscriptExt },\n { default: TextAlign },\n { TextStyle },\n { default: Color },\n { default: FontFamily },\n { default: Highlight },\n {\n MergeTagNode,\n MergeTagSuggestion,\n LogicMergeTagNode,\n FontSize,\n LineHeight,\n LetterSpacing,\n },\n ] = await Promise.all([\n import(\"@tiptap/vue-3\"),\n import(\"@tiptap/starter-kit\"),\n import(\"@tiptap/extension-link\"),\n import(\"@tiptap/extension-underline\"),\n import(\"@tiptap/extension-subscript\"),\n import(\"@tiptap/extension-superscript\"),\n import(\"@tiptap/extension-text-align\"),\n import(\"@tiptap/extension-text-style\"),\n import(\"@tiptap/extension-color\"),\n import(\"@tiptap/extension-font-family\"),\n import(\"@tiptap/extension-highlight\"),\n import(\"../../extensions\"),\n ]);\n\n return {\n TiptapEditor,\n EC,\n extensions: [\n StarterKit.configure({\n heading: false,\n codeBlock: false,\n blockquote: false,\n horizontalRule: false,\n // StarterKit bundles @tiptap/extension-link (openOnClick: true).\n // Disable it so the LinkExt below (openOnClick: false) is the only\n // link extension — otherwise clicking a link while editing opens it.\n link: false,\n // StarterKit also bundles @tiptap/extension-underline; the editor\n // registers its own UnderlineExt below, so disable StarterKit's copy\n // to avoid a duplicate `underline` extension (and its console warning).\n underline: false,\n }),\n UnderlineExt,\n SubscriptExt,\n SuperscriptExt,\n withLinkColor(LinkExt).configure({\n openOnClick: false,\n HTMLAttributes: {\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n }),\n TextAlign.configure({ types: [\"paragraph\"] }),\n TextStyle,\n Color,\n FontFamily,\n Highlight.configure({ multicolor: true }),\n FontSize,\n LineHeight,\n LetterSpacing,\n MergeTagNode.configure({ mergeTags, syntax }),\n LogicMergeTagNode.configure({ syntax }),\n ...(autocompleteEnabled && triggerChar && mergeTags.length > 0\n ? [\n MergeTagSuggestion.configure({\n mergeTags,\n char: triggerChar,\n emptyText: suggestionEmptyText,\n popoverRoot,\n }),\n ]\n : []),\n ],\n };\n },\n});\n</script>\n\n<template>\n <div class=\"tpl-text-editor-wrapper tpl:relative\">\n <ParagraphToolbar\n :editor=\"editor\"\n :toolbar-position=\"toolbarPosition\"\n :is-loading=\"isLoading\"\n :can-request-merge-tag=\"canRequestMergeTag\"\n :can-insert-logic-tag=\"canInsertLogicTag\"\n @open-link-dialog=\"openLinkDialog\"\n @add-merge-tag=\"handleAddMergeTag\"\n @add-logic-tag=\"handleAddLogicTag\"\n />\n\n <RichTextEditorContent\n :editor=\"editor\"\n :editor-content=\"EditorContent\"\n :is-loading=\"isLoading\"\n :init-error=\"initError\"\n @retry=\"retry\"\n />\n\n <RichTextLinkDialog\n :visible=\"showLinkDialog\"\n :is-editing-link=\"editor?.isActive('link') ?? false\"\n v-model:dialog-ref=\"linkDialogRef\"\n v-model:link-url=\"linkUrl\"\n v-model:link-color=\"linkColor\"\n @close=\"closeLinkDialog\"\n @insert=\"insertLink\"\n @remove=\"removeLink\"\n @keydown=\"handleLinkKeydown\"\n />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { useRichTextEditor } from \"../../composables/useRichTextEditor\";\nimport { usePopoverRoot } from \"../../composables/usePopoverRoot\";\nimport type { ParagraphBlock as ParagraphBlockType } from \"@templatical/types\";\nimport ParagraphToolbar from \"./ParagraphToolbar.vue\";\nimport RichTextLinkDialog from \"./RichTextLinkDialog.vue\";\nimport RichTextEditorContent from \"./RichTextEditorContent.vue\";\nimport { withLinkColor } from \"../../utils/linkColorExtension\";\n\nconst props = defineProps<{\n block: ParagraphBlockType;\n toolbarPosition: { top: number; left: number };\n}>();\n\nconst emit = defineEmits<{\n (e: \"done\"): void;\n}>();\n\nconst popoverRoot = usePopoverRoot();\n\nconst {\n editor,\n EditorContent,\n isLoading,\n initError,\n retry,\n showLinkDialog,\n linkUrl,\n linkColor,\n linkDialogRef,\n canRequestMergeTag,\n canInsertLogicTag,\n openLinkDialog,\n insertLink,\n removeLink,\n closeLinkDialog,\n handleLinkKeydown,\n handleAddMergeTag,\n handleAddLogicTag,\n} = useRichTextEditor({\n blockId: () => props.block.id,\n blockContent: () => props.block.content,\n onDone: () => emit(\"done\"),\n editorName: \"ParagraphEditor\",\n async loadExtensions({\n mergeTags,\n syntax,\n triggerChar,\n autocompleteEnabled,\n suggestionEmptyText,\n }) {\n const [\n { Editor: TiptapEditor, EditorContent: EC },\n { default: StarterKit },\n { default: LinkExt },\n { default: UnderlineExt },\n { default: SubscriptExt },\n { default: SuperscriptExt },\n { default: TextAlign },\n { TextStyle },\n { default: Color },\n { default: FontFamily },\n { default: Highlight },\n {\n MergeTagNode,\n MergeTagSuggestion,\n LogicMergeTagNode,\n FontSize,\n LineHeight,\n LetterSpacing,\n },\n ] = await Promise.all([\n import(\"@tiptap/vue-3\"),\n import(\"@tiptap/starter-kit\"),\n import(\"@tiptap/extension-link\"),\n import(\"@tiptap/extension-underline\"),\n import(\"@tiptap/extension-subscript\"),\n import(\"@tiptap/extension-superscript\"),\n import(\"@tiptap/extension-text-align\"),\n import(\"@tiptap/extension-text-style\"),\n import(\"@tiptap/extension-color\"),\n import(\"@tiptap/extension-font-family\"),\n import(\"@tiptap/extension-highlight\"),\n import(\"../../extensions\"),\n ]);\n\n return {\n TiptapEditor,\n EC,\n extensions: [\n StarterKit.configure({\n heading: false,\n codeBlock: false,\n blockquote: false,\n horizontalRule: false,\n // StarterKit bundles @tiptap/extension-link (openOnClick: true).\n // Disable it so the LinkExt below (openOnClick: false) is the only\n // link extension — otherwise clicking a link while editing opens it.\n link: false,\n // StarterKit also bundles @tiptap/extension-underline; the editor\n // registers its own UnderlineExt below, so disable StarterKit's copy\n // to avoid a duplicate `underline` extension (and its console warning).\n underline: false,\n }),\n UnderlineExt,\n SubscriptExt,\n SuperscriptExt,\n withLinkColor(LinkExt).configure({\n openOnClick: false,\n HTMLAttributes: {\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n }),\n TextAlign.configure({ types: [\"paragraph\"] }),\n TextStyle,\n Color,\n FontFamily,\n Highlight.configure({ multicolor: true }),\n FontSize,\n LineHeight,\n LetterSpacing,\n MergeTagNode.configure({ mergeTags, syntax }),\n LogicMergeTagNode.configure({ syntax }),\n ...(autocompleteEnabled && triggerChar && mergeTags.length > 0\n ? [\n MergeTagSuggestion.configure({\n mergeTags,\n char: triggerChar,\n emptyText: suggestionEmptyText,\n popoverRoot,\n }),\n ]\n : []),\n ],\n };\n },\n});\n</script>\n\n<template>\n <div class=\"tpl-text-editor-wrapper tpl:relative\">\n <ParagraphToolbar\n :editor=\"editor\"\n :toolbar-position=\"toolbarPosition\"\n :is-loading=\"isLoading\"\n :can-request-merge-tag=\"canRequestMergeTag\"\n :can-insert-logic-tag=\"canInsertLogicTag\"\n @open-link-dialog=\"openLinkDialog\"\n @add-merge-tag=\"handleAddMergeTag\"\n @add-logic-tag=\"handleAddLogicTag\"\n />\n\n <RichTextEditorContent\n :editor=\"editor\"\n :editor-content=\"EditorContent\"\n :is-loading=\"isLoading\"\n :init-error=\"initError\"\n @retry=\"retry\"\n />\n\n <RichTextLinkDialog\n :visible=\"showLinkDialog\"\n :is-editing-link=\"editor?.isActive('link') ?? false\"\n v-model:dialog-ref=\"linkDialogRef\"\n v-model:link-url=\"linkUrl\"\n v-model:link-color=\"linkColor\"\n @close=\"closeLinkDialog\"\n @insert=\"insertLink\"\n @remove=\"removeLink\"\n @keydown=\"handleLinkKeydown\"\n />\n </div>\n</template>\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"TitleEditor-CKjZ6Cgp.js","names":[],"sources":["../../../src/components/blocks/TitleEditor.vue","../../../src/components/blocks/TitleEditor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useI18n } from \"../../composables\";\nimport { useRichTextEditor } from \"../../composables/useRichTextEditor\";\nimport { usePopoverRoot } from \"../../composables/usePopoverRoot\";\nimport type { TitleBlock as TitleBlockType } from \"@templatical/types\";\nimport {\n Bold,\n Braces,\n Italic,\n Link,\n LoaderCircle,\n ScanLine,\n} from \"@lucide/vue\";\nimport { computed, inject } from \"vue\";\nimport {\n THEME_STYLES_KEY,\n UI_THEME_KEY,\n MERGE_TAG_PICKER_KEY,\n LOGIC_TAG_PICKER_KEY,\n} from \"../../keys\";\nimport RichTextLinkDialog from \"./RichTextLinkDialog.vue\";\nimport RichTextEditorContent from \"./RichTextEditorContent.vue\";\nimport { withLinkColor } from \"../../utils/linkColorExtension\";\n\nconst props = defineProps<{\n block: TitleBlockType;\n toolbarPosition: { top: number; left: number };\n}>();\n\nconst emit = defineEmits<{\n (e: \"done\"): void;\n}>();\n\nconst themeStyles = inject(THEME_STYLES_KEY, null);\nconst tplUiTheme = inject(UI_THEME_KEY, null);\nconst popoverRoot = usePopoverRoot();\n// Hide the floating toolbar while either built-in picker modal is open — see\n// ParagraphToolbar.vue for the same rationale.\nconst picker = inject(MERGE_TAG_PICKER_KEY, null);\nconst logicPicker = inject(LOGIC_TAG_PICKER_KEY, null);\nconst pickerIsOpen = computed(\n () => (picker?.isOpen.value ?? false) || (logicPicker?.isOpen.value ?? false),\n);\n\nconst { t } = useI18n();\n\nconst {\n editor,\n EditorContent,\n isLoading,\n initError,\n retry,\n showLinkDialog,\n linkUrl,\n linkColor,\n linkDialogRef,\n canRequestMergeTag,\n canInsertLogicTag,\n openLinkDialog,\n insertLink,\n removeLink,\n closeLinkDialog,\n handleLinkKeydown,\n handleAddMergeTag,\n handleAddLogicTag,\n} = useRichTextEditor({\n blockId: () => props.block.id,\n blockContent: () => props.block.content,\n onDone: () => emit(\"done\"),\n editorName: \"TitleEditor\",\n async loadExtensions({\n mergeTags,\n syntax,\n triggerChar,\n autocompleteEnabled,\n suggestionEmptyText,\n }) {\n const [\n { Editor: TiptapEditor, EditorContent: EC },\n { default: StarterKit },\n { default: LinkExt },\n { MergeTagNode, MergeTagSuggestion, LogicMergeTagNode },\n ] = await Promise.all([\n import(\"@tiptap/vue-3\"),\n import(\"@tiptap/starter-kit\"),\n import(\"@tiptap/extension-link\"),\n import(\"../../extensions\"),\n ]);\n\n return {\n TiptapEditor,\n EC,\n extensions: [\n StarterKit.configure({\n heading: false,\n codeBlock: false,\n blockquote: false,\n horizontalRule: false,\n bulletList: false,\n orderedList: false,\n listItem: false,\n strike: false,\n // StarterKit bundles @tiptap/extension-link (openOnClick: true).\n // Disable it so the LinkExt below (openOnClick: false) is the only\n // link extension — otherwise clicking a link while editing opens it.\n link: false,\n }),\n withLinkColor(LinkExt).configure({\n openOnClick: false,\n HTMLAttributes: {\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n }),\n MergeTagNode.configure({ mergeTags, syntax }),\n LogicMergeTagNode.configure({ syntax }),\n ...(autocompleteEnabled && triggerChar && mergeTags.length > 0\n ? [\n MergeTagSuggestion.configure({\n mergeTags,\n char: triggerChar,\n emptyText: suggestionEmptyText,\n popoverRoot,\n }),\n ]\n : []),\n ],\n };\n },\n});\n</script>\n\n<template>\n <div class=\"tpl-text-editor-wrapper tpl:relative\">\n <Teleport v-if=\"popoverRoot && !pickerIsOpen\" :to=\"popoverRoot\">\n <div\n :data-tpl-theme=\"tplUiTheme\"\n role=\"toolbar\"\n :aria-label=\"t.titleEditor.toolbar\"\n class=\"tpl tpl-text-toolbar tpl:fixed tpl:z-popover tpl:flex tpl:items-center tpl:gap-1 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-3 tpl:py-2 tpl:shadow-lg\"\n :style=\"{\n ...themeStyles,\n top: `${toolbarPosition.top}px`,\n left: `${toolbarPosition.left}px`,\n transform: 'translateY(-100%)',\n }\"\n >\n <template v-if=\"!isLoading && editor\">\n <!-- Bold -->\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': editor?.isActive('bold'),\n }\"\n :aria-label=\"t.titleEditor.bold\"\n :title=\"t.titleEditor.bold\"\n @click=\"editor?.chain().focus().toggleBold().run()\"\n >\n <Bold :size=\"16\" :stroke-width=\"2.5\" />\n </button>\n <!-- Italic -->\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': editor?.isActive('italic'),\n }\"\n :aria-label=\"t.titleEditor.italic\"\n :title=\"t.titleEditor.italic\"\n @click=\"editor?.chain().focus().toggleItalic().run()\"\n >\n <Italic :size=\"16\" :stroke-width=\"2\" />\n </button>\n <span\n class=\"tpl:mx-1.5 tpl:h-6 tpl:w-px tpl:bg-[var(--tpl-border)]\"\n aria-hidden=\"true\"\n ></span>\n <!-- Link -->\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': editor?.isActive('link'),\n }\"\n :aria-label=\"t.titleEditor.addLink\"\n :title=\"t.titleEditor.addLink\"\n @click=\"openLinkDialog\"\n >\n <Link :size=\"16\" :stroke-width=\"2\" />\n </button>\n <!-- Add Merge Tag -->\n <span\n v-if=\"canRequestMergeTag\"\n class=\"tpl:mx-1.5 tpl:h-6 tpl:w-px tpl:bg-[var(--tpl-border)]\"\n ></span>\n <button\n v-if=\"canRequestMergeTag\"\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.mergeTag.insert\"\n :title=\"t.mergeTag.insert\"\n @click=\"handleAddMergeTag\"\n >\n <ScanLine :size=\"16\" :stroke-width=\"2\" />\n {{ t.mergeTag.insertShort }}\n </button>\n <!-- Insert Logic -->\n <span\n v-if=\"canInsertLogicTag\"\n class=\"tpl:mx-1.5 tpl:h-6 tpl:w-px tpl:bg-[var(--tpl-border)]\"\n ></span>\n <button\n v-if=\"canInsertLogicTag\"\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.logicTag.insert\"\n :title=\"t.logicTag.insert\"\n data-testid=\"insert-logic-button\"\n @click=\"handleAddLogicTag\"\n >\n <Braces :size=\"16\" :stroke-width=\"2\" />\n {{ t.logicTag.insertShort }}\n </button>\n </template>\n <template v-else>\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n <LoaderCircle class=\"tpl-spinner\" :size=\"14\" :stroke-width=\"2\" />\n {{ t.errors.editorLoading }}\n </div>\n </template>\n </div>\n </Teleport>\n\n <RichTextEditorContent\n :editor=\"editor\"\n :editor-content=\"EditorContent\"\n :is-loading=\"isLoading\"\n :init-error=\"initError\"\n @retry=\"retry\"\n />\n\n <RichTextLinkDialog\n :visible=\"showLinkDialog\"\n :is-editing-link=\"editor?.isActive('link') ?? false\"\n v-model:dialog-ref=\"linkDialogRef\"\n v-model:link-url=\"linkUrl\"\n v-model:link-color=\"linkColor\"\n @close=\"closeLinkDialog\"\n @insert=\"insertLink\"\n @remove=\"removeLink\"\n @keydown=\"handleLinkKeydown\"\n />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { useI18n } from \"../../composables\";\nimport { useRichTextEditor } from \"../../composables/useRichTextEditor\";\nimport { usePopoverRoot } from \"../../composables/usePopoverRoot\";\nimport type { TitleBlock as TitleBlockType } from \"@templatical/types\";\nimport {\n Bold,\n Braces,\n Italic,\n Link,\n LoaderCircle,\n ScanLine,\n} from \"@lucide/vue\";\nimport { computed, inject } from \"vue\";\nimport {\n THEME_STYLES_KEY,\n UI_THEME_KEY,\n MERGE_TAG_PICKER_KEY,\n LOGIC_TAG_PICKER_KEY,\n} from \"../../keys\";\nimport RichTextLinkDialog from \"./RichTextLinkDialog.vue\";\nimport RichTextEditorContent from \"./RichTextEditorContent.vue\";\nimport { withLinkColor } from \"../../utils/linkColorExtension\";\n\nconst props = defineProps<{\n block: TitleBlockType;\n toolbarPosition: { top: number; left: number };\n}>();\n\nconst emit = defineEmits<{\n (e: \"done\"): void;\n}>();\n\nconst themeStyles = inject(THEME_STYLES_KEY, null);\nconst tplUiTheme = inject(UI_THEME_KEY, null);\nconst popoverRoot = usePopoverRoot();\n// Hide the floating toolbar while either built-in picker modal is open — see\n// ParagraphToolbar.vue for the same rationale.\nconst picker = inject(MERGE_TAG_PICKER_KEY, null);\nconst logicPicker = inject(LOGIC_TAG_PICKER_KEY, null);\nconst pickerIsOpen = computed(\n () => (picker?.isOpen.value ?? false) || (logicPicker?.isOpen.value ?? false),\n);\n\nconst { t } = useI18n();\n\nconst {\n editor,\n EditorContent,\n isLoading,\n initError,\n retry,\n showLinkDialog,\n linkUrl,\n linkColor,\n linkDialogRef,\n canRequestMergeTag,\n canInsertLogicTag,\n openLinkDialog,\n insertLink,\n removeLink,\n closeLinkDialog,\n handleLinkKeydown,\n handleAddMergeTag,\n handleAddLogicTag,\n} = useRichTextEditor({\n blockId: () => props.block.id,\n blockContent: () => props.block.content,\n onDone: () => emit(\"done\"),\n editorName: \"TitleEditor\",\n async loadExtensions({\n mergeTags,\n syntax,\n triggerChar,\n autocompleteEnabled,\n suggestionEmptyText,\n }) {\n const [\n { Editor: TiptapEditor, EditorContent: EC },\n { default: StarterKit },\n { default: LinkExt },\n { MergeTagNode, MergeTagSuggestion, LogicMergeTagNode },\n ] = await Promise.all([\n import(\"@tiptap/vue-3\"),\n import(\"@tiptap/starter-kit\"),\n import(\"@tiptap/extension-link\"),\n import(\"../../extensions\"),\n ]);\n\n return {\n TiptapEditor,\n EC,\n extensions: [\n StarterKit.configure({\n heading: false,\n codeBlock: false,\n blockquote: false,\n horizontalRule: false,\n bulletList: false,\n orderedList: false,\n listItem: false,\n strike: false,\n // StarterKit bundles @tiptap/extension-link (openOnClick: true).\n // Disable it so the LinkExt below (openOnClick: false) is the only\n // link extension — otherwise clicking a link while editing opens it.\n link: false,\n }),\n withLinkColor(LinkExt).configure({\n openOnClick: false,\n HTMLAttributes: {\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n }),\n MergeTagNode.configure({ mergeTags, syntax }),\n LogicMergeTagNode.configure({ syntax }),\n ...(autocompleteEnabled && triggerChar && mergeTags.length > 0\n ? [\n MergeTagSuggestion.configure({\n mergeTags,\n char: triggerChar,\n emptyText: suggestionEmptyText,\n popoverRoot,\n }),\n ]\n : []),\n ],\n };\n },\n});\n</script>\n\n<template>\n <div class=\"tpl-text-editor-wrapper tpl:relative\">\n <Teleport v-if=\"popoverRoot && !pickerIsOpen\" :to=\"popoverRoot\">\n <div\n :data-tpl-theme=\"tplUiTheme\"\n role=\"toolbar\"\n :aria-label=\"t.titleEditor.toolbar\"\n class=\"tpl tpl-text-toolbar tpl:fixed tpl:z-popover tpl:flex tpl:items-center tpl:gap-1 tpl:rounded-lg tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:px-3 tpl:py-2 tpl:shadow-lg\"\n :style=\"{\n ...themeStyles,\n top: `${toolbarPosition.top}px`,\n left: `${toolbarPosition.left}px`,\n transform: 'translateY(-100%)',\n }\"\n >\n <template v-if=\"!isLoading && editor\">\n <!-- Bold -->\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': editor?.isActive('bold'),\n }\"\n :aria-label=\"t.titleEditor.bold\"\n :title=\"t.titleEditor.bold\"\n @click=\"editor?.chain().focus().toggleBold().run()\"\n >\n <Bold :size=\"16\" :stroke-width=\"2.5\" />\n </button>\n <!-- Italic -->\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': editor?.isActive('italic'),\n }\"\n :aria-label=\"t.titleEditor.italic\"\n :title=\"t.titleEditor.italic\"\n @click=\"editor?.chain().focus().toggleItalic().run()\"\n >\n <Italic :size=\"16\" :stroke-width=\"2\" />\n </button>\n <span\n class=\"tpl:mx-1.5 tpl:h-6 tpl:w-px tpl:bg-[var(--tpl-border)]\"\n aria-hidden=\"true\"\n ></span>\n <!-- Link -->\n <button\n type=\"button\"\n class=\"tpl-text-toolbar-btn\"\n :class=\"{\n 'tpl-text-toolbar-btn--active': editor?.isActive('link'),\n }\"\n :aria-label=\"t.titleEditor.addLink\"\n :title=\"t.titleEditor.addLink\"\n @click=\"openLinkDialog\"\n >\n <Link :size=\"16\" :stroke-width=\"2\" />\n </button>\n <!-- Add Merge Tag -->\n <span\n v-if=\"canRequestMergeTag\"\n class=\"tpl:mx-1.5 tpl:h-6 tpl:w-px tpl:bg-[var(--tpl-border)]\"\n ></span>\n <button\n v-if=\"canRequestMergeTag\"\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.mergeTag.insert\"\n :title=\"t.mergeTag.insert\"\n @click=\"handleAddMergeTag\"\n >\n <ScanLine :size=\"16\" :stroke-width=\"2\" />\n {{ t.mergeTag.insertShort }}\n </button>\n <!-- Insert Logic -->\n <span\n v-if=\"canInsertLogicTag\"\n class=\"tpl:mx-1.5 tpl:h-6 tpl:w-px tpl:bg-[var(--tpl-border)]\"\n ></span>\n <button\n v-if=\"canInsertLogicTag\"\n type=\"button\"\n class=\"tpl:flex tpl:h-8 tpl:cursor-pointer tpl:items-center tpl:justify-center tpl:gap-1.5 tpl:rounded tpl:border-none tpl:bg-transparent tpl:px-2.5 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)] tpl:transition-all tpl:duration-150 tpl:hover:bg-[var(--tpl-bg-active)]\"\n :aria-label=\"t.logicTag.insert\"\n :title=\"t.logicTag.insert\"\n data-testid=\"insert-logic-button\"\n @click=\"handleAddLogicTag\"\n >\n <Braces :size=\"16\" :stroke-width=\"2\" />\n {{ t.logicTag.insertShort }}\n </button>\n </template>\n <template v-else>\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:px-2 tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n <LoaderCircle class=\"tpl-spinner\" :size=\"14\" :stroke-width=\"2\" />\n {{ t.errors.editorLoading }}\n </div>\n </template>\n </div>\n </Teleport>\n\n <RichTextEditorContent\n :editor=\"editor\"\n :editor-content=\"EditorContent\"\n :is-loading=\"isLoading\"\n :init-error=\"initError\"\n @retry=\"retry\"\n />\n\n <RichTextLinkDialog\n :visible=\"showLinkDialog\"\n :is-editing-link=\"editor?.isActive('link') ?? false\"\n v-model:dialog-ref=\"linkDialogRef\"\n v-model:link-url=\"linkUrl\"\n v-model:link-color=\"linkColor\"\n @close=\"closeLinkDialog\"\n @insert=\"insertLink\"\n @remove=\"removeLink\"\n @keydown=\"handleLinkKeydown\"\n />\n </div>\n</template>\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ca-DI1ViqMa.js","names":[],"sources":["../../../src/i18n/locales/ca.ts"],"sourcesContent":["import type en from \"./en\";\n\nconst ca: typeof en = {\n // Footer (OSS only)\n footer: {\n poweredBy: \"Amb la tecnologia de\",\n openSource: \"Codi obert\",\n },\n\n // History (undo/redo)\n history: {\n undo: \"Desfer\",\n redo: \"Refer\",\n collabWarning: \"Desfer pot afectar els canvis recents dels col·laboradors\",\n },\n\n // Viewport toggle\n viewport: {\n label: \"Àrea de visualització\",\n desktop: \"Escriptori\",\n mobile: \"Mòbil\",\n },\n\n // Dark mode preview\n darkMode: {\n enable: \"Vista prèvia del mode fosc\",\n disable: \"Vista prèvia del mode clar\",\n },\n\n // Preview mode\n previewMode: {\n enable: \"Mode de vista prèvia\",\n disable: \"Surt de la vista prèvia\",\n },\n\n // Sidebar - Block types\n blocks: {\n section: \"Secció\",\n image: \"Imatge\",\n title: \"Títol\",\n paragraph: \"Paràgraf\",\n button: \"Botó\",\n divider: \"Divisor\",\n video: \"Vídeo\",\n social: \"Xarxes socials\",\n spacer: \"Espaiador\",\n html: \"HTML\",\n menu: \"Menú\",\n table: \"Taula\",\n countdown: \"Compta enrere\",\n },\n\n // Right sidebar\n sidebar: {\n content: \"Contingut\",\n settings: \"Configuració\",\n noSelection: \"Cap element seleccionat\",\n noSelectionHint: \"Selecciona un bloc al llenç per editar-lo\",\n },\n\n // Toolbar - Common\n toolbar: {\n duplicate: \"Duplica\",\n delete: \"Elimina\",\n },\n\n // Title editor toolbar\n titleEditor: {\n toolbar: \"Format del títol\",\n bold: \"Negreta (Ctrl+B)\",\n italic: \"Cursiva (Ctrl+I)\",\n addLink: \"Afegeix un enllaç\",\n },\n\n // Paragraph editor toolbar\n paragraphEditor: {\n toolbar: \"Format del text\",\n bold: \"Negreta (Ctrl+B)\",\n italic: \"Cursiva (Ctrl+I)\",\n underline: \"Subratllat (Ctrl+U)\",\n strikethrough: \"Text ratllat\",\n subscript: \"Subíndex\",\n superscript: \"Superíndex\",\n addLink: \"Afegeix un enllaç\",\n bulletList: \"Llista de vinyetes\",\n numberedList: \"Llista numerada\",\n alignLeft: \"Alinea a l'esquerra\",\n alignCenter: \"Alinea al centre\",\n alignRight: \"Alinea a la dreta\",\n clearFormatting: \"Neteja el format\",\n insertEmoji: \"Insereix un emoji\",\n fontFamily: \"Tipus de lletra\",\n defaultFont: \"Per defecte\",\n fontSize: \"Mida de la font\",\n defaultSize: \"Per defecte\",\n textColor: \"Color del text\",\n highlightColor: \"Color de ressaltat\",\n lineHeight: \"Interlínia\",\n letterSpacing: \"Espaiat de lletres\",\n emojiItemLabel: \"Insereix l'emoji {emoji}\",\n closeEmojiPicker: \"Tanca el selector d'emojis\",\n },\n\n // Block actions (BlockWrapper)\n blockActions: {\n drag: \"Arrossega per reordenar, o prem Espai per moure amb el teclat\",\n dragLifted:\n \"Movent {block}. Utilitza les fletxes amunt i avall per reposicionar, Espai o Retorn per deixar anar, Esc per cancel·lar.\",\n duplicate: \"Duplica el bloc\",\n delete: \"Elimina el bloc\",\n hiddenOnViewport: \"Ocult a {viewport}\",\n saveAsModule: \"Desa com a mòdul\",\n conditionToggle: \"Alterna la condició de visualització\",\n comments: \"Comentaris ({count})\",\n lifted: \"{block} aixecat. Posició {position} de {total}.\",\n moved: \"{block} mogut a la posició {position} of {total}.\",\n dropped: \"{block} deixat anar a la posició {position} de {total}.\",\n cancelled:\n \"Moviment cancel·lat. {block} ha tornat a la posició {position}.\",\n },\n\n // Toolbar - Section\n section: {\n dropHere: \"Deixa anar els blocs aquí\",\n columns: \"Columnes\",\n column1: \"1 columna\",\n column2: \"2 columnes\",\n column3: \"3 columnes\",\n ratio12: \"Proporció 1:2\",\n ratio21: \"Proporció 2:1\",\n borderRadius: \"Radi de la vora\",\n wrapperEnable: \"Afegeix un contenidor\",\n stackOnMobile: \"Apila en mòbil\",\n },\n\n // Text editor link dialog\n linkDialog: {\n editLink: \"Edita l'enllaç\",\n insertLink: \"Insereix l'enllaç\",\n updateLink: \"Actualitza l'enllaç\",\n removeLink: \"Elimina l'enllaç\",\n cancel: \"Cancel·la\",\n urlPlaceholder: \"https://example.com\",\n urlLabel: \"URL\",\n colorLabel: \"Color de l'enllaç\",\n },\n\n // Toolbar - Title\n title: {\n level: \"Nivell d'encapçalament\",\n heading1: \"Encapçalament 1 (36px)\",\n heading2: \"Encapçalament 2 (28px)\",\n heading3: \"Encapçalament 3 (22px)\",\n heading4: \"Encapçalament 4 (18px)\",\n fontFamily: \"Tipus de lletra\",\n inheritFont: \"Utilitza la font de la plantilla\",\n color: \"Color\",\n align: \"Alineació\",\n alignLeft: \"Esquerra\",\n alignCenter: \"Centre\",\n alignRight: \"Dreta\",\n },\n\n // Emoji picker\n emoji: {\n smileys: \"Emoticones\",\n gestures: \"Gestos\",\n objects: \"Objectes\",\n },\n\n // Toolbar - Image\n image: {\n imageUrl: \"URL de la imatge\",\n imageUrlPlaceholder: \"https://...\",\n altText: \"Text alternatiu\",\n altTextPlaceholder: \"Descripció de la imatge\",\n width: \"Amplada\",\n fullWidth: \"Amplada completa\",\n widthCustom: \"Personalitzada\",\n linkUrl: \"URL de l'enllaç\",\n openInNewTab: \"Obre en una pestanya nova\",\n placeholderUrl: \"Imatge de mostra\",\n placeholderUrlPlaceholder: \"https://... (només per al disseny)\",\n placeholderUrlTooltip:\n \"Com que la URL de la imatge utilitza una etiqueta de fusió, podeu proporcionar una imatge real aquí per previsualitzar el disseny mentre dissenyeu. Això no s'inclou a la sortida final.\",\n clickToAdd: \"Feu clic per afegir la URL de la imatge\",\n browseMedia: \"Explora multimèdia\",\n dropToUpload: \"Deixeu anar la imatge per pujar-la\",\n uploading: \"Pujant…\",\n decorative: \"Imatge decorativa\",\n decorativeHint:\n \"Ocult per als lectors de pantalla. Utilitzeu-lo només per a espaiadors i detalls visuals.\",\n },\n\n // Toolbar - Video\n video: {\n videoUrl: \"URL del vídeo\",\n videoUrlPlaceholder: \"https://youtube.com/...\",\n youtube: \"YouTube\",\n vimeo: \"Vimeo\",\n detected: \"Vídeo detectat: la miniatura es generarà automàticament\",\n openInNewTab: \"Obre en una pestanya nova\",\n customThumbnail: \"Miniatura personalitzada\",\n optional: \"(opcional)\",\n thumbnailPlaceholder: \"Generat automàticament des de la URL del vídeo\",\n altText: \"Text alternatiu\",\n altTextPlaceholder: \"Descripció del vídeo\",\n width: \"Amplada\",\n fullWidth: \"Amplada completa\",\n placeholderUrl: \"Miniatura de mostra\",\n placeholderUrlPlaceholder: \"https://... (només per al disseny)\",\n placeholderUrlTooltip:\n \"Com que la URL del vídeo utilitza una etiqueta de fusió, podeu proporcionar una miniatura real aquí per previsualitzar el disseny mentre dissenyeu. Això no s'inclou a la sortida final.\",\n addVideo: \"Afegeix una URL de vídeo\",\n },\n\n // Toolbar - Button\n button: {\n fontFamily: \"Tipus de lletra\",\n inheritFont: \"Utilitza la font de la plantilla\",\n text: \"Text\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n openInNewTab: \"Obre en una pestanya nova\",\n background: \"Fons\",\n textColor: \"Color del text\",\n borderRadius: \"Radi de la vora\",\n fontSize: \"Mida de la font\",\n width: \"Amplada\",\n widthAuto: \"Ajusta al contingut\",\n fullWidth: \"Amplada completa\",\n widthCustom: \"Personalitzada\",\n },\n\n // Toolbar - Divider\n divider: {\n style: \"Estil\",\n solid: \"Sòlid\",\n dashed: \"Amb guions\",\n dotted: \"Amb punts\",\n color: \"Color\",\n thickness: \"Gruix\",\n },\n\n // Toolbar - Social Icons\n social: {\n icons: \"Icones\",\n addIcon: \"Afegeix una icona\",\n addIcons: \"Afegeix icones de xarxes socials\",\n removeIcon: \"Elimina\",\n platform: \"Plataforma\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n style: \"Estil\",\n styleSolid: \"Sòlid\",\n styleOutlined: \"Contornejat\",\n styleRounded: \"Arrodonit\",\n styleSquare: \"Quadrat\",\n styleCircle: \"Cercle\",\n size: \"Mida\",\n sizeSmall: \"S\",\n sizeMedium: \"M\",\n sizeLarge: \"L\",\n spacing: \"Espaiat\",\n align: \"Alineació\",\n platforms: {\n facebook: \"Facebook\",\n twitter: \"X (Twitter)\",\n instagram: \"Instagram\",\n linkedin: \"LinkedIn\",\n youtube: \"YouTube\",\n tiktok: \"TikTok\",\n pinterest: \"Pinterest\",\n email: \"Correu electrònic\",\n website: \"Lloc web\",\n whatsapp: \"WhatsApp\",\n telegram: \"Telegram\",\n discord: \"Discord\",\n snapchat: \"Snapchat\",\n reddit: \"Reddit\",\n github: \"GitHub\",\n dribbble: \"Dribbble\",\n behance: \"Behance\",\n },\n },\n\n // Toolbar - Menu\n menu: {\n items: \"Elements del menú\",\n addItem: \"Afegeix un element\",\n removeItem: \"Elimina\",\n text: \"Text\",\n url: \"URL\",\n urlPlaceholder: \"https://example.com\",\n openInNewTab: \"Obre en una pestanya nova\",\n bold: \"Negreta\",\n underline: \"Subratllat\",\n color: \"Color\",\n linkColor: \"Color de l'enllaç\",\n fontSize: \"Mida de la font\",\n fontFamily: \"Tipus de lletra\",\n separator: \"Separador\",\n separatorColor: \"Color del separador\",\n spacing: \"Espaiat\",\n textAlign: \"Alineació\",\n addLinks: \"Afegeix enllaços al menú\",\n },\n\n // Toolbar - Table\n table: {\n dimensions: \"Dimensions\",\n rows: \"Files\",\n columns: \"Columnes\",\n addRow: \"Afegeix una fila\",\n removeRow: \"Elimina la fila\",\n addColumn: \"Afegeix una columna\",\n removeColumn: \"Elimina la columna\",\n hasHeaderRow: \"Fila de capçalera\",\n headerBackgroundColor: \"Fons de la capçalera\",\n noHeaderBg: \"Sense fons\",\n borderColor: \"Color de la vora\",\n borderWidth: \"Gruix de la vora\",\n cellPadding: \"Farciment de la cel·la\",\n fontFamily: \"Tipus de lletra\",\n fontSize: \"Mida de la font\",\n color: \"Color del text\",\n textAlign: \"Alineació\",\n cellPlaceholder: \"Introdueix el text...\",\n empty: \"Afegeix una taula\",\n },\n\n // Toolbar - Spacer\n spacer: {\n height: \"Alçada\",\n },\n\n // Toolbar - Countdown\n countdown: {\n targetDate: \"Data límit\",\n timezone: \"Zona horària\",\n display: \"Visualització\",\n days: \"Dies\",\n hours: \"Hores\",\n minutes: \"Minuts\",\n seconds: \"Segons\",\n separator: \"Separador\",\n fontFamily: \"Tipus de lletra\",\n inheritFont: \"Per defecte\",\n digitFontSize: \"Mida dels dígits\",\n digitColor: \"Color dels dígits\",\n labelColor: \"Color de l'etiqueta\",\n labelFontSize: \"Mida de l'etiqueta\",\n background: \"Fons\",\n labels: \"Etiquetes\",\n expiry: \"Missatge de caducitat\",\n expiredMessagePlaceholder: \"Aquesta oferta ha caducat\",\n expiredImageUrl: \"URL de la imatge caducada\",\n hideOnExpiry: \"Oculta quan hagi caducat\",\n setDate: \"Defineix una data límit al panell de configuració\",\n hidden: \"Ocult (caducat)\",\n },\n\n // Custom Blocks\n customBlocks: {\n definitionNotFound:\n \"Tipus de bloc desconegut: aquest bloc no està registrat\",\n renderError:\n \"No s'ha pogut renderitzar aquest bloc. Comproveu si hi ha errors a la plantilla del bloc.\",\n fields: {\n required: \"Obligatori\",\n addItem: \"Afegeix un element\",\n removeItem: \"Elimina\",\n maxItemsReached: \"S'ha arribat al límit màxim d'elements\",\n minItemsRequired: \"Es requereix un mínim de {count} elements\",\n },\n toolbar: {\n noDefinition:\n \"Enregistreu aquest tipus de bloc a la configuració de l'SDK per editar-ne les propietats\",\n },\n dataSource: {\n fetchButton: \"Carrega el contingut\",\n changeButton: \"Canvia\",\n fetching: \"Carregant...\",\n readOnlyTooltip: \"Aquest valor es carrega des de la vostra font de dades\",\n fetchError: \"No s'ha pogut carregar el contingut\",\n },\n },\n\n // Toolbar - HTML\n html: {\n content: \"Contingut HTML\",\n preview: \"Bloc HTML personalitzat\",\n empty: \"Afegeix contingut HTML al panell\",\n sanitizationHint:\n \"Els scripts i els elements no segurs s'eliminen en exportar.\",\n },\n\n // Toolbar - Common block settings\n blockSettings: {\n spacing: \"Espaiat\",\n padding: \"Farciment\",\n background: \"Fons\",\n color: \"Color\",\n display: \"Visualització\",\n showOnDesktop: \"Mostra a l'escriptori\",\n showOnMobile: \"Mostra al mòbil\",\n hiddenOnDevice: \"Ocult a {device}\",\n displayCondition: \"Condició de visualització\",\n selectCondition: \"Selecciona una condició\",\n removeCondition: \"Elimina la condició\",\n noCondition: \"Sempre visible\",\n conditionApplied: \"Condició aplicada\",\n customCondition: \"Condició personalitzada\",\n customConditionLabel: \"Nom de la condició\",\n customConditionBefore: \"Abans (lògica d'obertura)\",\n customConditionAfter: \"Després (lògica de tancament)\",\n applyCondition: \"Aplica\",\n cancelCondition: \"Cancel·la\",\n customBadge: \"Personalitzat\",\n restoreHiddenBlocks: \"Mostra tots els blocs ocults\",\n },\n\n // Template settings\n templateSettings: {\n layout: \"Disposició\",\n widthPreset: \"Amplada predefinida\",\n customWidth: \"Amplada personalitzada\",\n appearance: \"Aparença\",\n backgroundColor: \"Color de fons\",\n textColor: \"Color del text\",\n linkColor: \"Color de l'enllaç\",\n linkUnderline: \"Subratllar enllaços\",\n fontFamily: \"Tipus de lletra\",\n preheaderText: \"Text de la precapçalera\",\n preheaderTextPlaceholder:\n \"Text de vista prèvia que es mostra després de la línia de l'assumpte a la bústia...\",\n preheaderTextHint:\n \"Aquest text apareix després de la línia de l'assumpte a les vistes prèvies dels clients de correu. Admet etiquetes de fusió.\",\n language: \"Idioma\",\n contentLocale: \"Idioma del contingut\",\n contentLocaleHint:\n \"Codi BCP 47 (p. ex. ca, en, de). Estableix l'atribut lang del correu renderitzat perquè els lectors de pantalla pronunciïn el contingut correctament.\",\n tips: \"Consells\",\n tip1: \"600px és l'amplada estàndard per a les plantilles de correu electrònic\",\n tip2: \"Utilitzeu fonts segures per a la web per obtenir la millor compatibilitat\",\n tip3: \"Els fons clars funcionen millor per a la llegibilitat\",\n },\n\n // Spacing control\n spacingControl: {\n lockAll: \"Bloqueja tots els costats\",\n unlock: \"Desbloqueja els costats\",\n top: \"Superior\",\n right: \"Dret\",\n bottom: \"Inferior\",\n left: \"Esquerre\",\n decreaseTop: \"Disminueix superior\",\n increaseTop: \"Augmenta superior\",\n decreaseLeft: \"Disminueix esquerre\",\n increaseLeft: \"Augmenta esquerre\",\n decreaseRight: \"Disminueix dret\",\n increaseRight: \"Augmenta dret\",\n decreaseBottom: \"Disminueix inferior\",\n increaseBottom: \"Augmenta inferior\",\n },\n\n // Color Picker\n colorPicker: {\n pickColor: \"Tria un color\",\n hexValue: \"Valor del color en Hex\",\n notSet: \"No definit\",\n clear: \"Neteja el color\",\n },\n\n // Merge Tag\n mergeTag: {\n clickToEdit: \"Feu clic per editar\",\n remove: \"Elimina l'etiqueta de fusió\",\n insert: \"Insereix l'etiqueta de fusió\",\n insertShort: \"Etiqueta de fusió\",\n editValue: \"Edita el valor de l'etiqueta de fusió\",\n deleteMergeTag: \"Elimina l'etiqueta de fusió\",\n suggestionEmpty: \"No hi ha etiquetes de fusió coincidents\",\n picker: {\n title: \"Insereix l'etiqueta de fusió\",\n searchPlaceholder: \"Cerca etiquetes de fusió\",\n searchAriaLabel: \"Cerca etiquetes de fusió\",\n noResults: \"No hi ha etiquetes de fusió coincidents\",\n empty: \"No hi ha etiquetes de fusió configurades\",\n otherGroup: \"Altres\",\n cancel: \"Cancel·la\",\n close: \"Tanca\",\n groupCount: \"{count}\",\n },\n },\n\n // Logic tags (standalone, separate from merge tags)\n logicTag: {\n insert: \"Insereix lògica\",\n insertShort: \"Lògica\",\n picker: {\n title: \"Insereix lògica\",\n searchPlaceholder: \"Cerca etiquetes de lògica\",\n searchAriaLabel: \"Cerca etiquetes de lògica\",\n noResults: \"No hi ha etiquetes de lògica coincidents\",\n empty: \"No hi ha etiquetes de lògica configurades\",\n otherGroup: \"Altres\",\n close: \"Tanca\",\n },\n },\n\n // Canvas\n canvas: {\n noBlocks: \"Encara no hi ha blocs\",\n dragHint: \"Comenceu des de zero arrossegant blocs des de la barra lateral\",\n dropHere: \"Deixeu anar aquí\",\n aiHintChat: \"o deixeu que\",\n aiHintChatSuffix:\n \"generi una plantilla completa per a vosaltres en pocs segons\",\n aiHintDesign:\n \"Teniu un disseny existent? Pugeu una captura de pantalla, una imatge o un PDF i\",\n aiHintDesignSuffix: \"el recrearà a l'instant\",\n },\n\n // Media Library (cloud)\n mediaLibrary: {\n title: \"Biblioteca multimèdia\",\n searchPlaceholder: \"Cerca fitxers...\",\n allFiles: \"Tots els fitxers\",\n filterAll: \"Tots els tipus\",\n filterImages: \"Imatges\",\n filterDocuments: \"Documents\",\n filterVideos: \"Vídeos\",\n filterAudio: \"Àudio\",\n newFolder: \"Nova carpeta\",\n folderName: \"Nom de la carpeta\",\n noFiles: \"No s'han trobat fitxers\",\n dropOrClick: \"Deixeu anar els fitxers aquí o feu clic per pujar-los\",\n acceptedFormats: \"Imatges, PDF, Vídeo, Àudio, Documents (màx. 10 MB)\",\n uploading: \"Pujant...\",\n uploadingProgress: \"Pujant {current} de {total}...\",\n selectImage: \"Selecciona la imatge\",\n selectFile: \"Selecciona el fitxer\",\n deleteSelected: \"Elimina\",\n copyUrl: \"Copia la URL\",\n copied: \"Copiat!\",\n browseMedia: \"Explora la biblioteca multimèdia\",\n renameFolder: \"Canvia el nom de la carpeta\",\n addSubfolder: \"Afegeix una subcarpeta\",\n subfolderName: \"Nom de la subcarpeta\",\n sortNewest: \"Els més nous primer\",\n sortOldest: \"Els més antics primer\",\n sortNameAsc: \"Nom A-Z\",\n sortNameDesc: \"Nom Z-A\",\n sortSizeAsc: \"Els més petits primer\",\n sortSizeDesc: \"Els més grans primer\",\n moveSelected: \"Mou\",\n moveToRoot: \"Tots els fitxers\",\n currentFolder: \"(actual)\",\n confirmDelete: \"Voleu eliminar aquest fitxer?\",\n renameFile: \"Canvia el nom\",\n editFile: \"Edita el fitxer\",\n fileName: \"Nom del fitxer\",\n altText: \"Text alternatiu\",\n altTextPlaceholder: \"Descriviu aquesta imatge per a l'accessibilitat\",\n saveChanges: \"Desa\",\n cancel: \"Cancel·la\",\n frequentlyUsed: \"Utilitzat freqüentment\",\n deleteWarningTitle: \"Elimina el fitxer\",\n deleteWarningMessage:\n \"Aquest fitxer s'eliminarà permanentment i no es podrà recuperar.\",\n deleteWarningUsageNote:\n \"Els fitxers següents s'utilitzen en plantilles. Eliminar-los pot trencar aquestes plantilles.\",\n deleteAnyway: \"Elimina el fitxer de totes maneres\",\n usedInTemplates: \"Utilitzat en {count} plantilla/es\",\n viewGrid: \"Vista de quadrícula\",\n viewList: \"Vista de llista\",\n showFolders: \"Mostra les carpetes\",\n hideFolders: \"Oculta les carpetes\",\n importFromUrl: \"Importa des d'una URL\",\n importUrlPlaceholder: \"https://example.com/image.jpg\",\n import: \"Importa\",\n importing: \"Important...\",\n importError: \"No s'ha pogut importar des de la URL\",\n conversionLabel: \"Mida\",\n conversionOriginal: \"Original\",\n conversionSmall: \"Petita (150px)\",\n conversionMedium: \"Mitjana (600px)\",\n conversionLarge: \"Gran (1200px)\",\n replaceFile: \"Substitueix el fitxer\",\n replaceWarningTitle: \"Substitueix el fitxer\",\n replaceWarningMessage:\n \"Esteu a punt de substituir aquest fitxer. El substitut ha de tenir la mateixa extensió de fitxer ({extension}).\",\n replaceWarningUsageNote:\n \"Aquest fitxer s'utilitza en {count} plantilla/es. Substituir-lo actualitzarà totes les referències.\",\n replaceSelectFile: \"Selecciona el fitxer de substitució\",\n replace: \"Substitueix\",\n replacing: \"Substituint...\",\n replaceError: \"No s'ha pogut substituir el fitxer\",\n saving: \"Desant...\",\n cropAspectRatio: \"Relació d'aspecte\",\n cropFree: \"Lliure\",\n cropSquare: \"1:1\",\n cropLandscape43: \"4:3\",\n cropLandscape169: \"16:9\",\n cropOriginal: \"Original\",\n cropMaxWidth: \"Amplada màxima\",\n cropMaxHeight: \"Alçada màxima\",\n cropOutputSize: \"Mida de sortida\",\n cropPixels: \"px\",\n cropOptional: \"(opcional)\",\n storageTooltip: \"{used} de {total} utilitzats (queden {remaining})\",\n },\n\n // Sidebar\n sidebarNav: {\n browseModules: \"Explora els mòduls desats\",\n expandSidebar: \"Expandeix la barra lateral de blocs\",\n palette: \"Paleta de blocs\",\n insertBlock: \"Insereix un bloc de tipus {block}\",\n },\n\n // Landmark region labels for assistive technology\n landmarks: {\n canvas: \"Llenç del correu\",\n blockToolbar: \"Propietats del bloc\",\n rightSidebar: \"Propietats del bloc i configuració de la plantilla\",\n reorderAnnouncements: \"Avisos de reordenació de blocs\",\n },\n\n // Design Reference (cloud)\n errors: {\n editorLoading: \"Carregant l'editor...\",\n editorLoadFailed: \"No s'ha pogut carregar l'editor.\",\n retry: \"Torna-ho a provar\",\n },\n\n issues: {\n panelTitle: \"Problemes\",\n panelTabLabel: \"Problemes\",\n groupErrors: \"Errors\",\n groupWarnings: \"Avisos\",\n groupInfo: \"Informació\",\n jump: \"Vés al bloc\",\n fix: \"Corregeix\",\n emptyState: \"Sense problemes, tot correcte.\",\n badgeError: \"Té errors\",\n badgeWarning: \"Té avisos\",\n issueCountTooltip: \"{count} problema/es\",\n },\n\n smallScreen: {\n title: \"Cal una pantalla més gran\",\n message:\n \"L'editor necessita més espai del que ofereix aquesta pantalla. Obriu-lo en una tauleta o ordinador d'escriptori per començar a editar.\",\n },\n};\n\nexport default ca;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"de-q9lTCMre.js","names":[],"sources":["../../../src/i18n/locales/de.ts"],"sourcesContent":["import type en from \"./en\";\n\nconst de: typeof en = {\n // Footer (OSS only)\n footer: {\n poweredBy: \"Erstellt mit\",\n openSource: \"Open Source\",\n },\n\n // History (undo/redo)\n history: {\n undo: \"Rückgängig\",\n redo: \"Wiederholen\",\n collabWarning:\n \"Rückgängig machen kann die Änderungen anderer Mitarbeiter beeinflussen\",\n },\n\n // Viewport toggle\n viewport: {\n label: \"Ansichtsgröße\",\n desktop: \"Desktop\",\n mobile: \"Mobil\",\n },\n\n // Dark mode preview\n darkMode: {\n enable: \"Dunkelmodus-Vorschau\",\n disable: \"Hellmodus-Vorschau\",\n },\n\n // Preview mode\n previewMode: {\n enable: \"Vorschaumodus\",\n disable: \"Vorschau beenden\",\n },\n\n // Sidebar - Block types\n blocks: {\n section: \"Abschnitt\",\n image: \"Bild\",\n title: \"Titel\",\n paragraph: \"Absatz\",\n button: \"Schaltfläche\",\n divider: \"Trennlinie\",\n video: \"Video\",\n social: \"Sozial\",\n spacer: \"Abstand\",\n html: \"HTML\",\n menu: \"Menü\",\n table: \"Tabelle\",\n countdown: \"Countdown\",\n },\n\n // Right sidebar\n sidebar: {\n content: \"Inhalt\",\n settings: \"Einstellungen\",\n noSelection: \"Kein Element ausgewählt\",\n noSelectionHint:\n \"Wählen Sie einen Block auf der Leinwand aus, um ihn zu bearbeiten\",\n },\n\n // Toolbar - Common\n toolbar: {\n duplicate: \"Duplizieren\",\n delete: \"Löschen\",\n },\n\n // Title editor toolbar\n titleEditor: {\n toolbar: \"Titelformatierung\",\n bold: \"Fett (Strg+B)\",\n italic: \"Kursiv (Strg+I)\",\n addLink: \"Link hinzufügen\",\n },\n\n // Paragraph editor toolbar\n paragraphEditor: {\n toolbar: \"Textformatierung\",\n bold: \"Fett (Strg+B)\",\n italic: \"Kursiv (Strg+I)\",\n underline: \"Unterstrichen (Strg+U)\",\n strikethrough: \"Durchgestrichen\",\n subscript: \"Tiefgestellt\",\n superscript: \"Hochgestellt\",\n addLink: \"Link hinzufügen\",\n bulletList: \"Aufzählungsliste\",\n numberedList: \"Nummerierte Liste\",\n alignLeft: \"Linksbündig\",\n alignCenter: \"Zentriert\",\n alignRight: \"Rechtsbündig\",\n clearFormatting: \"Formatierung entfernen\",\n insertEmoji: \"Emoji einfügen\",\n fontFamily: \"Schriftart\",\n defaultFont: \"Standard\",\n fontSize: \"Schriftgröße\",\n defaultSize: \"Standard\",\n textColor: \"Textfarbe\",\n highlightColor: \"Hervorhebungsfarbe\",\n lineHeight: \"Zeilenhöhe\",\n letterSpacing: \"Zeichenabstand\",\n emojiItemLabel: \"Emoji {emoji} einfügen\",\n closeEmojiPicker: \"Emoji-Auswahl schließen\",\n },\n\n // Block actions (BlockWrapper)\n blockActions: {\n drag: \"Zum Sortieren ziehen oder Leertaste drücken, um mit der Tastatur zu verschieben\",\n dragLifted:\n \"{block} wird verschoben. Pfeiltasten zum Positionieren, Leer- oder Eingabetaste zum Ablegen, Esc zum Abbrechen.\",\n duplicate: \"Block duplizieren\",\n delete: \"Block löschen\",\n hiddenOnViewport: \"Ausgeblendet auf {viewport}\",\n saveAsModule: \"Als Modul speichern\",\n conditionToggle: \"Anzeigebedingung umschalten\",\n comments: \"Kommentare ({count})\",\n lifted: \"{block} angehoben. Position {position} von {total}.\",\n moved: \"{block} auf Position {position} von {total} verschoben.\",\n dropped: \"{block} auf Position {position} von {total} abgelegt.\",\n cancelled:\n \"Verschieben abgebrochen. {block} auf Position {position} zurückgesetzt.\",\n },\n\n // Toolbar - Section\n section: {\n dropHere: \"Blöcke hierher ziehen\",\n columns: \"Spalten\",\n column1: \"1 Spalte\",\n column2: \"2 Spalten\",\n column3: \"3 Spalten\",\n ratio12: \"1:2 Verhältnis\",\n ratio21: \"2:1 Verhältnis\",\n borderRadius: \"Eckenradius\",\n wrapperEnable: \"Wrapper hinzufügen\",\n stackOnMobile: \"Auf Mobilgeräten stapeln\",\n },\n\n // Text editor link dialog\n linkDialog: {\n editLink: \"Link bearbeiten\",\n insertLink: \"Link einfügen\",\n updateLink: \"Link aktualisieren\",\n removeLink: \"Link entfernen\",\n cancel: \"Abbrechen\",\n urlPlaceholder: \"https://beispiel.de\",\n urlLabel: \"URL\",\n colorLabel: \"Linkfarbe\",\n },\n\n // Toolbar - Title\n title: {\n level: \"Überschriftenebene\",\n heading1: \"Überschrift 1 (36px)\",\n heading2: \"Überschrift 2 (28px)\",\n heading3: \"Überschrift 3 (22px)\",\n heading4: \"Überschrift 4 (18px)\",\n fontFamily: \"Schriftart\",\n inheritFont: \"Vorlagenschrift verwenden\",\n color: \"Farbe\",\n align: \"Ausrichtung\",\n alignLeft: \"Links\",\n alignCenter: \"Zentriert\",\n alignRight: \"Rechts\",\n },\n\n // Emoji picker\n emoji: {\n smileys: \"Smileys\",\n gestures: \"Gesten\",\n objects: \"Objekte\",\n },\n\n // Toolbar - Image\n image: {\n imageUrl: \"Bild-URL\",\n imageUrlPlaceholder: \"https://...\",\n altText: \"Alternativtext\",\n altTextPlaceholder: \"Bildbeschreibung\",\n width: \"Breite\",\n fullWidth: \"Volle Breite\",\n widthCustom: \"Benutzerdefiniert\",\n linkUrl: \"Link-URL\",\n openInNewTab: \"In neuem Tab öffnen\",\n placeholderUrl: \"Platzhalterbild\",\n placeholderUrlPlaceholder: \"https://... (nur zur Gestaltung)\",\n placeholderUrlTooltip:\n \"Da die Bild-URL ein Merge-Tag verwendet, können Sie hier ein echtes Bild angeben, um das Layout während der Gestaltung in der Vorschau anzuzeigen. Dies wird nicht in die endgültige Ausgabe aufgenommen.\",\n clickToAdd: \"Klicken Sie, um eine Bild-URL hinzuzufügen\",\n browseMedia: \"Medien durchsuchen\",\n dropToUpload: \"Bild zum Hochladen ablegen\",\n uploading: \"Wird hochgeladen…\",\n decorative: \"Dekoratives Bild\",\n decorativeHint:\n \"Wird von Bildschirmlesern ignoriert. Nur für Abstandshalter und visuelle Verzierungen verwenden.\",\n },\n\n // Toolbar - Video\n video: {\n videoUrl: \"Video-URL\",\n videoUrlPlaceholder: \"https://youtube.com/...\",\n youtube: \"YouTube\",\n vimeo: \"Vimeo\",\n detected: \"Video erkannt — Vorschaubild wird automatisch generiert\",\n openInNewTab: \"In neuem Tab öffnen\",\n customThumbnail: \"Eigenes Vorschaubild\",\n optional: \"(optional)\",\n thumbnailPlaceholder: \"Automatisch aus Video-URL generiert\",\n altText: \"Alternativtext\",\n altTextPlaceholder: \"Videobeschreibung\",\n width: \"Breite\",\n fullWidth: \"Volle Breite\",\n placeholderUrl: \"Platzhalter-Thumbnail\",\n placeholderUrlPlaceholder: \"https://... (nur zur Gestaltung)\",\n placeholderUrlTooltip:\n \"Da die Video-URL ein Merge-Tag verwendet, können Sie hier ein echtes Thumbnail angeben, um das Layout während der Gestaltung in der Vorschau anzuzeigen. Dies wird nicht in die endgültige Ausgabe aufgenommen.\",\n addVideo: \"Video-URL hinzufügen\",\n },\n\n // Toolbar - Button\n button: {\n fontFamily: \"Schriftart\",\n inheritFont: \"Vorlagenschrift verwenden\",\n text: \"Text\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n openInNewTab: \"In neuem Tab öffnen\",\n background: \"Hintergrund\",\n textColor: \"Textfarbe\",\n borderRadius: \"Eckenradius\",\n fontSize: \"Schriftgröße\",\n width: \"Breite\",\n widthAuto: \"An Inhalt anpassen\",\n fullWidth: \"Volle Breite\",\n widthCustom: \"Benutzerdefiniert\",\n },\n\n // Toolbar - Divider\n divider: {\n style: \"Stil\",\n solid: \"Durchgehend\",\n dashed: \"Gestrichelt\",\n dotted: \"Gepunktet\",\n color: \"Farbe\",\n thickness: \"Stärke\",\n },\n\n // Toolbar - Social Icons\n social: {\n icons: \"Symbole\",\n addIcon: \"Symbol hinzufügen\",\n addIcons: \"Soziale Symbole hinzufügen\",\n removeIcon: \"Entfernen\",\n platform: \"Plattform\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n style: \"Stil\",\n styleSolid: \"Gefüllt\",\n styleOutlined: \"Umrandet\",\n styleRounded: \"Abgerundet\",\n styleSquare: \"Eckig\",\n styleCircle: \"Rund\",\n size: \"Größe\",\n sizeSmall: \"K\",\n sizeMedium: \"M\",\n sizeLarge: \"G\",\n spacing: \"Abstand\",\n align: \"Ausrichtung\",\n platforms: {\n facebook: \"Facebook\",\n twitter: \"X (Twitter)\",\n instagram: \"Instagram\",\n linkedin: \"LinkedIn\",\n youtube: \"YouTube\",\n tiktok: \"TikTok\",\n pinterest: \"Pinterest\",\n email: \"E-Mail\",\n website: \"Website\",\n whatsapp: \"WhatsApp\",\n telegram: \"Telegram\",\n discord: \"Discord\",\n snapchat: \"Snapchat\",\n reddit: \"Reddit\",\n github: \"GitHub\",\n dribbble: \"Dribbble\",\n behance: \"Behance\",\n },\n },\n\n // Toolbar - Menu\n menu: {\n items: \"Menüpunkte\",\n addItem: \"Punkt hinzufügen\",\n removeItem: \"Entfernen\",\n text: \"Text\",\n url: \"URL\",\n urlPlaceholder: \"https://beispiel.de\",\n openInNewTab: \"In neuem Tab öffnen\",\n bold: \"Fett\",\n underline: \"Unterstrichen\",\n color: \"Farbe\",\n linkColor: \"Linkfarbe\",\n fontSize: \"Schriftgröße\",\n fontFamily: \"Schriftfamilie\",\n separator: \"Trennzeichen\",\n separatorColor: \"Trennzeichenfarbe\",\n spacing: \"Abstand\",\n textAlign: \"Ausrichtung\",\n addLinks: \"Menülinks hinzufügen\",\n },\n\n // Toolbar - Table\n table: {\n dimensions: \"Abmessungen\",\n rows: \"Zeilen\",\n columns: \"Spalten\",\n addRow: \"Zeile hinzufügen\",\n removeRow: \"Zeile entfernen\",\n addColumn: \"Spalte hinzufügen\",\n removeColumn: \"Spalte entfernen\",\n hasHeaderRow: \"Kopfzeile\",\n headerBackgroundColor: \"Kopfzeilen-Hintergrund\",\n noHeaderBg: \"Kein Hintergrund\",\n borderColor: \"Rahmenfarbe\",\n borderWidth: \"Rahmenbreite\",\n cellPadding: \"Zellenabstand\",\n fontFamily: \"Schriftart\",\n fontSize: \"Schriftgröße\",\n color: \"Textfarbe\",\n textAlign: \"Ausrichtung\",\n cellPlaceholder: \"Text eingeben...\",\n empty: \"Tabelle hinzufügen\",\n },\n\n // Toolbar - Spacer\n spacer: {\n height: \"Höhe\",\n },\n\n // Toolbar - Countdown\n countdown: {\n targetDate: \"Zieldatum\",\n timezone: \"Zeitzone\",\n display: \"Anzeige\",\n days: \"Tage\",\n hours: \"Stunden\",\n minutes: \"Minuten\",\n seconds: \"Sekunden\",\n separator: \"Trennzeichen\",\n fontFamily: \"Schriftart\",\n inheritFont: \"Standard\",\n digitFontSize: \"Zifferngröße\",\n digitColor: \"Ziffernfarbe\",\n labelColor: \"Beschriftungsfarbe\",\n labelFontSize: \"Beschriftungsgröße\",\n background: \"Hintergrund\",\n labels: \"Beschriftungen\",\n expiry: \"Ablaufnachricht\",\n expiredMessagePlaceholder: \"Dieses Angebot ist abgelaufen\",\n expiredImageUrl: \"Ablaufbild-URL\",\n hideOnExpiry: \"Bei Ablauf ausblenden\",\n setDate: \"Legen Sie ein Zieldatum im Einstellungsbereich fest\",\n hidden: \"Ausgeblendet (abgelaufen)\",\n },\n\n // Custom Blocks\n customBlocks: {\n definitionNotFound:\n \"Unbekannter Blocktyp — dieser Block ist nicht registriert\",\n renderError:\n \"Dieser Block konnte nicht gerendert werden. Überprüfen Sie die Block-Vorlage auf Fehler.\",\n fields: {\n required: \"Pflichtfeld\",\n addItem: \"Element hinzufügen\",\n removeItem: \"Entfernen\",\n maxItemsReached: \"Maximale Anzahl erreicht\",\n minItemsRequired: \"Mindestens {count} Elemente erforderlich\",\n },\n toolbar: {\n noDefinition:\n \"Registrieren Sie diesen Blocktyp in Ihrer SDK-Konfiguration, um seine Eigenschaften zu bearbeiten\",\n },\n dataSource: {\n fetchButton: \"Inhalt laden\",\n changeButton: \"Ändern\",\n fetching: \"Wird geladen...\",\n readOnlyTooltip: \"Dieser Wert wird aus Ihrer Datenquelle geladen\",\n fetchError: \"Inhalt konnte nicht geladen werden\",\n },\n },\n\n // Toolbar - HTML\n html: {\n content: \"HTML-Inhalt\",\n preview: \"Benutzerdefinierter HTML-Block\",\n empty: \"HTML-Inhalt im Bereich hinzufügen\",\n sanitizationHint:\n \"Skripte und unsichere Elemente werden beim Export entfernt.\",\n },\n\n // Toolbar - Common block settings\n blockSettings: {\n spacing: \"Abstände\",\n padding: \"Innenabstand\",\n background: \"Hintergrund\",\n color: \"Farbe\",\n display: \"Anzeige\",\n showOnDesktop: \"Auf Desktop anzeigen\",\n showOnMobile: \"Auf Mobilgerät anzeigen\",\n hiddenOnDevice: \"Ausgeblendet auf {device}\",\n displayCondition: \"Anzeigebedingung\",\n selectCondition: \"Bedingung auswählen\",\n removeCondition: \"Bedingung entfernen\",\n noCondition: \"Immer sichtbar\",\n conditionApplied: \"Bedingung angewendet\",\n customCondition: \"Eigene Bedingung\",\n customConditionLabel: \"Bedingungsname\",\n customConditionBefore: \"Vorher (öffnende Logik)\",\n customConditionAfter: \"Nachher (schließende Logik)\",\n applyCondition: \"Anwenden\",\n cancelCondition: \"Abbrechen\",\n customBadge: \"Eigene\",\n restoreHiddenBlocks: \"Alle ausgeblendeten Blöcke anzeigen\",\n },\n\n // Template settings\n templateSettings: {\n layout: \"Layout\",\n widthPreset: \"Breitenvoreinstellung\",\n customWidth: \"Benutzerdefinierte Breite\",\n appearance: \"Erscheinungsbild\",\n backgroundColor: \"Hintergrundfarbe\",\n textColor: \"Textfarbe\",\n linkColor: \"Linkfarbe\",\n linkUnderline: \"Links unterstreichen\",\n fontFamily: \"Schriftfamilie\",\n preheaderText: \"Preheader-Text\",\n preheaderTextPlaceholder:\n \"Vorschautext, der nach der Betreffzeile im Posteingang angezeigt wird...\",\n preheaderTextHint:\n \"Dieser Text erscheint nach der Betreffzeile in der E-Mail-Vorschau. Unterstützt Merge-Tags.\",\n language: \"Sprache\",\n contentLocale: \"Inhaltssprache\",\n contentLocaleHint:\n \"BCP-47-Code (z. B. en, de, pt-BR). Setzt das lang-Attribut der gerenderten E-Mail, damit Screenreader den Inhalt korrekt aussprechen.\",\n tips: \"Tipps\",\n tip1: \"600px ist die Standardbreite für E-Mail-Vorlagen\",\n tip2: \"Verwenden Sie websichere Schriften für beste Kompatibilität\",\n tip3: \"Helle Hintergründe eignen sich am besten für die Lesbarkeit\",\n },\n\n // Spacing control\n spacingControl: {\n lockAll: \"Alle Seiten sperren\",\n unlock: \"Seiten entsperren\",\n top: \"Oben\",\n right: \"Rechts\",\n bottom: \"Unten\",\n left: \"Links\",\n decreaseTop: \"Oben verringern\",\n increaseTop: \"Oben erhöhen\",\n decreaseLeft: \"Links verringern\",\n increaseLeft: \"Links erhöhen\",\n decreaseRight: \"Rechts verringern\",\n increaseRight: \"Rechts erhöhen\",\n decreaseBottom: \"Unten verringern\",\n increaseBottom: \"Unten erhöhen\",\n },\n\n // Color Picker\n colorPicker: {\n pickColor: \"Farbe auswählen\",\n hexValue: \"Hex-Farbwert\",\n notSet: \"Nicht festgelegt\",\n clear: \"Farbe entfernen\",\n },\n\n // Merge-Tag\n mergeTag: {\n clickToEdit: \"Zum Bearbeiten klicken\",\n remove: \"Merge-Tag entfernen\",\n insert: \"Merge-Tag einfügen\",\n insertShort: \"Merge-Tag\",\n editValue: \"Merge-Tag-Wert bearbeiten\",\n deleteMergeTag: \"Merge-Tag löschen\",\n suggestionEmpty: \"Keine passenden Merge-Tags\",\n picker: {\n title: \"Merge-Tag einfügen\",\n searchPlaceholder: \"Merge-Tags suchen\",\n searchAriaLabel: \"Merge-Tags suchen\",\n noResults: \"Keine passenden Merge-Tags\",\n empty: \"Keine Merge-Tags konfiguriert\",\n otherGroup: \"Sonstige\",\n cancel: \"Abbrechen\",\n close: \"Schließen\",\n groupCount: \"{count}\",\n },\n },\n\n // Logic tags (standalone, separate from merge tags)\n logicTag: {\n insert: \"Logik einfügen\",\n insertShort: \"Logik\",\n picker: {\n title: \"Logik einfügen\",\n searchPlaceholder: \"Logik-Tags suchen\",\n searchAriaLabel: \"Logik-Tags suchen\",\n noResults: \"Keine passenden Logik-Tags\",\n empty: \"Keine Logik-Tags konfiguriert\",\n otherGroup: \"Sonstige\",\n close: \"Schließen\",\n },\n },\n\n // Canvas\n canvas: {\n noBlocks: \"Noch keine Blöcke\",\n dragHint:\n \"Beginnen Sie von Grund auf, indem Sie Blöcke aus der Seitenleiste ziehen\",\n dropHere: \"Hier ablegen\",\n aiHintChat: \"oder lassen Sie\",\n aiHintChatSuffix: \"in Sekunden eine komplette Vorlage für Sie erstellen\",\n aiHintDesign:\n \"Haben Sie ein bestehendes Design? Laden Sie einen Screenshot, ein Bild oder PDF hoch und\",\n aiHintDesignSuffix: \"erstellt es sofort nach\",\n },\n\n // Media Library (cloud)\n mediaLibrary: {\n title: \"Medienbibliothek\",\n searchPlaceholder: \"Dateien suchen...\",\n allFiles: \"Alle Dateien\",\n filterAll: \"Alle Typen\",\n filterImages: \"Bilder\",\n filterDocuments: \"Dokumente\",\n filterVideos: \"Videos\",\n filterAudio: \"Audio\",\n newFolder: \"Neuer Ordner\",\n folderName: \"Ordnername\",\n noFiles: \"Keine Dateien gefunden\",\n dropOrClick: \"Dateien hierher ziehen oder klicken zum Hochladen\",\n acceptedFormats: \"Bilder, PDF, Video, Audio, Dokumente (max. 10 MB)\",\n uploading: \"Wird hochgeladen...\",\n uploadingProgress: \"{current} von {total} wird hochgeladen...\",\n selectImage: \"Bild auswählen\",\n selectFile: \"Datei auswählen\",\n deleteSelected: \"Löschen\",\n copyUrl: \"URL kopieren\",\n copied: \"Kopiert!\",\n browseMedia: \"Medienbibliothek durchsuchen\",\n renameFolder: \"Ordner umbenennen\",\n addSubfolder: \"Unterordner hinzufügen\",\n subfolderName: \"Unterordnername\",\n sortNewest: \"Neueste zuerst\",\n sortOldest: \"Älteste zuerst\",\n sortNameAsc: \"Name A-Z\",\n sortNameDesc: \"Name Z-A\",\n sortSizeAsc: \"Kleinste zuerst\",\n sortSizeDesc: \"Größte zuerst\",\n moveSelected: \"Verschieben\",\n moveToRoot: \"Alle Dateien\",\n currentFolder: \"(aktuell)\",\n confirmDelete: \"Diese Datei löschen?\",\n renameFile: \"Umbenennen\",\n editFile: \"Datei bearbeiten\",\n fileName: \"Dateiname\",\n altText: \"Alternativtext\",\n altTextPlaceholder: \"Bildbeschreibung für Barrierefreiheit\",\n saveChanges: \"Speichern\",\n cancel: \"Abbrechen\",\n frequentlyUsed: \"Häufig verwendet\",\n deleteWarningTitle: \"Datei löschen\",\n deleteWarningMessage:\n \"Diese Datei wird dauerhaft gelöscht und kann nicht wiederhergestellt werden.\",\n deleteWarningUsageNote:\n \"Die folgenden Dateien werden in Vorlagen verwendet. Das Löschen kann diese Vorlagen beschädigen.\",\n deleteAnyway: \"Datei löschen\",\n usedInTemplates: \"In {count} Vorlage(n) verwendet\",\n viewGrid: \"Rasteransicht\",\n viewList: \"Listenansicht\",\n showFolders: \"Ordner anzeigen\",\n hideFolders: \"Ordner ausblenden\",\n importFromUrl: \"Von URL importieren\",\n importUrlPlaceholder: \"https://example.com/image.jpg\",\n import: \"Importieren\",\n importing: \"Wird importiert...\",\n importError: \"Import von URL fehlgeschlagen\",\n conversionLabel: \"Groesse\",\n conversionOriginal: \"Original\",\n conversionSmall: \"Klein (150px)\",\n conversionMedium: \"Mittel (600px)\",\n conversionLarge: \"Gross (1200px)\",\n replaceFile: \"Datei ersetzen\",\n replaceWarningTitle: \"Datei ersetzen\",\n replaceWarningMessage:\n \"Sie sind dabei, diese Datei zu ersetzen. Die Ersatzdatei muss dieselbe Dateierweiterung haben ({extension}).\",\n replaceWarningUsageNote:\n \"Diese Datei wird in {count} Vorlage(n) verwendet. Das Ersetzen aktualisiert alle Verweise.\",\n replaceSelectFile: \"Ersatzdatei auswählen\",\n replace: \"Ersetzen\",\n replacing: \"Wird ersetzt...\",\n replaceError: \"Ersetzen der Datei fehlgeschlagen\",\n saving: \"Wird gespeichert...\",\n cropAspectRatio: \"Seitenverhältnis\",\n cropFree: \"Frei\",\n cropSquare: \"1:1\",\n cropLandscape43: \"4:3\",\n cropLandscape169: \"16:9\",\n cropOriginal: \"Original\",\n cropMaxWidth: \"Max. Breite\",\n cropMaxHeight: \"Max. Höhe\",\n cropOutputSize: \"Ausgabegröße\",\n cropPixels: \"px\",\n cropOptional: \"(optional)\",\n storageTooltip: \"{used} von {total} verwendet ({remaining} verfügbar)\",\n },\n\n // Seitenleiste\n sidebarNav: {\n browseModules: \"Gespeicherte Module durchsuchen\",\n expandSidebar: \"Block-Seitenleiste erweitern\",\n palette: \"Blockpalette\",\n insertBlock: \"{block}-Block einfügen\",\n },\n\n // Landmark-Bezeichnungen für Hilfstechnologien\n landmarks: {\n canvas: \"E-Mail-Leinwand\",\n blockToolbar: \"Blockeigenschaften\",\n rightSidebar: \"Blockeigenschaften und Vorlageneinstellungen\",\n reorderAnnouncements: \"Block-Neuanordnungsmeldungen\",\n },\n\n // Design Reference (cloud)\n errors: {\n editorLoading: \"Editor wird geladen...\",\n editorLoadFailed: \"Editor konnte nicht geladen werden.\",\n retry: \"Erneut versuchen\",\n },\n\n issues: {\n panelTitle: \"Probleme\",\n panelTabLabel: \"Probleme\",\n groupErrors: \"Fehler\",\n groupWarnings: \"Warnungen\",\n groupInfo: \"Hinweise\",\n jump: \"Zum Block springen\",\n fix: \"Beheben\",\n emptyState: \"Keine Probleme — sieht gut aus.\",\n badgeError: \"Hat Fehler\",\n badgeWarning: \"Hat Warnungen\",\n issueCountTooltip: \"{count} Problem(e)\",\n },\n\n smallScreen: {\n title: \"Größerer Bildschirm erforderlich\",\n message:\n \"Der Editor benötigt mehr Platz, als dieser Bildschirm bietet. Öffnen Sie ihn auf einem Tablet oder Desktop, um mit der Bearbeitung zu beginnen.\",\n },\n};\n\nexport default de;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"en-CR4LItrX.js","names":[],"sources":["../../../src/i18n/locales/en.ts"],"sourcesContent":["export default {\n // Footer (OSS only)\n footer: {\n poweredBy: \"Powered by\",\n openSource: \"Open Source\",\n },\n\n // History (undo/redo)\n history: {\n undo: \"Undo\",\n redo: \"Redo\",\n collabWarning: \"Undo may affect collaborators' recent changes\",\n },\n\n // Viewport toggle\n viewport: {\n label: \"Viewport\",\n desktop: \"Desktop\",\n mobile: \"Mobile\",\n },\n\n // Dark mode preview\n darkMode: {\n enable: \"Dark Mode Preview\",\n disable: \"Light Mode Preview\",\n },\n\n // Preview mode\n previewMode: {\n enable: \"Preview Mode\",\n disable: \"Exit Preview\",\n },\n\n // Sidebar - Block types\n blocks: {\n section: \"Section\",\n image: \"Image\",\n title: \"Title\",\n paragraph: \"Paragraph\",\n button: \"Button\",\n divider: \"Divider\",\n video: \"Video\",\n social: \"Social\",\n spacer: \"Spacer\",\n html: \"HTML\",\n menu: \"Menu\",\n table: \"Table\",\n countdown: \"Countdown\",\n },\n\n // Right sidebar\n sidebar: {\n content: \"Content\",\n settings: \"Settings\",\n noSelection: \"No element selected\",\n noSelectionHint: \"Select a block on the canvas to edit it\",\n },\n\n // Toolbar - Common\n toolbar: {\n duplicate: \"Duplicate\",\n delete: \"Delete\",\n },\n\n // Title editor toolbar\n titleEditor: {\n toolbar: \"Title formatting\",\n bold: \"Bold (Ctrl+B)\",\n italic: \"Italic (Ctrl+I)\",\n addLink: \"Add Link\",\n },\n\n // Paragraph editor toolbar\n paragraphEditor: {\n toolbar: \"Text formatting\",\n bold: \"Bold (Ctrl+B)\",\n italic: \"Italic (Ctrl+I)\",\n underline: \"Underline (Ctrl+U)\",\n strikethrough: \"Strikethrough\",\n subscript: \"Subscript\",\n superscript: \"Superscript\",\n addLink: \"Add Link\",\n bulletList: \"Bullet List\",\n numberedList: \"Numbered List\",\n alignLeft: \"Align Left\",\n alignCenter: \"Align Center\",\n alignRight: \"Align Right\",\n clearFormatting: \"Clear Formatting\",\n insertEmoji: \"Insert Emoji\",\n fontFamily: \"Font Family\",\n defaultFont: \"Default\",\n fontSize: \"Font Size\",\n defaultSize: \"Default\",\n textColor: \"Text Color\",\n highlightColor: \"Highlight Color\",\n lineHeight: \"Line Height\",\n letterSpacing: \"Letter Spacing\",\n emojiItemLabel: \"Insert emoji {emoji}\",\n closeEmojiPicker: \"Close emoji picker\",\n },\n\n // Block actions (BlockWrapper)\n blockActions: {\n drag: \"Drag to reorder, or press Space to move with keyboard\",\n dragLifted:\n \"Moving {block}. Use up and down arrow keys to reposition, Space or Enter to drop, Escape to cancel.\",\n duplicate: \"Duplicate block\",\n delete: \"Delete block\",\n hiddenOnViewport: \"Hidden on {viewport}\",\n saveAsModule: \"Save as Module\",\n conditionToggle: \"Toggle display condition\",\n comments: \"Comments ({count})\",\n lifted: \"{block} lifted. Position {position} of {total}.\",\n moved: \"{block} moved to position {position} of {total}.\",\n dropped: \"{block} dropped at position {position} of {total}.\",\n cancelled: \"Move cancelled. {block} returned to position {position}.\",\n },\n\n // Toolbar - Section\n section: {\n dropHere: \"Drop blocks here\",\n columns: \"Columns\",\n column1: \"1 Column\",\n column2: \"2 Columns\",\n column3: \"3 Columns\",\n ratio12: \"1:2 Ratio\",\n ratio21: \"2:1 Ratio\",\n borderRadius: \"Border Radius\",\n wrapperEnable: \"Add wrapper\",\n stackOnMobile: \"Stack on mobile\",\n },\n\n // Text editor link dialog\n linkDialog: {\n editLink: \"Edit Link\",\n insertLink: \"Insert Link\",\n updateLink: \"Update Link\",\n removeLink: \"Remove Link\",\n cancel: \"Cancel\",\n urlPlaceholder: \"https://example.com\",\n urlLabel: \"URL\",\n colorLabel: \"Link Color\",\n },\n\n // Toolbar - Title\n title: {\n level: \"Heading Level\",\n heading1: \"Heading 1 (36px)\",\n heading2: \"Heading 2 (28px)\",\n heading3: \"Heading 3 (22px)\",\n heading4: \"Heading 4 (18px)\",\n fontFamily: \"Font Family\",\n inheritFont: \"Use template font\",\n color: \"Color\",\n align: \"Align\",\n alignLeft: \"Left\",\n alignCenter: \"Center\",\n alignRight: \"Right\",\n },\n\n // Emoji picker\n emoji: {\n smileys: \"Smileys\",\n gestures: \"Gestures\",\n objects: \"Objects\",\n },\n\n // Toolbar - Image\n image: {\n imageUrl: \"Image URL\",\n imageUrlPlaceholder: \"https://...\",\n altText: \"Alt Text\",\n altTextPlaceholder: \"Image description\",\n width: \"Width\",\n fullWidth: \"Full Width\",\n widthCustom: \"Custom\",\n linkUrl: \"Link URL\",\n openInNewTab: \"Open in new tab\",\n placeholderUrl: \"Placeholder Image\",\n placeholderUrlPlaceholder: \"https://... (design-time only)\",\n placeholderUrlTooltip:\n \"Since the image URL uses a merge tag, you can provide a real image here to preview the layout while designing. This is not included in the final output.\",\n clickToAdd: \"Click to add image URL\",\n browseMedia: \"Browse Media\",\n dropToUpload: \"Drop image to upload\",\n uploading: \"Uploading…\",\n decorative: \"Decorative image\",\n decorativeHint:\n \"Hidden from screen readers. Use only for spacers and visual flourishes.\",\n },\n\n // Toolbar - Video\n video: {\n videoUrl: \"Video URL\",\n videoUrlPlaceholder: \"https://youtube.com/...\",\n youtube: \"YouTube\",\n vimeo: \"Vimeo\",\n detected: \"Video detected — thumbnail will be generated automatically\",\n openInNewTab: \"Open in new tab\",\n customThumbnail: \"Custom Thumbnail\",\n optional: \"(optional)\",\n thumbnailPlaceholder: \"Auto-generated from video URL\",\n altText: \"Alt Text\",\n altTextPlaceholder: \"Video description\",\n width: \"Width\",\n fullWidth: \"Full Width\",\n placeholderUrl: \"Placeholder Thumbnail\",\n placeholderUrlPlaceholder: \"https://... (design-time only)\",\n placeholderUrlTooltip:\n \"Since the video URL uses a merge tag, you can provide a real thumbnail here to preview the layout while designing. This is not included in the final output.\",\n addVideo: \"Add a video URL\",\n },\n\n // Toolbar - Button\n button: {\n fontFamily: \"Font Family\",\n inheritFont: \"Use template font\",\n text: \"Text\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n openInNewTab: \"Open in new tab\",\n background: \"Background\",\n textColor: \"Text Color\",\n borderRadius: \"Border Radius\",\n fontSize: \"Font Size\",\n width: \"Width\",\n widthAuto: \"Fit to content\",\n fullWidth: \"Full Width\",\n widthCustom: \"Custom\",\n },\n\n // Toolbar - Divider\n divider: {\n style: \"Style\",\n solid: \"Solid\",\n dashed: \"Dashed\",\n dotted: \"Dotted\",\n color: \"Color\",\n thickness: \"Thickness\",\n },\n\n // Toolbar - Social Icons\n social: {\n icons: \"Icons\",\n addIcon: \"Add Icon\",\n addIcons: \"Add social icons\",\n removeIcon: \"Remove\",\n platform: \"Platform\",\n url: \"URL\",\n urlPlaceholder: \"https://...\",\n style: \"Style\",\n styleSolid: \"Solid\",\n styleOutlined: \"Outlined\",\n styleRounded: \"Rounded\",\n styleSquare: \"Square\",\n styleCircle: \"Circle\",\n size: \"Size\",\n sizeSmall: \"S\",\n sizeMedium: \"M\",\n sizeLarge: \"L\",\n spacing: \"Spacing\",\n align: \"Alignment\",\n platforms: {\n facebook: \"Facebook\",\n twitter: \"X (Twitter)\",\n instagram: \"Instagram\",\n linkedin: \"LinkedIn\",\n youtube: \"YouTube\",\n tiktok: \"TikTok\",\n pinterest: \"Pinterest\",\n email: \"Email\",\n website: \"Website\",\n whatsapp: \"WhatsApp\",\n telegram: \"Telegram\",\n discord: \"Discord\",\n snapchat: \"Snapchat\",\n reddit: \"Reddit\",\n github: \"GitHub\",\n dribbble: \"Dribbble\",\n behance: \"Behance\",\n },\n },\n\n // Toolbar - Menu\n menu: {\n items: \"Menu Items\",\n addItem: \"Add Item\",\n removeItem: \"Remove\",\n text: \"Text\",\n url: \"URL\",\n urlPlaceholder: \"https://example.com\",\n openInNewTab: \"Open in new tab\",\n bold: \"Bold\",\n underline: \"Underline\",\n color: \"Color\",\n linkColor: \"Link Color\",\n fontSize: \"Font Size\",\n fontFamily: \"Font Family\",\n separator: \"Separator\",\n separatorColor: \"Separator Color\",\n spacing: \"Spacing\",\n textAlign: \"Alignment\",\n addLinks: \"Add menu links\",\n },\n\n // Toolbar - Table\n table: {\n dimensions: \"Dimensions\",\n rows: \"Rows\",\n columns: \"Columns\",\n addRow: \"Add Row\",\n removeRow: \"Remove Row\",\n addColumn: \"Add Column\",\n removeColumn: \"Remove Column\",\n hasHeaderRow: \"Header row\",\n headerBackgroundColor: \"Header Background\",\n noHeaderBg: \"No background\",\n borderColor: \"Border Color\",\n borderWidth: \"Border Width\",\n cellPadding: \"Cell Padding\",\n fontFamily: \"Font Family\",\n fontSize: \"Font Size\",\n color: \"Text Color\",\n textAlign: \"Alignment\",\n cellPlaceholder: \"Enter text...\",\n empty: \"Add a table\",\n },\n\n // Toolbar - Spacer\n spacer: {\n height: \"Height\",\n },\n\n // Toolbar - Countdown\n countdown: {\n targetDate: \"Target Date\",\n timezone: \"Timezone\",\n display: \"Display\",\n days: \"Days\",\n hours: \"Hours\",\n minutes: \"Minutes\",\n seconds: \"Seconds\",\n separator: \"Separator\",\n fontFamily: \"Font Family\",\n inheritFont: \"Default\",\n digitFontSize: \"Digit Size\",\n digitColor: \"Digit Color\",\n labelColor: \"Label Color\",\n labelFontSize: \"Label Size\",\n background: \"Background\",\n labels: \"Labels\",\n expiry: \"Expired Message\",\n expiredMessagePlaceholder: \"This offer has expired\",\n expiredImageUrl: \"Expired Image URL\",\n hideOnExpiry: \"Hide when expired\",\n setDate: \"Set a target date in the settings panel\",\n hidden: \"Hidden (expired)\",\n },\n\n // Custom Blocks\n customBlocks: {\n definitionNotFound: \"Unknown block type — this block is not registered\",\n renderError:\n \"This block could not be rendered. Check the block template for errors.\",\n fields: {\n required: \"Required\",\n addItem: \"Add item\",\n removeItem: \"Remove\",\n maxItemsReached: \"Maximum items reached\",\n minItemsRequired: \"Minimum {count} items required\",\n },\n toolbar: {\n noDefinition:\n \"Register this block type in your SDK configuration to edit its properties\",\n },\n dataSource: {\n fetchButton: \"Load content\",\n changeButton: \"Change\",\n fetching: \"Loading...\",\n readOnlyTooltip: \"This value is loaded from your data source\",\n fetchError: \"Failed to load content\",\n },\n },\n\n // Toolbar - HTML\n html: {\n content: \"HTML Content\",\n preview: \"Custom HTML block\",\n empty: \"Add HTML content in the panel\",\n sanitizationHint: \"Scripts and unsafe elements are removed on export.\",\n },\n\n // Toolbar - Common block settings\n blockSettings: {\n spacing: \"Spacing\",\n padding: \"Padding\",\n background: \"Background\",\n color: \"Color\",\n display: \"Display\",\n showOnDesktop: \"Show on desktop\",\n showOnMobile: \"Show on mobile\",\n hiddenOnDevice: \"Hidden on {device}\",\n displayCondition: \"Display Condition\",\n selectCondition: \"Select condition\",\n removeCondition: \"Remove condition\",\n noCondition: \"Always visible\",\n conditionApplied: \"Condition applied\",\n customCondition: \"Custom condition\",\n customConditionLabel: \"Condition name\",\n customConditionBefore: \"Before (opening logic)\",\n customConditionAfter: \"After (closing logic)\",\n applyCondition: \"Apply\",\n cancelCondition: \"Cancel\",\n customBadge: \"Custom\",\n restoreHiddenBlocks: \"Show all hidden blocks\",\n },\n\n // Template settings\n templateSettings: {\n layout: \"Layout\",\n widthPreset: \"Width Preset\",\n customWidth: \"Custom Width\",\n appearance: \"Appearance\",\n backgroundColor: \"Background Color\",\n textColor: \"Text Color\",\n linkColor: \"Link Color\",\n linkUnderline: \"Underline Links\",\n fontFamily: \"Font Family\",\n preheaderText: \"Preheader Text\",\n preheaderTextPlaceholder:\n \"Preview text shown after subject line in inbox...\",\n preheaderTextHint:\n \"This text appears after the subject line in email client previews. Supports merge tags.\",\n language: \"Language\",\n contentLocale: \"Content language\",\n contentLocaleHint:\n \"BCP 47 code (e.g. en, de, pt-BR). Sets the rendered email's lang attribute so screen readers pronounce content correctly.\",\n tips: \"Tips\",\n tip1: \"600px is the standard width for email templates\",\n tip2: \"Use web-safe fonts for best compatibility\",\n tip3: \"Light backgrounds work best for readability\",\n },\n\n // Spacing control\n spacingControl: {\n lockAll: \"Lock all sides\",\n unlock: \"Unlock sides\",\n top: \"Top\",\n right: \"Right\",\n bottom: \"Bottom\",\n left: \"Left\",\n decreaseTop: \"Decrease top\",\n increaseTop: \"Increase top\",\n decreaseLeft: \"Decrease left\",\n increaseLeft: \"Increase left\",\n decreaseRight: \"Decrease right\",\n increaseRight: \"Increase right\",\n decreaseBottom: \"Decrease bottom\",\n increaseBottom: \"Increase bottom\",\n },\n\n // Color Picker\n colorPicker: {\n pickColor: \"Pick a color\",\n hexValue: \"Hex color value\",\n notSet: \"Not set\",\n clear: \"Clear color\",\n },\n\n // Merge Tag\n mergeTag: {\n clickToEdit: \"Click to edit\",\n remove: \"Remove merge tag\",\n insert: \"Insert merge tag\",\n insertShort: \"Merge tag\",\n editValue: \"Edit merge tag value\",\n deleteMergeTag: \"Delete merge tag\",\n suggestionEmpty: \"No matching merge tags\",\n picker: {\n title: \"Insert merge tag\",\n searchPlaceholder: \"Search merge tags\",\n searchAriaLabel: \"Search merge tags\",\n noResults: \"No matching merge tags\",\n empty: \"No merge tags configured\",\n otherGroup: \"Other\",\n cancel: \"Cancel\",\n close: \"Close\",\n groupCount: \"{count}\",\n },\n },\n\n // Logic tags (standalone, separate from merge tags)\n logicTag: {\n insert: \"Insert logic\",\n insertShort: \"Logic\",\n picker: {\n title: \"Insert logic\",\n searchPlaceholder: \"Search logic tags\",\n searchAriaLabel: \"Search logic tags\",\n noResults: \"No matching logic tags\",\n empty: \"No logic tags configured\",\n otherGroup: \"Other\",\n close: \"Close\",\n },\n },\n\n // Canvas\n canvas: {\n noBlocks: \"No blocks yet\",\n dragHint: \"Start from scratch by dragging blocks from the sidebar\",\n dropHere: \"Drop here\",\n aiHintChat: \"or let\",\n aiHintChatSuffix: \"generate a complete template for you in seconds\",\n aiHintDesign:\n \"Have an existing design? Upload a screenshot, image, or PDF and\",\n aiHintDesignSuffix: \"will instantly recreate it\",\n },\n\n // Media Library (cloud)\n mediaLibrary: {\n title: \"Media Library\",\n searchPlaceholder: \"Search files...\",\n allFiles: \"All Files\",\n filterAll: \"All Types\",\n filterImages: \"Images\",\n filterDocuments: \"Documents\",\n filterVideos: \"Videos\",\n filterAudio: \"Audio\",\n newFolder: \"New Folder\",\n folderName: \"Folder name\",\n noFiles: \"No files found\",\n dropOrClick: \"Drop files here or click to upload\",\n acceptedFormats: \"Images, PDF, Video, Audio, Documents (max 10MB)\",\n uploading: \"Uploading...\",\n uploadingProgress: \"Uploading {current} of {total}...\",\n selectImage: \"Select Image\",\n selectFile: \"Select File\",\n deleteSelected: \"Delete\",\n copyUrl: \"Copy URL\",\n copied: \"Copied!\",\n browseMedia: \"Browse Media Library\",\n renameFolder: \"Rename folder\",\n addSubfolder: \"Add subfolder\",\n subfolderName: \"Subfolder name\",\n sortNewest: \"Newest First\",\n sortOldest: \"Oldest First\",\n sortNameAsc: \"Name A-Z\",\n sortNameDesc: \"Name Z-A\",\n sortSizeAsc: \"Smallest First\",\n sortSizeDesc: \"Largest First\",\n moveSelected: \"Move\",\n moveToRoot: \"All Files\",\n currentFolder: \"(current)\",\n confirmDelete: \"Delete this file?\",\n renameFile: \"Rename\",\n editFile: \"Edit File\",\n fileName: \"Filename\",\n altText: \"Alt Text\",\n altTextPlaceholder: \"Describe this image for accessibility\",\n saveChanges: \"Save\",\n cancel: \"Cancel\",\n frequentlyUsed: \"Frequently Used\",\n deleteWarningTitle: \"Delete File\",\n deleteWarningMessage:\n \"This file will be permanently deleted and cannot be recovered.\",\n deleteWarningUsageNote:\n \"The following files are used in templates. Deleting them may break those templates.\",\n deleteAnyway: \"Delete file\",\n usedInTemplates: \"Used in {count} template(s)\",\n viewGrid: \"Grid view\",\n viewList: \"List view\",\n showFolders: \"Show folders\",\n hideFolders: \"Hide folders\",\n importFromUrl: \"Import from URL\",\n importUrlPlaceholder: \"https://example.com/image.jpg\",\n import: \"Import\",\n importing: \"Importing...\",\n importError: \"Failed to import from URL\",\n conversionLabel: \"Size\",\n conversionOriginal: \"Original\",\n conversionSmall: \"Small (150px)\",\n conversionMedium: \"Medium (600px)\",\n conversionLarge: \"Large (1200px)\",\n replaceFile: \"Replace File\",\n replaceWarningTitle: \"Replace File\",\n replaceWarningMessage:\n \"You are about to replace this file. The replacement must have the same file extension ({extension}).\",\n replaceWarningUsageNote:\n \"This file is used in {count} template(s). Replacing it will update all references.\",\n replaceSelectFile: \"Select replacement file\",\n replace: \"Replace\",\n replacing: \"Replacing...\",\n replaceError: \"Failed to replace file\",\n saving: \"Saving...\",\n cropAspectRatio: \"Aspect Ratio\",\n cropFree: \"Free\",\n cropSquare: \"1:1\",\n cropLandscape43: \"4:3\",\n cropLandscape169: \"16:9\",\n cropOriginal: \"Original\",\n cropMaxWidth: \"Max Width\",\n cropMaxHeight: \"Max Height\",\n cropOutputSize: \"Output Size\",\n cropPixels: \"px\",\n cropOptional: \"(optional)\",\n storageTooltip: \"{used} of {total} used ({remaining} remaining)\",\n },\n\n // Sidebar\n sidebarNav: {\n browseModules: \"Browse saved modules\",\n expandSidebar: \"Expand block sidebar\",\n palette: \"Block palette\",\n insertBlock: \"Insert {block} block\",\n },\n\n // Landmark region labels for assistive technology\n landmarks: {\n canvas: \"Email canvas\",\n blockToolbar: \"Block properties\",\n rightSidebar: \"Block properties and template settings\",\n reorderAnnouncements: \"Block reorder announcements\",\n },\n\n // Design Reference (cloud)\n errors: {\n editorLoading: \"Loading editor...\",\n editorLoadFailed: \"Failed to load editor.\",\n retry: \"Retry\",\n },\n\n issues: {\n panelTitle: \"Issues\",\n panelTabLabel: \"Issues\",\n groupErrors: \"Errors\",\n groupWarnings: \"Warnings\",\n groupInfo: \"Info\",\n jump: \"Jump to block\",\n fix: \"Fix\",\n emptyState: \"No issues — looking good.\",\n badgeError: \"Has errors\",\n badgeWarning: \"Has warnings\",\n issueCountTooltip: \"{count} issue(s)\",\n },\n\n smallScreen: {\n title: \"Larger screen required\",\n message:\n \"The editor needs more space than this screen offers. Open it on a tablet or desktop to start editing.\",\n },\n};\n"],"mappings":"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"}