@verbb/plugin-kit-web 2.0.25 → 2.0.27

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 (51) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/custom-elements.json +27 -0
  3. package/dist/chunks/{pk-dialog-C7KZGpQs.js → pk-dialog-Dh4F92mG.js} +7 -15
  4. package/dist/chunks/pk-dialog-Dh4F92mG.js.map +1 -0
  5. package/dist/chunks/{pk-tiptap-content-DmS_2EUi.js → pk-tiptap-content-5UcUhLeB.js} +5 -2
  6. package/dist/chunks/pk-tiptap-content-5UcUhLeB.js.map +1 -0
  7. package/dist/chunks/{pk-tiptap-editor-DCgHtgoi.js → pk-tiptap-editor-C7tOOMC0.js} +6 -3
  8. package/dist/chunks/pk-tiptap-editor-C7tOOMC0.js.map +1 -0
  9. package/dist/chunks/{pk-tiptap-input-asrD-8W6.js → pk-tiptap-input-B8faxeqa.js} +5 -2
  10. package/dist/chunks/pk-tiptap-input-B8faxeqa.js.map +1 -0
  11. package/dist/chunks/{tiptap.styles-Cwb_cj9g.js → tiptap.styles-CUvGoddW.js} +72 -8
  12. package/dist/chunks/tiptap.styles-CUvGoddW.js.map +1 -0
  13. package/dist/components/connect/pk-connect.js +1 -1
  14. package/dist/components/dialog/pk-dialog.d.ts.map +1 -1
  15. package/dist/components/dialog/pk-dialog.js +1 -1
  16. package/dist/components/dialog.js +1 -1
  17. package/dist/components/tiptap/index.d.ts +1 -0
  18. package/dist/components/tiptap/index.d.ts.map +1 -1
  19. package/dist/components/tiptap/pk-tiptap-content.d.ts +3 -0
  20. package/dist/components/tiptap/pk-tiptap-content.d.ts.map +1 -1
  21. package/dist/components/tiptap/pk-tiptap-content.js +1 -1
  22. package/dist/components/tiptap/pk-tiptap-editor.d.ts +3 -0
  23. package/dist/components/tiptap/pk-tiptap-editor.d.ts.map +1 -1
  24. package/dist/components/tiptap/pk-tiptap-editor.js +1 -1
  25. package/dist/components/tiptap/pk-tiptap-input.d.ts +3 -0
  26. package/dist/components/tiptap/pk-tiptap-input.d.ts.map +1 -1
  27. package/dist/components/tiptap/pk-tiptap-input.js +1 -1
  28. package/dist/components/tiptap/tiptap.styles.d.ts.map +1 -1
  29. package/dist/components/tiptap/variable-tag-node-view.d.ts +7 -0
  30. package/dist/components/tiptap/variable-tag-node-view.d.ts.map +1 -1
  31. package/dist/components/tiptap-content.js +1 -1
  32. package/dist/components/tiptap-editor.js +1 -1
  33. package/dist/components/tiptap-input.js +1 -1
  34. package/dist/connect/register-cp-connect.js +1 -1
  35. package/dist/index.js +4 -4
  36. package/dist/register.js +4 -4
  37. package/dist/utils/craft-host-modal.d.ts +1 -0
  38. package/dist/utils/craft-host-modal.d.ts.map +1 -1
  39. package/dist-loader/chunks/{pk-dialog-BJs5fVHS.js → pk-dialog-ChX96jyg.js} +6 -14
  40. package/dist-loader/chunks/{tiptap.styles-CZUkf2K6.js → tiptap.styles-CJqK0Wft.js} +71 -7
  41. package/dist-loader/components/connect/connect.js +1 -1
  42. package/dist-loader/components/dialog/dialog.js +1 -1
  43. package/dist-loader/components/tiptap/tiptap-content.js +4 -1
  44. package/dist-loader/components/tiptap/tiptap-editor.js +5 -2
  45. package/dist-loader/components/tiptap/tiptap-input.js +4 -1
  46. package/package.json +7 -7
  47. package/dist/chunks/pk-dialog-C7KZGpQs.js.map +0 -1
  48. package/dist/chunks/pk-tiptap-content-DmS_2EUi.js.map +0 -1
  49. package/dist/chunks/pk-tiptap-editor-DCgHtgoi.js.map +0 -1
  50. package/dist/chunks/pk-tiptap-input-asrD-8W6.js.map +0 -1
  51. package/dist/chunks/tiptap.styles-Cwb_cj9g.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 2.0.27 - 2026-10-20
6
+
7
+ ### Fixed
8
+ - Restored transform name badges and orange default-value corner markers on variable tags across inputs, editors, and read-only content.
9
+
10
+ ## 2.0.26 - 2026-10-20
11
+
12
+ ### Fixed
13
+ - Fixed element pickers opening behind dialogs launched from Craft live preview or another modal.
14
+
5
15
  ## 2.0.25 - 2026-10-15
6
16
 
7
17
  ### Fixed
@@ -36904,6 +36904,15 @@
36904
36904
  "default": "''",
36905
36905
  "attribute": "value"
36906
36906
  },
36907
+ {
36908
+ "kind": "field",
36909
+ "name": "variableTransformerRegistry",
36910
+ "type": {
36911
+ "text": "PkVariableTransformerRegistry"
36912
+ },
36913
+ "default": "{}",
36914
+ "description": "Transform names displayed as badges on configured variable tags."
36915
+ },
36907
36916
  {
36908
36917
  "kind": "method",
36909
36918
  "name": "mountEditor",
@@ -37244,6 +37253,15 @@
37244
37253
  "attribute": "invalid",
37245
37254
  "reflects": true
37246
37255
  },
37256
+ {
37257
+ "kind": "field",
37258
+ "name": "variableTransformerRegistry",
37259
+ "type": {
37260
+ "text": "PkVariableTransformerRegistry"
37261
+ },
37262
+ "default": "{}",
37263
+ "description": "Transform names displayed as badges on configured variable tags."
37264
+ },
37247
37265
  {
37248
37266
  "kind": "field",
37249
37267
  "name": "variableTagConfigure",
@@ -39012,6 +39030,15 @@
39012
39030
  "default": "{}",
39013
39031
  "description": "Variable options used to resolve chip labels when hydrating from `{token}` strings.\nWithout this, saved field tokens fall back to UID title-casing after reload."
39014
39032
  },
39033
+ {
39034
+ "kind": "field",
39035
+ "name": "variableTransformerRegistry",
39036
+ "type": {
39037
+ "text": "PkVariableTransformerRegistry"
39038
+ },
39039
+ "default": "{}",
39040
+ "description": "Transform names displayed as badges on configured variable tags."
39041
+ },
39015
39042
  {
39016
39043
  "kind": "field",
39017
39044
  "name": "variableTagConfigure",
@@ -20,16 +20,7 @@ var isVisiblyShown = (element) => {
20
20
  const style = getComputedStyle(element);
21
21
  return style.display !== "none" && style.visibility !== "hidden" && Number.parseFloat(style.opacity || "1") > 0;
22
22
  };
23
- /** True when a Craft/Garnish modal or shade is present and visible. */
24
- function isCraftHostModalOpen(root = document) {
25
- const nodes = root.querySelectorAll(HOST_MODAL_SELECTOR);
26
- for (const node of nodes) {
27
- if (!(node instanceof HTMLElement)) continue;
28
- if (node.closest("pk-dialog")) continue;
29
- if (isVisiblyShown(node)) return true;
30
- }
31
- return false;
32
- }
23
+ var visibleHostModals = (root) => Array.from(root.querySelectorAll(HOST_MODAL_SELECTOR)).filter((node) => node instanceof HTMLElement && !node.closest("pk-dialog") && isVisiblyShown(node));
33
24
  /**
34
25
  * Watch the document for Craft modal mount/unmount and invoke `onChange`
35
26
  * whenever presence flips. Used by `pk-dialog` to leave/re-enter the top layer.
@@ -37,9 +28,11 @@ function isCraftHostModalOpen(root = document) {
37
28
  function observeCraftHostModal(onChange, options = {}) {
38
29
  const doc = options.getDocument?.() ?? document;
39
30
  const root = options.root ?? doc.body;
40
- let lastOpen = isCraftHostModalOpen(doc);
31
+ const existing = new Set(options.ignoreExisting ? visibleHostModals(doc) : []);
32
+ const hasNewModal = () => visibleHostModals(doc).some((node) => !existing.has(node));
33
+ let lastOpen = hasNewModal();
41
34
  const emit = () => {
42
- const next = isCraftHostModalOpen(doc);
35
+ const next = hasNewModal();
43
36
  if (next === lastOpen) return;
44
37
  lastOpen = next;
45
38
  onChange(next);
@@ -538,8 +531,7 @@ var PkDialog = class PkDialog extends PkElement {
538
531
  document.addEventListener("keydown", this.handleDocumentKeyDown);
539
532
  registerDismissible(this);
540
533
  this.hostModalObserver?.disconnect();
541
- this.hostModalObserver = observeCraftHostModal(this.onHostModalPresenceChange);
542
- this.onHostModalPresenceChange(isCraftHostModalOpen());
534
+ this.hostModalObserver = observeCraftHostModal(this.onHostModalPresenceChange, { ignoreExisting: true });
543
535
  }
544
536
  removeOpenListeners() {
545
537
  document.removeEventListener("keydown", this.handleDocumentKeyDown);
@@ -645,4 +637,4 @@ PkDialog = __decorate([customElement("pk-dialog")], PkDialog);
645
637
  //#endregion
646
638
  export { PkDialog as t };
647
639
 
648
- //# sourceMappingURL=pk-dialog-C7KZGpQs.js.map
640
+ //# sourceMappingURL=pk-dialog-Dh4F92mG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pk-dialog-Dh4F92mG.js","names":["xmark","_decorate"],"sources":["../../src/utils/craft-host-modal.ts","../../src/components/dialog/pk-dialog.styles.ts","../../src/components/dialog/pk-dialog.ts"],"sourcesContent":["/**\n * Craft CP Garnish modals (element selector, asset picker, …) live in normal\n * document stacking — not the browser top layer. Native `<dialog>.showModal()`\n * always paints above them, so open kit dialogs must briefly yield.\n */\n\nconst HOST_MODAL_SELECTOR = '.modal-shade, .modal';\n\nconst isVisiblyShown = (element: HTMLElement): boolean => {\n const style = getComputedStyle(element);\n\n return style.display !== 'none'\n && style.visibility !== 'hidden'\n && Number.parseFloat(style.opacity || '1') > 0;\n};\n\nconst visibleHostModals = (root: ParentNode): HTMLElement[] =>\n Array.from(root.querySelectorAll(HOST_MODAL_SELECTOR)).filter((node): node is HTMLElement =>\n node instanceof HTMLElement && !node.closest('pk-dialog') && isVisiblyShown(node),\n );\n\n/** True when a Craft/Garnish modal or shade is present and visible. */\nexport function isCraftHostModalOpen(root: ParentNode = document): boolean {\n return visibleHostModals(root).length > 0;\n}\n\nexport type CraftHostModalObserver = {\n disconnect: () => void;\n};\n\n/**\n * Watch the document for Craft modal mount/unmount and invoke `onChange`\n * whenever presence flips. Used by `pk-dialog` to leave/re-enter the top layer.\n */\nexport function observeCraftHostModal(\n onChange: (open: boolean) => void,\n options: { root?: ParentNode; getDocument?: () => Document; ignoreExisting?: boolean } = {},\n): CraftHostModalObserver {\n const doc = options.getDocument?.() ?? document;\n const root = options.root ?? doc.body;\n // A dialog opened from Preview owns a newer layer than Preview's shade.\n // Only later host modals should make it yield; an existing shade must not\n // mask the opening or closing of a child element picker.\n const existing = new Set(options.ignoreExisting ? visibleHostModals(doc) : []);\n const hasNewModal = () => visibleHostModals(doc).some(node => !existing.has(node));\n let lastOpen = hasNewModal();\n\n const emit = () => {\n const next = hasNewModal();\n if (next === lastOpen) {\n return;\n }\n lastOpen = next;\n onChange(next);\n };\n\n const observer = new MutationObserver(() => {\n emit();\n });\n\n observer.observe(root, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['class', 'style', 'hidden'],\n });\n\n // Craft sometimes toggles visibility a frame after insert.\n const intervalId = window.setInterval(emit, 250);\n\n return {\n disconnect: () => {\n observer.disconnect();\n window.clearInterval(intervalId);\n },\n };\n}\n","import { css } from 'lit';\n\nexport const pkDialogStyles = css`\n @layer pk-component {\n :host {\n /* Not display:contents — that flattens the trigger slot into flex parents\n (e.g. playground cards) and stretches pk-button full width, same class of\n bug as the dropdown host. Dialog host is display none/block, not contents. */\n display: inline-block;\n width: fit-content;\n max-width: 100%;\n align-self: flex-start;\n flex: none;\n vertical-align: middle;\n }\n\n /*\n * Controlled dialogs (no slot=\"trigger\") — panel is top-layer / fixed while\n * yielding. An inline-block host still sizes to the open <dialog> box in some\n * engines and expands parents (Formie nested field cards grow a blank gap).\n *\n * Zero box ≠ gone from the tree: Tailwind space-y-* uses :not(:last-child) on\n * DOM siblings, so an in-tree host still steals last-child and margins the\n * previous sibling. Prefer flex/grid gap-* (skips out-of-flow children), or\n * mount overlays outside the spaced stack. True light-DOM portal would also fix it.\n */\n :host(:not([data-has-trigger])) {\n position: absolute;\n width: 0;\n height: 0;\n max-width: none;\n margin: 0;\n padding: 0;\n overflow: visible;\n vertical-align: unset;\n }\n\n .dialog {\n display: flex;\n flex-direction: column;\n width: min(100%, var(--pk-dialog-width, var(--pk-dialog-max-width, 32rem)));\n min-width: var(--pk-dialog-min-width, 0);\n /* Keep UA :modal inset (0) — that + margin:auto centers the panel. Do not\n * unset inset; it breaks centering (field edit landed top-left). */\n height: var(--pk-dialog-height, fit-content);\n min-height: var(--pk-dialog-min-height, 0);\n max-height: var(--pk-dialog-max-height, calc(100vh - 2rem));\n margin: auto;\n padding: 0;\n /* v1 DialogContent: no CSS border — edge is the 1px ring inside --pk-shadow-modal. */\n border: 0;\n border-radius: var(--pk-radius-lg);\n background: var(--pk-color-white);\n box-shadow: var(--pk-shadow-modal);\n color: var(--pk-color-gray-900);\n overflow: hidden;\n opacity: 1;\n transform: scale(1);\n }\n\n .dialog:focus,\n .dialog:focus-visible {\n outline: none;\n }\n\n .dialog:not([open]) {\n display: none;\n }\n\n .dialog--wide {\n --pk-dialog-max-width: 42rem;\n }\n\n /* motion only via animateWithClass — never auto-animate on [open] alone. */\n .dialog.show {\n animation: pk-dialog-in 0.15s ease;\n }\n\n .dialog.hide {\n animation: pk-dialog-out 0.15s ease forwards;\n }\n\n .dialog.pulse {\n animation: pk-dialog-pulse 0.25s ease;\n }\n\n @keyframes pk-dialog-in {\n from {\n opacity: 0;\n transform: scale(0.95);\n }\n\n to {\n opacity: 1;\n transform: scale(1);\n }\n }\n\n @keyframes pk-dialog-out {\n from {\n opacity: 1;\n transform: scale(1);\n }\n\n to {\n opacity: 0;\n transform: scale(0.95);\n }\n }\n\n @keyframes pk-dialog-pulse {\n 0%, 100% {\n transform: scale(1);\n }\n\n 50% {\n transform: scale(0.98);\n }\n }\n\n .dialog.show::backdrop {\n animation: pk-dialog-backdrop-in 0.15s ease;\n }\n\n .dialog.hide::backdrop {\n animation: pk-dialog-backdrop-in 0.15s ease reverse;\n }\n\n .dialog::backdrop {\n background: hsl(from var(--pk-color-gray-900) h s l / 0.2);\n opacity: 1;\n }\n\n @keyframes pk-dialog-backdrop-in {\n from {\n opacity: 0;\n }\n\n to {\n opacity: 1;\n }\n }\n\n .header {\n position: relative;\n display: flex;\n flex-shrink: 0;\n flex-direction: column;\n gap: 0.2rem;\n padding: 1rem;\n border-bottom: 1px solid var(--pk-color-gray-150);\n border-radius: var(--pk-radius-lg) var(--pk-radius-lg) 0 0;\n background: #f3f7fb;\n text-align: left;\n }\n\n .title {\n margin: 0;\n padding-inline-end: 2rem;\n font-size: 0.9375rem;\n font-weight: 600;\n line-height: 1.2;\n color: var(--pk-color-gray-900);\n }\n\n .description {\n margin: 0;\n padding-inline-end: 2rem;\n font-size: 0.75rem;\n font-weight: 400;\n line-height: 1.4;\n color: var(--pk-color-gray-500);\n }\n\n .close {\n --pk-dialog-close-focus-padding: 0.25rem;\n position: absolute;\n top: calc(1rem - var(--pk-dialog-close-focus-padding));\n right: calc(1rem - var(--pk-dialog-close-focus-padding));\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: calc(1.125rem + 2 * var(--pk-dialog-close-focus-padding));\n height: calc(1.125rem + 2 * var(--pk-dialog-close-focus-padding));\n margin: 0;\n padding: var(--pk-dialog-close-focus-padding);\n border: 0;\n border-radius: var(--pk-radius-sm);\n background: transparent;\n color: var(--pk-color-gray-600);\n cursor: pointer;\n line-height: 0;\n opacity: 0.7;\n transition: opacity 0.12s ease;\n box-sizing: border-box;\n }\n\n .close-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n line-height: 0;\n }\n\n .close-icon svg {\n display: block;\n width: 1.125rem;\n height: 1.125rem;\n }\n\n .close:hover {\n opacity: 1;\n background: transparent;\n }\n\n .close:focus-visible {\n opacity: 1;\n box-shadow: 0 0 0 2px var(--pk-color-gray-600);\n }\n\n .body {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n padding: 0;\n /* v1 DialogContent inherited CP text defaults (14px / gray-700) — do not\n * downshift body copy to sm/gray-600 or slotted content reads smaller than v1. */\n font-size: var(--pk-font-size-base);\n line-height: 1.5;\n color: var(--pk-color-gray-700);\n }\n\n .body--padded {\n padding: 1rem;\n }\n\n .footer {\n display: flex;\n flex-shrink: 0;\n flex-direction: row;\n justify-content: flex-end;\n gap: 0.5rem;\n padding: 0.625rem 1rem;\n border-top: 1px solid var(--pk-color-gray-150);\n border-radius: 0 0 var(--pk-radius-lg) var(--pk-radius-lg);\n background: #e4edf6;\n }\n }\n`;\n","import { html, nothing } from 'lit';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { customElement, property, query, state } from '../../decorators.js';\nimport type { PropertyValues } from 'lit';\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js';\n\nimport { isTopDismissible, registerDismissible, unregisterDismissible } from '../../a11y/dismissible-stack.js';\nimport { lockBodyScrolling, unlockBodyScrolling } from '../../a11y/scroll-lock.js';\nimport { PkElement } from '../../base/pk-element.js';\nimport { xmark, renderIconHtml } from '../../icons/index.js';\nimport {\n PkAfterHideEvent,\n PkAfterShowEvent,\n PkHideEvent,\n PkShowEvent,\n type PkOverlaySource,\n} from '../../events/overlay-lifecycle.js';\nimport { animateWithClass } from '../../utils/animate-with-class.js';\nimport { observeCraftHostModal, type CraftHostModalObserver } from '../../utils/craft-host-modal.js';\nimport { pkDialogStyles } from './pk-dialog.styles.js';\n\nconst CLOSE_ICON = renderIconHtml(xmark);\n\n/**\n * Modal dialog — literal `pk-dialog` lifecycle with Plugin Kit styling.\n *\n * Craft CP Garnish modals (asset/element selectors) are not top-layer. While one\n * is open, this dialog temporarily uses `show()` instead of `showModal()` so the\n * Craft UI can stack above — same interop intent as v1 Base UI dialog + `.modal`.\n *\n * @slot trigger - Opens the dialog (optional — use `open` for declarative control)\n * @slot header - Custom header region (replaces the built-in `label` header)\n * @slot label - Dialog title\n * @slot footer - Dialog footer actions\n * @slot - Dialog body\n *\n * @csspart panel - Native dialog element\n * @csspart header - Header region\n * @csspart body - Body region\n * @csspart footer - Footer region\n */\n@customElement('pk-dialog')\nexport class PkDialog extends PkElement {\n static override styles = pkDialogStyles;\n\n @property({ type: Boolean, reflect: true })\n open = false;\n\n @property()\n label = '';\n\n /** Optional subtitle under the title in the built-in header (v1 DialogDescription). */\n @property()\n description = '';\n\n /** Maps to `light-dismiss` (inverted). */\n @property({ attribute: 'disable-pointer-dismissal', type: Boolean, reflect: true })\n disablePointerDismissal = false;\n\n @property({ attribute: 'without-header', type: Boolean, reflect: true })\n withoutHeader = false;\n\n /**\n * Opt out of the default 1rem body padding applied when the built-in header is shown.\n * Use for flush layouts (sidebars, full-bleed pickers) that own their own inset.\n */\n @property({ attribute: 'without-body-padding', type: Boolean, reflect: true })\n withoutBodyPadding = false;\n\n /**\n * Skip document scroll lock while open. Useful for labs / rare cases where the\n * page should keep scrolling under the modal (native dialog still traps focus).\n */\n @property({ attribute: 'disable-scroll-lock', type: Boolean, reflect: true })\n disableScrollLock = false;\n\n @property({ reflect: true })\n size: 'default' | 'wide' = 'default';\n\n @query('dialog')\n private dialogElement!: HTMLDialogElement;\n\n @state()\n private triggerElement: HTMLElement | null = null;\n\n private previouslyFocused: HTMLElement | null = null;\n\n /** True while demoted from `showModal` so a Craft Garnish modal can stack above. */\n private yieldingToHostModal = false;\n\n private hostModalObserver: CraftHostModalObserver | null = null;\n\n /** Inline box captured before yield — cleared on restore. */\n private yieldBox: { top: number; left: number; width: number; height: number } | null = null;\n\n /** Light-DOM `slot=\"header\"` only — ignore built-in header fallback inside the shadow slot. */\n private hasCustomHeaderSlot(): boolean {\n return this.querySelector(':scope > [slot=\"header\"]') !== null;\n }\n\n private handleDocumentKeyDown = (event: KeyboardEvent): void => {\n // Craft modal owns Escape while we have yielded the top layer.\n if (this.yieldingToHostModal) {\n return;\n }\n\n if (event.key === 'Escape' && this.open && isTopDismissible(this)) {\n event.preventDefault();\n event.stopPropagation();\n void this.requestClose('escape');\n }\n };\n\n /** Pin modeless dialog to the viewport box it had under `showModal`. */\n private applyYieldPosition(box: { top: number; left: number; width: number; height: number }): void {\n const el = this.dialogElement;\n el.style.position = 'fixed';\n el.style.top = `${box.top}px`;\n el.style.left = `${box.left}px`;\n el.style.width = `${box.width}px`;\n el.style.height = `${box.height}px`;\n el.style.margin = '0';\n el.style.maxHeight = 'none';\n // Below typical Garnish.Modal z-index (≥100); keeps page chrome from covering us.\n el.style.zIndex = '99';\n el.toggleAttribute('data-yielding', true);\n }\n\n private clearYieldPosition(): void {\n const el = this.dialogElement;\n if (!el) {\n return;\n }\n\n el.style.position = '';\n el.style.top = '';\n el.style.left = '';\n el.style.width = '';\n el.style.height = '';\n el.style.margin = '';\n el.style.maxHeight = '';\n el.style.zIndex = '';\n el.removeAttribute('data-yielding');\n this.yieldBox = null;\n }\n\n /** Demote `showModal` → `show` so Craft Garnish can paint above (not inert/under). */\n private yieldToHostModal(): void {\n if (this.yieldingToHostModal || !this.open || !this.dialogElement?.open) {\n return;\n }\n\n // Capture centered modal box before leaving the top layer — `show()` is\n // in-flow and would otherwise jump to the host's layout position.\n const rect = this.dialogElement.getBoundingClientRect();\n this.yieldBox = {\n top: rect.top,\n left: rect.left,\n width: rect.width,\n height: rect.height,\n };\n this.yieldingToHostModal = true;\n\n try {\n this.dialogElement.close();\n this.dialogElement.show();\n this.applyYieldPosition(this.yieldBox);\n } catch {\n this.yieldingToHostModal = false;\n this.clearYieldPosition();\n }\n }\n\n /** Restore top-layer modal after Craft Garnish closes. */\n private restoreFromHostModal(): void {\n if (!this.yieldingToHostModal) {\n return;\n }\n\n this.yieldingToHostModal = false;\n this.clearYieldPosition();\n\n if (!this.open || !this.dialogElement) {\n return;\n }\n\n try {\n if (this.dialogElement.open) {\n this.dialogElement.close();\n }\n this.dialogElement.showModal();\n } catch {\n /* noop — next open cycle will recover */\n }\n }\n\n private onHostModalPresenceChange = (hostModalOpen: boolean): void => {\n if (hostModalOpen) {\n this.yieldToHostModal();\n } else {\n this.restoreFromHostModal();\n }\n };\n\n override firstUpdated(): void {\n // Mount-with-open (React `{open && <Dialog open>}` / `<Dialog open>`) must\n // use show() so the enter animation runs. A bare showModal() here used to\n // open instantly, then updated()→show() no-op'd because dialogElement.open\n // was already true — page-settings (always mounted, open toggled) still\n // animated because it only went through show().\n if (this.open) {\n void this.show();\n }\n }\n\n override disconnectedCallback(): void {\n if (!this.disableScrollLock) {\n unlockBodyScrolling(this);\n }\n\n this.removeOpenListeners();\n super.disconnectedCallback();\n }\n\n override updated(changed: PropertyValues): void {\n super.updated(changed);\n\n if (!changed.has('open') || !this.hasUpdated) {\n return;\n }\n\n this.handleOpenChange();\n }\n\n /** `handleOpenChange` — declarative `open` drives show/close. */\n private handleOpenChange(): void {\n if (this.open && !this.dialogElement.open) {\n void this.show();\n } else if (!this.open && this.dialogElement.open) {\n this.open = true;\n void this.requestClose('api');\n }\n }\n\n private showing = false;\n\n /** Shows the dialog — `show()`. */\n async show(_source: PkOverlaySource = 'api'): Promise<void> {\n if (this.showing || this.dialogElement?.open) {\n return;\n }\n\n this.showing = true;\n\n try {\n const showEvent = new PkShowEvent();\n\n if (!this.dispatchEvent(showEvent)) {\n this.open = false;\n return;\n }\n\n this.addOpenListeners();\n this.previouslyFocused = document.activeElement as HTMLElement | null;\n this.open = true;\n this.dialogElement.showModal();\n\n if (!this.disableScrollLock) {\n lockBodyScrolling(this);\n }\n\n requestAnimationFrame(() => {\n const elementToFocus = this.querySelector<HTMLElement>('[autofocus]');\n\n if (elementToFocus) {\n const innerControl = elementToFocus.shadowRoot?.querySelector<HTMLElement>(\n 'input, textarea, select, button',\n );\n\n (innerControl ?? elementToFocus).focus({ preventScroll: true });\n return;\n }\n\n this.dialogElement.focus({ preventScroll: true });\n });\n\n await animateWithClass(this.dialogElement, 'show');\n\n this.dispatchEvent(new CustomEvent('pk-open-change', {\n detail: { open: true },\n bubbles: true,\n composed: true,\n }));\n this.dispatchEvent(new PkAfterShowEvent());\n } finally {\n this.showing = false;\n }\n }\n\n async hide(source: PkOverlaySource = 'unknown'): Promise<void> {\n await this.requestClose(source);\n }\n\n closeDialog(): void {\n void this.requestClose('close-button');\n }\n\n /** `requestClose()`. */\n async requestClose(source: PkOverlaySource | EventTarget = 'unknown'): Promise<void> {\n const overlaySource: PkOverlaySource = typeof source === 'string'\n ? source\n : 'close-button';\n\n const hideEvent = new PkHideEvent(overlaySource);\n\n if (!this.dispatchEvent(hideEvent)) {\n this.open = true;\n await animateWithClass(this.dialogElement, 'pulse');\n return;\n }\n\n this.removeOpenListeners();\n await animateWithClass(this.dialogElement, 'hide');\n this.open = false;\n this.dialogElement.close();\n\n if (!this.disableScrollLock) {\n unlockBodyScrolling(this);\n }\n\n const restoreFocus = this.previouslyFocused;\n this.previouslyFocused = null;\n\n if (restoreFocus?.isConnected) {\n window.setTimeout(() => {\n restoreFocus.focus({ preventScroll: true });\n }, 0);\n }\n\n this.dispatchEvent(new PkAfterHideEvent());\n this.dispatchEvent(new CustomEvent('pk-open-change', {\n detail: { open: false },\n bubbles: true,\n composed: true,\n }));\n }\n\n /** Recovery hook — clears hung modal state from overlay races. */\n forceOverlayReset(): void {\n this.open = false;\n this.yieldingToHostModal = false;\n this.clearYieldPosition();\n this.removeOpenListeners();\n\n if (this.dialogElement?.open) {\n try {\n this.dialogElement.close();\n } catch {\n /* noop */\n }\n }\n\n this.dialogElement?.classList.remove('hide', 'show', 'pulse');\n\n if (!this.disableScrollLock) {\n unlockBodyScrolling(this);\n }\n }\n\n private addOpenListeners(): void {\n document.addEventListener('keydown', this.handleDocumentKeyDown);\n registerDismissible(this);\n this.hostModalObserver?.disconnect();\n this.hostModalObserver = observeCraftHostModal(this.onHostModalPresenceChange, { ignoreExisting: true });\n }\n\n private removeOpenListeners(): void {\n document.removeEventListener('keydown', this.handleDocumentKeyDown);\n unregisterDismissible(this);\n this.hostModalObserver?.disconnect();\n this.hostModalObserver = null;\n this.yieldingToHostModal = false;\n this.clearYieldPosition();\n }\n\n private handleDialogCancel = (event: Event): void => {\n event.preventDefault();\n\n if (!this.dialogElement.classList.contains('hide') && isTopDismissible(this)) {\n void this.requestClose('escape');\n }\n };\n\n private handleDialogClick = (event: Event): void => {\n const closeViaPath = event.composedPath().some(\n (node): node is Element =>\n node instanceof Element && node.matches('[data-dialog=\"close\"], [data-dialog-close]'),\n );\n\n if (closeViaPath) {\n event.stopPropagation();\n void this.requestClose('close-button');\n }\n };\n\n private handleDialogPointerDown = async (event: Event): Promise<void> => {\n if (event.target !== this.dialogElement) {\n return;\n }\n\n // Nested overlays (dropdown / select / combobox) register above us on the\n // dismissible stack. Their capture-phase light-dismiss runs first; skip closing\n // the dialog for the same click so “click off the menu” doesn’t also dismiss us.\n if (!isTopDismissible(this)) {\n return;\n }\n\n if (!this.disablePointerDismissal) {\n void this.requestClose('pointer-dismiss');\n return;\n }\n\n await animateWithClass(this.dialogElement, 'pulse');\n };\n\n private syncHasTriggerAttribute(): void {\n // Drives :host(:not([data-has-trigger])) zero-footprint layout (see styles).\n this.toggleAttribute('data-has-trigger', Boolean(this.triggerElement));\n }\n\n private onTriggerSlotChange(event: Event): void {\n const slot = event.target as HTMLSlotElement;\n const [trigger] = slot.assignedElements({ flatten: true }) as HTMLElement[];\n\n if (this.triggerElement) {\n this.triggerElement.removeEventListener('click', this.onTriggerClick);\n }\n\n this.triggerElement = trigger ?? null;\n this.syncHasTriggerAttribute();\n\n if (this.triggerElement) {\n this.triggerElement.addEventListener('click', this.onTriggerClick);\n }\n }\n\n private onTriggerClick = (event: Event): void => {\n event.preventDefault();\n this.open = true;\n };\n\n /** Re-render when footer actions are added/removed so the footer is not shown empty. */\n private onFooterSlotChange = (): void => {\n this.requestUpdate();\n };\n\n override render() {\n const showBuiltInHeader = !this.hasCustomHeaderSlot()\n && !this.withoutHeader\n && Boolean(this.label);\n const padBody = showBuiltInHeader && !this.withoutBodyPadding;\n const hasFooter = this.querySelector(':scope > [slot=\"footer\"]') !== null;\n\n return html`\n <slot name=\"trigger\" @slotchange=${this.onTriggerSlotChange}></slot>\n <dialog\n part=\"panel\"\n class=${classMap({\n dialog: true,\n open: this.open,\n 'dialog--wide': this.size === 'wide',\n })}\n tabindex=\"-1\"\n @cancel=${this.handleDialogCancel}\n @click=${this.handleDialogClick}\n @pointerdown=${this.handleDialogPointerDown}\n >\n <slot name=\"header\">\n ${showBuiltInHeader\n ? html`\n <header part=\"header\" class=\"header\">\n <h2 part=\"title\" class=\"title\">\n <slot name=\"label\">${this.label}</slot>\n </h2>\n ${this.description\n ? html`\n <p part=\"description\" class=\"description\">\n <slot name=\"description\">${this.description}</slot>\n </p>\n `\n : html`<slot name=\"description\" hidden></slot>`}\n <button type=\"button\" class=\"close\" data-dialog=\"close\" aria-label=\"Close\">\n <span class=\"close-icon\" aria-hidden=\"true\">${unsafeSVG(CLOSE_ICON)}</span>\n </button>\n </header>\n `\n : nothing}\n </slot>\n <div\n part=\"body\"\n class=${classMap({\n body: true,\n 'body--padded': padBody,\n })}\n >\n <slot></slot>\n </div>\n ${hasFooter\n ? html`\n <footer part=\"footer\" class=\"footer\">\n <slot name=\"footer\" @slotchange=${this.onFooterSlotChange}></slot>\n </footer>\n `\n : html`<slot name=\"footer\" @slotchange=${this.onFooterSlotChange} hidden></slot>`}\n </dialog>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'pk-dialog': PkDialog;\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { i as customElement, n as PkElement, t as __decorate } from "./decorate-Br_PE9pq.js";
2
2
  import { n as query, t as property } from "./decorators-BkErmuYK.js";
3
- import { i as createVariableTagDomNodeView, t as tiptapContentProseMirrorStyles } from "./tiptap.styles-Cwb_cj9g.js";
3
+ import { a as refreshVariableTagPresentation, i as createVariableTagDomNodeView, t as tiptapContentProseMirrorStyles } from "./tiptap.styles-CUvGoddW.js";
4
4
  import { css, html } from "lit";
5
5
  import { Editor } from "@tiptap/core";
6
6
  import { createTiptapExtensions, valueToContent } from "@verbb/plugin-kit-tiptap-core";
@@ -30,6 +30,7 @@ var PkTiptapContent = class PkTiptapContent extends PkElement {
30
30
  super(..._args);
31
31
  this.editor = null;
32
32
  this.value = "";
33
+ this.variableTransformerRegistry = {};
33
34
  }
34
35
  static {
35
36
  this.styles = [pkTiptapContentStyles, tiptapContentProseMirrorStyles];
@@ -40,6 +41,7 @@ var PkTiptapContent = class PkTiptapContent extends PkElement {
40
41
  super.disconnectedCallback();
41
42
  }
42
43
  updated(changed) {
44
+ if (changed.has("variableTransformerRegistry")) refreshVariableTagPresentation(this);
43
45
  if (changed.has("value") && this.editor) this.syncContent();
44
46
  super.updated(changed);
45
47
  }
@@ -72,8 +74,9 @@ var PkTiptapContent = class PkTiptapContent extends PkElement {
72
74
  };
73
75
  __decorate([query(".editor-mount")], PkTiptapContent.prototype, "editorMount", void 0);
74
76
  __decorate([property({ attribute: "value" })], PkTiptapContent.prototype, "value", void 0);
77
+ __decorate([property({ attribute: false })], PkTiptapContent.prototype, "variableTransformerRegistry", void 0);
75
78
  PkTiptapContent = __decorate([customElement("pk-tiptap-content")], PkTiptapContent);
76
79
  //#endregion
77
80
  export { PkTiptapContent as t };
78
81
 
79
- //# sourceMappingURL=pk-tiptap-content-DmS_2EUi.js.map
82
+ //# sourceMappingURL=pk-tiptap-content-5UcUhLeB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pk-tiptap-content-5UcUhLeB.js","names":["_decorate"],"sources":["../../src/components/tiptap/pk-tiptap-content.styles.ts","../../src/components/tiptap/pk-tiptap-content.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const pkTiptapContentStyles = css`\n @layer pk-component {\n :host {\n display: block;\n width: 100%;\n /* Inherit light-DOM color/size (warning banners, badges). Tokens override when set. */\n color: var(--pk-tiptap-content-color, inherit);\n font-family: var(--pk-font-family);\n font-size: var(--pk-tiptap-content-font-size, inherit);\n line-height: var(--pk-tiptap-content-line-height, 1.4);\n }\n }\n`;\n","import { html } from 'lit';\nimport { customElement, property, query } from '../../decorators.js';\nimport type { PropertyValues } from 'lit';\nimport { Editor } from '@tiptap/core';\nimport {\n createTiptapExtensions,\n valueToContent,\n} from '@verbb/plugin-kit-tiptap-core';\n\nimport { PkElement } from '../../base/pk-element.js';\nimport {\n createVariableTagDomNodeView,\n refreshVariableTagPresentation,\n type PkVariableTransformerRegistry,\n} from './variable-tag-node-view.js';\nimport { pkTiptapContentStyles } from './pk-tiptap-content.styles.js';\nimport { tiptapContentProseMirrorStyles } from './tiptap.styles.js';\n\nfunction serializeContent(doc: ReturnType<typeof valueToContent>): string {\n if (!doc) {\n return '[]';\n }\n\n if (Array.isArray(doc.content)) {\n return JSON.stringify(doc.content);\n }\n\n return JSON.stringify(doc);\n}\n\n/**\n * Read-only TipTap / ProseMirror renderer.\n *\n * Pass the same `value` shapes as TiptapEditor: node array, doc object, or JSON string.\n */\n@customElement('pk-tiptap-content')\nexport class PkTiptapContent extends PkElement {\n static override styles = [pkTiptapContentStyles, tiptapContentProseMirrorStyles];\n\n @query('.editor-mount')\n private editorMount!: HTMLDivElement;\n\n private editor: Editor | null = null;\n\n @property({ attribute: 'value' })\n value = '';\n\n /** Transform names displayed as badges on configured variable tags. */\n @property({ attribute: false })\n variableTransformerRegistry: PkVariableTransformerRegistry = {};\n\n override disconnectedCallback(): void {\n this.editor?.destroy();\n this.editor = null;\n super.disconnectedCallback();\n }\n\n override updated(changed: PropertyValues): void {\n if (changed.has('variableTransformerRegistry')) {\n refreshVariableTagPresentation(this);\n }\n\n if (changed.has('value') && this.editor) {\n this.syncContent();\n }\n\n super.updated(changed);\n }\n\n override firstUpdated(): void {\n this.mountEditor();\n }\n\n private mountEditor(): void {\n this.editor = new Editor({\n element: this.editorMount,\n extensions: createTiptapExtensions({\n variableTagNodeView: createVariableTagDomNodeView(),\n surface: 'content',\n }),\n content: valueToContent(this.value),\n editable: false,\n });\n }\n\n private syncContent(): void {\n if (!this.editor) {\n return;\n }\n\n const doc = valueToContent(this.value) ?? { type: 'doc', content: [] };\n const incoming = serializeContent(valueToContent(this.value));\n const current = serializeContent(this.editor.getJSON() as ReturnType<typeof valueToContent>);\n\n if (incoming === current) {\n return;\n }\n\n this.editor.commands.setContent(doc);\n }\n\n override render() {\n return html`<div class=\"editor-mount\" part=\"content\"></div>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'pk-tiptap-content': PkTiptapContent;\n }\n}\n"],"mappings":";;;;;;;AAEA,IAAa,wBAAwB,GAAG;;;;;;;;;;;;;;;ACgBxC,SAAS,iBAAiB,KAAgD;CACtE,IAAI,CAAC,KACD,OAAO;CAGX,IAAI,MAAM,QAAQ,IAAI,OAAO,GACzB,OAAO,KAAK,UAAU,IAAI,OAAO;CAGrC,OAAO,KAAK,UAAU,GAAG;AAC7B;AAQO,IAAM,kBAAN,MAAM,wBAAwB,UAAU;;;EAMX,KAAA,SAAA;EAGxB,KAAA,QAAA;EAIqD,KAAA,8BAAA,CAAC;;;EAZrC,KAAA,SAAA,CAAC,uBAAuB,8BAA8B;;CAc/E,uBAAsC;EAClC,KAAK,QAAQ,QAAQ;EACrB,KAAK,SAAS;EACd,MAAM,qBAAqB;CAC/B;CAEA,QAAiB,SAA+B;EAC5C,IAAI,QAAQ,IAAI,6BAA6B,GACzC,+BAA+B,IAAI;EAGvC,IAAI,QAAQ,IAAI,OAAO,KAAK,KAAK,QAC7B,KAAK,YAAY;EAGrB,MAAM,QAAQ,OAAO;CACzB;CAEA,eAA8B;EAC1B,KAAK,YAAY;CACrB;CAEA,cAA4B;EACxB,KAAK,SAAS,IAAI,OAAO;GACrB,SAAS,KAAK;GACd,YAAY,uBAAuB;IAC/B,qBAAqB,6BAA6B;IAClD,SAAS;GACb,CAAC;GACD,SAAS,eAAe,KAAK,KAAK;GAClC,UAAU;EACd,CAAC;CACL;CAEA,cAA4B;EACxB,IAAI,CAAC,KAAK,QACN;EAGJ,MAAM,MAAM,eAAe,KAAK,KAAK,KAAK;GAAE,MAAM;GAAO,SAAS,CAAC;EAAE;EAIrE,IAHiB,iBAAiB,eAAe,KAAK,KAAK,CAGvD,MAFY,iBAAiB,KAAK,OAAO,QAAQ,CAEpC,GACb;EAGJ,KAAK,OAAO,SAAS,WAAW,GAAG;CACvC;CAEA,SAAkB;EACd,OAAO,IAAI;CACf;AACJ;AAjEKA,WAAA,CAAA,MAAM,eAAe,CAAA,GAAA,gBAAA,WAAA,eAAA,KAAA,CAAA;AAKrBA,WAAA,CAAA,SAAS,EAAE,WAAW,QAAQ,CAAC,CAAA,GAAA,gBAAA,WAAA,SAAA,KAAA,CAAA;AAI/BA,WAAA,CAAA,SAAS,EAAE,WAAW,MAAM,CAAC,CAAA,GAAA,gBAAA,WAAA,+BAAA,KAAA,CAAA;AAbjC,kBAAAA,WAAA,CAAA,cAAc,mBAAmB,CAAA,GAAA,eAAA"}
@@ -9,14 +9,14 @@ import "./pk-checkbox-L5uRex3b.js";
9
9
  import { t as formControlStyles } from "./form-control.styles-CQ93gnVf.js";
10
10
  import { i as uniqueId } from "./focus-DcVUPVqn.js";
11
11
  import "./pk-input-BUbXj9We.js";
12
- import "./pk-dialog-C7KZGpQs.js";
12
+ import "./pk-dialog-Dh4F92mG.js";
13
13
  import "./pk-dropdown-item-Ck2N_suK.js";
14
14
  import "./pk-dropdown-menu-DBsO1uYR.js";
15
15
  import "./pk-dropdown-label-BdZLeizJ.js";
16
16
  import "../components/dropdown-menu/pk-dropdown-separator.js";
17
17
  import "./pk-field--PCE9nOd.js";
18
18
  import "./pk-tooltip-Cvv2f7T5.js";
19
- import { i as createVariableTagDomNodeView, r as tiptapProseMirrorStyles } from "./tiptap.styles-Cwb_cj9g.js";
19
+ import { a as refreshVariableTagPresentation, i as createVariableTagDomNodeView, r as tiptapProseMirrorStyles } from "./tiptap.styles-CUvGoddW.js";
20
20
  import { css, html, nothing } from "lit";
21
21
  import { unsafeSVG } from "lit/directives/unsafe-svg.js";
22
22
  import { Editor, getMarkRange, posToDOMRect } from "@tiptap/core";
@@ -597,6 +597,7 @@ var PkTiptapEditor = class PkTiptapEditor extends PkFormAssociatedElement {
597
597
  this.placeholder = "";
598
598
  this.readonly = false;
599
599
  this.invalid = false;
600
+ this.variableTransformerRegistry = {};
600
601
  this.variableTagConfigure = null;
601
602
  this.invalidContentMessage = "";
602
603
  this.toolbarTooltips = true;
@@ -730,6 +731,7 @@ var PkTiptapEditor = class PkTiptapEditor extends PkFormAssociatedElement {
730
731
  super.disconnectedCallback();
731
732
  }
732
733
  updated(changed) {
734
+ if (changed.has("variableTransformerRegistry")) refreshVariableTagPresentation(this);
733
735
  if (changed.has("value") && !changed.has("defaultValue")) this.syncEditorContent();
734
736
  if (changed.has("defaultValue") && !this.valueHasChanged) this.syncEditorContent();
735
737
  if (changed.has("disabled") || changed.has("readonly")) this.host.editor?.setEditable(!this.disabled && !this.readonly);
@@ -1382,6 +1384,7 @@ __decorate([property({
1382
1384
  type: Boolean,
1383
1385
  reflect: true
1384
1386
  })], PkTiptapEditor.prototype, "invalid", void 0);
1387
+ __decorate([property({ attribute: false })], PkTiptapEditor.prototype, "variableTransformerRegistry", void 0);
1385
1388
  __decorate([property({ attribute: false })], PkTiptapEditor.prototype, "variableTagConfigure", void 0);
1386
1389
  __decorate([property({ attribute: "invalid-content-message" })], PkTiptapEditor.prototype, "invalidContentMessage", void 0);
1387
1390
  __decorate([property({
@@ -1404,4 +1407,4 @@ PkTiptapEditor = __decorate([customElement("pk-tiptap-editor")], PkTiptapEditor)
1404
1407
  //#endregion
1405
1408
  export { PkTiptapEditor as t };
1406
1409
 
1407
- //# sourceMappingURL=pk-tiptap-editor-DCgHtgoi.js.map
1410
+ //# sourceMappingURL=pk-tiptap-editor-C7tOOMC0.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pk-tiptap-editor-C7tOOMC0.js","names":["chevronDown","bold","italic","underline","strikethrough","subscript","superscript","smallCaps","bracketsCurly","code","highlighter","h1","h2","h3","h4","h5","h6","heading","paragraph","listUl","listOl","quoteRight","alignLeft","alignCenter","alignRight","alignJustify","textSlash","minus","fileDashedLine","link","table","arrowRotateLeft","arrowRotateRight","triangleExclamation","_decorate"],"sources":["../../src/components/tiptap/tiptap-editor-host.ts","../../src/components/tiptap/tiptap-utils.ts","../../src/components/tiptap/tiptap-toolbar.ts","../../src/components/tiptap/pk-tiptap-editor.styles.ts","../../src/components/tiptap/pk-tiptap-editor.ts"],"sourcesContent":["import { Editor, type Extensions } from '@tiptap/core';\nimport {\n createTiptapExtensions,\n normalizeContentArray,\n valueToContent,\n} from '@verbb/plugin-kit-tiptap-core';\n\nexport function serializeTiptapDocumentContent(content: unknown): string {\n return JSON.stringify(normalizeContentArray(content));\n}\n\n/** Normalize React/HTML `value` into the JSON string the editor stores and emits. */\nexport function serializeTiptapDocumentValue(raw: string | unknown[] | null | undefined): string {\n if (raw == null) {\n return '[]';\n }\n\n if (typeof raw === 'string') {\n return raw;\n }\n\n if (Array.isArray(raw)) {\n return JSON.stringify(raw);\n }\n\n return '[]';\n}\n\nexport function parseTiptapDocumentValue(raw: string | unknown[] | null | undefined): unknown[] {\n if (raw == null || raw === '') {\n return [];\n }\n\n // React often passes a document array prop — accept it without JSON.parse.\n if (Array.isArray(raw)) {\n return raw;\n }\n\n if (typeof raw !== 'string') {\n return [];\n }\n\n try {\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\nexport type TiptapEditorHostOptions = {\n element: HTMLElement;\n extensions?: Extensions;\n content: unknown;\n editable: boolean;\n trailingCursorText?: string;\n minHeight?: string;\n onUpdate?: (content: unknown[]) => void;\n};\n\nexport class TiptapEditorHost {\n editor: Editor | null = null;\n\n private lastEmitted: string | null = null;\n\n /** Skip TipTap `onUpdate` while applying controlled prop content — otherwise setContent\n * re-emits pk-change → React setValue → value prop → setContent … forever. */\n private suppressUpdateEmission = false;\n\n mount({\n element,\n extensions,\n content,\n editable,\n trailingCursorText = '\\u2060',\n minHeight,\n onUpdate,\n }: TiptapEditorHostOptions): void {\n const doc = valueToContent(content, { trailingCursorText });\n\n this.editor = new Editor({\n element,\n extensions: extensions ?? createTiptapExtensions({ trailingCursorText }),\n content: doc,\n editable,\n onUpdate: ({ editor }) => {\n const normalized = normalizeContentArray(editor.getJSON().content);\n const serialized = JSON.stringify(normalized);\n this.lastEmitted = serialized;\n\n if (this.suppressUpdateEmission) {\n return;\n }\n\n onUpdate?.(normalized);\n },\n });\n\n if (minHeight) {\n this.editor.view.dom.style.minHeight = minHeight;\n }\n }\n\n setContent(content: unknown, options: { trailingCursorText?: string; respectFocus?: boolean } = {}): void {\n if (!this.editor) {\n return;\n }\n\n const { trailingCursorText = '\\u2060', respectFocus = true } = options;\n\n if (respectFocus && this.editor.isFocused) {\n return;\n }\n\n const doc = valueToContent(content, { trailingCursorText });\n const incoming = JSON.stringify(doc?.content ?? []);\n const current = JSON.stringify(this.editor.getJSON().content ?? []);\n\n if (incoming === current || incoming === this.lastEmitted) {\n return;\n }\n\n this.suppressUpdateEmission = true;\n try {\n this.editor.commands.setContent(doc ?? { type: 'doc', content: [] });\n } finally {\n this.suppressUpdateEmission = false;\n }\n }\n\n destroy(): void {\n this.editor?.destroy();\n this.editor = null;\n this.lastEmitted = null;\n this.suppressUpdateEmission = false;\n }\n}\n","import type {\n ElementSelectorHost,\n LinkOptionsInput,\n ToolbarNode,\n} from '@verbb/plugin-kit-tiptap-core';\nimport { parseToolbarConfig } from '@verbb/plugin-kit-tiptap-core';\n\ndeclare global {\n interface Window {\n Craft?: {\n createElementSelectorModal?: ElementSelectorHost['openElementSelector'];\n };\n }\n}\n\nexport function createCraftElementSelectorHost(): ElementSelectorHost {\n return {\n openElementSelector: (elementType, options) => {\n const craft = window.Craft;\n\n if (!craft?.createElementSelectorModal) {\n throw new Error('Craft element selector is not available in this environment.');\n }\n\n // Craft reads its selector registry through `this`, so preserve the global as receiver.\n craft.createElementSelectorModal(elementType, options);\n },\n };\n}\n\nexport function parseLinkOptionsAttribute(raw: string | null): LinkOptionsInput | undefined {\n if (!raw) {\n return undefined;\n }\n\n try {\n return JSON.parse(raw) as LinkOptionsInput;\n } catch {\n return undefined;\n }\n}\n\nexport function parseButtonsAttribute(raw: string | null | undefined): string[] {\n if (!raw) {\n return ['bold', 'italic'];\n }\n\n return raw\n .split(',')\n .map((button) => button.trim())\n .filter(Boolean);\n}\n\nexport function parseToolbarAttribute(\n toolbarRaw: string | ToolbarNode[] | null | undefined,\n buttonsRaw: string | string[] | null | undefined,\n): ToolbarNode[] {\n if (Array.isArray(toolbarRaw)) {\n return parseToolbarConfig(toolbarRaw);\n }\n\n if (typeof toolbarRaw === 'string' && toolbarRaw.trim()) {\n return parseToolbarConfig(toolbarRaw);\n }\n\n if (Array.isArray(buttonsRaw)) {\n return parseToolbarConfig(buttonsRaw.join(','));\n }\n\n return parseToolbarConfig(buttonsRaw ?? 'bold,italic');\n}\n","import { getRegisteredTiptapToolbarControl } from '@verbb/plugin-kit-tiptap-core';\n\nimport {\n alignCenter,\n alignJustify,\n alignLeft,\n alignRight,\n arrowRotateLeft,\n arrowRotateRight,\n bold,\n bracketsCurly,\n chevronDown,\n code,\n fileDashedLine,\n h1,\n h2,\n h3,\n h4,\n h5,\n h6,\n heading,\n highlighter,\n italic,\n link,\n listOl,\n listUl,\n minus,\n paragraph,\n quoteRight,\n smallCaps,\n strikethrough,\n subscript,\n superscript,\n table,\n textSlash,\n underline,\n renderIconHtml,\n} from '../../icons/index.js';\n\nexport const TOOLBAR_CHEVRON_HTML = renderIconHtml(chevronDown);\n\nexport const TOOLBAR_ICONS: Record<string, string> = {\n bold: renderIconHtml(bold),\n italic: renderIconHtml(italic),\n underline: renderIconHtml(underline),\n strikethrough: renderIconHtml(strikethrough),\n subscript: renderIconHtml(subscript),\n superscript: renderIconHtml(superscript),\n 'small-caps': renderIconHtml(smallCaps),\n code: renderIconHtml(bracketsCurly),\n 'code-block': renderIconHtml(code),\n highlight: renderIconHtml(highlighter),\n h1: renderIconHtml(h1),\n h2: renderIconHtml(h2),\n h3: renderIconHtml(h3),\n h4: renderIconHtml(h4),\n h5: renderIconHtml(h5),\n h6: renderIconHtml(h6),\n heading: renderIconHtml(heading),\n paragraph: renderIconHtml(paragraph),\n 'unordered-list': renderIconHtml(listUl),\n 'ordered-list': renderIconHtml(listOl),\n blockquote: renderIconHtml(quoteRight),\n 'align-left': renderIconHtml(alignLeft),\n 'align-center': renderIconHtml(alignCenter),\n 'align-right': renderIconHtml(alignRight),\n 'align-justify': renderIconHtml(alignJustify),\n 'clear-format': renderIconHtml(textSlash),\n hr: renderIconHtml(minus),\n 'line-break': renderIconHtml(fileDashedLine),\n link: renderIconHtml(link),\n table: renderIconHtml(table),\n undo: renderIconHtml(arrowRotateLeft),\n redo: renderIconHtml(arrowRotateRight),\n};\n\nexport const TOOLBAR_LABELS: Record<string, string> = {\n bold: 'Bold',\n italic: 'Italic',\n underline: 'Underline',\n strikethrough: 'Strikethrough',\n subscript: 'Subscript',\n superscript: 'Superscript',\n 'small-caps': 'Small caps',\n 'font-family': 'Font family',\n 'font-size': 'Font size',\n 'text-color': 'Text and background color',\n 'line-height': 'Line height',\n code: 'Inline code',\n 'code-block': 'Code block',\n highlight: 'Highlight',\n h1: 'Heading 1',\n h2: 'Heading 2',\n h3: 'Heading 3',\n h4: 'Heading 4',\n h5: 'Heading 5',\n h6: 'Heading 6',\n paragraph: 'Paragraph',\n 'unordered-list': 'Bullet list',\n 'ordered-list': 'Numbered list',\n blockquote: 'Blockquote',\n 'align-left': 'Align left',\n 'align-center': 'Align center',\n 'align-right': 'Align right',\n 'align-justify': 'Justify',\n 'clear-format': 'Clear format',\n hr: 'Horizontal rule',\n 'line-break': 'Line break',\n link: 'Link',\n table: 'Table',\n undo: 'Undo',\n redo: 'Redo',\n};\n\nexport function getToolbarMenuItemLabel(buttonName: string): string {\n return TOOLBAR_LABELS[buttonName]\n ?? getRegisteredTiptapToolbarControl(buttonName)?.label\n ?? buttonName;\n}\n\nexport function getToolbarButtonIcon(buttonName: string): string | undefined {\n const registeredIcon = getRegisteredTiptapToolbarControl(buttonName)?.icon;\n\n return TOOLBAR_ICONS[buttonName]\n ?? (registeredIcon ? renderIconHtml(registeredIcon) : undefined);\n}\n\n/** Prefix icon for `pk-dropdown-item` — SVG must carry `slot=\"prefix\"` directly. */\nexport function createToolbarPrefixIcon(buttonName: string): SVGSVGElement | null {\n const iconHtml = getToolbarButtonIcon(buttonName);\n\n if (!iconHtml) {\n return null;\n }\n\n const template = document.createElement('template');\n template.innerHTML = iconHtml.trim();\n const icon = template.content.firstElementChild;\n\n if (!(icon instanceof SVGSVGElement)) {\n return null;\n }\n\n icon.setAttribute('slot', 'prefix');\n icon.setAttribute('aria-hidden', 'true');\n icon.setAttribute('width', '12');\n icon.setAttribute('height', '12');\n icon.classList.add('pk-dropdown-item__prefix-icon');\n\n return icon;\n}\n","import { css } from 'lit';\n\nexport const pkTiptapEditorStyles = css`\n @layer pk-component {\n :host {\n display: block;\n width: 100%;\n font-family: var(--pk-font-family);\n }\n\n .shell {\n overflow: hidden;\n border: var(--pk-input-border);\n border-radius: var(--pk-radius-md);\n background: #fff;\n }\n\n :host([invalid]) .shell,\n :host(:state(user-invalid)) .shell {\n border-color: var(--pk-color-rose-600);\n }\n\n .toolbar {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n border-bottom: 1px solid rgba(96, 125, 159, 0.4);\n background: #fff;\n box-shadow: 0 2px 3px rgba(49, 49, 93, 0.07);\n }\n\n .toolbar-item {\n display: inline-flex;\n }\n\n .toolbar-item pk-tooltip {\n display: contents;\n }\n\n .toolbar-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n margin: 0;\n padding: 0;\n border: 0;\n border-radius: var(--pk-radius-md);\n background: transparent;\n color: #1c2e36;\n cursor: pointer;\n }\n\n .toolbar-btn:hover:not(:disabled) {\n background: rgb(241, 245, 249);\n }\n\n .toolbar-btn[data-state='active'] {\n background: rgb(226, 232, 240);\n }\n\n .toolbar-btn:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n .toolbar-btn svg {\n display: block;\n width: 1rem;\n height: 1rem;\n pointer-events: none;\n }\n\n .toolbar-btn--menu {\n width: auto;\n min-width: 2rem;\n gap: 0.125rem;\n padding: 0 0.375rem;\n }\n\n .toolbar-btn__trigger-label {\n font-size: 0.625rem;\n font-weight: 700;\n line-height: 1;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n }\n\n .toolbar-btn__chevron {\n display: inline-flex;\n flex-shrink: 0;\n opacity: 0.7;\n }\n\n .toolbar-btn__chevron svg {\n width: 0.5rem;\n height: 0.5rem;\n }\n\n .toolbar-separator {\n align-self: center;\n flex-shrink: 0;\n width: 1px;\n height: 1.25rem;\n margin: 0 0.125rem;\n background: rgba(96, 125, 159, 0.35);\n }\n\n .toolbar-btn__label {\n font-size: 0.625rem;\n font-weight: 600;\n line-height: 1;\n text-transform: uppercase;\n letter-spacing: 0.02em;\n }\n\n .toolbar-btn--text-style {\n max-width: 9rem;\n padding-inline: 0.5rem;\n }\n\n .toolbar-btn__text-style-value {\n overflow: hidden;\n font-size: var(--pk-font-size-xs);\n line-height: 1;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .toolbar-btn--color .toolbar-btn__text-style-value {\n min-width: 1rem;\n border-bottom: 2px solid var(--text-style-trigger-color, currentColor);\n color: var(--text-style-trigger-color, currentColor);\n font-weight: 700;\n text-align: center;\n }\n\n pk-dropdown-menu.text-style-palette::part(panel) {\n display: grid;\n grid-template-columns: repeat(5, 2rem);\n gap: 0.625rem 0.75rem;\n width: max-content;\n min-width: 0;\n padding: 1rem;\n }\n\n .text-style-palette__label {\n grid-column: 1 / -1;\n color: var(--pk-color-gray-900);\n }\n\n .text-style-palette__label::part(label) {\n padding: 0 0 0.125rem;\n font-size: var(--pk-font-size-base);\n font-weight: 600;\n }\n\n .text-style-palette__label--highlight {\n margin-top: 0.375rem;\n }\n\n .text-style-palette__option {\n width: 2rem;\n height: 2rem;\n --pk-dropdown-item-gap: 0;\n --pk-dropdown-item-icon-size: 1.625rem;\n }\n\n .text-style-palette__option::part(item) {\n justify-content: center;\n width: 2rem;\n height: 2rem;\n min-height: 0;\n padding: 0;\n border-radius: 50%;\n background: transparent;\n }\n\n .text-style-palette__option:hover::part(item),\n .text-style-palette__option:focus-within::part(item),\n .text-style-palette__option[data-highlighted]::part(item),\n .text-style-palette__option[checked]::part(item) {\n background: transparent;\n }\n\n .text-style-palette__option::part(prefix) {\n width: 1.625rem;\n height: 1.625rem;\n }\n\n .text-style-palette__option::part(label) {\n position: absolute;\n }\n\n .text-style-palette__option::part(check) {\n display: none;\n }\n\n .text-style-palette__swatch {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.625rem;\n height: 1.625rem;\n box-sizing: border-box;\n border: 1px solid rgba(15, 23, 42, 0.16);\n border-radius: 50%;\n }\n\n /* Keep the state treatment concentric with the slotted swatch. The\n dropdown item's shadow button is wider than its prefix in some hosts. */\n .text-style-palette__option:hover .text-style-palette__swatch,\n .text-style-palette__option:focus-within .text-style-palette__swatch,\n .text-style-palette__option[data-highlighted] .text-style-palette__swatch,\n .text-style-palette__option[checked] .text-style-palette__swatch {\n box-shadow: 0 0 0 0.25rem var(--pk-color-slate-100);\n }\n\n .text-style-palette__swatch--text {\n border-color: var(--text-style-swatch, rgba(15, 23, 42, 0.35));\n color: var(--text-style-swatch, #1f2937);\n font-size: var(--pk-font-size-base);\n font-weight: 500;\n line-height: 1;\n }\n\n .text-style-palette__swatch--highlight {\n background: var(--text-style-swatch, #fff);\n }\n\n .text-style-palette__accessible-label {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n .text-style-palette pk-tooltip {\n display: contents;\n }\n\n /* Full toolbar replace (slot=toolbar on host when hasCustomToolbar). */\n .toolbar ::slotted([slot='toolbar']) {\n display: contents;\n }\n\n /* Append lane inside the stock toolbar — one flex item per slotted root (same gap). */\n .toolbar ::slotted([slot='toolbar-end']) {\n display: inline-flex;\n align-items: center;\n }\n\n .editor-mount {\n position: relative;\n }\n\n .content-error {\n display: flex;\n gap: 0.5rem;\n padding: 0.5rem 1rem;\n border-bottom: 1px solid var(--pk-color-rose-200);\n background: var(--pk-color-rose-50);\n color: var(--pk-color-rose-800);\n font-size: var(--pk-font-size-sm);\n }\n\n .mirror-input {\n display: none;\n }\n\n /* No trigger slot — collapse the host so it does not reserve shell space.\n Toolbar refresh while open is still gated by linkDialogBusy / open. */\n .link-dialog {\n display: contents;\n }\n\n .link-dialog__fields {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n }\n\n .link-bubble {\n position: absolute;\n z-index: 250;\n display: flex;\n align-items: center;\n gap: 0;\n width: max-content;\n max-width: calc(100% - 1rem);\n padding: 0;\n border: 0;\n border-radius: var(--pk-radius-md);\n background: #1c2e36;\n color: #fff;\n font-size: 12px;\n line-height: 1.5;\n overflow: visible;\n pointer-events: auto;\n white-space: nowrap;\n }\n\n .link-bubble__arrow {\n position: absolute;\n left: 50%;\n bottom: -0.25rem;\n width: 0.5rem;\n height: 0.5rem;\n background: #1c2e36;\n transform: translateX(-50%) rotate(45deg);\n pointer-events: none;\n }\n\n .link-bubble__url,\n .link-bubble__action {\n box-sizing: border-box;\n padding: 6px 8px;\n font-size: 12px;\n line-height: 1.5;\n }\n\n .link-bubble__url {\n display: inline-flex;\n align-items: center;\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .link-bubble__divider {\n flex-shrink: 0;\n align-self: center;\n width: 1px;\n height: 12px;\n background: #616d73;\n }\n\n .link-bubble__action {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n margin: 0;\n border: 0;\n border-radius: var(--pk-radius-sm);\n background: transparent;\n color: #fff;\n font-family: inherit;\n font-weight: inherit;\n white-space: nowrap;\n cursor: pointer;\n outline: none;\n appearance: none;\n -webkit-appearance: none;\n min-height: 0;\n transition: color 0.15s ease;\n }\n\n .link-bubble__action:hover {\n color: rgb(255 255 255 / 0.7);\n }\n }\n`;\n","import { html, nothing } from 'lit';\nimport { customElement, property, query, state } from '../../decorators.js';\nimport type { PropertyValues } from 'lit';\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js';\nimport {\n applyLinkToEditor,\n createTiptapExtensions,\n getCraftLinkOptions,\n getFatalTiptapContentError,\n getRegisteredTiptapToolbarControl,\n getLinkEditState,\n getLinkOptionsElementSiteId,\n getLinkOpenInNewTab,\n getSelectedText,\n getToolbarGroupDefaultIcon,\n getToolbarGroupMenuItems,\n getToolbarGroupTriggerState,\n isFormattingToolbarPreset,\n isHeadingsOnlyToolbarPreset,\n isTiptapButtonActive,\n isToolbarButtonActive,\n openCraftElementLinkSelector,\n runToolbarButton,\n resolveTiptapTextStyleToolbarConfig,\n toolbarIncludesButton,\n unsetLinkFromEditor,\n type LinkElementConfig,\n type LinkOptionsInput,\n type ToolbarGroup,\n type ToolbarNode,\n type TiptapTextStyleOption,\n type TiptapTextStyleToolbarConfig,\n} from '@verbb/plugin-kit-tiptap-core';\nimport { getMarkRange, posToDOMRect } from '@tiptap/core';\n\nimport { formControlStyles } from '../../base/form-control.styles.js';\nimport { PkFormAssociatedElement } from '../../base/pk-form-associated-element.js';\nimport { uniqueId } from '../../a11y/focus.js';\nimport { MirrorValidator } from '../../validators/index.js';\nimport {\n link,\n triangleExclamation,\n renderIconHtml,\n} from '../../icons/index.js';\n\nimport '../button/pk-button.js';\nimport '../checkbox/pk-checkbox.js';\nimport '../dialog/pk-dialog.js';\nimport '../dropdown-menu/pk-dropdown-item.js';\nimport '../dropdown-menu/pk-dropdown-label.js';\nimport '../field/pk-field.js';\nimport '../input/pk-input.js';\nimport '../dropdown-menu/pk-dropdown-menu.js';\nimport '../dropdown-menu/pk-dropdown-separator.js';\nimport '../tooltip/pk-tooltip.js';\nimport type { PkButton } from '../button/pk-button.js';\nimport type { PkCheckbox } from '../checkbox/pk-checkbox.js';\nimport type { PkDialog } from '../dialog/pk-dialog.js';\nimport type { PkDropdownItem } from '../dropdown-menu/pk-dropdown-item.js';\nimport type { PkDropdownMenu } from '../dropdown-menu/pk-dropdown-menu.js';\nimport type { PkInput } from '../input/pk-input.js';\nimport { TiptapEditorHost, parseTiptapDocumentValue, serializeTiptapDocumentContent, serializeTiptapDocumentValue } from './tiptap-editor-host.js';\nimport { createCraftElementSelectorHost, parseLinkOptionsAttribute, parseToolbarAttribute } from './tiptap-utils.js';\nimport {\n TOOLBAR_CHEVRON_HTML,\n TOOLBAR_ICONS,\n TOOLBAR_LABELS,\n createToolbarPrefixIcon,\n getToolbarButtonIcon,\n getToolbarMenuItemLabel,\n} from './tiptap-toolbar.js';\nimport {\n createVariableTagDomNodeView,\n refreshVariableTagPresentation,\n type PkVariableTransformerRegistry,\n} from './variable-tag-node-view.js';\nimport { pkTiptapEditorStyles } from './pk-tiptap-editor.styles.js';\nimport { tiptapProseMirrorStyles } from './tiptap.styles.js';\n\ntype LinkDialogSeed = {\n url?: string;\n text?: string;\n openInNewTab?: boolean;\n from?: number;\n to?: number;\n};\n\n/**\n * TipTap document editor with a Craft-styled toolbar.\n *\n * @slot toolbar - Replace the entire default toolbar (opt-in via light-DOM presence).\n * @slot toolbar-end - Append controls after stock toolbar buttons (same flex gap).\n */\n@customElement('pk-tiptap-editor')\nexport class PkTiptapEditor extends PkFormAssociatedElement {\n static override styles = [formControlStyles, pkTiptapEditorStyles, tiptapProseMirrorStyles];\n\n static override get validators() {\n return [...super.validators, MirrorValidator()];\n }\n\n override assumeInteractionOn = ['blur', 'input'];\n\n @query('.editor-mount')\n private editorMount!: HTMLDivElement;\n\n @query('.mirror-input')\n override input!: HTMLInputElement;\n\n @query('.link-dialog')\n private linkDialog?: PkDialog;\n\n @query('pk-input.link-dialog__url-input')\n private linkUrlInput?: PkInput;\n\n @query('pk-input.link-dialog__text-input')\n private linkTextInput?: PkInput;\n\n @query('pk-checkbox')\n private linkNewTabCheckbox?: PkCheckbox;\n\n @query('pk-button.link-dialog__submit')\n private linkSubmitButton?: PkButton;\n\n private readonly linkUrlInputId = uniqueId('pk-tiptap-link-url');\n\n private readonly linkTextInputId = uniqueId('pk-tiptap-link-text');\n\n private readonly host = new TiptapEditorHost();\n\n private _value: string | null = null;\n\n /**\n * Flat toolbar button list. HTML uses a comma-separated attribute; React may\n * pass a `string[]`. Named `buttons` (not `buttonsAttr`) so React can set the\n * property — a getter-only `buttons` previously threw on assign.\n */\n @property({\n attribute: 'buttons',\n converter: {\n fromAttribute: (value: string | null) => value ?? 'bold,italic',\n toAttribute: (value: string | string[] | null | undefined) => {\n if (value == null) {\n return 'bold,italic';\n }\n\n return Array.isArray(value) ? value.join(',') : value;\n },\n },\n })\n buttons: string | string[] = 'bold,italic';\n\n /** Structured toolbar config — JSON string attribute, or a node array from React. */\n @property({\n attribute: 'toolbar',\n converter: {\n fromAttribute: (value: string | null) => value,\n toAttribute: (value: string | ToolbarNode[] | null | undefined) => {\n if (value == null) {\n return null;\n }\n\n return typeof value === 'string' ? value : JSON.stringify(value);\n },\n },\n })\n toolbar: string | ToolbarNode[] | null = null;\n\n /** Values shown by the optional TextStyle toolbar controls. */\n @property({\n attribute: 'text-style-options',\n converter: {\n fromAttribute: (value: string | null) => {\n if (!value) {\n return null;\n }\n\n try {\n return JSON.parse(value) as TiptapTextStyleToolbarConfig;\n } catch {\n return null;\n }\n },\n toAttribute: (value: TiptapTextStyleToolbarConfig | null | undefined) => (\n value ? JSON.stringify(value) : null\n ),\n },\n })\n textStyleOptions: TiptapTextStyleToolbarConfig | null = null;\n\n /** JSON configuration for Craft entry, asset, category, or custom element links. */\n @property({ attribute: 'link-options' })\n linkOptions: string | null = null;\n\n /** Required storage-key prefix when Craft element link options are enabled. */\n @property({ attribute: 'link-selector-storage-key-prefix' })\n linkSelectorStorageKeyPrefix?: string;\n\n @property({ type: Number })\n rows = 4;\n\n @property()\n placeholder = '';\n\n @property({ type: Boolean, reflect: true })\n readonly = false;\n\n @property({ type: Boolean, reflect: true })\n invalid = false;\n\n /** Transform names displayed as badges on configured variable tags. */\n @property({ attribute: false })\n variableTransformerRegistry: PkVariableTransformerRegistry = {};\n\n /**\n * Formie / React configure bridge — called when a chip is activated for editing.\n * Prefer this over listening for `pk-variable-tag-configure` from React.\n */\n @property({ attribute: false })\n variableTagConfigure: ((detail: import('./variable-tag-node-view.js').PkVariableTagConfigureDetail) => void) | null = null;\n\n @property({ attribute: 'invalid-content-message' })\n invalidContentMessage = '';\n\n /** Show `pk-tooltip` hints on toolbar buttons (default: on). */\n @property({ type: Boolean, attribute: 'toolbar-tooltips' })\n toolbarTooltips = true;\n\n private linkDialogBusy = false;\n\n private linkDialogSeed: LinkDialogSeed = {};\n\n @state()\n private linkDialogTitle = 'Insert Link';\n\n @state()\n private linkDialogSubmitLabel = 'Insert';\n\n @state()\n private linkDialogMounted = false;\n\n @state()\n private linkBubbleVisible = false;\n\n @state()\n private linkBubbleHref = '';\n\n @state()\n private linkBubbleTop = 0;\n\n @state()\n private linkBubbleLeft = 0;\n\n private hasCustomToolbar = false;\n\n private readonly linkButtonId = uniqueId('pk-tiptap-link-btn');\n\n private readonly toolbarButtonIds = new Map<string, string>();\n\n private readonly toolbarGroupIds = new Map<string, string>();\n\n private selectionListenerAttached = false;\n\n get value(): string {\n if (this.valueHasChanged) {\n return this._value ?? '[]';\n }\n\n return this._value ?? this.defaultValue ?? '[]';\n }\n\n /**\n * Document JSON string. Also accepts a TipTap node array (common from React)\n * and serializes it — arrays previously bypassed JSON.parse and mounted empty.\n */\n @state()\n set value(val: string | unknown[] | null) {\n const next = serializeTiptapDocumentValue(val);\n\n if (this._value === next) {\n return;\n }\n\n this.valueHasChanged = true;\n this._value = next;\n }\n\n @property({ attribute: 'value', reflect: true })\n defaultValue: string | null = '[]';\n\n get editor() {\n return this.host.editor;\n }\n\n get toolbarNodes(): ToolbarNode[] {\n const buttonsRaw = Array.isArray(this.buttons) ? this.buttons.join(',') : this.buttons;\n\n return parseToolbarAttribute(this.toolbar, buttonsRaw)\n .filter((node) => node.type !== 'button' || node.name !== 'variableTag');\n }\n\n /** Resolved flat button names from the active toolbar config. */\n get buttonNames(): string[] {\n return this.toolbarNodes\n .filter((node): node is Extract<ToolbarNode, { type: 'button' }> => node.type === 'button')\n .map((node) => node.name);\n }\n\n private toolbarHasLink(): boolean {\n return toolbarIncludesButton(this.toolbarNodes, 'link');\n }\n\n private resolveLinkOptions(): LinkOptionsInput | undefined {\n return parseLinkOptionsAttribute(this.linkOptions);\n }\n\n private get contentError(): string {\n return this.resolveContentError();\n }\n\n protected override syncFormValue(): void {\n this.setValue(this.value || '[]');\n\n if (this.input) {\n this.input.value = this.value || '[]';\n }\n }\n\n protected override resetToDefaultValue(): void {\n this.valueHasChanged = false;\n this._value = null;\n this.syncEditorContent();\n }\n\n protected override restoreFormState(state: string | File | FormData | null): void {\n if (typeof state === 'string') {\n this.value = state;\n this.syncEditorContent();\n }\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.hasCustomToolbar = Boolean(this.querySelector('[slot=\"toolbar\"]'));\n }\n\n override disconnectedCallback(): void {\n this.linkDialog?.forceOverlayReset();\n this.linkDialogBusy = false;\n this.host.destroy();\n this.selectionListenerAttached = false;\n super.disconnectedCallback();\n }\n\n override updated(changed: PropertyValues): void {\n if (changed.has('variableTransformerRegistry')) {\n refreshVariableTagPresentation(this);\n }\n\n if (changed.has('value') && !changed.has('defaultValue')) {\n this.syncEditorContent();\n }\n\n if (changed.has('defaultValue') && !this.valueHasChanged) {\n this.syncEditorContent();\n }\n\n if (changed.has('disabled') || changed.has('readonly')) {\n this.host.editor?.setEditable(!this.disabled && !this.readonly);\n }\n\n super.updated(changed);\n }\n\n override firstUpdated(): void {\n queueMicrotask(() => {\n this.mountEditor();\n this.syncFormValue();\n });\n }\n\n private resolveContentError(): string {\n const detected = getFatalTiptapContentError(this.value);\n return detected ? (this.invalidContentMessage || detected) : '';\n }\n\n private mountEditor(): void {\n const content = this.contentError ? null : parseTiptapDocumentValue(this.value);\n const normalizedRows = Math.max(1, Number(this.rows || 0));\n const minHeight = `${(normalizedRows * 24) + 32}px`;\n\n this.host.mount({\n element: this.editorMount,\n extensions: createTiptapExtensions({\n trailingCursorText: '\\u2060',\n variableTagNodeView: createVariableTagDomNodeView(),\n }),\n content,\n editable: !this.disabled && !this.readonly && !this.contentError,\n trailingCursorText: '\\u2060',\n minHeight,\n onUpdate: (nextContent) => {\n const serialized = serializeTiptapDocumentContent(nextContent);\n this.value = serialized;\n\n if (this.input) {\n this.input.value = serialized;\n }\n\n this.syncFormValue();\n // Emit JSON string (matches `value` prop) — arrays caused Formie controlled\n // fields to write mismatched types and re-enter sync forever.\n this.emitValueChange(serialized);\n },\n });\n\n queueMicrotask(() => {\n this.attachSelectionListeners();\n // Visibility predicates need the mounted Editor instance before the\n // first custom-control render can be authoritative.\n this.requestUpdate();\n });\n }\n\n private attachSelectionListeners(): void {\n const editor = this.host.editor;\n\n if (!editor || this.selectionListenerAttached) {\n return;\n }\n\n const refreshToolbar = () => {\n if (this.linkDialogBusy || this.linkDialog?.open) {\n this.linkBubbleVisible = false;\n return;\n }\n\n this.updateLinkBubble();\n\n queueMicrotask(() => {\n if (this.isConnected && !this.linkDialogBusy && !this.linkDialog?.open) {\n this.requestUpdate();\n }\n });\n };\n\n editor.on('selectionUpdate', refreshToolbar);\n editor.on('transaction', refreshToolbar);\n editor.on('focus', refreshToolbar);\n editor.on('blur', () => {\n this.linkBubbleVisible = false;\n this.requestUpdate();\n });\n this.selectionListenerAttached = true;\n }\n\n private updateLinkBubble(): void {\n const editor = this.host.editor;\n\n if (\n !editor\n || this.disabled\n || this.readonly\n || this.linkDialogBusy\n || this.linkDialog?.open\n || !editor.isFocused\n || !editor.isActive('link')\n ) {\n this.linkBubbleVisible = false;\n return;\n }\n\n const linkType = editor.state.schema.marks.link;\n const range = getMarkRange(editor.state.selection.$from, linkType);\n\n if (!range) {\n this.linkBubbleVisible = false;\n return;\n }\n\n const linkRect = posToDOMRect(editor.view, range.from, range.to);\n const mountRect = this.editorMount.getBoundingClientRect();\n const bubbleOffset = 8;\n\n this.linkBubbleHref = String(editor.getAttributes('link').href ?? '');\n this.linkBubbleTop = linkRect.top - mountRect.top - bubbleOffset;\n this.linkBubbleLeft = linkRect.left - mountRect.left + (linkRect.width / 2);\n this.linkBubbleVisible = true;\n }\n\n private handleLinkBubbleEdit = (event: Event): void => {\n event.preventDefault();\n\n const editor = this.host.editor;\n\n if (!editor) {\n return;\n }\n\n const state = getLinkEditState(editor);\n this.linkBubbleVisible = false;\n this.openLinkDialog({\n url: state.href,\n text: state.text,\n openInNewTab: state.openInNewTab,\n from: state.from,\n to: state.to,\n });\n };\n\n private handleLinkBubbleUnlink = (event: Event): void => {\n event.preventDefault();\n\n const editor = this.host.editor;\n\n if (!editor) {\n return;\n }\n\n unsetLinkFromEditor(editor);\n this.linkBubbleVisible = false;\n };\n\n private renderLinkBubble() {\n return html`\n <div\n class=\"link-bubble\"\n role=\"toolbar\"\n aria-label=\"Link actions\"\n tabindex=\"0\"\n style=${`top:${this.linkBubbleTop}px;left:${this.linkBubbleLeft}px;transform:translate(-50%, -100%);`}\n >\n <span class=\"link-bubble__arrow\" aria-hidden=\"true\"></span>\n <span class=\"link-bubble__url\">${this.linkBubbleHref}</span>\n <span class=\"link-bubble__divider\" aria-hidden=\"true\"></span>\n <button\n type=\"button\"\n class=\"link-bubble__action\"\n @mousedown=${(event: Event) => event.preventDefault()}\n @click=${this.handleLinkBubbleEdit}\n >Edit</button>\n <span class=\"link-bubble__divider\" aria-hidden=\"true\"></span>\n <button\n type=\"button\"\n class=\"link-bubble__action\"\n @mousedown=${(event: Event) => event.preventDefault()}\n @click=${this.handleLinkBubbleUnlink}\n >Unlink</button>\n </div>\n `;\n }\n\n private syncEditorContent(): void {\n const content = this.contentError ? null : parseTiptapDocumentValue(this.value);\n this.host.setContent(content, { trailingCursorText: '\\u2060' });\n\n if (this.input) {\n this.input.value = this.value || '[]';\n }\n }\n\n private emitValueChange(value: string): void {\n this.dispatchEvent(new CustomEvent('pk-change', {\n detail: { value },\n bubbles: true,\n composed: true,\n }));\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));\n }\n\n private handleToolbarCommand(buttonName: string): void {\n const editor = this.host.editor;\n\n if (!editor) {\n return;\n }\n\n runToolbarButton(editor, buttonName);\n }\n\n private openLinkMenu(): void {\n const editor = this.host.editor;\n\n if (!editor) {\n return;\n }\n\n const selected = getSelectedText(editor);\n const { from, to } = editor.state.selection;\n\n const menu = this.shadowRoot?.querySelector<PkDropdownMenu>(\n `pk-dropdown-menu[for=\"${this.linkButtonId}\"]`,\n );\n\n void (async () => {\n await menu?.whenClosed();\n this.openLinkDialog(from !== to ? { text: selected, from, to } : undefined);\n })();\n }\n\n private openLinkDialog(initial?: LinkDialogSeed): void {\n const editor = this.host.editor;\n const url = initial?.url ?? '';\n\n this.linkDialogBusy = true;\n this.linkBubbleVisible = false;\n this.linkDialogSeed = {\n url,\n text: initial?.text ?? '',\n openInNewTab: initial?.openInNewTab ?? (editor ? getLinkOpenInNewTab(editor) : false),\n from: initial?.from,\n to: initial?.to,\n };\n this.linkDialogTitle = url.trim() ? 'Update Link' : 'Insert Link';\n this.linkDialogSubmitLabel = url.trim() ? 'Update' : 'Insert';\n\n if (!this.linkDialogMounted) {\n this.linkDialogMounted = true;\n }\n\n // Mount first, then open after the dropdown has fully demoted (caller awaits\n // whenClosed). Busy flag still suppresses toolbar refresh during show animation.\n queueMicrotask(async () => {\n await this.updateComplete;\n await this.linkDialog?.updateComplete;\n this.syncLinkDialogFields();\n // Prefer show() over flipping `open` before firstUpdated — that path only\n // call showModal() and skips PkShowEvent / enter animation.\n await this.linkDialog?.show();\n });\n }\n\n private closeLinkDialog(): void {\n void this.linkDialog?.hide('close-button');\n }\n\n private handleLinkDialogAfterHide = (): void => {\n this.linkDialogBusy = false;\n\n queueMicrotask(() => {\n if (this.isConnected && !this.linkDialog?.open) {\n this.requestUpdate();\n }\n });\n };\n\n private syncLinkDialogFields(): void {\n const seed = this.linkDialogSeed;\n\n if (this.linkUrlInput) {\n this.linkUrlInput.value = seed.url ?? '';\n }\n\n if (this.linkTextInput) {\n this.linkTextInput.value = seed.text ?? '';\n }\n\n if (this.linkNewTabCheckbox) {\n this.linkNewTabCheckbox.checked = Boolean(seed.openInNewTab);\n }\n\n this.updateLinkDialogSubmitState();\n }\n\n private updateLinkDialogSubmitState(): void {\n const canSubmit = Boolean(this.linkUrlInput?.value.trim());\n\n if (this.linkSubmitButton) {\n this.linkSubmitButton.disabled = !canSubmit;\n }\n }\n\n private handleLinkUrlInput = (): void => {\n this.updateLinkDialogSubmitState();\n };\n\n private handleLinkDialogKeyDown = (event: KeyboardEvent): void => {\n if (event.key !== 'Enter') {\n return;\n }\n\n const path = event.composedPath();\n\n if (path.some((node) => node instanceof HTMLElement && node.localName === 'pk-checkbox')) {\n return;\n }\n\n if (path.some((node) => node instanceof HTMLElement && node.localName === 'pk-button')) {\n return;\n }\n\n if (path.some((node) => node instanceof HTMLButtonElement)) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n this.submitLinkDialog();\n };\n\n private handleLinkDialogSubmit = (): void => {\n this.submitLinkDialog();\n };\n\n private submitLinkDialog(): void {\n const editor = this.host.editor;\n const url = this.linkUrlInput?.value.trim() ?? '';\n\n if (!editor || !url) {\n return;\n }\n\n applyLinkToEditor(editor, {\n url,\n text: this.linkTextInput?.value ?? '',\n openInNewTab: Boolean(this.linkNewTabCheckbox?.checked),\n from: this.linkDialogSeed.from,\n to: this.linkDialogSeed.to,\n });\n\n this.closeLinkDialog();\n }\n\n private isLinkActive(): boolean {\n const editor = this.host.editor;\n return editor ? isTiptapButtonActive(editor, 'link') : false;\n }\n\n private renderLinkDialog() {\n return html`\n <pk-dialog\n class=\"link-dialog\"\n size=\"wide\"\n label=${this.linkDialogTitle}\n @pk-after-hide=${this.handleLinkDialogAfterHide}\n @keydown=${this.handleLinkDialogKeyDown}\n >\n <div class=\"link-dialog__fields\">\n <pk-field label=\"URL\" required .for=${this.linkUrlInputId}>\n <pk-input\n id=${this.linkUrlInputId}\n class=\"link-dialog__url-input\"\n type=\"url\"\n placeholder=\"https://\"\n autofocus\n @input=${this.handleLinkUrlInput}\n ></pk-input>\n </pk-field>\n <pk-field label=\"Text\" .for=${this.linkTextInputId}>\n <pk-input\n id=${this.linkTextInputId}\n class=\"link-dialog__text-input\"\n type=\"text\"\n ></pk-input>\n </pk-field>\n <pk-checkbox>Open link in new tab</pk-checkbox>\n </div>\n <pk-button slot=\"footer\" data-dialog-close>Cancel</pk-button>\n <pk-button\n slot=\"footer\"\n class=\"link-dialog__submit\"\n variant=\"primary\"\n disabled\n @click=${this.handleLinkDialogSubmit}\n >\n ${this.linkDialogSubmitLabel}\n </pk-button>\n </pk-dialog>\n `;\n }\n\n private getToolbarButtonId(buttonName: string): string {\n let id = this.toolbarButtonIds.get(buttonName);\n\n if (!id) {\n id = uniqueId(`pk-tiptap-toolbar-${buttonName}`);\n this.toolbarButtonIds.set(buttonName, id);\n }\n\n return id;\n }\n\n private getToolbarButtonLabel(buttonName: string): string {\n return TOOLBAR_LABELS[buttonName]\n ?? getRegisteredTiptapToolbarControl(buttonName)?.label\n ?? buttonName;\n }\n\n private renderToolbarTooltip(buttonId: string, label: string) {\n if (!this.toolbarTooltips) {\n return nothing;\n }\n\n return html`\n <pk-tooltip for=${buttonId} content=${label} placement=\"top\"></pk-tooltip>\n `;\n }\n\n private renderToolbarButton(buttonName: string) {\n const editor = this.host.editor;\n const registered = getRegisteredTiptapToolbarControl(buttonName);\n\n if (registered?.isVisible && (!editor || !registered.isVisible(editor))) {\n return nothing;\n }\n\n const icon = getToolbarButtonIcon(buttonName);\n const label = this.getToolbarButtonLabel(buttonName);\n const buttonId = this.getToolbarButtonId(buttonName);\n const active = editor ? isTiptapButtonActive(editor, buttonName) : false;\n\n return html`\n <div class=\"toolbar-item\">\n <button\n id=${buttonId}\n type=\"button\"\n class=\"toolbar-btn\"\n aria-label=${label}\n ?disabled=${this.disabled || this.readonly}\n data-state=${active ? 'active' : nothing}\n @click=${() => this.handleToolbarCommand(buttonName)}\n >\n ${icon ? unsafeSVG(icon) : html`<span class=\"toolbar-btn__label\">${label}</span>`}\n </button>\n ${this.renderToolbarTooltip(buttonId, label)}\n </div>\n `;\n }\n\n private get textStyleToolbarConfig() {\n return resolveTiptapTextStyleToolbarConfig(this.textStyleOptions);\n }\n\n private getTextStyleValue(attribute: string): string | null {\n const value = this.host.editor?.getAttributes('textStyle')[attribute];\n return typeof value === 'string' && value ? value : null;\n }\n\n private setTextStyleValue(attribute: string, value: string | null): void {\n const editor = this.host.editor;\n\n if (!editor) {\n return;\n }\n\n const chain = editor.chain().focus();\n\n switch (attribute) {\n case 'fontFamily':\n value ? chain.setFontFamily(value).run() : chain.unsetFontFamily().run();\n break;\n case 'fontSize':\n value ? chain.setFontSize(value).run() : chain.unsetFontSize().run();\n break;\n case 'color':\n value ? chain.setColor(value).run() : chain.unsetColor().run();\n break;\n case 'backgroundColor':\n value ? chain.setBackgroundColor(value).run() : chain.unsetBackgroundColor().run();\n break;\n case 'lineHeight':\n value ? chain.setLineHeight(value).run() : chain.unsetLineHeight().run();\n break;\n }\n }\n\n private getTextStyleOptionLabel(options: TiptapTextStyleOption[], value: string | null): string {\n return options.find((option) => option.value === value)?.label\n ?? options.find((option) => option.value === null)?.label\n ?? 'Default';\n }\n\n private renderTextStyleOptions(attribute: string, options: TiptapTextStyleOption[]) {\n const currentValue = this.getTextStyleValue(attribute);\n\n return options.map((option) => html`\n <pk-dropdown-item\n type=\"radio\"\n radio-group=${attribute}\n value=${option.value ?? ''}\n ?checked=${option.value === currentValue}\n @click=${() => this.setTextStyleValue(attribute, option.value)}\n >\n ${option.label}\n </pk-dropdown-item>\n `);\n }\n\n private renderTextStylePaletteOptions(\n attribute: 'color' | 'backgroundColor',\n options: TiptapTextStyleOption[],\n idPrefix: string,\n ) {\n const currentValue = this.getTextStyleValue(attribute);\n const isTextColor = attribute === 'color';\n\n return options.map((option, index) => {\n const optionId = `${idPrefix}-${attribute}-${index}`;\n const accessibleLabel = option.value\n ? `${option.label} ${isTextColor ? 'text' : 'highlight'}`\n : isTextColor ? 'Default text color' : 'No highlight';\n\n return html`\n <pk-dropdown-item\n id=${optionId}\n class=\"text-style-palette__option\"\n type=\"radio\"\n radio-group=${attribute}\n value=${option.value ?? ''}\n ?checked=${option.value === currentValue}\n @click=${() => this.setTextStyleValue(attribute, option.value)}\n >\n <span\n slot=\"start\"\n class=\"text-style-palette__swatch ${isTextColor ? 'text-style-palette__swatch--text' : 'text-style-palette__swatch--highlight'}\"\n style=${option.value ? `--text-style-swatch:${option.value}` : ''}\n data-empty=${option.value === null ? '' : nothing}\n aria-hidden=\"true\"\n >${isTextColor ? 'A' : nothing}</span>\n <span class=\"text-style-palette__accessible-label\">${accessibleLabel}</span>\n </pk-dropdown-item>\n ${this.toolbarTooltips ? html`\n <pk-tooltip for=${optionId} content=${accessibleLabel} placement=\"top\"></pk-tooltip>\n ` : nothing}\n `;\n });\n }\n\n private handleTextStylePaletteKeyDown(event: KeyboardEvent): void {\n const deltas: Partial<Record<KeyboardEvent['key'], number>> = {\n ArrowLeft: -1,\n ArrowRight: 1,\n ArrowUp: -5,\n ArrowDown: 5,\n };\n const delta = deltas[event.key];\n\n if (!delta) {\n return;\n }\n\n const menu = event.currentTarget as PkDropdownMenu;\n const item = event.composedPath().find((node): node is PkDropdownItem => (\n node instanceof HTMLElement\n && node.localName === 'pk-dropdown-item'\n && node.classList.contains('text-style-palette__option')\n ));\n const items = menu.getItems().filter((candidate) => (\n candidate.classList.contains('text-style-palette__option')\n ));\n const index = item ? items.indexOf(item) : -1;\n\n if (index === -1) {\n return;\n }\n\n // The menu remains the focus/dismissal owner; only its directional\n // movement changes to match the palette's five-column visual layout.\n const target = items[Math.max(0, Math.min(index + delta, items.length - 1))];\n\n event.preventDefault();\n event.stopPropagation();\n target?.focusControl();\n }\n\n private renderTextStyleToolbar(buttonName: string) {\n const config = this.textStyleToolbarConfig;\n const buttonId = this.getToolbarButtonId(buttonName);\n const triggerColor = buttonName === 'text-color' ? this.getTextStyleValue('color') : null;\n let triggerLabel = '';\n let menuContent: unknown = nothing;\n\n if (buttonName === 'font-family') {\n triggerLabel = this.getTextStyleOptionLabel(config.fontFamilies, this.getTextStyleValue('fontFamily'));\n menuContent = html`${this.renderTextStyleOptions('fontFamily', config.fontFamilies)}`;\n } else if (buttonName === 'font-size') {\n triggerLabel = this.getTextStyleOptionLabel(config.fontSizes, this.getTextStyleValue('fontSize'));\n menuContent = html`${this.renderTextStyleOptions('fontSize', config.fontSizes)}`;\n } else if (buttonName === 'line-height') {\n triggerLabel = this.getTextStyleOptionLabel(config.lineHeights, this.getTextStyleValue('lineHeight'));\n menuContent = html`${this.renderTextStyleOptions('lineHeight', config.lineHeights)}`;\n } else {\n triggerLabel = 'A';\n menuContent = html`\n <pk-dropdown-label class=\"text-style-palette__label\">Text color</pk-dropdown-label>\n ${this.renderTextStylePaletteOptions('color', config.textColors, buttonId)}\n <pk-dropdown-label class=\"text-style-palette__label text-style-palette__label--highlight\">Highlight color</pk-dropdown-label>\n ${this.renderTextStylePaletteOptions('backgroundColor', config.backgroundColors, buttonId)}\n `;\n }\n\n const label = this.getToolbarButtonLabel(buttonName);\n\n return html`\n <div class=\"toolbar-item\">\n <button\n id=${buttonId}\n type=\"button\"\n class=\"toolbar-btn toolbar-btn--menu toolbar-btn--text-style ${buttonName === 'text-color' ? 'toolbar-btn--color' : ''}\"\n aria-label=${label}\n aria-haspopup=\"menu\"\n ?disabled=${this.disabled || this.readonly}\n style=${triggerColor ? `--text-style-trigger-color:${triggerColor}` : ''}\n >\n <span class=\"toolbar-btn__text-style-value\">${triggerLabel}</span>\n <span class=\"toolbar-btn__chevron\">${unsafeSVG(TOOLBAR_CHEVRON_HTML)}</span>\n </button>\n ${this.renderToolbarTooltip(buttonId, label)}\n <pk-dropdown-menu\n for=${buttonId}\n placement=\"bottom-start\"\n class=${buttonName === 'text-color' ? 'text-style-palette' : ''}\n @keydown=${buttonName === 'text-color' ? this.handleTextStylePaletteKeyDown : nothing}\n >\n ${menuContent}\n </pk-dropdown-menu>\n </div>\n `;\n }\n\n private handleCraftLink(config: LinkElementConfig): void {\n const editor = this.host.editor;\n\n if (!editor) {\n return;\n }\n\n openCraftElementLinkSelector({\n config,\n elementSiteId: getLinkOptionsElementSiteId(this.resolveLinkOptions()),\n linkSelectorStorageKeyPrefix: this.linkSelectorStorageKeyPrefix,\n getSelectedText: () => getSelectedText(editor),\n onSelect: ({ url, text }) => { this.openLinkDialog({ url, text }); },\n host: createCraftElementSelectorHost(),\n });\n }\n\n private getToolbarGroupId(groupKey: string): string {\n let id = this.toolbarGroupIds.get(groupKey);\n\n if (!id) {\n id = uniqueId('pk-tiptap-toolbar-group');\n this.toolbarGroupIds.set(groupKey, id);\n }\n\n return id;\n }\n\n private renderToolbarSeparator() {\n return html`<span class=\"toolbar-separator\" aria-hidden=\"true\"></span>`;\n }\n\n private renderGroupTriggerContent(group: ToolbarGroup, triggerLabel: string, iconName: string) {\n const icon = getToolbarButtonIcon(iconName);\n const showTextLabel = Boolean(group.label);\n\n if (showTextLabel && triggerLabel) {\n return html`\n <span class=\"toolbar-btn__trigger-label\">${triggerLabel}</span>\n <span class=\"toolbar-btn__chevron\">${unsafeSVG(TOOLBAR_CHEVRON_HTML)}</span>\n `;\n }\n\n return html`\n ${icon ? unsafeSVG(icon) : html`<span class=\"toolbar-btn__trigger-label\">${triggerLabel}</span>`}\n <span class=\"toolbar-btn__chevron\">${unsafeSVG(TOOLBAR_CHEVRON_HTML)}</span>\n `;\n }\n\n private renderToolbarGroup(group: ToolbarGroup, groupKey: string) {\n const editor = this.host.editor;\n const groupId = this.getToolbarGroupId(groupKey);\n const trigger = editor ? getToolbarGroupTriggerState(editor, group) : {\n activeName: null,\n label: group.label ?? '',\n isActive: false,\n icon: group.icon ?? getToolbarGroupDefaultIcon(group),\n };\n const menuItems = getToolbarGroupMenuItems(group).filter((entry) => {\n if (entry.type === 'separator') {\n return true;\n }\n\n const control = getRegisteredTiptapToolbarControl(entry.name);\n return !control?.isVisible || Boolean(editor && control.isVisible(editor));\n });\n\n if (!menuItems.some((entry) => entry.type === 'item')) {\n return nothing;\n }\n const tooltipLabel = group.label\n ?? (isHeadingsOnlyToolbarPreset(group.preset) ? 'Headings'\n : isFormattingToolbarPreset(group.preset) ? 'Formatting'\n : group.preset === 'lists' ? 'Lists'\n : group.preset === 'align' ? 'Alignment'\n : 'More');\n\n return html`\n <div class=\"toolbar-item\">\n <button\n id=${groupId}\n type=\"button\"\n class=\"toolbar-btn toolbar-btn--menu\"\n aria-label=${tooltipLabel}\n aria-haspopup=\"menu\"\n ?disabled=${this.disabled || this.readonly}\n data-state=${trigger.isActive ? 'active' : nothing}\n >\n ${this.renderGroupTriggerContent(group, trigger.label, trigger.icon)}\n </button>\n ${this.renderToolbarTooltip(groupId, tooltipLabel)}\n <pk-dropdown-menu for=${groupId} placement=\"bottom-start\">\n ${menuItems.map((entry, itemIndex) => {\n if (entry.type === 'separator') {\n return html`<pk-dropdown-separator key=${`${groupKey}-sep-${itemIndex}`}></pk-dropdown-separator>`;\n }\n\n const itemName = entry.name;\n const active = editor ? isToolbarButtonActive(editor, itemName) : false;\n const prefixIcon = createToolbarPrefixIcon(itemName);\n const itemLabel = getToolbarMenuItemLabel(itemName);\n\n return html`\n <pk-dropdown-item\n key=${`${groupKey}-${itemName}-${itemIndex}`}\n ?data-active=${active || nothing}\n @click=${() => this.handleToolbarCommand(itemName)}\n >\n ${prefixIcon ?? nothing}\n ${itemLabel}\n </pk-dropdown-item>\n `;\n })}\n </pk-dropdown-menu>\n </div>\n `;\n }\n\n private renderToolbarNode(node: ToolbarNode, index: number) {\n if (node.type === 'separator') {\n return this.renderToolbarSeparator();\n }\n\n if (node.type === 'group') {\n return this.renderToolbarGroup(node.group, `group-${index}`);\n }\n\n if (node.name === 'link') {\n return this.renderLinkToolbarButton();\n }\n\n if (['font-family', 'font-size', 'text-color', 'line-height'].includes(node.name)) {\n return this.renderTextStyleToolbar(node.name);\n }\n\n return this.renderToolbarButton(node.name);\n }\n\n private renderDefaultToolbar() {\n // `toolbar-end` — append custom controls (Formie variable picker, etc.) into the\n // stock toolbar flex/gap. Prefer over replacing the whole bar via slot=\"toolbar\".\n return html`\n <div class=\"toolbar\" part=\"toolbar\">\n ${this.toolbarNodes.map((node, index) => this.renderToolbarNode(node, index))}\n <slot name=\"toolbar-end\"></slot>\n </div>\n `;\n }\n\n private renderLinkToolbarButton() {\n const editor = this.host.editor;\n const craftOptions = getCraftLinkOptions(this.resolveLinkOptions());\n const label = this.getToolbarButtonLabel('link');\n const active = this.isLinkActive();\n\n return html`\n <div class=\"toolbar-item\">\n <button\n id=${this.linkButtonId}\n type=\"button\"\n class=\"toolbar-btn\"\n aria-label=${label}\n aria-haspopup=\"menu\"\n ?disabled=${this.disabled || this.readonly}\n data-state=${active ? 'active' : nothing}\n >\n ${unsafeSVG(TOOLBAR_ICONS.link)}\n </button>\n ${this.renderToolbarTooltip(this.linkButtonId, label)}\n <pk-dropdown-menu for=${this.linkButtonId} placement=\"bottom-start\">\n ${craftOptions.map((option) => html`\n <pk-dropdown-item @click=${() => this.handleCraftLink(option)}>\n ${option.optionTitle}\n </pk-dropdown-item>\n `)}\n ${craftOptions.length > 0 ? html`<pk-dropdown-separator></pk-dropdown-separator>` : nothing}\n <pk-dropdown-item @click=${() => this.openLinkMenu()}>Insert Link</pk-dropdown-item>\n <pk-dropdown-item\n ?disabled=${!active}\n @click=${() => editor && unsetLinkFromEditor(editor)}\n >Unlink</pk-dropdown-item>\n </pk-dropdown-menu>\n </div>\n `;\n }\n\n override render() {\n return html`\n <div class=\"shell\" part=\"shell\">\n ${this.hasCustomToolbar\n ? html`<slot name=\"toolbar\"></slot>`\n : this.renderDefaultToolbar()}\n\n <div class=\"editor-mount\" part=\"editor\">\n ${this.contentError ? html`\n <div class=\"content-error\">\n <span>${unsafeSVG(renderIconHtml(triangleExclamation))}</span>\n <span>${this.contentError}</span>\n </div>\n ` : nothing}\n ${this.toolbarHasLink() && this.linkBubbleVisible ? this.renderLinkBubble() : nothing}\n </div>\n\n <input class=\"mirror-input\" type=\"text\" .value=${this.value} readonly tabindex=\"-1\" aria-hidden=\"true\" />\n ${this.toolbarHasLink() && this.linkDialogMounted ? this.renderLinkDialog() : nothing}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'pk-tiptap-editor': PkTiptapEditor;\n }\n}\n"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { n as query, r as state, t as property } from "./decorators-BkErmuYK.js"
3
3
  import { t as PkFormAssociatedElement } from "./pk-form-associated-element-Doh2K3pG.js";
4
4
  import { t as MirrorValidator } from "./mirror-validator-BkZlEv1Z.js";
5
5
  import { t as formControlStyles } from "./form-control.styles-CQ93gnVf.js";
6
- import { i as createVariableTagDomNodeView, n as tiptapInputProseMirrorStyles } from "./tiptap.styles-Cwb_cj9g.js";
6
+ import { a as refreshVariableTagPresentation, i as createVariableTagDomNodeView, n as tiptapInputProseMirrorStyles } from "./tiptap.styles-CUvGoddW.js";
7
7
  import { css, html } from "lit";
8
8
  import { Editor } from "@tiptap/core";
9
9
  import { contentToValue, createTiptapInputExtensions, dedupeVariableOptions, flattenVariableOptions, inputValueToContent } from "@verbb/plugin-kit-tiptap-core";
@@ -89,6 +89,7 @@ var PkTiptapInput = class PkTiptapInput extends PkFormAssociatedElement {
89
89
  this.suppressUpdateEmission = false;
90
90
  this._value = null;
91
91
  this.variableCategories = {};
92
+ this.variableTransformerRegistry = {};
92
93
  this.variableTagConfigure = null;
93
94
  this.readonly = false;
94
95
  this.invalid = false;
@@ -152,6 +153,7 @@ var PkTiptapInput = class PkTiptapInput extends PkFormAssociatedElement {
152
153
  super.disconnectedCallback();
153
154
  }
154
155
  updated(changed) {
156
+ if (changed.has("variableTransformerRegistry")) refreshVariableTagPresentation(this);
155
157
  if (changed.has("value") && !changed.has("defaultValue")) this.syncEditorContent();
156
158
  if (changed.has("defaultValue") && !this.valueHasChanged) this.syncEditorContent();
157
159
  if (changed.has("variableCategories") && this.editor) this.syncEditorContent(true);
@@ -224,6 +226,7 @@ var PkTiptapInput = class PkTiptapInput extends PkFormAssociatedElement {
224
226
  __decorate([query(".editor-mount")], PkTiptapInput.prototype, "editorMount", void 0);
225
227
  __decorate([query(".mirror-input")], PkTiptapInput.prototype, "input", void 0);
226
228
  __decorate([property({ attribute: false })], PkTiptapInput.prototype, "variableCategories", void 0);
229
+ __decorate([property({ attribute: false })], PkTiptapInput.prototype, "variableTransformerRegistry", void 0);
227
230
  __decorate([property({ attribute: false })], PkTiptapInput.prototype, "variableTagConfigure", void 0);
228
231
  __decorate([property({
229
232
  type: Boolean,
@@ -247,4 +250,4 @@ PkTiptapInput = __decorate([customElement("pk-tiptap-input")], PkTiptapInput);
247
250
  //#endregion
248
251
  export { PkTiptapInput as t };
249
252
 
250
- //# sourceMappingURL=pk-tiptap-input-asrD-8W6.js.map
253
+ //# sourceMappingURL=pk-tiptap-input-B8faxeqa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pk-tiptap-input-B8faxeqa.js","names":["_decorate"],"sources":["../../src/components/tiptap/pk-tiptap-input.styles.ts","../../src/components/tiptap/pk-tiptap-input.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const pkTiptapInputStyles = css`\n @layer pk-component {\n :host {\n display: block;\n width: 100%;\n font-family: var(--pk-font-family);\n font-size: var(--pk-font-size-base);\n line-height: 1.4;\n }\n\n /* Same chrome as pk-input .input — border/radius live on the shell. */\n .shell {\n box-sizing: border-box;\n border: var(--pk-input-border);\n border-radius: var(--pk-input-border-radius, var(--pk-radius-sm));\n background: var(--pk-input-bg);\n overflow: hidden;\n }\n\n :host([invalid]) .shell,\n :host(:state(user-invalid)) .shell {\n border-color: var(--pk-color-rose-600);\n }\n\n /* Editable-table cells (v1): flush TipTap shell — chips sit in the row, not a boxed field. */\n :host([fit-cell]),\n :host([data-editable-table-input]) {\n display: block;\n height: 100%;\n min-height: 100%;\n box-sizing: border-box;\n }\n\n :host([fit-cell]) .shell,\n :host([data-editable-table-input]) .shell {\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n height: 100%;\n min-height: 100%;\n }\n\n /* Read-only display (lists, picker cards): v1 skipped input chrome when readOnly. */\n :host([readonly]) .shell {\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n overflow: visible;\n }\n\n :host([fit-cell][invalid]) .shell,\n :host([fit-cell]:state(user-invalid)) .shell,\n :host([data-editable-table-input][invalid]) .shell,\n :host([data-editable-table-input]:state(user-invalid)) .shell {\n border: none;\n box-shadow: inset 0 0 0 1px var(--pk-color-rose-600);\n }\n\n .editor-mount {\n display: block;\n min-width: 0;\n }\n\n .mirror-input {\n display: none;\n }\n }\n`;\n","import { html } from 'lit';\nimport { customElement, property, query, state } from '../../decorators.js';\nimport type { PropertyValues } from 'lit';\nimport {\n contentToValue,\n createTiptapInputExtensions,\n dedupeVariableOptions,\n flattenVariableOptions,\n inputValueToContent,\n type VariableOption,\n} from '@verbb/plugin-kit-tiptap-core';\nimport { Editor } from '@tiptap/core';\n\nimport { formControlStyles } from '../../base/form-control.styles.js';\nimport { PkFormAssociatedElement } from '../../base/pk-form-associated-element.js';\nimport { MirrorValidator } from '../../validators/index.js';\nimport {\n createVariableTagDomNodeView,\n refreshVariableTagPresentation,\n type PkVariableTransformerRegistry,\n} from './variable-tag-node-view.js';\nimport { pkTiptapInputStyles } from './pk-tiptap-input.styles.js';\nimport { tiptapInputProseMirrorStyles } from './tiptap.styles.js';\n\n/** Category map keyed like Formie / kit v1 (`fieldsVariables`, `formVariables`, …). */\nexport type PkTiptapVariableCategories = Record<string, VariableOption[]>;\n\n@customElement('pk-tiptap-input')\nexport class PkTiptapInput extends PkFormAssociatedElement {\n // Compact input chrome only — do not pull in editor `tiptapProseMirrorStyles`\n // (padding: 1rem) or single-line fields look massively padded.\n static override styles = [formControlStyles, pkTiptapInputStyles, tiptapInputProseMirrorStyles];\n\n static override get validators() {\n return [...super.validators, MirrorValidator()];\n }\n\n override assumeInteractionOn = ['blur', 'input'];\n\n @query('.editor-mount')\n private editorMount!: HTMLDivElement;\n\n @query('.mirror-input')\n override input!: HTMLInputElement;\n\n private editor: Editor | null = null;\n\n private lastEmitted: string | null = null;\n\n /** Avoid setContent → onUpdate → pk-change loops with controlled React values. */\n private suppressUpdateEmission = false;\n\n private _value: string | null = null;\n\n /**\n * Variable options used to resolve chip labels when hydrating from `{token}` strings.\n * Without this, saved field tokens fall back to UID title-casing after reload.\n */\n @property({ attribute: false })\n variableCategories: PkTiptapVariableCategories = {};\n\n /** Transform names displayed as badges on configured variable tags. */\n @property({ attribute: false })\n variableTransformerRegistry: PkVariableTransformerRegistry = {};\n\n /**\n * Formie / React configure bridge — called when a chip is activated for editing.\n * Prefer this over listening for `pk-variable-tag-configure` from React.\n */\n @property({ attribute: false })\n variableTagConfigure: ((detail: import('./variable-tag-node-view.js').PkVariableTagConfigureDetail) => void) | null = null;\n\n @property({ type: Boolean, reflect: true })\n readonly = false;\n\n @property({ type: Boolean, reflect: true })\n invalid = false;\n\n /** Flush + fill parent cell (editable tables). */\n @property({ type: Boolean, reflect: true, attribute: 'fit-cell' })\n fitCell = false;\n\n get value(): string {\n if (this.valueHasChanged) {\n return this._value ?? '';\n }\n\n return this._value ?? this.defaultValue ?? '';\n }\n\n @state()\n set value(val: string | null) {\n const next = val ?? '';\n\n if (this._value === next) {\n return;\n }\n\n this.valueHasChanged = true;\n this._value = next;\n }\n\n @property({ attribute: 'value', reflect: true })\n defaultValue: string | null = '';\n\n get editorInstance() {\n return this.editor;\n }\n\n private resolveVariableLists(): {\n topLevel: VariableOption[];\n all: VariableOption[];\n } {\n const topLevel = dedupeVariableOptions(\n Object.values(this.variableCategories ?? {}).flatMap((items) => {\n return Array.isArray(items) ? items : [];\n }),\n );\n\n return {\n topLevel,\n all: flattenVariableOptions(topLevel),\n };\n }\n\n private resolveEditorContent() {\n const { topLevel, all } = this.resolveVariableLists();\n return inputValueToContent(this.value, topLevel, all);\n }\n\n protected override syncFormValue(): void {\n this.setValue(this.value || '');\n\n if (this.input) {\n this.input.value = this.value || '';\n }\n }\n\n protected override resetToDefaultValue(): void {\n this.valueHasChanged = false;\n this._value = null;\n this.syncEditorContent(true);\n }\n\n protected override restoreFormState(state: string | File | FormData | null): void {\n if (typeof state === 'string') {\n this.value = state;\n this.syncEditorContent(true);\n }\n }\n\n override disconnectedCallback(): void {\n this.editor?.destroy();\n this.editor = null;\n super.disconnectedCallback();\n }\n\n override updated(changed: PropertyValues): void {\n if (changed.has('variableTransformerRegistry')) {\n refreshVariableTagPresentation(this);\n }\n\n if (changed.has('value') && !changed.has('defaultValue')) {\n this.syncEditorContent();\n }\n\n if (changed.has('defaultValue') && !this.valueHasChanged) {\n this.syncEditorContent();\n }\n\n // Categories often arrive with the field after first paint — re-hydrate labels.\n if (changed.has('variableCategories') && this.editor) {\n this.syncEditorContent(true);\n }\n\n if (changed.has('disabled') || changed.has('readonly')) {\n this.editor?.setEditable(!this.disabled && !this.readonly);\n }\n\n super.updated(changed);\n }\n\n override firstUpdated(): void {\n this.mountEditor();\n this.syncFormValue();\n }\n\n private mountEditor(): void {\n const content = this.resolveEditorContent();\n\n this.editor = new Editor({\n element: this.editorMount,\n extensions: createTiptapInputExtensions({\n variableTagNodeView: createVariableTagDomNodeView(),\n }),\n content,\n editable: !this.disabled && !this.readonly,\n onUpdate: ({ editor }) => {\n const nextValue = contentToValue(editor.getJSON().content);\n this.lastEmitted = nextValue;\n\n if (this.suppressUpdateEmission) {\n return;\n }\n\n this.value = nextValue;\n\n if (this.input) {\n this.input.value = nextValue;\n }\n\n this.syncFormValue();\n this.emitValueChange(nextValue);\n },\n });\n }\n\n private syncEditorContent(force = false): void {\n if (!this.editor) {\n return;\n }\n\n if (!force && !this.readonly && this.editor.isFocused) {\n return;\n }\n\n const nextContent = this.resolveEditorContent();\n const currentContent = this.editor.getJSON();\n\n if (JSON.stringify(nextContent) === JSON.stringify(currentContent)) {\n return;\n }\n\n // Same token string with newly available categories still needs a force remount\n // so chip labels upgrade from UID fallback → option labels.\n if (!force && this.lastEmitted === this.value) {\n return;\n }\n\n this.suppressUpdateEmission = true;\n try {\n this.editor.commands.setContent(nextContent ?? { type: 'doc', content: [] });\n } finally {\n this.suppressUpdateEmission = false;\n }\n }\n\n private emitValueChange(value: string): void {\n this.dispatchEvent(new CustomEvent('pk-change', {\n detail: { value },\n bubbles: true,\n composed: true,\n }));\n this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));\n this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));\n }\n\n override render() {\n return html`\n <div class=\"shell\" part=\"shell\">\n <div class=\"editor-mount\" part=\"editor\"></div>\n <input class=\"mirror-input\" type=\"text\" .value=${this.value} readonly tabindex=\"-1\" aria-hidden=\"true\" />\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'pk-tiptap-input': PkTiptapInput;\n }\n}\n"],"mappings":"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"}