@bikdotai/bik-component-library 0.0.810 → 0.0.811-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. package/dist/cjs/editor/extensions/plainClipboard/PasteNormalizationExtension.js +1 -1
  2. package/dist/cjs/editor/extensions/plainClipboard/PasteNormalizationExtension.js.map +1 -1
  3. package/dist/cjs/editor/extensions/plainClipboard/pasteUtils.js +1 -1
  4. package/dist/cjs/editor/extensions/plainClipboard/pasteUtils.js.map +1 -1
  5. package/dist/cjs/src/components/QueryBuilder/Triggers/EVENTS/components/EventsTrigger.d.ts +1 -1
  6. package/dist/cjs/src/components/QueryBuilder/Triggers/EVENTS/selectors/useIGTriggerNameCacheSelector.d.ts +1 -1
  7. package/dist/cjs/src/components/QueryBuilder/Triggers/IG/components/IGTrigger.d.ts +1 -1
  8. package/dist/cjs/src/components/QueryBuilder/Triggers/IG/selectors/useIGTriggerNameCacheSelector.d.ts +1 -1
  9. package/dist/cjs/src/components/QueryBuilder/Triggers/components/BaseTriggerQueryBuilderNode.d.ts +2 -2
  10. package/dist/cjs/src/components/bik-layout/MockMenus.d.ts +1 -0
  11. package/dist/cjs/src/editor/extensions/plainClipboard/pasteUtils.d.ts +11 -0
  12. package/dist/esm/editor/extensions/plainClipboard/PasteNormalizationExtension.js +1 -1
  13. package/dist/esm/editor/extensions/plainClipboard/PasteNormalizationExtension.js.map +1 -1
  14. package/dist/esm/editor/extensions/plainClipboard/pasteUtils.js +1 -1
  15. package/dist/esm/editor/extensions/plainClipboard/pasteUtils.js.map +1 -1
  16. package/dist/esm/src/components/QueryBuilder/Triggers/EVENTS/components/EventsTrigger.d.ts +1 -1
  17. package/dist/esm/src/components/QueryBuilder/Triggers/EVENTS/selectors/useIGTriggerNameCacheSelector.d.ts +1 -1
  18. package/dist/esm/src/components/QueryBuilder/Triggers/IG/components/IGTrigger.d.ts +1 -1
  19. package/dist/esm/src/components/QueryBuilder/Triggers/IG/selectors/useIGTriggerNameCacheSelector.d.ts +1 -1
  20. package/dist/esm/src/components/QueryBuilder/Triggers/components/BaseTriggerQueryBuilderNode.d.ts +2 -2
  21. package/dist/esm/src/components/bik-layout/MockMenus.d.ts +1 -0
  22. package/dist/esm/src/editor/extensions/plainClipboard/pasteUtils.d.ts +11 -0
  23. package/package.json +1 -1
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../../../node_modules/@tiptap/core/dist/index.js"),t=require("@tiptap/pm/model"),r=require("@tiptap/pm/state"),a=require("@tiptap/pm/view"),n=require("./pasteUtils.js");const i=e.Extension.create({name:"pasteNormalization",addOptions:()=>({preserveMarks:!1}),addProseMirrorPlugins(){const e=this.options.preserveMarks;return[new r.Plugin({props:{decorations(e){const t=[];return e.doc.descendants(((e,r)=>{"paragraph"===e.type.name&&0===e.childCount&&t.push(a.Decoration.node(r,r+e.nodeSize,{class:"is-blank"}))})),a.DecorationSet.create(e.doc,t)},handlePaste(e,t){var r,a;const i=null===(r=t.clipboardData)||void 0===r?void 0:r.getData("text/html");if(null==i?void 0:i.includes("data-pm-slice"))return!1;const s=null===(a=t.clipboardData)||void 0===a?void 0:a.getData("text/plain");if(!s)return!1;const o=n.parseClipboardText(s,e.state.schema);return e.dispatch(e.state.tr.replaceSelection(o)),!0},clipboardTextParser:(e,t,r,a)=>n.parseClipboardText(e,a.state.schema),transformPastedHTML(e){if(e.includes("data-pm-slice"))return e;const t=document.createElement("div");return t.innerHTML=e,n.wrapInlineContent(t),n.cleanBlockBrs(t),n.stripTrailingBrs(t),t.innerHTML},transformPasted(r){let a=n.normalizeHardBreaks(r.content);return e||(a=n.stripRichMarks(a)),new t.Slice(a,r.openStart,r.openEnd)}}})]}});exports.PasteNormalizationExtension=i;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../../../node_modules/@tiptap/core/dist/index.js"),t=require("@tiptap/pm/model"),r=require("@tiptap/pm/state"),a=require("@tiptap/pm/view"),n=require("./pasteUtils.js");const i=e.Extension.create({name:"pasteNormalization",addOptions:()=>({preserveMarks:!1}),addProseMirrorPlugins(){const e=this.options.preserveMarks;return[new r.Plugin({props:{decorations(e){const t=[];return e.doc.descendants(((e,r)=>{"paragraph"===e.type.name&&0===e.childCount&&t.push(a.Decoration.node(r,r+e.nodeSize,{class:"is-blank"}))})),a.DecorationSet.create(e.doc,t)},handlePaste(e,t){var r,a;const i=null===(r=t.clipboardData)||void 0===r?void 0:r.getData("text/html");if(null==i?void 0:i.includes("data-pm-slice"))return!1;const s=(i?n.extractTextFromHtml(i):void 0)||(null===(a=t.clipboardData)||void 0===a?void 0:a.getData("text/plain"));if(!s)return!1;const o=n.parseClipboardText(s,e.state.schema);return e.dispatch(e.state.tr.replaceSelection(o)),!0},clipboardTextParser:(e,t,r,a)=>n.parseClipboardText(e,a.state.schema),transformPastedHTML(e){if(e.includes("data-pm-slice"))return e;const t=document.createElement("div");return t.innerHTML=e,n.wrapInlineContent(t),n.cleanBlockBrs(t),n.stripTrailingBrs(t),t.innerHTML},transformPasted(r){let a=n.normalizeHardBreaks(r.content);return e||(a=n.stripRichMarks(a)),new t.Slice(a,r.openStart,r.openEnd)}}})]}});exports.PasteNormalizationExtension=i;
2
2
  //# sourceMappingURL=PasteNormalizationExtension.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PasteNormalizationExtension.js","sources":["../../../../../src/editor/extensions/plainClipboard/PasteNormalizationExtension.ts"],"sourcesContent":["import { Extension } from '@tiptap/core';\nimport { Slice } from '@tiptap/pm/model';\nimport { Plugin } from '@tiptap/pm/state';\nimport { Decoration, DecorationSet } from '@tiptap/pm/view';\nimport {\n\tcleanBlockBrs,\n\tnormalizeHardBreaks,\n\tparseClipboardText,\n\tstripRichMarks,\n\tstripTrailingBrs,\n\twrapInlineContent,\n} from './pasteUtils';\n\n/**\n * Unified paste normalizer for all editor channels.\n *\n * Uses ProseMirror's recommended hooks instead of overriding handlePaste:\n * - clipboardTextParser: plain text → Slice (preserves blank lines)\n * - transformPastedHTML: HTML → HTML (cleans Google Docs / Word artifacts)\n * - transformPasted: Slice → Slice (normalizes hardBreaks, strips marks)\n *\n * Also decorates empty paragraphs with an `is-blank` CSS class so the\n * editor stylesheet can give blank lines precise height without extra margins.\n */\nexport const PasteNormalizationExtension = Extension.create({\n\tname: 'pasteNormalization',\n\taddOptions() {\n\t\treturn {\n\t\t\tpreserveMarks: false,\n\t\t};\n\t},\n\taddProseMirrorPlugins() {\n\t\tconst preserveMarks = this.options.preserveMarks;\n\t\treturn [\n\t\t\tnew Plugin({\n\t\t\t\tprops: {\n\t\t\t\t\tdecorations(state) {\n\t\t\t\t\t\tconst decorations: Decoration[] = [];\n\t\t\t\t\t\tstate.doc.descendants((node, pos) => {\n\t\t\t\t\t\t\tif (node.type.name === 'paragraph' && node.childCount === 0) {\n\t\t\t\t\t\t\t\tdecorations.push(\n\t\t\t\t\t\t\t\t\tDecoration.node(pos, pos + node.nodeSize, {\n\t\t\t\t\t\t\t\t\t\tclass: 'is-blank',\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn DecorationSet.create(state.doc, decorations);\n\t\t\t\t\t},\n\n\t\t\t\t\thandlePaste(view, event) {\n\t\t\t\t\t\tconst html = event.clipboardData?.getData('text/html');\n\t\t\t\t\t\tif (html?.includes('data-pm-slice')) return false;\n\t\t\t\t\t\tconst text = event.clipboardData?.getData('text/plain');\n\t\t\t\t\t\tif (!text) return false;\n\t\t\t\t\t\tconst slice = parseClipboardText(text, view.state.schema);\n\t\t\t\t\t\tview.dispatch(view.state.tr.replaceSelection(slice));\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t},\n\n\t\t\t\t\tclipboardTextParser(text, _$context, _plain, view) {\n\t\t\t\t\t\treturn parseClipboardText(text, view.state.schema);\n\t\t\t\t\t},\n\n\t\t\t\t\ttransformPastedHTML(html) {\n\t\t\t\t\t\tif (html.includes('data-pm-slice')) return html;\n\t\t\t\t\t\tconst container = document.createElement('div');\n\t\t\t\t\t\tcontainer.innerHTML = html;\n\t\t\t\t\t\twrapInlineContent(container);\n\t\t\t\t\t\tcleanBlockBrs(container);\n\t\t\t\t\t\tstripTrailingBrs(container);\n\t\t\t\t\t\treturn container.innerHTML;\n\t\t\t\t\t},\n\n\t\t\t\t\ttransformPasted(slice) {\n\t\t\t\t\t\tlet content = normalizeHardBreaks(slice.content);\n\t\t\t\t\t\tif (!preserveMarks) {\n\t\t\t\t\t\t\tcontent = stripRichMarks(content);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn new Slice(content, slice.openStart, slice.openEnd);\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t];\n\t},\n});\n"],"names":["PasteNormalizationExtension","Extension","create","name","addOptions","preserveMarks","addProseMirrorPlugins","this","options","Plugin","props","decorations","state","doc","descendants","node","pos","type","childCount","push","Decoration","nodeSize","class","DecorationSet","handlePaste","view","event","html","_a","clipboardData","getData","includes","text","_b","slice","parseClipboardText","schema","dispatch","tr","replaceSelection","clipboardTextParser","_$context","_plain","transformPastedHTML","container","document","createElement","innerHTML","wrapInlineContent","cleanBlockBrs","stripTrailingBrs","transformPasted","content","normalizeHardBreaks","stripRichMarks","Slice","openStart","openEnd"],"mappings":"kQAwBaA,EAA8BC,EAASA,UAACC,OAAO,CAC3DC,KAAM,qBACNC,WAAUA,KACF,CACNC,eAAe,IAGjBC,wBACC,MAAMD,EAAgBE,KAAKC,QAAQH,cACnC,MAAO,CACN,IAAII,EAAAA,OAAO,CACVC,MAAO,CACNC,YAAYC,GACX,MAAMD,EAA4B,GAUlC,OATAC,EAAMC,IAAIC,aAAY,CAACC,EAAMC,KACL,cAAnBD,EAAKE,KAAKd,MAA4C,IAApBY,EAAKG,YAC1CP,EAAYQ,KACXC,aAAWL,KAAKC,EAAKA,EAAMD,EAAKM,SAAU,CACzCC,MAAO,aAGT,IAEKC,EAAaA,cAACrB,OAAOU,EAAMC,IAAKF,EACvC,EAEDa,YAAYC,EAAMC,WACjB,MAAMC,EAA0B,QAAnBC,EAAAF,EAAMG,qBAAa,IAAAD,OAAA,EAAAA,EAAEE,QAAQ,aAC1C,GAAIH,aAAI,EAAJA,EAAMI,SAAS,iBAAkB,OAAO,EAC5C,MAAMC,EAA0B,QAAnBC,EAAAP,EAAMG,qBAAa,IAAAI,OAAA,EAAAA,EAAEH,QAAQ,cAC1C,IAAKE,EAAM,OAAO,EAClB,MAAME,EAAQC,EAAAA,mBAAmBH,EAAMP,EAAKb,MAAMwB,QAElD,OADAX,EAAKY,SAASZ,EAAKb,MAAM0B,GAAGC,iBAAiBL,KACtC,CACP,EAEDM,oBAAmBA,CAACR,EAAMS,EAAWC,EAAQjB,IACrCU,EAAkBA,mBAACH,EAAMP,EAAKb,MAAMwB,QAG5CO,oBAAoBhB,GACnB,GAAIA,EAAKI,SAAS,iBAAkB,OAAOJ,EAC3C,MAAMiB,EAAYC,SAASC,cAAc,OAKzC,OAJAF,EAAUG,UAAYpB,EACtBqB,EAAiBA,kBAACJ,GAClBK,EAAaA,cAACL,GACdM,EAAgBA,iBAACN,GACVA,EAAUG,SACjB,EAEDI,gBAAgBjB,GACf,IAAIkB,EAAUC,EAAAA,oBAAoBnB,EAAMkB,SAIxC,OAHK/C,IACJ+C,EAAUE,EAAAA,eAAeF,IAEnB,IAAIG,EAAKA,MAACH,EAASlB,EAAMsB,UAAWtB,EAAMuB,QAClD,KAIJ"}
1
+ {"version":3,"file":"PasteNormalizationExtension.js","sources":["../../../../../src/editor/extensions/plainClipboard/PasteNormalizationExtension.ts"],"sourcesContent":["import { Extension } from '@tiptap/core';\nimport { Slice } from '@tiptap/pm/model';\nimport { Plugin } from '@tiptap/pm/state';\nimport { Decoration, DecorationSet } from '@tiptap/pm/view';\nimport {\n\tcleanBlockBrs,\n\textractTextFromHtml,\n\tnormalizeHardBreaks,\n\tparseClipboardText,\n\tstripRichMarks,\n\tstripTrailingBrs,\n\twrapInlineContent,\n} from './pasteUtils';\n\n/**\n * Unified paste normalizer for all editor channels.\n *\n * Uses ProseMirror's recommended hooks instead of overriding handlePaste:\n * - clipboardTextParser: plain text → Slice (preserves blank lines)\n * - transformPastedHTML: HTML → HTML (cleans Google Docs / Word artifacts)\n * - transformPasted: Slice → Slice (normalizes hardBreaks, strips marks)\n *\n * Also decorates empty paragraphs with an `is-blank` CSS class so the\n * editor stylesheet can give blank lines precise height without extra margins.\n */\nexport const PasteNormalizationExtension = Extension.create({\n\tname: 'pasteNormalization',\n\taddOptions() {\n\t\treturn {\n\t\t\tpreserveMarks: false,\n\t\t};\n\t},\n\taddProseMirrorPlugins() {\n\t\tconst preserveMarks = this.options.preserveMarks;\n\t\treturn [\n\t\t\tnew Plugin({\n\t\t\t\tprops: {\n\t\t\t\t\tdecorations(state) {\n\t\t\t\t\t\tconst decorations: Decoration[] = [];\n\t\t\t\t\t\tstate.doc.descendants((node, pos) => {\n\t\t\t\t\t\t\tif (node.type.name === 'paragraph' && node.childCount === 0) {\n\t\t\t\t\t\t\t\tdecorations.push(\n\t\t\t\t\t\t\t\t\tDecoration.node(pos, pos + node.nodeSize, {\n\t\t\t\t\t\t\t\t\t\tclass: 'is-blank',\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn DecorationSet.create(state.doc, decorations);\n\t\t\t\t\t},\n\n\t\t\t\t\thandlePaste(view, event) {\n\t\t\t\t\t\tconst html = event.clipboardData?.getData('text/html');\n\t\t\t\t\t\tif (html?.includes('data-pm-slice')) return false;\n\t\t\t\t\t\tconst text =\n\t\t\t\t\t\t\t(html ? extractTextFromHtml(html) : undefined) ||\n\t\t\t\t\t\t\tevent.clipboardData?.getData('text/plain');\n\t\t\t\t\t\tif (!text) return false;\n\t\t\t\t\t\tconst slice = parseClipboardText(text, view.state.schema);\n\t\t\t\t\t\tview.dispatch(view.state.tr.replaceSelection(slice));\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t},\n\n\t\t\t\t\tclipboardTextParser(text, _$context, _plain, view) {\n\t\t\t\t\t\treturn parseClipboardText(text, view.state.schema);\n\t\t\t\t\t},\n\n\t\t\t\t\ttransformPastedHTML(html) {\n\t\t\t\t\t\tif (html.includes('data-pm-slice')) return html;\n\t\t\t\t\t\tconst container = document.createElement('div');\n\t\t\t\t\t\tcontainer.innerHTML = html;\n\t\t\t\t\t\twrapInlineContent(container);\n\t\t\t\t\t\tcleanBlockBrs(container);\n\t\t\t\t\t\tstripTrailingBrs(container);\n\t\t\t\t\t\treturn container.innerHTML;\n\t\t\t\t\t},\n\n\t\t\t\t\ttransformPasted(slice) {\n\t\t\t\t\t\tlet content = normalizeHardBreaks(slice.content);\n\t\t\t\t\t\tif (!preserveMarks) {\n\t\t\t\t\t\t\tcontent = stripRichMarks(content);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn new Slice(content, slice.openStart, slice.openEnd);\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t];\n\t},\n});\n"],"names":["PasteNormalizationExtension","Extension","create","name","addOptions","preserveMarks","addProseMirrorPlugins","this","options","Plugin","props","decorations","state","doc","descendants","node","pos","type","childCount","push","Decoration","nodeSize","class","DecorationSet","handlePaste","view","event","html","_a","clipboardData","getData","includes","text","extractTextFromHtml","undefined","_b","slice","parseClipboardText","schema","dispatch","tr","replaceSelection","clipboardTextParser","_$context","_plain","transformPastedHTML","container","document","createElement","innerHTML","wrapInlineContent","cleanBlockBrs","stripTrailingBrs","transformPasted","content","normalizeHardBreaks","stripRichMarks","Slice","openStart","openEnd"],"mappings":"kQAyBaA,EAA8BC,EAASA,UAACC,OAAO,CAC3DC,KAAM,qBACNC,WAAUA,KACF,CACNC,eAAe,IAGjBC,wBACC,MAAMD,EAAgBE,KAAKC,QAAQH,cACnC,MAAO,CACN,IAAII,EAAAA,OAAO,CACVC,MAAO,CACNC,YAAYC,GACX,MAAMD,EAA4B,GAUlC,OATAC,EAAMC,IAAIC,aAAY,CAACC,EAAMC,KACL,cAAnBD,EAAKE,KAAKd,MAA4C,IAApBY,EAAKG,YAC1CP,EAAYQ,KACXC,aAAWL,KAAKC,EAAKA,EAAMD,EAAKM,SAAU,CACzCC,MAAO,aAGT,IAEKC,EAAaA,cAACrB,OAAOU,EAAMC,IAAKF,EACvC,EAEDa,YAAYC,EAAMC,WACjB,MAAMC,EAA0B,QAAnBC,EAAAF,EAAMG,qBAAa,IAAAD,OAAA,EAAAA,EAAEE,QAAQ,aAC1C,GAAIH,aAAI,EAAJA,EAAMI,SAAS,iBAAkB,OAAO,EAC5C,MAAMC,GACJL,EAAOM,EAAmBA,oBAACN,QAAQO,KACjB,QAAnBC,EAAAT,EAAMG,qBAAa,IAAAM,OAAA,EAAAA,EAAEL,QAAQ,eAC9B,IAAKE,EAAM,OAAO,EAClB,MAAMI,EAAQC,EAAAA,mBAAmBL,EAAMP,EAAKb,MAAM0B,QAElD,OADAb,EAAKc,SAASd,EAAKb,MAAM4B,GAAGC,iBAAiBL,KACtC,CACP,EAEDM,oBAAmBA,CAACV,EAAMW,EAAWC,EAAQnB,IACrCY,EAAkBA,mBAACL,EAAMP,EAAKb,MAAM0B,QAG5CO,oBAAoBlB,GACnB,GAAIA,EAAKI,SAAS,iBAAkB,OAAOJ,EAC3C,MAAMmB,EAAYC,SAASC,cAAc,OAKzC,OAJAF,EAAUG,UAAYtB,EACtBuB,EAAiBA,kBAACJ,GAClBK,EAAaA,cAACL,GACdM,EAAgBA,iBAACN,GACVA,EAAUG,SACjB,EAEDI,gBAAgBjB,GACf,IAAIkB,EAAUC,EAAAA,oBAAoBnB,EAAMkB,SAIxC,OAHKjD,IACJiD,EAAUE,EAAAA,eAAeF,IAEnB,IAAIG,EAAKA,MAACH,EAASlB,EAAMsB,UAAWtB,EAAMuB,QAClD,KAIJ"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@tiptap/pm/model");const t=new Set(["P","LI","H1","H2","H3","H4","H5","H6","TD","TH","PRE"]),r="p,div,h1,h2,h3,h4,h5,h6,ul,ol,li,blockquote,table,pre",o=new Set(["bold","italic","strike","underline","code"]);exports.BLOCK_SELECTOR=r,exports.TEXTBLOCK_TAGS=t,exports.cleanBlockBrs=function(e){const r=Array.from(e.querySelectorAll("br"));for(const o of r){let r=!1,n=o.parentElement;for(;n&&n!==e;){if(t.has(n.tagName)){r=!0;break}n=n.parentElement}r||o.parentElement.replaceChild(document.createElement("p"),o)}},exports.normalizeHardBreaks=function t(r){const o=[];return r.forEach((r=>{var n,l;if("paragraph"===r.type.name){if(1===r.childCount&&"hardBreak"===(null===(n=r.firstChild)||void 0===n?void 0:n.type.name))return void o.push(r.type.create(r.attrs));if(r.childCount>1&&"hardBreak"===(null===(l=r.lastChild)||void 0===l?void 0:l.type.name)){const t=[];return r.content.forEach(((e,o,n)=>{n<r.childCount-1&&t.push(e)})),void o.push(r.copy(e.Fragment.from(t)))}}r.isBlock&&!r.isLeaf?o.push(r.copy(t(r.content))):o.push(r)})),e.Fragment.from(o)},exports.parseClipboardText=function(t,r){const o=t.split("\n").map((e=>r.node("paragraph",null,e?[r.text(e)]:[])));return new e.Slice(e.Fragment.fromArray(o),1,1)},exports.stripRichMarks=function t(r){const n=[];return r.forEach((e=>{if(e.isText){const t=e.marks.filter((e=>o.has(e.type.name)));n.push(t.length===e.marks.length?e:e.mark(t))}else n.push(e.copy(t(e.content)))})),e.Fragment.from(n)},exports.stripTrailingBrs=function(e){for(const t of["p","div"])for(const r of Array.from(e.querySelectorAll(t))){const e=r.lastElementChild;"BR"===(null==e?void 0:e.tagName)&&r.childNodes.length>1&&e.remove()}},exports.wrapInlineContent=function(e){if(e.querySelector(r))return;const t=Array.from(e.childNodes),o=[[]];for(let e=0;e<t.length;e++){const r=t[e];r instanceof HTMLBRElement&&t[e+1]instanceof HTMLBRElement?(o.push([]),e++):o[o.length-1].push(r)}for(;e.firstChild;)e.firstChild.remove();for(const t of o){const r=document.createElement("p");for(const e of t)r.appendChild(e);e.appendChild(r)}};
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@tiptap/pm/model");const t=new Set(["P","LI","H1","H2","H3","H4","H5","H6","TD","TH","PRE"]),r="p,div,h1,h2,h3,h4,h5,h6,ul,ol,li,blockquote,table,pre",n=new Set(["bold","italic","strike","underline","code"]);function o(e){if(e.querySelector(r))return;const t=Array.from(e.childNodes),n=[[]];for(let e=0;e<t.length;e++){const r=t[e];r instanceof HTMLBRElement&&t[e+1]instanceof HTMLBRElement?(n.push([]),e++):n[n.length-1].push(r)}for(;e.firstChild;)e.firstChild.remove();for(const t of n){const r=document.createElement("p");for(const e of t)r.appendChild(e);e.appendChild(r)}}function l(e){const r=Array.from(e.querySelectorAll("br"));for(const n of r){let r=!1,o=n.parentElement;for(;o&&o!==e;){if(t.has(o.tagName)){r=!0;break}o=o.parentElement}r||n.parentElement.replaceChild(document.createElement("p"),n)}}function a(e){for(const t of["p","div"])for(const r of Array.from(e.querySelectorAll(t))){const e=r.lastElementChild;"BR"===(null==e?void 0:e.tagName)&&r.childNodes.length>1&&e.remove()}}exports.BLOCK_SELECTOR=r,exports.TEXTBLOCK_TAGS=t,exports.cleanBlockBrs=l,exports.extractTextFromHtml=function(e){const t=document.createElement("div");t.innerHTML=e,o(t),l(t),a(t);const r="p,h1,h2,h3,h4,h5,h6,li,pre,td,th",n=Array.from(t.querySelectorAll(r));if(0===n.length)return;return n.filter((e=>!e.querySelector(r))).map((e=>e.textContent||"")).join("\n")},exports.normalizeHardBreaks=function t(r){const n=[];return r.forEach((r=>{var o,l;if("paragraph"===r.type.name){if(1===r.childCount&&"hardBreak"===(null===(o=r.firstChild)||void 0===o?void 0:o.type.name))return void n.push(r.type.create(r.attrs));if(r.childCount>1&&"hardBreak"===(null===(l=r.lastChild)||void 0===l?void 0:l.type.name)){const t=[];return r.content.forEach(((e,n,o)=>{o<r.childCount-1&&t.push(e)})),void n.push(r.copy(e.Fragment.from(t)))}}r.isBlock&&!r.isLeaf?n.push(r.copy(t(r.content))):n.push(r)})),e.Fragment.from(n)},exports.parseClipboardText=function(t,r){const n=t.split("\n").map((e=>r.node("paragraph",null,e?[r.text(e)]:[])));return new e.Slice(e.Fragment.fromArray(n),1,1)},exports.stripRichMarks=function t(r){const o=[];return r.forEach((e=>{if(e.isText){const t=e.marks.filter((e=>n.has(e.type.name)));o.push(t.length===e.marks.length?e:e.mark(t))}else o.push(e.copy(t(e.content)))})),e.Fragment.from(o)},exports.stripTrailingBrs=a,exports.wrapInlineContent=o;
2
2
  //# sourceMappingURL=pasteUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pasteUtils.js","sources":["../../../../../src/editor/extensions/plainClipboard/pasteUtils.ts"],"sourcesContent":["import { Fragment, Node as PMNode, Schema, Slice } from '@tiptap/pm/model';\n\nexport const TEXTBLOCK_TAGS = new Set([\n\t'P',\n\t'LI',\n\t'H1',\n\t'H2',\n\t'H3',\n\t'H4',\n\t'H5',\n\t'H6',\n\t'TD',\n\t'TH',\n\t'PRE',\n]);\n\nexport const BLOCK_SELECTOR =\n\t'p,div,h1,h2,h3,h4,h5,h6,ul,ol,li,blockquote,table,pre';\n\nconst BASIC_MARKS = new Set(['bold', 'italic', 'strike', 'underline', 'code']);\n\n/**\n * When pasted HTML is entirely inline (no block elements), split at\n * `<br><br>` boundaries into `<p>` elements. Single `<br>` stays as a\n * line break inside the paragraph.\n */\nexport function wrapInlineContent(container: HTMLElement): void {\n\tif (container.querySelector(BLOCK_SELECTOR)) return;\n\n\tconst children = Array.from(container.childNodes);\n\tconst groups: Node[][] = [[]];\n\n\tfor (let i = 0; i < children.length; i++) {\n\t\tconst node = children[i];\n\t\tif (\n\t\t\tnode instanceof HTMLBRElement &&\n\t\t\tchildren[i + 1] instanceof HTMLBRElement\n\t\t) {\n\t\t\tgroups.push([]);\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\tgroups[groups.length - 1].push(node);\n\t}\n\n\twhile (container.firstChild) container.firstChild.remove();\n\n\tfor (const group of groups) {\n\t\tconst p = document.createElement('p');\n\t\tfor (const node of group) p.appendChild(node);\n\t\tcontainer.appendChild(p);\n\t}\n}\n\n/**\n * Replace `<br>` elements that sit at block level (not inside a textblock\n * like `<p>`, `<li>`, etc.) with empty `<p></p>` elements. Google Docs\n * puts standalone `<br>` tags between paragraphs to represent blank lines.\n */\nexport function cleanBlockBrs(container: HTMLElement): void {\n\tconst brs = Array.from(container.querySelectorAll('br'));\n\tfor (const br of brs) {\n\t\tlet insideTextblock = false;\n\t\tlet el = br.parentElement;\n\t\twhile (el && el !== container) {\n\t\t\tif (TEXTBLOCK_TAGS.has(el.tagName)) {\n\t\t\t\tinsideTextblock = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tel = el.parentElement;\n\t\t}\n\t\tif (!insideTextblock) {\n\t\t\tbr.parentElement!.replaceChild(document.createElement('p'), br);\n\t\t}\n\t}\n}\n\n/**\n * Strip trailing `<br>` from content paragraphs in the DOM.\n * Google Docs adds a `<br>` at the end of non-empty paragraphs as a cursor\n * placeholder. Without this, ProseMirror creates a trailing hardBreak that\n * adds a visual blank line at the bottom of the paragraph.\n */\nexport function stripTrailingBrs(container: HTMLElement): void {\n\tfor (const tag of ['p', 'div']) {\n\t\tfor (const el of Array.from(container.querySelectorAll(tag))) {\n\t\t\tconst last = el.lastElementChild;\n\t\t\tif (last?.tagName === 'BR' && el.childNodes.length > 1) {\n\t\t\t\tlast.remove();\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Convert paragraphs containing only a hardBreak into truly empty paragraphs.\n * Google Docs represents blank lines as `<p><br></p>` — ProseMirror parses\n * the `<br>` as a hardBreak node, which renders double-height. Converting to\n * an empty paragraph (childCount 0) gives a single-height blank line.\n *\n * Does NOT collapse consecutive empties — that would destroy user intent.\n */\nexport function normalizeHardBreaks(fragment: Fragment): Fragment {\n\tconst nodes: PMNode[] = [];\n\tfragment.forEach((node) => {\n\t\tif (node.type.name === 'paragraph') {\n\t\t\tif (node.childCount === 1 && node.firstChild?.type.name === 'hardBreak') {\n\t\t\t\tnodes.push(node.type.create(node.attrs));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (node.childCount > 1 && node.lastChild?.type.name === 'hardBreak') {\n\t\t\t\tconst children: PMNode[] = [];\n\t\t\t\tnode.content.forEach((child, _offset, index) => {\n\t\t\t\t\tif (index < node.childCount - 1) children.push(child);\n\t\t\t\t});\n\t\t\t\tnodes.push(node.copy(Fragment.from(children)));\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif (node.isBlock && !node.isLeaf) {\n\t\t\tnodes.push(node.copy(normalizeHardBreaks(node.content)));\n\t\t} else {\n\t\t\tnodes.push(node);\n\t\t}\n\t});\n\treturn Fragment.from(nodes);\n}\n\n/**\n * Strip \"rich\" marks (link, textStyle, highlight, etc.) while keeping\n * basic marks (bold, italic, strike, underline, code) that messaging\n * channels can represent.\n */\nexport function stripRichMarks(fragment: Fragment): Fragment {\n\tconst nodes: PMNode[] = [];\n\tfragment.forEach((node) => {\n\t\tif (node.isText) {\n\t\t\tconst kept = node.marks.filter((m) => BASIC_MARKS.has(m.type.name));\n\t\t\tnodes.push(kept.length === node.marks.length ? node : node.mark(kept));\n\t\t} else {\n\t\t\tnodes.push(node.copy(stripRichMarks(node.content)));\n\t\t}\n\t});\n\treturn Fragment.from(nodes);\n}\n\n/**\n * Parse plain clipboard text into a ProseMirror Slice, preserving blank\n * lines as empty paragraphs. This replaces ProseMirror's default text\n * parser which uses `\\n+` and loses all blank lines.\n *\n * Best for channels with compact paragraph gaps (e.g. WhatsApp) where\n * blank lines need structural representation as empty paragraphs.\n */\nexport function parseClipboardText(text: string, schema: Schema): Slice {\n\tconst paragraphs = text\n\t\t.split('\\n')\n\t\t.map((line) =>\n\t\t\tschema.node('paragraph', null, line ? [schema.text(line)] : []),\n\t\t);\n\treturn new Slice(Fragment.fromArray(paragraphs), 1, 1);\n}\n\n/**\n * Parse plain clipboard text into a single paragraph with hardBreaks for\n * every `\\n`. Produces the same structure as Gmail's Cmd+Shift+V output:\n * one block element with `<br>` for line breaks and `<br><br>` for blank\n * lines. This gives identical html and text output to Gmail.\n */\nexport function parseClipboardTextAsBreaks(\n\ttext: string,\n\tschema: Schema,\n): Slice {\n\tconst trimmed = text.replace(/\\n+$/, '');\n\tif (!trimmed) {\n\t\treturn new Slice(Fragment.from(schema.node('paragraph', null, [])), 1, 1);\n\t}\n\tconst hardBreak = schema.nodes['hardBreak'];\n\tconst lines = trimmed.split('\\n');\n\tconst children: PMNode[] = [];\n\tlines.forEach((line, i) => {\n\t\tif (line) children.push(schema.text(line));\n\t\tif (i < lines.length - 1 && hardBreak) {\n\t\t\tchildren.push(hardBreak.create());\n\t\t}\n\t});\n\treturn new Slice(\n\t\tFragment.from(\n\t\t\tschema.node('paragraph', null, children.length ? children : []),\n\t\t),\n\t\t1,\n\t\t1,\n\t);\n}\n"],"names":["TEXTBLOCK_TAGS","Set","BLOCK_SELECTOR","BASIC_MARKS","container","brs","Array","from","querySelectorAll","br","insideTextblock","el","parentElement","has","tagName","replaceChild","document","createElement","normalizeHardBreaks","fragment","nodes","forEach","node","type","name","childCount","_a","firstChild","push","create","attrs","_b","lastChild","children","content","child","_offset","index","copy","Fragment","isBlock","isLeaf","text","schema","paragraphs","split","map","line","Slice","fromArray","stripRichMarks","isText","kept","marks","filter","m","length","mark","tag","last","lastElementChild","childNodes","remove","querySelector","groups","i","HTMLBRElement","group","p","appendChild"],"mappings":"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"}
1
+ {"version":3,"file":"pasteUtils.js","sources":["../../../../../src/editor/extensions/plainClipboard/pasteUtils.ts"],"sourcesContent":["import { Fragment, Node as PMNode, Schema, Slice } from '@tiptap/pm/model';\n\nexport const TEXTBLOCK_TAGS = new Set([\n\t'P',\n\t'LI',\n\t'H1',\n\t'H2',\n\t'H3',\n\t'H4',\n\t'H5',\n\t'H6',\n\t'TD',\n\t'TH',\n\t'PRE',\n]);\n\nexport const BLOCK_SELECTOR =\n\t'p,div,h1,h2,h3,h4,h5,h6,ul,ol,li,blockquote,table,pre';\n\nconst BASIC_MARKS = new Set(['bold', 'italic', 'strike', 'underline', 'code']);\n\n/**\n * When pasted HTML is entirely inline (no block elements), split at\n * `<br><br>` boundaries into `<p>` elements. Single `<br>` stays as a\n * line break inside the paragraph.\n */\nexport function wrapInlineContent(container: HTMLElement): void {\n\tif (container.querySelector(BLOCK_SELECTOR)) return;\n\n\tconst children = Array.from(container.childNodes);\n\tconst groups: Node[][] = [[]];\n\n\tfor (let i = 0; i < children.length; i++) {\n\t\tconst node = children[i];\n\t\tif (\n\t\t\tnode instanceof HTMLBRElement &&\n\t\t\tchildren[i + 1] instanceof HTMLBRElement\n\t\t) {\n\t\t\tgroups.push([]);\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\tgroups[groups.length - 1].push(node);\n\t}\n\n\twhile (container.firstChild) container.firstChild.remove();\n\n\tfor (const group of groups) {\n\t\tconst p = document.createElement('p');\n\t\tfor (const node of group) p.appendChild(node);\n\t\tcontainer.appendChild(p);\n\t}\n}\n\n/**\n * Replace `<br>` elements that sit at block level (not inside a textblock\n * like `<p>`, `<li>`, etc.) with empty `<p></p>` elements. Google Docs\n * puts standalone `<br>` tags between paragraphs to represent blank lines.\n */\nexport function cleanBlockBrs(container: HTMLElement): void {\n\tconst brs = Array.from(container.querySelectorAll('br'));\n\tfor (const br of brs) {\n\t\tlet insideTextblock = false;\n\t\tlet el = br.parentElement;\n\t\twhile (el && el !== container) {\n\t\t\tif (TEXTBLOCK_TAGS.has(el.tagName)) {\n\t\t\t\tinsideTextblock = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tel = el.parentElement;\n\t\t}\n\t\tif (!insideTextblock) {\n\t\t\tbr.parentElement!.replaceChild(document.createElement('p'), br);\n\t\t}\n\t}\n}\n\n/**\n * Strip trailing `<br>` from content paragraphs in the DOM.\n * Google Docs adds a `<br>` at the end of non-empty paragraphs as a cursor\n * placeholder. Without this, ProseMirror creates a trailing hardBreak that\n * adds a visual blank line at the bottom of the paragraph.\n */\nexport function stripTrailingBrs(container: HTMLElement): void {\n\tfor (const tag of ['p', 'div']) {\n\t\tfor (const el of Array.from(container.querySelectorAll(tag))) {\n\t\t\tconst last = el.lastElementChild;\n\t\t\tif (last?.tagName === 'BR' && el.childNodes.length > 1) {\n\t\t\t\tlast.remove();\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Convert paragraphs containing only a hardBreak into truly empty paragraphs.\n * Google Docs represents blank lines as `<p><br></p>` — ProseMirror parses\n * the `<br>` as a hardBreak node, which renders double-height. Converting to\n * an empty paragraph (childCount 0) gives a single-height blank line.\n *\n * Does NOT collapse consecutive empties — that would destroy user intent.\n */\nexport function normalizeHardBreaks(fragment: Fragment): Fragment {\n\tconst nodes: PMNode[] = [];\n\tfragment.forEach((node) => {\n\t\tif (node.type.name === 'paragraph') {\n\t\t\tif (node.childCount === 1 && node.firstChild?.type.name === 'hardBreak') {\n\t\t\t\tnodes.push(node.type.create(node.attrs));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (node.childCount > 1 && node.lastChild?.type.name === 'hardBreak') {\n\t\t\t\tconst children: PMNode[] = [];\n\t\t\t\tnode.content.forEach((child, _offset, index) => {\n\t\t\t\t\tif (index < node.childCount - 1) children.push(child);\n\t\t\t\t});\n\t\t\t\tnodes.push(node.copy(Fragment.from(children)));\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif (node.isBlock && !node.isLeaf) {\n\t\t\tnodes.push(node.copy(normalizeHardBreaks(node.content)));\n\t\t} else {\n\t\t\tnodes.push(node);\n\t\t}\n\t});\n\treturn Fragment.from(nodes);\n}\n\n/**\n * Strip \"rich\" marks (link, textStyle, highlight, etc.) while keeping\n * basic marks (bold, italic, strike, underline, code) that messaging\n * channels can represent.\n */\nexport function stripRichMarks(fragment: Fragment): Fragment {\n\tconst nodes: PMNode[] = [];\n\tfragment.forEach((node) => {\n\t\tif (node.isText) {\n\t\t\tconst kept = node.marks.filter((m) => BASIC_MARKS.has(m.type.name));\n\t\t\tnodes.push(kept.length === node.marks.length ? node : node.mark(kept));\n\t\t} else {\n\t\t\tnodes.push(node.copy(stripRichMarks(node.content)));\n\t\t}\n\t});\n\treturn Fragment.from(nodes);\n}\n\n/**\n * Extract plain text from clipboard HTML, using the DOM structure for\n * paragraph boundaries instead of relying on `text/plain` (which differs\n * between Mac and Windows for the same source, e.g. Google Docs).\n *\n * Reuses the existing HTML normalizers so `<br>` between blocks becomes an\n * empty `<p>`, then pulls `textContent` from each leaf block element.\n * Returns `undefined` when no block structure is found so the caller can\n * fall back to `text/plain`.\n */\nexport function extractTextFromHtml(html: string): string | undefined {\n\tconst container = document.createElement('div');\n\tcontainer.innerHTML = html;\n\n\twrapInlineContent(container);\n\tcleanBlockBrs(container);\n\tstripTrailingBrs(container);\n\n\tconst selector = 'p,h1,h2,h3,h4,h5,h6,li,pre,td,th';\n\tconst blocks = Array.from(container.querySelectorAll(selector));\n\n\tif (blocks.length === 0) return undefined;\n\n\tconst leafBlocks = blocks.filter((el) => !el.querySelector(selector));\n\n\treturn leafBlocks.map((el) => el.textContent || '').join('\\n');\n}\n\n/**\n * Parse plain clipboard text into a ProseMirror Slice, preserving blank\n * lines as empty paragraphs. This replaces ProseMirror's default text\n * parser which uses `\\n+` and loses all blank lines.\n *\n * Best for channels with compact paragraph gaps (e.g. WhatsApp) where\n * blank lines need structural representation as empty paragraphs.\n */\nexport function parseClipboardText(text: string, schema: Schema): Slice {\n\tconst paragraphs = text\n\t\t.split('\\n')\n\t\t.map((line) =>\n\t\t\tschema.node('paragraph', null, line ? [schema.text(line)] : []),\n\t\t);\n\treturn new Slice(Fragment.fromArray(paragraphs), 1, 1);\n}\n\n/**\n * Parse plain clipboard text into a single paragraph with hardBreaks for\n * every `\\n`. Produces the same structure as Gmail's Cmd+Shift+V output:\n * one block element with `<br>` for line breaks and `<br><br>` for blank\n * lines. This gives identical html and text output to Gmail.\n */\nexport function parseClipboardTextAsBreaks(\n\ttext: string,\n\tschema: Schema,\n): Slice {\n\tconst trimmed = text.replace(/\\n+$/, '');\n\tif (!trimmed) {\n\t\treturn new Slice(Fragment.from(schema.node('paragraph', null, [])), 1, 1);\n\t}\n\tconst hardBreak = schema.nodes['hardBreak'];\n\tconst lines = trimmed.split('\\n');\n\tconst children: PMNode[] = [];\n\tlines.forEach((line, i) => {\n\t\tif (line) children.push(schema.text(line));\n\t\tif (i < lines.length - 1 && hardBreak) {\n\t\t\tchildren.push(hardBreak.create());\n\t\t}\n\t});\n\treturn new Slice(\n\t\tFragment.from(\n\t\t\tschema.node('paragraph', null, children.length ? children : []),\n\t\t),\n\t\t1,\n\t\t1,\n\t);\n}\n"],"names":["TEXTBLOCK_TAGS","Set","BLOCK_SELECTOR","BASIC_MARKS","wrapInlineContent","container","querySelector","children","Array","from","childNodes","groups","i","length","node","HTMLBRElement","push","firstChild","remove","group","p","document","createElement","appendChild","cleanBlockBrs","brs","querySelectorAll","br","insideTextblock","el","parentElement","has","tagName","replaceChild","stripTrailingBrs","tag","last","lastElementChild","html","innerHTML","selector","blocks","filter","map","textContent","join","normalizeHardBreaks","fragment","nodes","forEach","type","name","childCount","_a","create","attrs","_b","lastChild","content","child","_offset","index","copy","Fragment","isBlock","isLeaf","text","schema","paragraphs","split","line","Slice","fromArray","stripRichMarks","isText","kept","marks","m","mark"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
- import { QueryBuilderNodeProps } from "../../../types/QueryBuilderNodeProps.type";
2
+ import { QueryBuilderNodeProps } from "../../../Types/QueryBuilderNodeProps.type";
3
3
  declare const EventsTrigger: React.FC<QueryBuilderNodeProps>;
4
4
  export default EventsTrigger;
@@ -1,2 +1,2 @@
1
- import { QueryBuilderAPIData } from "../../../types/QueryBuilderAPI.type";
1
+ import { QueryBuilderAPIData } from "../../../Types/QueryBuilderAPI.type";
2
2
  export declare const useIGTriggerNameCacheSelector: () => QueryBuilderAPIData[];
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
- import { QueryBuilderNodeProps } from "../../../types/QueryBuilderNodeProps.type";
2
+ import { QueryBuilderNodeProps } from "../../../Types/QueryBuilderNodeProps.type";
3
3
  declare const IGTrigger: React.FC<QueryBuilderNodeProps>;
4
4
  export default IGTrigger;
@@ -1,2 +1,2 @@
1
- import { QueryBuilderAPIData } from "../../../types/QueryBuilderAPI.type";
1
+ import { QueryBuilderAPIData } from "../../../Types/QueryBuilderAPI.type";
2
2
  export declare const useIGTriggerNameCacheSelector: () => QueryBuilderAPIData[];
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { DropdownOption } from "../../../dropdown/type";
3
- import { QueryBuilderProperty } from "../../types/QueryBuilder.type";
4
- import { QueryBuilderNodeProps } from "../../types/QueryBuilderNodeProps.type";
3
+ import { QueryBuilderProperty } from "../../Types/QueryBuilder.type";
4
+ import { QueryBuilderNodeProps } from "../../Types/QueryBuilderNodeProps.type";
5
5
  declare const BaseTriggerQueryBuilderNode: React.FC<QueryBuilderNodeProps & {
6
6
  cacheKey: string;
7
7
  propertyAddBtnText: string;
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  export declare const Menus: ({
2
3
  displayName: string;
3
4
  key: number;
@@ -35,6 +35,17 @@ export declare function normalizeHardBreaks(fragment: Fragment): Fragment;
35
35
  * channels can represent.
36
36
  */
37
37
  export declare function stripRichMarks(fragment: Fragment): Fragment;
38
+ /**
39
+ * Extract plain text from clipboard HTML, using the DOM structure for
40
+ * paragraph boundaries instead of relying on `text/plain` (which differs
41
+ * between Mac and Windows for the same source, e.g. Google Docs).
42
+ *
43
+ * Reuses the existing HTML normalizers so `<br>` between blocks becomes an
44
+ * empty `<p>`, then pulls `textContent` from each leaf block element.
45
+ * Returns `undefined` when no block structure is found so the caller can
46
+ * fall back to `text/plain`.
47
+ */
48
+ export declare function extractTextFromHtml(html: string): string | undefined;
38
49
  /**
39
50
  * Parse plain clipboard text into a ProseMirror Slice, preserving blank
40
51
  * lines as empty paragraphs. This replaces ProseMirror's default text
@@ -1,2 +1,2 @@
1
- import{Extension as t}from"../../../node_modules/@tiptap/core/dist/index.js";import{Slice as e}from"@tiptap/pm/model";import{Plugin as r}from"@tiptap/pm/state";import{Decoration as a,DecorationSet as n}from"@tiptap/pm/view";import{parseClipboardText as o,wrapInlineContent as s,cleanBlockBrs as i,stripTrailingBrs as p,normalizeHardBreaks as d,stripRichMarks as c}from"./pasteUtils.js";const l=t.create({name:"pasteNormalization",addOptions:()=>({preserveMarks:!1}),addProseMirrorPlugins(){const t=this.options.preserveMarks;return[new r({props:{decorations(t){const e=[];return t.doc.descendants(((t,r)=>{"paragraph"===t.type.name&&0===t.childCount&&e.push(a.node(r,r+t.nodeSize,{class:"is-blank"}))})),n.create(t.doc,e)},handlePaste(t,e){var r,a;const n=null===(r=e.clipboardData)||void 0===r?void 0:r.getData("text/html");if(null==n?void 0:n.includes("data-pm-slice"))return!1;const s=null===(a=e.clipboardData)||void 0===a?void 0:a.getData("text/plain");if(!s)return!1;const i=o(s,t.state.schema);return t.dispatch(t.state.tr.replaceSelection(i)),!0},clipboardTextParser:(t,e,r,a)=>o(t,a.state.schema),transformPastedHTML(t){if(t.includes("data-pm-slice"))return t;const e=document.createElement("div");return e.innerHTML=t,s(e),i(e),p(e),e.innerHTML},transformPasted(r){let a=d(r.content);return t||(a=c(a)),new e(a,r.openStart,r.openEnd)}}})]}});export{l as PasteNormalizationExtension};
1
+ import{Extension as t}from"../../../node_modules/@tiptap/core/dist/index.js";import{Slice as e}from"@tiptap/pm/model";import{Plugin as r}from"@tiptap/pm/state";import{Decoration as a,DecorationSet as n}from"@tiptap/pm/view";import{extractTextFromHtml as o,parseClipboardText as s,wrapInlineContent as i,cleanBlockBrs as p,stripTrailingBrs as d,normalizeHardBreaks as c,stripRichMarks as l}from"./pasteUtils.js";const m=t.create({name:"pasteNormalization",addOptions:()=>({preserveMarks:!1}),addProseMirrorPlugins(){const t=this.options.preserveMarks;return[new r({props:{decorations(t){const e=[];return t.doc.descendants(((t,r)=>{"paragraph"===t.type.name&&0===t.childCount&&e.push(a.node(r,r+t.nodeSize,{class:"is-blank"}))})),n.create(t.doc,e)},handlePaste(t,e){var r,a;const n=null===(r=e.clipboardData)||void 0===r?void 0:r.getData("text/html");if(null==n?void 0:n.includes("data-pm-slice"))return!1;const i=(n?o(n):void 0)||(null===(a=e.clipboardData)||void 0===a?void 0:a.getData("text/plain"));if(!i)return!1;const p=s(i,t.state.schema);return t.dispatch(t.state.tr.replaceSelection(p)),!0},clipboardTextParser:(t,e,r,a)=>s(t,a.state.schema),transformPastedHTML(t){if(t.includes("data-pm-slice"))return t;const e=document.createElement("div");return e.innerHTML=t,i(e),p(e),d(e),e.innerHTML},transformPasted(r){let a=c(r.content);return t||(a=l(a)),new e(a,r.openStart,r.openEnd)}}})]}});export{m as PasteNormalizationExtension};
2
2
  //# sourceMappingURL=PasteNormalizationExtension.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PasteNormalizationExtension.js","sources":["../../../../../src/editor/extensions/plainClipboard/PasteNormalizationExtension.ts"],"sourcesContent":["import { Extension } from '@tiptap/core';\nimport { Slice } from '@tiptap/pm/model';\nimport { Plugin } from '@tiptap/pm/state';\nimport { Decoration, DecorationSet } from '@tiptap/pm/view';\nimport {\n\tcleanBlockBrs,\n\tnormalizeHardBreaks,\n\tparseClipboardText,\n\tstripRichMarks,\n\tstripTrailingBrs,\n\twrapInlineContent,\n} from './pasteUtils';\n\n/**\n * Unified paste normalizer for all editor channels.\n *\n * Uses ProseMirror's recommended hooks instead of overriding handlePaste:\n * - clipboardTextParser: plain text → Slice (preserves blank lines)\n * - transformPastedHTML: HTML → HTML (cleans Google Docs / Word artifacts)\n * - transformPasted: Slice → Slice (normalizes hardBreaks, strips marks)\n *\n * Also decorates empty paragraphs with an `is-blank` CSS class so the\n * editor stylesheet can give blank lines precise height without extra margins.\n */\nexport const PasteNormalizationExtension = Extension.create({\n\tname: 'pasteNormalization',\n\taddOptions() {\n\t\treturn {\n\t\t\tpreserveMarks: false,\n\t\t};\n\t},\n\taddProseMirrorPlugins() {\n\t\tconst preserveMarks = this.options.preserveMarks;\n\t\treturn [\n\t\t\tnew Plugin({\n\t\t\t\tprops: {\n\t\t\t\t\tdecorations(state) {\n\t\t\t\t\t\tconst decorations: Decoration[] = [];\n\t\t\t\t\t\tstate.doc.descendants((node, pos) => {\n\t\t\t\t\t\t\tif (node.type.name === 'paragraph' && node.childCount === 0) {\n\t\t\t\t\t\t\t\tdecorations.push(\n\t\t\t\t\t\t\t\t\tDecoration.node(pos, pos + node.nodeSize, {\n\t\t\t\t\t\t\t\t\t\tclass: 'is-blank',\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn DecorationSet.create(state.doc, decorations);\n\t\t\t\t\t},\n\n\t\t\t\t\thandlePaste(view, event) {\n\t\t\t\t\t\tconst html = event.clipboardData?.getData('text/html');\n\t\t\t\t\t\tif (html?.includes('data-pm-slice')) return false;\n\t\t\t\t\t\tconst text = event.clipboardData?.getData('text/plain');\n\t\t\t\t\t\tif (!text) return false;\n\t\t\t\t\t\tconst slice = parseClipboardText(text, view.state.schema);\n\t\t\t\t\t\tview.dispatch(view.state.tr.replaceSelection(slice));\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t},\n\n\t\t\t\t\tclipboardTextParser(text, _$context, _plain, view) {\n\t\t\t\t\t\treturn parseClipboardText(text, view.state.schema);\n\t\t\t\t\t},\n\n\t\t\t\t\ttransformPastedHTML(html) {\n\t\t\t\t\t\tif (html.includes('data-pm-slice')) return html;\n\t\t\t\t\t\tconst container = document.createElement('div');\n\t\t\t\t\t\tcontainer.innerHTML = html;\n\t\t\t\t\t\twrapInlineContent(container);\n\t\t\t\t\t\tcleanBlockBrs(container);\n\t\t\t\t\t\tstripTrailingBrs(container);\n\t\t\t\t\t\treturn container.innerHTML;\n\t\t\t\t\t},\n\n\t\t\t\t\ttransformPasted(slice) {\n\t\t\t\t\t\tlet content = normalizeHardBreaks(slice.content);\n\t\t\t\t\t\tif (!preserveMarks) {\n\t\t\t\t\t\t\tcontent = stripRichMarks(content);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn new Slice(content, slice.openStart, slice.openEnd);\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t];\n\t},\n});\n"],"names":["PasteNormalizationExtension","Extension","create","name","addOptions","preserveMarks","addProseMirrorPlugins","this","options","Plugin","props","decorations","state","doc","descendants","node","pos","type","childCount","push","Decoration","nodeSize","class","DecorationSet","handlePaste","view","event","html","_a","clipboardData","getData","includes","text","_b","slice","parseClipboardText","schema","dispatch","tr","replaceSelection","clipboardTextParser","_$context","_plain","transformPastedHTML","container","document","createElement","innerHTML","wrapInlineContent","cleanBlockBrs","stripTrailingBrs","transformPasted","content","normalizeHardBreaks","stripRichMarks","Slice","openStart","openEnd"],"mappings":"wYAwBaA,EAA8BC,EAAUC,OAAO,CAC3DC,KAAM,qBACNC,WAAUA,KACF,CACNC,eAAe,IAGjBC,wBACC,MAAMD,EAAgBE,KAAKC,QAAQH,cACnC,MAAO,CACN,IAAII,EAAO,CACVC,MAAO,CACNC,YAAYC,GACX,MAAMD,EAA4B,GAUlC,OATAC,EAAMC,IAAIC,aAAY,CAACC,EAAMC,KACL,cAAnBD,EAAKE,KAAKd,MAA4C,IAApBY,EAAKG,YAC1CP,EAAYQ,KACXC,EAAWL,KAAKC,EAAKA,EAAMD,EAAKM,SAAU,CACzCC,MAAO,aAGT,IAEKC,EAAcrB,OAAOU,EAAMC,IAAKF,EACvC,EAEDa,YAAYC,EAAMC,WACjB,MAAMC,EAA0B,QAAnBC,EAAAF,EAAMG,qBAAa,IAAAD,OAAA,EAAAA,EAAEE,QAAQ,aAC1C,GAAIH,aAAI,EAAJA,EAAMI,SAAS,iBAAkB,OAAO,EAC5C,MAAMC,EAA0B,QAAnBC,EAAAP,EAAMG,qBAAa,IAAAI,OAAA,EAAAA,EAAEH,QAAQ,cAC1C,IAAKE,EAAM,OAAO,EAClB,MAAME,EAAQC,EAAmBH,EAAMP,EAAKb,MAAMwB,QAElD,OADAX,EAAKY,SAASZ,EAAKb,MAAM0B,GAAGC,iBAAiBL,KACtC,CACP,EAEDM,oBAAmBA,CAACR,EAAMS,EAAWC,EAAQjB,IACrCU,EAAmBH,EAAMP,EAAKb,MAAMwB,QAG5CO,oBAAoBhB,GACnB,GAAIA,EAAKI,SAAS,iBAAkB,OAAOJ,EAC3C,MAAMiB,EAAYC,SAASC,cAAc,OAKzC,OAJAF,EAAUG,UAAYpB,EACtBqB,EAAkBJ,GAClBK,EAAcL,GACdM,EAAiBN,GACVA,EAAUG,SACjB,EAEDI,gBAAgBjB,GACf,IAAIkB,EAAUC,EAAoBnB,EAAMkB,SAIxC,OAHK/C,IACJ+C,EAAUE,EAAeF,IAEnB,IAAIG,EAAMH,EAASlB,EAAMsB,UAAWtB,EAAMuB,QAClD,KAIJ"}
1
+ {"version":3,"file":"PasteNormalizationExtension.js","sources":["../../../../../src/editor/extensions/plainClipboard/PasteNormalizationExtension.ts"],"sourcesContent":["import { Extension } from '@tiptap/core';\nimport { Slice } from '@tiptap/pm/model';\nimport { Plugin } from '@tiptap/pm/state';\nimport { Decoration, DecorationSet } from '@tiptap/pm/view';\nimport {\n\tcleanBlockBrs,\n\textractTextFromHtml,\n\tnormalizeHardBreaks,\n\tparseClipboardText,\n\tstripRichMarks,\n\tstripTrailingBrs,\n\twrapInlineContent,\n} from './pasteUtils';\n\n/**\n * Unified paste normalizer for all editor channels.\n *\n * Uses ProseMirror's recommended hooks instead of overriding handlePaste:\n * - clipboardTextParser: plain text → Slice (preserves blank lines)\n * - transformPastedHTML: HTML → HTML (cleans Google Docs / Word artifacts)\n * - transformPasted: Slice → Slice (normalizes hardBreaks, strips marks)\n *\n * Also decorates empty paragraphs with an `is-blank` CSS class so the\n * editor stylesheet can give blank lines precise height without extra margins.\n */\nexport const PasteNormalizationExtension = Extension.create({\n\tname: 'pasteNormalization',\n\taddOptions() {\n\t\treturn {\n\t\t\tpreserveMarks: false,\n\t\t};\n\t},\n\taddProseMirrorPlugins() {\n\t\tconst preserveMarks = this.options.preserveMarks;\n\t\treturn [\n\t\t\tnew Plugin({\n\t\t\t\tprops: {\n\t\t\t\t\tdecorations(state) {\n\t\t\t\t\t\tconst decorations: Decoration[] = [];\n\t\t\t\t\t\tstate.doc.descendants((node, pos) => {\n\t\t\t\t\t\t\tif (node.type.name === 'paragraph' && node.childCount === 0) {\n\t\t\t\t\t\t\t\tdecorations.push(\n\t\t\t\t\t\t\t\t\tDecoration.node(pos, pos + node.nodeSize, {\n\t\t\t\t\t\t\t\t\t\tclass: 'is-blank',\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn DecorationSet.create(state.doc, decorations);\n\t\t\t\t\t},\n\n\t\t\t\t\thandlePaste(view, event) {\n\t\t\t\t\t\tconst html = event.clipboardData?.getData('text/html');\n\t\t\t\t\t\tif (html?.includes('data-pm-slice')) return false;\n\t\t\t\t\t\tconst text =\n\t\t\t\t\t\t\t(html ? extractTextFromHtml(html) : undefined) ||\n\t\t\t\t\t\t\tevent.clipboardData?.getData('text/plain');\n\t\t\t\t\t\tif (!text) return false;\n\t\t\t\t\t\tconst slice = parseClipboardText(text, view.state.schema);\n\t\t\t\t\t\tview.dispatch(view.state.tr.replaceSelection(slice));\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t},\n\n\t\t\t\t\tclipboardTextParser(text, _$context, _plain, view) {\n\t\t\t\t\t\treturn parseClipboardText(text, view.state.schema);\n\t\t\t\t\t},\n\n\t\t\t\t\ttransformPastedHTML(html) {\n\t\t\t\t\t\tif (html.includes('data-pm-slice')) return html;\n\t\t\t\t\t\tconst container = document.createElement('div');\n\t\t\t\t\t\tcontainer.innerHTML = html;\n\t\t\t\t\t\twrapInlineContent(container);\n\t\t\t\t\t\tcleanBlockBrs(container);\n\t\t\t\t\t\tstripTrailingBrs(container);\n\t\t\t\t\t\treturn container.innerHTML;\n\t\t\t\t\t},\n\n\t\t\t\t\ttransformPasted(slice) {\n\t\t\t\t\t\tlet content = normalizeHardBreaks(slice.content);\n\t\t\t\t\t\tif (!preserveMarks) {\n\t\t\t\t\t\t\tcontent = stripRichMarks(content);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn new Slice(content, slice.openStart, slice.openEnd);\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t];\n\t},\n});\n"],"names":["PasteNormalizationExtension","Extension","create","name","addOptions","preserveMarks","addProseMirrorPlugins","this","options","Plugin","props","decorations","state","doc","descendants","node","pos","type","childCount","push","Decoration","nodeSize","class","DecorationSet","handlePaste","view","event","html","_a","clipboardData","getData","includes","text","extractTextFromHtml","undefined","_b","slice","parseClipboardText","schema","dispatch","tr","replaceSelection","clipboardTextParser","_$context","_plain","transformPastedHTML","container","document","createElement","innerHTML","wrapInlineContent","cleanBlockBrs","stripTrailingBrs","transformPasted","content","normalizeHardBreaks","stripRichMarks","Slice","openStart","openEnd"],"mappings":"iaAyBaA,EAA8BC,EAAUC,OAAO,CAC3DC,KAAM,qBACNC,WAAUA,KACF,CACNC,eAAe,IAGjBC,wBACC,MAAMD,EAAgBE,KAAKC,QAAQH,cACnC,MAAO,CACN,IAAII,EAAO,CACVC,MAAO,CACNC,YAAYC,GACX,MAAMD,EAA4B,GAUlC,OATAC,EAAMC,IAAIC,aAAY,CAACC,EAAMC,KACL,cAAnBD,EAAKE,KAAKd,MAA4C,IAApBY,EAAKG,YAC1CP,EAAYQ,KACXC,EAAWL,KAAKC,EAAKA,EAAMD,EAAKM,SAAU,CACzCC,MAAO,aAGT,IAEKC,EAAcrB,OAAOU,EAAMC,IAAKF,EACvC,EAEDa,YAAYC,EAAMC,WACjB,MAAMC,EAA0B,QAAnBC,EAAAF,EAAMG,qBAAa,IAAAD,OAAA,EAAAA,EAAEE,QAAQ,aAC1C,GAAIH,aAAI,EAAJA,EAAMI,SAAS,iBAAkB,OAAO,EAC5C,MAAMC,GACJL,EAAOM,EAAoBN,QAAQO,KACjB,QAAnBC,EAAAT,EAAMG,qBAAa,IAAAM,OAAA,EAAAA,EAAEL,QAAQ,eAC9B,IAAKE,EAAM,OAAO,EAClB,MAAMI,EAAQC,EAAmBL,EAAMP,EAAKb,MAAM0B,QAElD,OADAb,EAAKc,SAASd,EAAKb,MAAM4B,GAAGC,iBAAiBL,KACtC,CACP,EAEDM,oBAAmBA,CAACV,EAAMW,EAAWC,EAAQnB,IACrCY,EAAmBL,EAAMP,EAAKb,MAAM0B,QAG5CO,oBAAoBlB,GACnB,GAAIA,EAAKI,SAAS,iBAAkB,OAAOJ,EAC3C,MAAMmB,EAAYC,SAASC,cAAc,OAKzC,OAJAF,EAAUG,UAAYtB,EACtBuB,EAAkBJ,GAClBK,EAAcL,GACdM,EAAiBN,GACVA,EAAUG,SACjB,EAEDI,gBAAgBjB,GACf,IAAIkB,EAAUC,EAAoBnB,EAAMkB,SAIxC,OAHKjD,IACJiD,EAAUE,EAAeF,IAEnB,IAAIG,EAAMH,EAASlB,EAAMsB,UAAWtB,EAAMuB,QAClD,KAIJ"}
@@ -1,2 +1,2 @@
1
- import{Fragment as e,Slice as t}from"@tiptap/pm/model";const o=new Set(["P","LI","H1","H2","H3","H4","H5","H6","TD","TH","PRE"]),n="p,div,h1,h2,h3,h4,h5,h6,ul,ol,li,blockquote,table,pre",r=new Set(["bold","italic","strike","underline","code"]);function l(e){if(e.querySelector(n))return;const t=Array.from(e.childNodes),o=[[]];for(let e=0;e<t.length;e++){const n=t[e];n instanceof HTMLBRElement&&t[e+1]instanceof HTMLBRElement?(o.push([]),e++):o[o.length-1].push(n)}for(;e.firstChild;)e.firstChild.remove();for(const t of o){const o=document.createElement("p");for(const e of t)o.appendChild(e);e.appendChild(o)}}function a(e){const t=Array.from(e.querySelectorAll("br"));for(const n of t){let t=!1,r=n.parentElement;for(;r&&r!==e;){if(o.has(r.tagName)){t=!0;break}r=r.parentElement}t||n.parentElement.replaceChild(document.createElement("p"),n)}}function c(e){for(const t of["p","div"])for(const o of Array.from(e.querySelectorAll(t))){const e=o.lastElementChild;"BR"===(null==e?void 0:e.tagName)&&o.childNodes.length>1&&e.remove()}}function i(t){const o=[];return t.forEach((t=>{var n,r;if("paragraph"===t.type.name){if(1===t.childCount&&"hardBreak"===(null===(n=t.firstChild)||void 0===n?void 0:n.type.name))return void o.push(t.type.create(t.attrs));if(t.childCount>1&&"hardBreak"===(null===(r=t.lastChild)||void 0===r?void 0:r.type.name)){const n=[];return t.content.forEach(((e,o,r)=>{r<t.childCount-1&&n.push(e)})),void o.push(t.copy(e.from(n)))}}t.isBlock&&!t.isLeaf?o.push(t.copy(i(t.content))):o.push(t)})),e.from(o)}function s(t){const o=[];return t.forEach((e=>{if(e.isText){const t=e.marks.filter((e=>r.has(e.type.name)));o.push(t.length===e.marks.length?e:e.mark(t))}else o.push(e.copy(s(e.content)))})),e.from(o)}function f(o,n){const r=o.split("\n").map((e=>n.node("paragraph",null,e?[n.text(e)]:[])));return new t(e.fromArray(r),1,1)}export{n as BLOCK_SELECTOR,o as TEXTBLOCK_TAGS,a as cleanBlockBrs,i as normalizeHardBreaks,f as parseClipboardText,s as stripRichMarks,c as stripTrailingBrs,l as wrapInlineContent};
1
+ import{Fragment as e,Slice as t}from"@tiptap/pm/model";const n=new Set(["P","LI","H1","H2","H3","H4","H5","H6","TD","TH","PRE"]),r="p,div,h1,h2,h3,h4,h5,h6,ul,ol,li,blockquote,table,pre",o=new Set(["bold","italic","strike","underline","code"]);function l(e){if(e.querySelector(r))return;const t=Array.from(e.childNodes),n=[[]];for(let e=0;e<t.length;e++){const r=t[e];r instanceof HTMLBRElement&&t[e+1]instanceof HTMLBRElement?(n.push([]),e++):n[n.length-1].push(r)}for(;e.firstChild;)e.firstChild.remove();for(const t of n){const n=document.createElement("p");for(const e of t)n.appendChild(e);e.appendChild(n)}}function c(e){const t=Array.from(e.querySelectorAll("br"));for(const r of t){let t=!1,o=r.parentElement;for(;o&&o!==e;){if(n.has(o.tagName)){t=!0;break}o=o.parentElement}t||r.parentElement.replaceChild(document.createElement("p"),r)}}function i(e){for(const t of["p","div"])for(const n of Array.from(e.querySelectorAll(t))){const e=n.lastElementChild;"BR"===(null==e?void 0:e.tagName)&&n.childNodes.length>1&&e.remove()}}function a(t){const n=[];return t.forEach((t=>{var r,o;if("paragraph"===t.type.name){if(1===t.childCount&&"hardBreak"===(null===(r=t.firstChild)||void 0===r?void 0:r.type.name))return void n.push(t.type.create(t.attrs));if(t.childCount>1&&"hardBreak"===(null===(o=t.lastChild)||void 0===o?void 0:o.type.name)){const r=[];return t.content.forEach(((e,n,o)=>{o<t.childCount-1&&r.push(e)})),void n.push(t.copy(e.from(r)))}}t.isBlock&&!t.isLeaf?n.push(t.copy(a(t.content))):n.push(t)})),e.from(n)}function h(t){const n=[];return t.forEach((e=>{if(e.isText){const t=e.marks.filter((e=>o.has(e.type.name)));n.push(t.length===e.marks.length?e:e.mark(t))}else n.push(e.copy(h(e.content)))})),e.from(n)}function f(e){const t=document.createElement("div");t.innerHTML=e,l(t),c(t),i(t);const n="p,h1,h2,h3,h4,h5,h6,li,pre,td,th",r=Array.from(t.querySelectorAll(n));if(0===r.length)return;return r.filter((e=>!e.querySelector(n))).map((e=>e.textContent||"")).join("\n")}function s(n,r){const o=n.split("\n").map((e=>r.node("paragraph",null,e?[r.text(e)]:[])));return new t(e.fromArray(o),1,1)}export{r as BLOCK_SELECTOR,n as TEXTBLOCK_TAGS,c as cleanBlockBrs,f as extractTextFromHtml,a as normalizeHardBreaks,s as parseClipboardText,h as stripRichMarks,i as stripTrailingBrs,l as wrapInlineContent};
2
2
  //# sourceMappingURL=pasteUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pasteUtils.js","sources":["../../../../../src/editor/extensions/plainClipboard/pasteUtils.ts"],"sourcesContent":["import { Fragment, Node as PMNode, Schema, Slice } from '@tiptap/pm/model';\n\nexport const TEXTBLOCK_TAGS = new Set([\n\t'P',\n\t'LI',\n\t'H1',\n\t'H2',\n\t'H3',\n\t'H4',\n\t'H5',\n\t'H6',\n\t'TD',\n\t'TH',\n\t'PRE',\n]);\n\nexport const BLOCK_SELECTOR =\n\t'p,div,h1,h2,h3,h4,h5,h6,ul,ol,li,blockquote,table,pre';\n\nconst BASIC_MARKS = new Set(['bold', 'italic', 'strike', 'underline', 'code']);\n\n/**\n * When pasted HTML is entirely inline (no block elements), split at\n * `<br><br>` boundaries into `<p>` elements. Single `<br>` stays as a\n * line break inside the paragraph.\n */\nexport function wrapInlineContent(container: HTMLElement): void {\n\tif (container.querySelector(BLOCK_SELECTOR)) return;\n\n\tconst children = Array.from(container.childNodes);\n\tconst groups: Node[][] = [[]];\n\n\tfor (let i = 0; i < children.length; i++) {\n\t\tconst node = children[i];\n\t\tif (\n\t\t\tnode instanceof HTMLBRElement &&\n\t\t\tchildren[i + 1] instanceof HTMLBRElement\n\t\t) {\n\t\t\tgroups.push([]);\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\tgroups[groups.length - 1].push(node);\n\t}\n\n\twhile (container.firstChild) container.firstChild.remove();\n\n\tfor (const group of groups) {\n\t\tconst p = document.createElement('p');\n\t\tfor (const node of group) p.appendChild(node);\n\t\tcontainer.appendChild(p);\n\t}\n}\n\n/**\n * Replace `<br>` elements that sit at block level (not inside a textblock\n * like `<p>`, `<li>`, etc.) with empty `<p></p>` elements. Google Docs\n * puts standalone `<br>` tags between paragraphs to represent blank lines.\n */\nexport function cleanBlockBrs(container: HTMLElement): void {\n\tconst brs = Array.from(container.querySelectorAll('br'));\n\tfor (const br of brs) {\n\t\tlet insideTextblock = false;\n\t\tlet el = br.parentElement;\n\t\twhile (el && el !== container) {\n\t\t\tif (TEXTBLOCK_TAGS.has(el.tagName)) {\n\t\t\t\tinsideTextblock = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tel = el.parentElement;\n\t\t}\n\t\tif (!insideTextblock) {\n\t\t\tbr.parentElement!.replaceChild(document.createElement('p'), br);\n\t\t}\n\t}\n}\n\n/**\n * Strip trailing `<br>` from content paragraphs in the DOM.\n * Google Docs adds a `<br>` at the end of non-empty paragraphs as a cursor\n * placeholder. Without this, ProseMirror creates a trailing hardBreak that\n * adds a visual blank line at the bottom of the paragraph.\n */\nexport function stripTrailingBrs(container: HTMLElement): void {\n\tfor (const tag of ['p', 'div']) {\n\t\tfor (const el of Array.from(container.querySelectorAll(tag))) {\n\t\t\tconst last = el.lastElementChild;\n\t\t\tif (last?.tagName === 'BR' && el.childNodes.length > 1) {\n\t\t\t\tlast.remove();\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Convert paragraphs containing only a hardBreak into truly empty paragraphs.\n * Google Docs represents blank lines as `<p><br></p>` — ProseMirror parses\n * the `<br>` as a hardBreak node, which renders double-height. Converting to\n * an empty paragraph (childCount 0) gives a single-height blank line.\n *\n * Does NOT collapse consecutive empties — that would destroy user intent.\n */\nexport function normalizeHardBreaks(fragment: Fragment): Fragment {\n\tconst nodes: PMNode[] = [];\n\tfragment.forEach((node) => {\n\t\tif (node.type.name === 'paragraph') {\n\t\t\tif (node.childCount === 1 && node.firstChild?.type.name === 'hardBreak') {\n\t\t\t\tnodes.push(node.type.create(node.attrs));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (node.childCount > 1 && node.lastChild?.type.name === 'hardBreak') {\n\t\t\t\tconst children: PMNode[] = [];\n\t\t\t\tnode.content.forEach((child, _offset, index) => {\n\t\t\t\t\tif (index < node.childCount - 1) children.push(child);\n\t\t\t\t});\n\t\t\t\tnodes.push(node.copy(Fragment.from(children)));\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif (node.isBlock && !node.isLeaf) {\n\t\t\tnodes.push(node.copy(normalizeHardBreaks(node.content)));\n\t\t} else {\n\t\t\tnodes.push(node);\n\t\t}\n\t});\n\treturn Fragment.from(nodes);\n}\n\n/**\n * Strip \"rich\" marks (link, textStyle, highlight, etc.) while keeping\n * basic marks (bold, italic, strike, underline, code) that messaging\n * channels can represent.\n */\nexport function stripRichMarks(fragment: Fragment): Fragment {\n\tconst nodes: PMNode[] = [];\n\tfragment.forEach((node) => {\n\t\tif (node.isText) {\n\t\t\tconst kept = node.marks.filter((m) => BASIC_MARKS.has(m.type.name));\n\t\t\tnodes.push(kept.length === node.marks.length ? node : node.mark(kept));\n\t\t} else {\n\t\t\tnodes.push(node.copy(stripRichMarks(node.content)));\n\t\t}\n\t});\n\treturn Fragment.from(nodes);\n}\n\n/**\n * Parse plain clipboard text into a ProseMirror Slice, preserving blank\n * lines as empty paragraphs. This replaces ProseMirror's default text\n * parser which uses `\\n+` and loses all blank lines.\n *\n * Best for channels with compact paragraph gaps (e.g. WhatsApp) where\n * blank lines need structural representation as empty paragraphs.\n */\nexport function parseClipboardText(text: string, schema: Schema): Slice {\n\tconst paragraphs = text\n\t\t.split('\\n')\n\t\t.map((line) =>\n\t\t\tschema.node('paragraph', null, line ? [schema.text(line)] : []),\n\t\t);\n\treturn new Slice(Fragment.fromArray(paragraphs), 1, 1);\n}\n\n/**\n * Parse plain clipboard text into a single paragraph with hardBreaks for\n * every `\\n`. Produces the same structure as Gmail's Cmd+Shift+V output:\n * one block element with `<br>` for line breaks and `<br><br>` for blank\n * lines. This gives identical html and text output to Gmail.\n */\nexport function parseClipboardTextAsBreaks(\n\ttext: string,\n\tschema: Schema,\n): Slice {\n\tconst trimmed = text.replace(/\\n+$/, '');\n\tif (!trimmed) {\n\t\treturn new Slice(Fragment.from(schema.node('paragraph', null, [])), 1, 1);\n\t}\n\tconst hardBreak = schema.nodes['hardBreak'];\n\tconst lines = trimmed.split('\\n');\n\tconst children: PMNode[] = [];\n\tlines.forEach((line, i) => {\n\t\tif (line) children.push(schema.text(line));\n\t\tif (i < lines.length - 1 && hardBreak) {\n\t\t\tchildren.push(hardBreak.create());\n\t\t}\n\t});\n\treturn new Slice(\n\t\tFragment.from(\n\t\t\tschema.node('paragraph', null, children.length ? children : []),\n\t\t),\n\t\t1,\n\t\t1,\n\t);\n}\n"],"names":["TEXTBLOCK_TAGS","Set","BLOCK_SELECTOR","BASIC_MARKS","wrapInlineContent","container","querySelector","children","Array","from","childNodes","groups","i","length","node","HTMLBRElement","push","firstChild","remove","group","p","document","createElement","appendChild","cleanBlockBrs","brs","querySelectorAll","br","insideTextblock","el","parentElement","has","tagName","replaceChild","stripTrailingBrs","tag","last","lastElementChild","normalizeHardBreaks","fragment","nodes","forEach","type","name","childCount","_a","create","attrs","_b","lastChild","content","child","_offset","index","copy","Fragment","isBlock","isLeaf","stripRichMarks","isText","kept","marks","filter","m","mark","parseClipboardText","text","schema","paragraphs","split","map","line","Slice","fromArray"],"mappings":"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"}
1
+ {"version":3,"file":"pasteUtils.js","sources":["../../../../../src/editor/extensions/plainClipboard/pasteUtils.ts"],"sourcesContent":["import { Fragment, Node as PMNode, Schema, Slice } from '@tiptap/pm/model';\n\nexport const TEXTBLOCK_TAGS = new Set([\n\t'P',\n\t'LI',\n\t'H1',\n\t'H2',\n\t'H3',\n\t'H4',\n\t'H5',\n\t'H6',\n\t'TD',\n\t'TH',\n\t'PRE',\n]);\n\nexport const BLOCK_SELECTOR =\n\t'p,div,h1,h2,h3,h4,h5,h6,ul,ol,li,blockquote,table,pre';\n\nconst BASIC_MARKS = new Set(['bold', 'italic', 'strike', 'underline', 'code']);\n\n/**\n * When pasted HTML is entirely inline (no block elements), split at\n * `<br><br>` boundaries into `<p>` elements. Single `<br>` stays as a\n * line break inside the paragraph.\n */\nexport function wrapInlineContent(container: HTMLElement): void {\n\tif (container.querySelector(BLOCK_SELECTOR)) return;\n\n\tconst children = Array.from(container.childNodes);\n\tconst groups: Node[][] = [[]];\n\n\tfor (let i = 0; i < children.length; i++) {\n\t\tconst node = children[i];\n\t\tif (\n\t\t\tnode instanceof HTMLBRElement &&\n\t\t\tchildren[i + 1] instanceof HTMLBRElement\n\t\t) {\n\t\t\tgroups.push([]);\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\tgroups[groups.length - 1].push(node);\n\t}\n\n\twhile (container.firstChild) container.firstChild.remove();\n\n\tfor (const group of groups) {\n\t\tconst p = document.createElement('p');\n\t\tfor (const node of group) p.appendChild(node);\n\t\tcontainer.appendChild(p);\n\t}\n}\n\n/**\n * Replace `<br>` elements that sit at block level (not inside a textblock\n * like `<p>`, `<li>`, etc.) with empty `<p></p>` elements. Google Docs\n * puts standalone `<br>` tags between paragraphs to represent blank lines.\n */\nexport function cleanBlockBrs(container: HTMLElement): void {\n\tconst brs = Array.from(container.querySelectorAll('br'));\n\tfor (const br of brs) {\n\t\tlet insideTextblock = false;\n\t\tlet el = br.parentElement;\n\t\twhile (el && el !== container) {\n\t\t\tif (TEXTBLOCK_TAGS.has(el.tagName)) {\n\t\t\t\tinsideTextblock = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tel = el.parentElement;\n\t\t}\n\t\tif (!insideTextblock) {\n\t\t\tbr.parentElement!.replaceChild(document.createElement('p'), br);\n\t\t}\n\t}\n}\n\n/**\n * Strip trailing `<br>` from content paragraphs in the DOM.\n * Google Docs adds a `<br>` at the end of non-empty paragraphs as a cursor\n * placeholder. Without this, ProseMirror creates a trailing hardBreak that\n * adds a visual blank line at the bottom of the paragraph.\n */\nexport function stripTrailingBrs(container: HTMLElement): void {\n\tfor (const tag of ['p', 'div']) {\n\t\tfor (const el of Array.from(container.querySelectorAll(tag))) {\n\t\t\tconst last = el.lastElementChild;\n\t\t\tif (last?.tagName === 'BR' && el.childNodes.length > 1) {\n\t\t\t\tlast.remove();\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Convert paragraphs containing only a hardBreak into truly empty paragraphs.\n * Google Docs represents blank lines as `<p><br></p>` — ProseMirror parses\n * the `<br>` as a hardBreak node, which renders double-height. Converting to\n * an empty paragraph (childCount 0) gives a single-height blank line.\n *\n * Does NOT collapse consecutive empties — that would destroy user intent.\n */\nexport function normalizeHardBreaks(fragment: Fragment): Fragment {\n\tconst nodes: PMNode[] = [];\n\tfragment.forEach((node) => {\n\t\tif (node.type.name === 'paragraph') {\n\t\t\tif (node.childCount === 1 && node.firstChild?.type.name === 'hardBreak') {\n\t\t\t\tnodes.push(node.type.create(node.attrs));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (node.childCount > 1 && node.lastChild?.type.name === 'hardBreak') {\n\t\t\t\tconst children: PMNode[] = [];\n\t\t\t\tnode.content.forEach((child, _offset, index) => {\n\t\t\t\t\tif (index < node.childCount - 1) children.push(child);\n\t\t\t\t});\n\t\t\t\tnodes.push(node.copy(Fragment.from(children)));\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif (node.isBlock && !node.isLeaf) {\n\t\t\tnodes.push(node.copy(normalizeHardBreaks(node.content)));\n\t\t} else {\n\t\t\tnodes.push(node);\n\t\t}\n\t});\n\treturn Fragment.from(nodes);\n}\n\n/**\n * Strip \"rich\" marks (link, textStyle, highlight, etc.) while keeping\n * basic marks (bold, italic, strike, underline, code) that messaging\n * channels can represent.\n */\nexport function stripRichMarks(fragment: Fragment): Fragment {\n\tconst nodes: PMNode[] = [];\n\tfragment.forEach((node) => {\n\t\tif (node.isText) {\n\t\t\tconst kept = node.marks.filter((m) => BASIC_MARKS.has(m.type.name));\n\t\t\tnodes.push(kept.length === node.marks.length ? node : node.mark(kept));\n\t\t} else {\n\t\t\tnodes.push(node.copy(stripRichMarks(node.content)));\n\t\t}\n\t});\n\treturn Fragment.from(nodes);\n}\n\n/**\n * Extract plain text from clipboard HTML, using the DOM structure for\n * paragraph boundaries instead of relying on `text/plain` (which differs\n * between Mac and Windows for the same source, e.g. Google Docs).\n *\n * Reuses the existing HTML normalizers so `<br>` between blocks becomes an\n * empty `<p>`, then pulls `textContent` from each leaf block element.\n * Returns `undefined` when no block structure is found so the caller can\n * fall back to `text/plain`.\n */\nexport function extractTextFromHtml(html: string): string | undefined {\n\tconst container = document.createElement('div');\n\tcontainer.innerHTML = html;\n\n\twrapInlineContent(container);\n\tcleanBlockBrs(container);\n\tstripTrailingBrs(container);\n\n\tconst selector = 'p,h1,h2,h3,h4,h5,h6,li,pre,td,th';\n\tconst blocks = Array.from(container.querySelectorAll(selector));\n\n\tif (blocks.length === 0) return undefined;\n\n\tconst leafBlocks = blocks.filter((el) => !el.querySelector(selector));\n\n\treturn leafBlocks.map((el) => el.textContent || '').join('\\n');\n}\n\n/**\n * Parse plain clipboard text into a ProseMirror Slice, preserving blank\n * lines as empty paragraphs. This replaces ProseMirror's default text\n * parser which uses `\\n+` and loses all blank lines.\n *\n * Best for channels with compact paragraph gaps (e.g. WhatsApp) where\n * blank lines need structural representation as empty paragraphs.\n */\nexport function parseClipboardText(text: string, schema: Schema): Slice {\n\tconst paragraphs = text\n\t\t.split('\\n')\n\t\t.map((line) =>\n\t\t\tschema.node('paragraph', null, line ? [schema.text(line)] : []),\n\t\t);\n\treturn new Slice(Fragment.fromArray(paragraphs), 1, 1);\n}\n\n/**\n * Parse plain clipboard text into a single paragraph with hardBreaks for\n * every `\\n`. Produces the same structure as Gmail's Cmd+Shift+V output:\n * one block element with `<br>` for line breaks and `<br><br>` for blank\n * lines. This gives identical html and text output to Gmail.\n */\nexport function parseClipboardTextAsBreaks(\n\ttext: string,\n\tschema: Schema,\n): Slice {\n\tconst trimmed = text.replace(/\\n+$/, '');\n\tif (!trimmed) {\n\t\treturn new Slice(Fragment.from(schema.node('paragraph', null, [])), 1, 1);\n\t}\n\tconst hardBreak = schema.nodes['hardBreak'];\n\tconst lines = trimmed.split('\\n');\n\tconst children: PMNode[] = [];\n\tlines.forEach((line, i) => {\n\t\tif (line) children.push(schema.text(line));\n\t\tif (i < lines.length - 1 && hardBreak) {\n\t\t\tchildren.push(hardBreak.create());\n\t\t}\n\t});\n\treturn new Slice(\n\t\tFragment.from(\n\t\t\tschema.node('paragraph', null, children.length ? children : []),\n\t\t),\n\t\t1,\n\t\t1,\n\t);\n}\n"],"names":["TEXTBLOCK_TAGS","Set","BLOCK_SELECTOR","BASIC_MARKS","wrapInlineContent","container","querySelector","children","Array","from","childNodes","groups","i","length","node","HTMLBRElement","push","firstChild","remove","group","p","document","createElement","appendChild","cleanBlockBrs","brs","querySelectorAll","br","insideTextblock","el","parentElement","has","tagName","replaceChild","stripTrailingBrs","tag","last","lastElementChild","normalizeHardBreaks","fragment","nodes","forEach","type","name","childCount","_a","create","attrs","_b","lastChild","content","child","_offset","index","copy","Fragment","isBlock","isLeaf","stripRichMarks","isText","kept","marks","filter","m","mark","extractTextFromHtml","html","innerHTML","selector","blocks","map","textContent","join","parseClipboardText","text","schema","paragraphs","split","line","Slice","fromArray"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
- import { QueryBuilderNodeProps } from "../../../types/QueryBuilderNodeProps.type";
2
+ import { QueryBuilderNodeProps } from "../../../Types/QueryBuilderNodeProps.type";
3
3
  declare const EventsTrigger: React.FC<QueryBuilderNodeProps>;
4
4
  export default EventsTrigger;
@@ -1,2 +1,2 @@
1
- import { QueryBuilderAPIData } from "../../../types/QueryBuilderAPI.type";
1
+ import { QueryBuilderAPIData } from "../../../Types/QueryBuilderAPI.type";
2
2
  export declare const useIGTriggerNameCacheSelector: () => QueryBuilderAPIData[];
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
- import { QueryBuilderNodeProps } from "../../../types/QueryBuilderNodeProps.type";
2
+ import { QueryBuilderNodeProps } from "../../../Types/QueryBuilderNodeProps.type";
3
3
  declare const IGTrigger: React.FC<QueryBuilderNodeProps>;
4
4
  export default IGTrigger;
@@ -1,2 +1,2 @@
1
- import { QueryBuilderAPIData } from "../../../types/QueryBuilderAPI.type";
1
+ import { QueryBuilderAPIData } from "../../../Types/QueryBuilderAPI.type";
2
2
  export declare const useIGTriggerNameCacheSelector: () => QueryBuilderAPIData[];
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { DropdownOption } from "../../../dropdown/type";
3
- import { QueryBuilderProperty } from "../../types/QueryBuilder.type";
4
- import { QueryBuilderNodeProps } from "../../types/QueryBuilderNodeProps.type";
3
+ import { QueryBuilderProperty } from "../../Types/QueryBuilder.type";
4
+ import { QueryBuilderNodeProps } from "../../Types/QueryBuilderNodeProps.type";
5
5
  declare const BaseTriggerQueryBuilderNode: React.FC<QueryBuilderNodeProps & {
6
6
  cacheKey: string;
7
7
  propertyAddBtnText: string;
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  export declare const Menus: ({
2
3
  displayName: string;
3
4
  key: number;
@@ -35,6 +35,17 @@ export declare function normalizeHardBreaks(fragment: Fragment): Fragment;
35
35
  * channels can represent.
36
36
  */
37
37
  export declare function stripRichMarks(fragment: Fragment): Fragment;
38
+ /**
39
+ * Extract plain text from clipboard HTML, using the DOM structure for
40
+ * paragraph boundaries instead of relying on `text/plain` (which differs
41
+ * between Mac and Windows for the same source, e.g. Google Docs).
42
+ *
43
+ * Reuses the existing HTML normalizers so `<br>` between blocks becomes an
44
+ * empty `<p>`, then pulls `textContent` from each leaf block element.
45
+ * Returns `undefined` when no block structure is found so the caller can
46
+ * fall back to `text/plain`.
47
+ */
48
+ export declare function extractTextFromHtml(html: string): string | undefined;
38
49
  /**
39
50
  * Parse plain clipboard text into a ProseMirror Slice, preserving blank
40
51
  * lines as empty paragraphs. This replaces ProseMirror's default text
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bikdotai/bik-component-library",
3
- "version": "0.0.810",
3
+ "version": "0.0.811-beta.0",
4
4
  "description": "Bik Component Library",
5
5
  "repository": {
6
6
  "type": "git",