@verbb/plugin-kit-web 2.0.16 → 2.0.17
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.
- package/CHANGELOG.md +16 -0
- package/README.md +3 -3
- package/custom-elements.json +19620 -19410
- package/dist/chunks/{pk-autocomplete-kOT0Zlld.js → pk-autocomplete-IFL-u-RF.js} +2 -2
- package/dist/chunks/{pk-autocomplete-kOT0Zlld.js.map → pk-autocomplete-IFL-u-RF.js.map} +1 -1
- package/dist/chunks/{pk-combobox-Dn7UJ_CV.js → pk-combobox-CL9En0J-.js} +2 -2
- package/dist/chunks/{pk-combobox-Dn7UJ_CV.js.map → pk-combobox-CL9En0J-.js.map} +1 -1
- package/dist/chunks/pk-copy-button-BVaOLtYG.js.map +1 -1
- package/dist/chunks/{pk-date-picker-DfIvmoZ1.js → pk-date-picker-BEAd4Ngl.js} +2 -2
- package/dist/chunks/{pk-date-picker-DfIvmoZ1.js.map → pk-date-picker-BEAd4Ngl.js.map} +1 -1
- package/dist/chunks/pk-dialog-VMQqLW1f.js.map +1 -1
- package/dist/chunks/{pk-dropdown-item-BZQS87U0.js → pk-dropdown-item-D9OaG5o-.js} +8 -4
- package/dist/chunks/pk-dropdown-item-D9OaG5o-.js.map +1 -0
- package/dist/chunks/{pk-dropdown-menu-D60p2-9X.js → pk-dropdown-menu-DW1wI8xQ.js} +5 -3
- package/dist/chunks/pk-dropdown-menu-DW1wI8xQ.js.map +1 -0
- package/dist/chunks/{pk-editable-table-BQ47MXpu.js → pk-editable-table-BoqfveXO.js} +7 -7
- package/dist/chunks/pk-editable-table-BoqfveXO.js.map +1 -0
- package/dist/chunks/{pk-image-browser-BXFDfch3.js → pk-image-browser-DwiCFOIG.js} +3 -3
- package/dist/chunks/pk-image-browser-DwiCFOIG.js.map +1 -0
- package/dist/chunks/pk-input-CF_icEtR.js.map +1 -1
- package/dist/chunks/{pk-input-group-CWdoVhkH.js → pk-input-group-BLqKPnfc.js} +2 -2
- package/dist/chunks/{pk-input-group-CWdoVhkH.js.map → pk-input-group-BLqKPnfc.js.map} +1 -1
- package/dist/chunks/{pk-popover-KSIOYlbs.js → pk-popover-D3jkHfwB.js} +2 -2
- package/dist/chunks/pk-popover-D3jkHfwB.js.map +1 -0
- package/dist/chunks/{pk-popup-B9AgBC2V.js → pk-popup-B65tZMQH.js} +23 -1
- package/dist/chunks/pk-popup-B65tZMQH.js.map +1 -0
- package/dist/chunks/{pk-select-DQtORz-v.js → pk-select-CdQdhnZN.js} +2 -2
- package/dist/chunks/{pk-select-DQtORz-v.js.map → pk-select-CdQdhnZN.js.map} +1 -1
- package/dist/chunks/{pk-time-picker-DLUBYLFo.js → pk-time-picker-CebRqydV.js} +2 -2
- package/dist/chunks/{pk-time-picker-DLUBYLFo.js.map → pk-time-picker-CebRqydV.js.map} +1 -1
- package/dist/chunks/{pk-tiptap-content-BwkqYVJb.js → pk-tiptap-content-CL8smjGi.js} +5 -2
- package/dist/chunks/{pk-tiptap-content-BwkqYVJb.js.map → pk-tiptap-content-CL8smjGi.js.map} +1 -1
- package/dist/chunks/{pk-tiptap-editor-De8UUTis.js → pk-tiptap-editor-CTz-yfHL.js} +327 -11
- package/dist/chunks/pk-tiptap-editor-CTz-yfHL.js.map +1 -0
- package/dist/chunks/{pk-tooltip-Cmmc0916.js → pk-tooltip--QBV6puX.js} +2 -2
- package/dist/chunks/{pk-tooltip-Cmmc0916.js.map → pk-tooltip--QBV6puX.js.map} +1 -1
- package/dist/chunks/{register-posLyX3U.js → register-aJw-9RWi.js} +14 -14
- package/dist/chunks/{register-posLyX3U.js.map → register-aJw-9RWi.js.map} +1 -1
- package/dist/components/autocomplete/pk-autocomplete.js +1 -1
- package/dist/components/autocomplete.js +1 -1
- package/dist/components/combobox/pk-combobox.js +1 -1
- package/dist/components/combobox.js +1 -1
- package/dist/components/connect/pk-connect-oauth.d.ts +1 -1
- package/dist/components/connect/pk-connect-oauth.js.map +1 -1
- package/dist/components/copy-button/pk-copy-button.d.ts +1 -1
- package/dist/components/date-picker/pk-date-picker.js +1 -1
- package/dist/components/date-picker.js +1 -1
- package/dist/components/dialog/pk-dialog.d.ts +1 -1
- package/dist/components/dropdown-menu/pk-dropdown-item.d.ts +3 -1
- package/dist/components/dropdown-menu/pk-dropdown-item.d.ts.map +1 -1
- package/dist/components/dropdown-menu/pk-dropdown-item.js +1 -1
- package/dist/components/dropdown-menu/pk-dropdown-item.styles.d.ts.map +1 -1
- package/dist/components/dropdown-menu/pk-dropdown-menu.js +1 -1
- package/dist/components/dropdown-menu/pk-dropdown-menu.styles.d.ts.map +1 -1
- package/dist/components/dropdown-menu.js +2 -2
- package/dist/components/editable-table/pk-editable-table.d.ts +1 -1
- package/dist/components/editable-table/pk-editable-table.d.ts.map +1 -1
- package/dist/components/editable-table/pk-editable-table.js +1 -1
- package/dist/components/editable-table.js +1 -1
- package/dist/components/image-browser/pk-image-browser.d.ts +1 -1
- package/dist/components/image-browser/pk-image-browser.js +1 -1
- package/dist/components/image-browser.js +1 -1
- package/dist/components/input/pk-input.d.ts +2 -2
- package/dist/components/input-group/pk-input-group.d.ts +2 -2
- package/dist/components/input-group/pk-input-group.d.ts.map +1 -1
- package/dist/components/input-group/pk-input-group.js +1 -1
- package/dist/components/input-group.js +1 -1
- package/dist/components/popover/pk-popover.d.ts +2 -2
- package/dist/components/popover/pk-popover.js +1 -1
- package/dist/components/popover.js +1 -1
- package/dist/components/popup/pk-popup.d.ts +4 -0
- package/dist/components/popup/pk-popup.d.ts.map +1 -1
- package/dist/components/popup/pk-popup.js +1 -1
- package/dist/components/popup.js +1 -1
- package/dist/components/select/pk-select.js +1 -1
- package/dist/components/select.js +1 -1
- package/dist/components/time-picker/pk-time-picker.js +1 -1
- package/dist/components/time-picker.js +1 -1
- package/dist/components/tiptap/pk-tiptap-content.d.ts.map +1 -1
- package/dist/components/tiptap/pk-tiptap-content.js +1 -1
- package/dist/components/tiptap/pk-tiptap-editor.d.ts +11 -1
- package/dist/components/tiptap/pk-tiptap-editor.d.ts.map +1 -1
- package/dist/components/tiptap/pk-tiptap-editor.js +1 -1
- package/dist/components/tiptap/pk-tiptap-editor.styles.d.ts.map +1 -1
- package/dist/components/tiptap/tiptap-toolbar.d.ts +1 -0
- package/dist/components/tiptap/tiptap-toolbar.d.ts.map +1 -1
- package/dist/components/tiptap-content.js +1 -1
- package/dist/components/tiptap-editor.js +1 -1
- package/dist/components/tooltip/pk-tooltip.js +1 -1
- package/dist/components/tooltip.js +1 -1
- package/dist/index.js +14 -14
- package/dist/register.js +14 -14
- package/dist-loader/chunks/{option-filter-Z7bomRrK.js → option-filter-Bc5aNNT0.js} +1 -1
- package/dist-loader/chunks/{pk-button-dngp-vOd.js → pk-button-saBDszJV.js} +1 -1
- package/dist-loader/chunks/{pk-calendar-BE4HRfCq.js → pk-calendar-BrF8i3dW.js} +2 -2
- package/dist-loader/chunks/{pk-combobox-DMBKXPLB.js → pk-combobox-Cpx0w1KV.js} +6 -6
- package/dist-loader/chunks/{pk-date-picker-wntQmeIM.js → pk-date-picker-DEoiTOxN.js} +5 -5
- package/dist-loader/chunks/{pk-dialog-B6lzsRur.js → pk-dialog-C6aaPokv.js} +2 -2
- package/dist-loader/chunks/{pk-dropdown-item-DJ5TeF1r.js → pk-dropdown-item-D8RrwjxL.js} +9 -5
- package/dist-loader/chunks/pk-dropdown-label-Cg32UgRe.js +51 -0
- package/dist-loader/chunks/{pk-dropdown-menu-B87bsdlI.js → pk-dropdown-menu-CAHCltlX.js} +4 -2
- package/dist-loader/chunks/{pk-field-D_SNOJpl.js → pk-field-V7JOy26T.js} +2 -2
- package/dist-loader/chunks/{pk-icon-B5ob3JdK.js → pk-icon-Bph-EBqp.js} +1 -1
- package/dist-loader/chunks/{pk-option-Cc6QWw-0.js → pk-option-BrDMERSl.js} +2 -2
- package/dist-loader/chunks/{pk-popup-BooGjXgH.js → pk-popup-CrxxR-Hb.js} +23 -1
- package/dist-loader/chunks/{pk-select-BG8qPsBd.js → pk-select-Dok-JdSe.js} +5 -5
- package/dist-loader/chunks/{pk-time-picker-CDVFNhN7.js → pk-time-picker-h5Wgd4a_.js} +4 -4
- package/dist-loader/chunks/{pk-tooltip-BS2dNLOS.js → pk-tooltip-Dd_Q0Bn5.js} +1 -1
- package/dist-loader/chunks/{render-BKfL_WRl.js → render-Bnzcxfss.js} +1 -1
- package/dist-loader/chunks/{svg-BiAlXtCn.js → svg-Bz-bXZn7.js} +7 -1
- package/dist-loader/chunks/{tiptap-Db7MTUH1.js → tiptap-CgXkiK8d.js} +283 -13
- package/dist-loader/chunks/{tiptap.styles-BFGP4eTV.js → tiptap.styles-C0E1NpSx.js} +222 -3
- package/dist-loader/components/autocomplete/autocomplete.js +6 -6
- package/dist-loader/components/button/button.js +1 -1
- package/dist-loader/components/calendar/calendar.js +1 -1
- package/dist-loader/components/code-editor/code-editor.js +5 -5
- package/dist-loader/components/combobox/combobox.js +1 -1
- package/dist-loader/components/connect/connect-oauth.js +3 -3
- package/dist-loader/components/connect/connect.js +5 -5
- package/dist-loader/components/copy-button/copy-button.js +3 -3
- package/dist-loader/components/date-picker/date-picker.js +1 -1
- package/dist-loader/components/dialog/dialog.js +1 -1
- package/dist-loader/components/dropdown-menu/dropdown-item.js +1 -1
- package/dist-loader/components/dropdown-menu/dropdown-label.js +1 -50
- package/dist-loader/components/dropdown-menu/dropdown-menu.js +1 -1
- package/dist-loader/components/editable-table/editable-table.js +11 -11
- package/dist-loader/components/field/field.js +1 -1
- package/dist-loader/components/icon/icon.js +2 -2
- package/dist-loader/components/image-browser/image-browser.js +5 -5
- package/dist-loader/components/input-group/input-group.js +1 -1
- package/dist-loader/components/lightswitch/lightswitch.js +1 -1
- package/dist-loader/components/popover/popover.js +2 -2
- package/dist-loader/components/popup/popup.js +1 -1
- package/dist-loader/components/select/option.js +1 -1
- package/dist-loader/components/select/select.js +1 -1
- package/dist-loader/components/status/status.js +1 -1
- package/dist-loader/components/time-picker/time-picker.js +1 -1
- package/dist-loader/components/tiptap/tiptap-content.js +6 -3
- package/dist-loader/components/tiptap/tiptap-editor.js +332 -16
- package/dist-loader/components/tiptap/tiptap-input.js +2 -2
- package/dist-loader/components/tooltip/tooltip.js +1 -1
- package/package.json +11 -8
- package/dist/chunks/pk-dropdown-item-BZQS87U0.js.map +0 -1
- package/dist/chunks/pk-dropdown-menu-D60p2-9X.js.map +0 -1
- package/dist/chunks/pk-editable-table-BQ47MXpu.js.map +0 -1
- package/dist/chunks/pk-image-browser-BXFDfch3.js.map +0 -1
- package/dist/chunks/pk-popover-KSIOYlbs.js.map +0 -1
- package/dist/chunks/pk-popup-B9AgBC2V.js.map +0 -1
- package/dist/chunks/pk-tiptap-editor-De8UUTis.js.map +0 -1
- /package/dist-loader/chunks/{floating-ui-DU6GNott.js → floating-ui-Cj0imr6d.js} +0 -0
- /package/dist-loader/chunks/{pk-connect.styles-Bfgwu0VH.js → pk-connect.styles-k61snd3X.js} +0 -0
- /package/dist-loader/chunks/{pk-lightswitch-DRxY8511.js → pk-lightswitch-m23Cy3_D.js} +0 -0
- /package/dist-loader/chunks/{pk-status-D3ArH2ui.js → pk-status-D2g_77m_.js} +0 -0
- /package/dist-loader/chunks/{popup-pointer-caPc8kwB.js → popup-pointer-Ck28WdVP.js} +0 -0
- /package/dist-loader/chunks/{sync-listbox-separators-Dk_E_IVa.js → sync-listbox-separators-Ch5krDUs.js} +0 -0
|
@@ -9,16 +9,17 @@ import { n as renderIconHtml } from "./render-Dvc3MHQR.js";
|
|
|
9
9
|
import { i as uniqueId } from "./focus-aa5dlv8k.js";
|
|
10
10
|
import "./pk-input-CF_icEtR.js";
|
|
11
11
|
import "./pk-dialog-VMQqLW1f.js";
|
|
12
|
-
import "./pk-dropdown-item-
|
|
13
|
-
import "./pk-dropdown-menu-
|
|
12
|
+
import "./pk-dropdown-item-D9OaG5o-.js";
|
|
13
|
+
import "./pk-dropdown-menu-DW1wI8xQ.js";
|
|
14
|
+
import "./pk-dropdown-label-CRNWMWQd.js";
|
|
14
15
|
import "../components/dropdown-menu/pk-dropdown-separator.js";
|
|
15
16
|
import "./pk-field-UAlMq6mQ.js";
|
|
16
|
-
import "./pk-tooltip
|
|
17
|
+
import "./pk-tooltip--QBV6puX.js";
|
|
17
18
|
import { i as createVariableTagDomNodeView, r as tiptapProseMirrorStyles } from "./tiptap.styles-CPRows--.js";
|
|
18
19
|
import { css, html, nothing } from "lit";
|
|
19
20
|
import { unsafeSVG } from "lit/directives/unsafe-svg.js";
|
|
20
21
|
import { Editor, getMarkRange, posToDOMRect } from "@tiptap/core";
|
|
21
|
-
import { applyLinkToEditor, createTiptapExtensions, getCraftLinkOptions, getFatalTiptapContentError, getLinkEditState, getLinkOpenInNewTab, getLinkOptionsElementSiteId, getSelectedText, getToolbarGroupDefaultIcon, getToolbarGroupMenuItems, getToolbarGroupTriggerState, isFormattingToolbarPreset, isHeadingsOnlyToolbarPreset, isTiptapButtonActive, isToolbarButtonActive, normalizeContentArray, openCraftElementLinkSelector, parseToolbarConfig, runToolbarButton, toolbarIncludesButton, unsetLinkFromEditor, valueToContent } from "@verbb/plugin-kit-tiptap-core";
|
|
22
|
+
import { applyLinkToEditor, createTiptapExtensions, getCraftLinkOptions, getFatalTiptapContentError, getLinkEditState, getLinkOpenInNewTab, getLinkOptionsElementSiteId, getRegisteredTiptapToolbarControl, getSelectedText, getToolbarGroupDefaultIcon, getToolbarGroupMenuItems, getToolbarGroupTriggerState, isFormattingToolbarPreset, isHeadingsOnlyToolbarPreset, isTiptapButtonActive, isToolbarButtonActive, normalizeContentArray, openCraftElementLinkSelector, parseToolbarConfig, resolveTiptapTextStyleToolbarConfig, runToolbarButton, toolbarIncludesButton, unsetLinkFromEditor, valueToContent } from "@verbb/plugin-kit-tiptap-core";
|
|
22
23
|
//#region src/components/tiptap/tiptap-editor-host.ts
|
|
23
24
|
function serializeTiptapDocumentContent(content) {
|
|
24
25
|
return JSON.stringify(normalizeContentArray(content));
|
|
@@ -121,6 +122,7 @@ var TOOLBAR_ICONS = {
|
|
|
121
122
|
strikethrough: renderIconHtml(icons_exports.strikethrough),
|
|
122
123
|
subscript: renderIconHtml(icons_exports.subscript),
|
|
123
124
|
superscript: renderIconHtml(icons_exports.superscript),
|
|
125
|
+
"small-caps": renderIconHtml(icons_exports.smallCaps),
|
|
124
126
|
code: renderIconHtml(icons_exports.bracketsCurly),
|
|
125
127
|
"code-block": renderIconHtml(icons_exports.code),
|
|
126
128
|
highlight: renderIconHtml(icons_exports.highlighter),
|
|
@@ -154,6 +156,11 @@ var TOOLBAR_LABELS = {
|
|
|
154
156
|
strikethrough: "Strikethrough",
|
|
155
157
|
subscript: "Subscript",
|
|
156
158
|
superscript: "Superscript",
|
|
159
|
+
"small-caps": "Small caps",
|
|
160
|
+
"font-family": "Font family",
|
|
161
|
+
"font-size": "Font size",
|
|
162
|
+
"text-color": "Text and background color",
|
|
163
|
+
"line-height": "Line height",
|
|
157
164
|
code: "Inline code",
|
|
158
165
|
"code-block": "Code block",
|
|
159
166
|
highlight: "Highlight",
|
|
@@ -180,11 +187,15 @@ var TOOLBAR_LABELS = {
|
|
|
180
187
|
redo: "Redo"
|
|
181
188
|
};
|
|
182
189
|
function getToolbarMenuItemLabel(buttonName) {
|
|
183
|
-
return TOOLBAR_LABELS[buttonName] ?? buttonName;
|
|
190
|
+
return TOOLBAR_LABELS[buttonName] ?? getRegisteredTiptapToolbarControl(buttonName)?.label ?? buttonName;
|
|
191
|
+
}
|
|
192
|
+
function getToolbarButtonIcon(buttonName) {
|
|
193
|
+
const registeredIcon = getRegisteredTiptapToolbarControl(buttonName)?.icon;
|
|
194
|
+
return TOOLBAR_ICONS[buttonName] ?? (registeredIcon ? renderIconHtml(registeredIcon) : void 0);
|
|
184
195
|
}
|
|
185
196
|
/** Prefix icon for `pk-dropdown-item` — SVG must carry `slot="prefix"` directly. */
|
|
186
197
|
function createToolbarPrefixIcon(buttonName) {
|
|
187
|
-
const iconHtml =
|
|
198
|
+
const iconHtml = getToolbarButtonIcon(buttonName);
|
|
188
199
|
if (!iconHtml) return null;
|
|
189
200
|
const template = document.createElement("template");
|
|
190
201
|
template.innerHTML = iconHtml.trim();
|
|
@@ -315,6 +326,136 @@ var pkTiptapEditorStyles = css`
|
|
|
315
326
|
letter-spacing: 0.02em;
|
|
316
327
|
}
|
|
317
328
|
|
|
329
|
+
.toolbar-btn--text-style {
|
|
330
|
+
max-width: 9rem;
|
|
331
|
+
padding-inline: 0.5rem;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.toolbar-btn__text-style-value {
|
|
335
|
+
overflow: hidden;
|
|
336
|
+
font-size: var(--pk-font-size-xs);
|
|
337
|
+
line-height: 1;
|
|
338
|
+
text-overflow: ellipsis;
|
|
339
|
+
white-space: nowrap;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.toolbar-btn--color .toolbar-btn__text-style-value {
|
|
343
|
+
min-width: 1rem;
|
|
344
|
+
border-bottom: 2px solid var(--text-style-trigger-color, currentColor);
|
|
345
|
+
color: var(--text-style-trigger-color, currentColor);
|
|
346
|
+
font-weight: 700;
|
|
347
|
+
text-align: center;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
pk-dropdown-menu.text-style-palette::part(panel) {
|
|
351
|
+
display: grid;
|
|
352
|
+
grid-template-columns: repeat(5, 2rem);
|
|
353
|
+
gap: 0.625rem 0.75rem;
|
|
354
|
+
width: max-content;
|
|
355
|
+
min-width: 0;
|
|
356
|
+
padding: 1rem;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.text-style-palette__label {
|
|
360
|
+
grid-column: 1 / -1;
|
|
361
|
+
color: var(--pk-color-gray-900);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.text-style-palette__label::part(label) {
|
|
365
|
+
padding: 0 0 0.125rem;
|
|
366
|
+
font-size: var(--pk-font-size-base);
|
|
367
|
+
font-weight: 600;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.text-style-palette__label--highlight {
|
|
371
|
+
margin-top: 0.375rem;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.text-style-palette__option {
|
|
375
|
+
width: 2rem;
|
|
376
|
+
height: 2rem;
|
|
377
|
+
--pk-dropdown-item-gap: 0;
|
|
378
|
+
--pk-dropdown-item-icon-size: 1.625rem;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.text-style-palette__option::part(item) {
|
|
382
|
+
justify-content: center;
|
|
383
|
+
width: 2rem;
|
|
384
|
+
height: 2rem;
|
|
385
|
+
min-height: 0;
|
|
386
|
+
padding: 0;
|
|
387
|
+
border-radius: 50%;
|
|
388
|
+
background: transparent;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.text-style-palette__option:hover::part(item),
|
|
392
|
+
.text-style-palette__option:focus-within::part(item),
|
|
393
|
+
.text-style-palette__option[data-highlighted]::part(item),
|
|
394
|
+
.text-style-palette__option[checked]::part(item) {
|
|
395
|
+
background: transparent;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.text-style-palette__option::part(prefix) {
|
|
399
|
+
width: 1.625rem;
|
|
400
|
+
height: 1.625rem;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.text-style-palette__option::part(label) {
|
|
404
|
+
position: absolute;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.text-style-palette__option::part(check) {
|
|
408
|
+
display: none;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.text-style-palette__swatch {
|
|
412
|
+
display: inline-flex;
|
|
413
|
+
align-items: center;
|
|
414
|
+
justify-content: center;
|
|
415
|
+
width: 1.625rem;
|
|
416
|
+
height: 1.625rem;
|
|
417
|
+
box-sizing: border-box;
|
|
418
|
+
border: 1px solid rgba(15, 23, 42, 0.16);
|
|
419
|
+
border-radius: 50%;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/* Keep the state treatment concentric with the slotted swatch. The
|
|
423
|
+
dropdown item's shadow button is wider than its prefix in some hosts. */
|
|
424
|
+
.text-style-palette__option:hover .text-style-palette__swatch,
|
|
425
|
+
.text-style-palette__option:focus-within .text-style-palette__swatch,
|
|
426
|
+
.text-style-palette__option[data-highlighted] .text-style-palette__swatch,
|
|
427
|
+
.text-style-palette__option[checked] .text-style-palette__swatch {
|
|
428
|
+
box-shadow: 0 0 0 0.25rem var(--pk-color-slate-100);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.text-style-palette__swatch--text {
|
|
432
|
+
border-color: var(--text-style-swatch, rgba(15, 23, 42, 0.35));
|
|
433
|
+
color: var(--text-style-swatch, #1f2937);
|
|
434
|
+
font-size: var(--pk-font-size-base);
|
|
435
|
+
font-weight: 500;
|
|
436
|
+
line-height: 1;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.text-style-palette__swatch--highlight {
|
|
440
|
+
background: var(--text-style-swatch, #fff);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.text-style-palette__accessible-label {
|
|
444
|
+
position: absolute;
|
|
445
|
+
width: 1px;
|
|
446
|
+
height: 1px;
|
|
447
|
+
padding: 0;
|
|
448
|
+
margin: -1px;
|
|
449
|
+
overflow: hidden;
|
|
450
|
+
clip: rect(0, 0, 0, 0);
|
|
451
|
+
white-space: nowrap;
|
|
452
|
+
border: 0;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
.text-style-palette pk-tooltip {
|
|
456
|
+
display: contents;
|
|
457
|
+
}
|
|
458
|
+
|
|
318
459
|
/* Full toolbar replace (slot=toolbar on host when hasCustomToolbar). */
|
|
319
460
|
.toolbar ::slotted([slot='toolbar']) {
|
|
320
461
|
display: contents;
|
|
@@ -449,6 +590,7 @@ var PkTiptapEditor = class PkTiptapEditor extends PkFormAssociatedElement {
|
|
|
449
590
|
this._value = null;
|
|
450
591
|
this.buttons = "bold,italic";
|
|
451
592
|
this.toolbar = null;
|
|
593
|
+
this.textStyleOptions = null;
|
|
452
594
|
this.linkOptions = null;
|
|
453
595
|
this.rows = 4;
|
|
454
596
|
this.placeholder = "";
|
|
@@ -625,6 +767,7 @@ var PkTiptapEditor = class PkTiptapEditor extends PkFormAssociatedElement {
|
|
|
625
767
|
});
|
|
626
768
|
queueMicrotask(() => {
|
|
627
769
|
this.attachSelectionListeners();
|
|
770
|
+
this.requestUpdate();
|
|
628
771
|
});
|
|
629
772
|
}
|
|
630
773
|
attachSelectionListeners() {
|
|
@@ -841,7 +984,7 @@ var PkTiptapEditor = class PkTiptapEditor extends PkFormAssociatedElement {
|
|
|
841
984
|
return id;
|
|
842
985
|
}
|
|
843
986
|
getToolbarButtonLabel(buttonName) {
|
|
844
|
-
return TOOLBAR_LABELS[buttonName] ?? buttonName;
|
|
987
|
+
return TOOLBAR_LABELS[buttonName] ?? getRegisteredTiptapToolbarControl(buttonName)?.label ?? buttonName;
|
|
845
988
|
}
|
|
846
989
|
renderToolbarTooltip(buttonId, label) {
|
|
847
990
|
if (!this.toolbarTooltips) return nothing;
|
|
@@ -851,7 +994,9 @@ var PkTiptapEditor = class PkTiptapEditor extends PkFormAssociatedElement {
|
|
|
851
994
|
}
|
|
852
995
|
renderToolbarButton(buttonName) {
|
|
853
996
|
const editor = this.host.editor;
|
|
854
|
-
const
|
|
997
|
+
const registered = getRegisteredTiptapToolbarControl(buttonName);
|
|
998
|
+
if (registered?.isVisible && (!editor || !registered.isVisible(editor))) return nothing;
|
|
999
|
+
const icon = getToolbarButtonIcon(buttonName);
|
|
855
1000
|
const label = this.getToolbarButtonLabel(buttonName);
|
|
856
1001
|
const buttonId = this.getToolbarButtonId(buttonName);
|
|
857
1002
|
const active = editor ? isTiptapButtonActive(editor, buttonName) : false;
|
|
@@ -872,6 +1017,152 @@ var PkTiptapEditor = class PkTiptapEditor extends PkFormAssociatedElement {
|
|
|
872
1017
|
</div>
|
|
873
1018
|
`;
|
|
874
1019
|
}
|
|
1020
|
+
get textStyleToolbarConfig() {
|
|
1021
|
+
return resolveTiptapTextStyleToolbarConfig(this.textStyleOptions);
|
|
1022
|
+
}
|
|
1023
|
+
getTextStyleValue(attribute) {
|
|
1024
|
+
const value = this.host.editor?.getAttributes("textStyle")[attribute];
|
|
1025
|
+
return typeof value === "string" && value ? value : null;
|
|
1026
|
+
}
|
|
1027
|
+
setTextStyleValue(attribute, value) {
|
|
1028
|
+
const editor = this.host.editor;
|
|
1029
|
+
if (!editor) return;
|
|
1030
|
+
const chain = editor.chain().focus();
|
|
1031
|
+
switch (attribute) {
|
|
1032
|
+
case "fontFamily":
|
|
1033
|
+
value ? chain.setFontFamily(value).run() : chain.unsetFontFamily().run();
|
|
1034
|
+
break;
|
|
1035
|
+
case "fontSize":
|
|
1036
|
+
value ? chain.setFontSize(value).run() : chain.unsetFontSize().run();
|
|
1037
|
+
break;
|
|
1038
|
+
case "color":
|
|
1039
|
+
value ? chain.setColor(value).run() : chain.unsetColor().run();
|
|
1040
|
+
break;
|
|
1041
|
+
case "backgroundColor":
|
|
1042
|
+
value ? chain.setBackgroundColor(value).run() : chain.unsetBackgroundColor().run();
|
|
1043
|
+
break;
|
|
1044
|
+
case "lineHeight":
|
|
1045
|
+
value ? chain.setLineHeight(value).run() : chain.unsetLineHeight().run();
|
|
1046
|
+
break;
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
getTextStyleOptionLabel(options, value) {
|
|
1050
|
+
return options.find((option) => option.value === value)?.label ?? options.find((option) => option.value === null)?.label ?? "Default";
|
|
1051
|
+
}
|
|
1052
|
+
renderTextStyleOptions(attribute, options) {
|
|
1053
|
+
const currentValue = this.getTextStyleValue(attribute);
|
|
1054
|
+
return options.map((option) => html`
|
|
1055
|
+
<pk-dropdown-item
|
|
1056
|
+
type="radio"
|
|
1057
|
+
radio-group=${attribute}
|
|
1058
|
+
value=${option.value ?? ""}
|
|
1059
|
+
?checked=${option.value === currentValue}
|
|
1060
|
+
@click=${() => this.setTextStyleValue(attribute, option.value)}
|
|
1061
|
+
>
|
|
1062
|
+
${option.label}
|
|
1063
|
+
</pk-dropdown-item>
|
|
1064
|
+
`);
|
|
1065
|
+
}
|
|
1066
|
+
renderTextStylePaletteOptions(attribute, options, idPrefix) {
|
|
1067
|
+
const currentValue = this.getTextStyleValue(attribute);
|
|
1068
|
+
const isTextColor = attribute === "color";
|
|
1069
|
+
return options.map((option, index) => {
|
|
1070
|
+
const optionId = `${idPrefix}-${attribute}-${index}`;
|
|
1071
|
+
const accessibleLabel = option.value ? `${option.label} ${isTextColor ? "text" : "highlight"}` : isTextColor ? "Default text color" : "No highlight";
|
|
1072
|
+
return html`
|
|
1073
|
+
<pk-dropdown-item
|
|
1074
|
+
id=${optionId}
|
|
1075
|
+
class="text-style-palette__option"
|
|
1076
|
+
type="radio"
|
|
1077
|
+
radio-group=${attribute}
|
|
1078
|
+
value=${option.value ?? ""}
|
|
1079
|
+
?checked=${option.value === currentValue}
|
|
1080
|
+
@click=${() => this.setTextStyleValue(attribute, option.value)}
|
|
1081
|
+
>
|
|
1082
|
+
<span
|
|
1083
|
+
slot="start"
|
|
1084
|
+
class="text-style-palette__swatch ${isTextColor ? "text-style-palette__swatch--text" : "text-style-palette__swatch--highlight"}"
|
|
1085
|
+
style=${option.value ? `--text-style-swatch:${option.value}` : ""}
|
|
1086
|
+
data-empty=${option.value === null ? "" : nothing}
|
|
1087
|
+
aria-hidden="true"
|
|
1088
|
+
>${isTextColor ? "A" : nothing}</span>
|
|
1089
|
+
<span class="text-style-palette__accessible-label">${accessibleLabel}</span>
|
|
1090
|
+
</pk-dropdown-item>
|
|
1091
|
+
${this.toolbarTooltips ? html`
|
|
1092
|
+
<pk-tooltip for=${optionId} content=${accessibleLabel} placement="top"></pk-tooltip>
|
|
1093
|
+
` : nothing}
|
|
1094
|
+
`;
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
handleTextStylePaletteKeyDown(event) {
|
|
1098
|
+
const delta = {
|
|
1099
|
+
ArrowLeft: -1,
|
|
1100
|
+
ArrowRight: 1,
|
|
1101
|
+
ArrowUp: -5,
|
|
1102
|
+
ArrowDown: 5
|
|
1103
|
+
}[event.key];
|
|
1104
|
+
if (!delta) return;
|
|
1105
|
+
const menu = event.currentTarget;
|
|
1106
|
+
const item = event.composedPath().find((node) => node instanceof HTMLElement && node.localName === "pk-dropdown-item" && node.classList.contains("text-style-palette__option"));
|
|
1107
|
+
const items = menu.getItems().filter((candidate) => candidate.classList.contains("text-style-palette__option"));
|
|
1108
|
+
const index = item ? items.indexOf(item) : -1;
|
|
1109
|
+
if (index === -1) return;
|
|
1110
|
+
const target = items[Math.max(0, Math.min(index + delta, items.length - 1))];
|
|
1111
|
+
event.preventDefault();
|
|
1112
|
+
event.stopPropagation();
|
|
1113
|
+
target?.focusControl();
|
|
1114
|
+
}
|
|
1115
|
+
renderTextStyleToolbar(buttonName) {
|
|
1116
|
+
const config = this.textStyleToolbarConfig;
|
|
1117
|
+
const buttonId = this.getToolbarButtonId(buttonName);
|
|
1118
|
+
const triggerColor = buttonName === "text-color" ? this.getTextStyleValue("color") : null;
|
|
1119
|
+
let triggerLabel = "";
|
|
1120
|
+
let menuContent = nothing;
|
|
1121
|
+
if (buttonName === "font-family") {
|
|
1122
|
+
triggerLabel = this.getTextStyleOptionLabel(config.fontFamilies, this.getTextStyleValue("fontFamily"));
|
|
1123
|
+
menuContent = html`${this.renderTextStyleOptions("fontFamily", config.fontFamilies)}`;
|
|
1124
|
+
} else if (buttonName === "font-size") {
|
|
1125
|
+
triggerLabel = this.getTextStyleOptionLabel(config.fontSizes, this.getTextStyleValue("fontSize"));
|
|
1126
|
+
menuContent = html`${this.renderTextStyleOptions("fontSize", config.fontSizes)}`;
|
|
1127
|
+
} else if (buttonName === "line-height") {
|
|
1128
|
+
triggerLabel = this.getTextStyleOptionLabel(config.lineHeights, this.getTextStyleValue("lineHeight"));
|
|
1129
|
+
menuContent = html`${this.renderTextStyleOptions("lineHeight", config.lineHeights)}`;
|
|
1130
|
+
} else {
|
|
1131
|
+
triggerLabel = "A";
|
|
1132
|
+
menuContent = html`
|
|
1133
|
+
<pk-dropdown-label class="text-style-palette__label">Text color</pk-dropdown-label>
|
|
1134
|
+
${this.renderTextStylePaletteOptions("color", config.textColors, buttonId)}
|
|
1135
|
+
<pk-dropdown-label class="text-style-palette__label text-style-palette__label--highlight">Highlight color</pk-dropdown-label>
|
|
1136
|
+
${this.renderTextStylePaletteOptions("backgroundColor", config.backgroundColors, buttonId)}
|
|
1137
|
+
`;
|
|
1138
|
+
}
|
|
1139
|
+
const label = this.getToolbarButtonLabel(buttonName);
|
|
1140
|
+
return html`
|
|
1141
|
+
<div class="toolbar-item">
|
|
1142
|
+
<button
|
|
1143
|
+
id=${buttonId}
|
|
1144
|
+
type="button"
|
|
1145
|
+
class="toolbar-btn toolbar-btn--menu toolbar-btn--text-style ${buttonName === "text-color" ? "toolbar-btn--color" : ""}"
|
|
1146
|
+
aria-label=${label}
|
|
1147
|
+
aria-haspopup="menu"
|
|
1148
|
+
?disabled=${this.disabled || this.readonly}
|
|
1149
|
+
style=${triggerColor ? `--text-style-trigger-color:${triggerColor}` : ""}
|
|
1150
|
+
>
|
|
1151
|
+
<span class="toolbar-btn__text-style-value">${triggerLabel}</span>
|
|
1152
|
+
<span class="toolbar-btn__chevron">${unsafeSVG(TOOLBAR_CHEVRON_HTML)}</span>
|
|
1153
|
+
</button>
|
|
1154
|
+
${this.renderToolbarTooltip(buttonId, label)}
|
|
1155
|
+
<pk-dropdown-menu
|
|
1156
|
+
for=${buttonId}
|
|
1157
|
+
placement="bottom-start"
|
|
1158
|
+
class=${buttonName === "text-color" ? "text-style-palette" : ""}
|
|
1159
|
+
@keydown=${buttonName === "text-color" ? this.handleTextStylePaletteKeyDown : nothing}
|
|
1160
|
+
>
|
|
1161
|
+
${menuContent}
|
|
1162
|
+
</pk-dropdown-menu>
|
|
1163
|
+
</div>
|
|
1164
|
+
`;
|
|
1165
|
+
}
|
|
875
1166
|
handleCraftLink(config) {
|
|
876
1167
|
const editor = this.host.editor;
|
|
877
1168
|
if (!editor) return;
|
|
@@ -901,7 +1192,7 @@ var PkTiptapEditor = class PkTiptapEditor extends PkFormAssociatedElement {
|
|
|
901
1192
|
return html`<span class="toolbar-separator" aria-hidden="true"></span>`;
|
|
902
1193
|
}
|
|
903
1194
|
renderGroupTriggerContent(group, triggerLabel, iconName) {
|
|
904
|
-
const icon =
|
|
1195
|
+
const icon = getToolbarButtonIcon(iconName);
|
|
905
1196
|
if (Boolean(group.label) && triggerLabel) return html`
|
|
906
1197
|
<span class="toolbar-btn__trigger-label">${triggerLabel}</span>
|
|
907
1198
|
<span class="toolbar-btn__chevron">${unsafeSVG(TOOLBAR_CHEVRON_HTML)}</span>
|
|
@@ -920,7 +1211,12 @@ var PkTiptapEditor = class PkTiptapEditor extends PkFormAssociatedElement {
|
|
|
920
1211
|
isActive: false,
|
|
921
1212
|
icon: group.icon ?? getToolbarGroupDefaultIcon(group)
|
|
922
1213
|
};
|
|
923
|
-
const menuItems = getToolbarGroupMenuItems(group)
|
|
1214
|
+
const menuItems = getToolbarGroupMenuItems(group).filter((entry) => {
|
|
1215
|
+
if (entry.type === "separator") return true;
|
|
1216
|
+
const control = getRegisteredTiptapToolbarControl(entry.name);
|
|
1217
|
+
return !control?.isVisible || Boolean(editor && control.isVisible(editor));
|
|
1218
|
+
});
|
|
1219
|
+
if (!menuItems.some((entry) => entry.type === "item")) return nothing;
|
|
924
1220
|
const tooltipLabel = group.label ?? (isHeadingsOnlyToolbarPreset(group.preset) ? "Headings" : isFormattingToolbarPreset(group.preset) ? "Formatting" : group.preset === "lists" ? "Lists" : group.preset === "align" ? "Alignment" : "More");
|
|
925
1221
|
return html`
|
|
926
1222
|
<div class="toolbar-item">
|
|
@@ -962,6 +1258,12 @@ var PkTiptapEditor = class PkTiptapEditor extends PkFormAssociatedElement {
|
|
|
962
1258
|
if (node.type === "separator") return this.renderToolbarSeparator();
|
|
963
1259
|
if (node.type === "group") return this.renderToolbarGroup(node.group, `group-${index}`);
|
|
964
1260
|
if (node.name === "link") return this.renderLinkToolbarButton();
|
|
1261
|
+
if ([
|
|
1262
|
+
"font-family",
|
|
1263
|
+
"font-size",
|
|
1264
|
+
"text-color",
|
|
1265
|
+
"line-height"
|
|
1266
|
+
].includes(node.name)) return this.renderTextStyleToolbar(node.name);
|
|
965
1267
|
return this.renderToolbarButton(node.name);
|
|
966
1268
|
}
|
|
967
1269
|
renderDefaultToolbar() {
|
|
@@ -1055,6 +1357,20 @@ __decorate([property({
|
|
|
1055
1357
|
}
|
|
1056
1358
|
}
|
|
1057
1359
|
})], PkTiptapEditor.prototype, "toolbar", void 0);
|
|
1360
|
+
__decorate([property({
|
|
1361
|
+
attribute: "text-style-options",
|
|
1362
|
+
converter: {
|
|
1363
|
+
fromAttribute: (value) => {
|
|
1364
|
+
if (!value) return null;
|
|
1365
|
+
try {
|
|
1366
|
+
return JSON.parse(value);
|
|
1367
|
+
} catch {
|
|
1368
|
+
return null;
|
|
1369
|
+
}
|
|
1370
|
+
},
|
|
1371
|
+
toAttribute: (value) => value ? JSON.stringify(value) : null
|
|
1372
|
+
}
|
|
1373
|
+
})], PkTiptapEditor.prototype, "textStyleOptions", void 0);
|
|
1058
1374
|
__decorate([property({ attribute: "link-options" })], PkTiptapEditor.prototype, "linkOptions", void 0);
|
|
1059
1375
|
__decorate([property({ attribute: "link-selector-storage-key-prefix" })], PkTiptapEditor.prototype, "linkSelectorStorageKeyPrefix", void 0);
|
|
1060
1376
|
__decorate([property({ type: Number })], PkTiptapEditor.prototype, "rows", void 0);
|
|
@@ -1089,4 +1405,4 @@ PkTiptapEditor = __decorate([customElement("pk-tiptap-editor")], PkTiptapEditor)
|
|
|
1089
1405
|
//#endregion
|
|
1090
1406
|
export { PkTiptapEditor as t };
|
|
1091
1407
|
|
|
1092
|
-
//# sourceMappingURL=pk-tiptap-editor-
|
|
1408
|
+
//# sourceMappingURL=pk-tiptap-editor-CTz-yfHL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pk-tiptap-editor-CTz-yfHL.js","names":[],"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 open = window.Craft?.createElementSelectorModal;\n\n if (!open) {\n throw new Error('Craft element selector is not available in this environment.');\n }\n\n open(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 { createVariableTagDomNodeView } 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 @property({ attribute: 'link-options' })\n linkOptions: string | null = null;\n\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 /**\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('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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"}
|