@formfeed/engine 0.3.10 → 0.3.12

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 (71) hide show
  1. package/index.cjs +4728 -438
  2. package/index.js +4728 -438
  3. package/package.json +3 -2
  4. package/types/frame/fit.d.cts +13 -0
  5. package/types/frame/fit.d.ts +13 -0
  6. package/types/frame/fit.entry.d.cts +1 -0
  7. package/types/frame/fit.entry.d.ts +1 -0
  8. package/types/frame/stage.d.cts +22 -0
  9. package/types/frame/stage.d.ts +22 -0
  10. package/types/frame/stage.entry.d.cts +1 -0
  11. package/types/frame/stage.entry.d.ts +1 -0
  12. package/types/frame/text-edit.d.cts +82 -0
  13. package/types/frame/text-edit.d.ts +82 -0
  14. package/types/frame/text-edit.entry.d.cts +1 -0
  15. package/types/frame/text-edit.entry.d.ts +1 -0
  16. package/types/index.d.cts +23 -14
  17. package/types/index.d.ts +23 -14
  18. package/types/lib/assemble.d.cts +13 -0
  19. package/types/lib/assemble.d.ts +13 -0
  20. package/types/lib/design/emit.d.cts +20 -0
  21. package/types/lib/design/emit.d.ts +20 -0
  22. package/types/lib/design/fonts.d.cts +27 -0
  23. package/types/lib/design/fonts.d.ts +27 -0
  24. package/types/lib/design/hash.d.cts +6 -0
  25. package/types/lib/design/hash.d.ts +6 -0
  26. package/types/lib/design/index.d.cts +12 -0
  27. package/types/lib/design/index.d.ts +12 -0
  28. package/types/lib/design/layers.d.cts +12 -0
  29. package/types/lib/design/layers.d.ts +12 -0
  30. package/types/lib/design/parse.d.cts +25 -0
  31. package/types/lib/design/parse.d.ts +25 -0
  32. package/types/lib/design/starters.d.cts +14 -0
  33. package/types/lib/design/starters.d.ts +14 -0
  34. package/types/lib/design/types.d.cts +171 -0
  35. package/types/lib/design/types.d.ts +171 -0
  36. package/types/lib/dialect.d.cts +32 -0
  37. package/types/lib/dialect.d.ts +32 -0
  38. package/types/lib/einvoice/check.d.cts +181 -0
  39. package/types/lib/einvoice/check.d.ts +181 -0
  40. package/types/lib/einvoice/cii.d.cts +18 -0
  41. package/types/lib/einvoice/cii.d.ts +18 -0
  42. package/types/lib/einvoice/codes.generated.d.cts +14 -0
  43. package/types/lib/einvoice/codes.generated.d.ts +14 -0
  44. package/types/lib/einvoice/decimal.d.cts +29 -0
  45. package/types/lib/einvoice/decimal.d.ts +29 -0
  46. package/types/lib/einvoice/display.d.cts +43 -0
  47. package/types/lib/einvoice/display.d.ts +43 -0
  48. package/types/lib/einvoice/html-text.d.cts +17 -0
  49. package/types/lib/einvoice/html-text.d.ts +17 -0
  50. package/types/lib/einvoice/index.d.cts +45 -0
  51. package/types/lib/einvoice/index.d.ts +45 -0
  52. package/types/lib/einvoice/locate.d.cts +21 -0
  53. package/types/lib/einvoice/locate.d.ts +21 -0
  54. package/types/lib/einvoice/report.d.cts +59 -0
  55. package/types/lib/einvoice/report.d.ts +59 -0
  56. package/types/lib/einvoice/schema.d.cts +293 -0
  57. package/types/lib/einvoice/schema.d.ts +293 -0
  58. package/types/lib/einvoice/skeleton.d.cts +10 -0
  59. package/types/lib/einvoice/skeleton.d.ts +10 -0
  60. package/types/lib/generated/frames.d.cts +6 -0
  61. package/types/lib/generated/frames.d.ts +6 -0
  62. package/types/lib/preview.d.cts +22 -2
  63. package/types/lib/preview.d.ts +22 -2
  64. package/types/lib/source-edit.d.cts +117 -0
  65. package/types/lib/source-edit.d.ts +117 -0
  66. package/types/lib/source-positions.d.cts +12 -3
  67. package/types/lib/source-positions.d.ts +12 -3
  68. package/types/lib/source-scan.d.cts +61 -0
  69. package/types/lib/source-scan.d.ts +61 -0
  70. package/types/lib/translation.d.cts +17 -0
  71. package/types/lib/translation.d.ts +17 -0
@@ -0,0 +1,6 @@
1
+ /** Bundled from src/frame/text-edit.entry.ts. */
2
+ export declare const textEditRuntime = "\"use strict\";(()=>{var O=`\nhtml.ff-edit-mode [data-ff-edit] { cursor: text; }\nhtml.ff-edit-mode [data-ff-edit]:hover { outline: 1px dashed rgba(37,99,235,.85); outline-offset: 2px; }\nhtml.ff-edit-mode [data-ff-edit=\"t\"]:hover { outline-color: rgba(147,51,234,.9); }\n.ff-editing { outline: 2px solid #2563eb !important; outline-offset: 2px; cursor: text; }\n.ff-editing .ff-chip { background: rgba(37,99,235,.14) !important; box-shadow: inset 0 0 0 1px rgba(37,99,235,.45) !important; border-radius: 3px !important; padding: 0 1px !important; cursor: default; }\n.ff-edit-badge { position: absolute; z-index: 2147483647; font: 500 11px/1.4 system-ui, sans-serif !important; color: #fff !important; background: #2563eb !important; padding: 1px 6px !important; border-radius: 4px !important; pointer-events: none; white-space: nowrap; }\n`;function F(l,d={}){let m=d.clicks!==!1,g=d.live===!0,o=l.document,i=null,s=null,f=e=>{try{l.parent.postMessage(e,\"*\")}catch{}},v=m?o.querySelector('meta[name=\"formfeed:document\"]')?.getAttribute(\"content\")??null:null,h=!1;l.addEventListener(\"blur\",()=>{h=!0}),l.addEventListener(\"focus\",()=>{h=!1});let y=o.createElement(\"style\");y.setAttribute(\"data-formfeed\",\"edit\"),y.setAttribute(\"data-pagedjs-ignore\",\"\"),y.textContent=O,(o.head??o.documentElement).appendChild(y),m&&o.documentElement.classList.add(\"ff-edit-mode\");let M=e=>(e&&typeof e.closest==\"function\"?e:null)?.closest(\"[data-ff-edit]\")??null;o.addEventListener(\"click\",e=>{if(!m)return;if(i&&!i.done&&i.element.contains(e.target)){e.stopImmediatePropagation();return}let t=M(e.target);t&&(e.preventDefault(),e.stopImmediatePropagation(),C(t,{x:e.clientX,y:e.clientY}))},!0);function C(e,t){i&&!i.done&&x();let n=e.getAttribute(\"data-ff-src\")??\"\",r=e.getBoundingClientRect(),u=Array.from(o.querySelectorAll(`[data-ff-src=\"${n.replace(/\"/g,\"\")}\"]`));s={src:n,element:e,point:t},f({type:\"formfeed:edit-request\",src:n,doc:v,edit:e.getAttribute(\"data-ff-edit\"),text:e.textContent??\"\",elements:e.childElementCount,count:u.length,index:Math.max(0,u.indexOf(e)),split:e.hasAttribute(\"data-split-from\")||e.hasAttribute(\"data-split-to\"),rect:{left:r.left,top:r.top,width:r.width,height:r.height}})}o.addEventListener(\"keydown\",e=>{if(!m||i&&!i.done||!(e.ctrlKey||e.metaKey)||e.altKey)return;let t=e.key.toLowerCase();(t===\"z\"||t===\"y\")&&(e.preventDefault(),f({type:t===\"y\"||e.shiftKey?\"formfeed:redo\":\"formfeed:undo\"}))}),l.addEventListener(\"message\",e=>{if(e.source!==l.parent)return;let t=e.data;!t||typeof t.type!=\"string\"||(t.type===\"formfeed:edit-begin\"?P(t):t.type===\"formfeed:edit-refuse\"||t.type===\"formfeed:edit-end\"?(s=null,i&&!i.done&&E(!1)):t.type===\"formfeed:edit-open\"&&B(t))});function B(e){if(!m||typeof e.src!=\"string\"||i&&!i.done)return;let t=Array.from(o.querySelectorAll(`[data-ff-src=\"${e.src.replace(/\"/g,\"\")}\"][data-ff-edit]`)),n=Number.isInteger(e.index)?Number(e.index):0,r=t[n]??t[0];r&&C(r,null)}if(m){let e=()=>f({type:\"formfeed:edit-ready\",doc:v}),t=l;t.PagedConfig?t.formfeedEditReady=e:o.readyState===\"loading\"?o.addEventListener(\"DOMContentLoaded\",e):e()}function P(e){i&&!i.done&&E(!1);let t=e.layer?o.querySelector(`[data-ff-layer=\"${String(e.layer).replace(/\"/g,\"\")}\"] > .ff-text`):s&&s.src===e.src?s.element:o.querySelector(`[data-ff-src=\"${String(e.src).replace(/\"/g,\"\")}\"]`),n=e.at,r=e.layer?n&&Number.isFinite(n.x)&&Number.isFinite(n.y)?{x:Number(n.x),y:Number(n.y)}:null:s&&s.src===e.src?s.point:null;s=null;let u=h&&!o.hasFocus();if(!t||!Array.isArray(e.items)||u){f({type:\"formfeed:edit-cancel\",token:String(e.token)});return}let c=Array.from(t.childNodes),b=o.createDocumentFragment();for(let a of e.items)if(a.kind===\"text\")b.appendChild(o.createTextNode(String(a.text)));else if(a.kind===\"break\")b.appendChild(o.createElement(\"br\"));else if(a.kind===\"chip\"){let p=o.createElement(\"span\");p.className=\"ff-chip\",p.setAttribute(\"data-ff-chip\",String(a.index)),p.setAttribute(\"contenteditable\",\"false\"),a.title&&(p.title=String(a.title)),p.textContent=String(a.text),b.appendChild(p)}for(let a of c)t.removeChild(a);t.appendChild(b),t.contentEditable=\"true\",t.classList.add(\"ff-editing\"),t.setAttribute(\"role\",\"textbox\"),e.label&&t.setAttribute(\"aria-label\",String(e.label)),t.spellcheck=!0,i={token:String(e.token),element:t,saved:c,allowBreaks:e.allowBreaks===!0,badge:e.note?H(t,String(e.note)):null,done:!1},t.addEventListener(\"keydown\",A),t.addEventListener(\"beforeinput\",T),t.addEventListener(\"paste\",S),t.addEventListener(\"drop\",N),t.addEventListener(\"focusout\",R),g&&t.addEventListener(\"input\",k),t.focus(),e.select===\"all\"?I(t):K(t,r),f({type:\"formfeed:edit-started\",token:i.token}),typeof e.insert==\"string\"&&e.insert&&L(e.insert.replace(/\\r\\n?|\\n/g,\" \"))}function L(e){if(typeof o.execCommand==\"function\"&&o.execCommand(\"insertText\",!1,e))return;let t=l.getSelection(),n=t&&t.rangeCount?t.getRangeAt(0):null;n&&(n.deleteContents(),n.insertNode(o.createTextNode(e)),n.collapse(!1),g&&k())}function k(){i&&!i.done&&f({type:\"formfeed:edit-input\",token:i.token,items:D(i.element)})}function H(e,t){let n=o.createElement(\"div\");n.className=\"ff-edit-badge\",n.textContent=t;let r=e.getBoundingClientRect();return n.style.left=`${r.left+l.scrollX}px`,n.style.top=`${Math.max(0,r.top+l.scrollY-22)}px`,o.body.appendChild(n),n}function I(e){let t=l.getSelection();if(!t)return;let n=o.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n)}function K(e,t){let n=l.getSelection();if(!n)return;let r=null,u=o;if(t){if(u.caretRangeFromPoint)r=u.caretRangeFromPoint(t.x,t.y);else if(u.caretPositionFromPoint){let c=u.caretPositionFromPoint(t.x,t.y);c&&(r=o.createRange(),r.setStart(c.offsetNode,c.offset))}}if(!r||!e.contains(r.startContainer))r=o.createRange(),r.selectNodeContents(e),r.collapse(!1);else if(t){let c=r.startContainer,a=(c.nodeType===1?c:c.parentElement)?.closest(\"[data-ff-chip]\")??null;if(a&&a!==e&&e.contains(a)){let p=a.getBoundingClientRect();r=o.createRange(),t.x<p.left+p.width/2?r.setStartBefore(a):r.setStartAfter(a),r.collapse(!0)}}n.removeAllRanges(),n.addRange(r)}function A(e){let t=e.key;t===\"Escape\"?(e.preventDefault(),E(!0)):t===\"Enter\"&&!e.shiftKey?(e.preventDefault(),x()):t===\"Enter\"?(e.preventDefault(),i?.allowBreaks&&q()):t===\"Tab\"?(e.preventDefault(),x()):(e.ctrlKey||e.metaKey)&&[\"b\",\"i\",\"u\"].includes(t.toLowerCase())&&(e.preventDefault(),g&&i&&!e.altKey&&f({type:\"formfeed:edit-style\",token:i.token,key:t.toLowerCase()}))}function T(e){let t=e.inputType??\"\";(t.startsWith(\"format\")||t===\"insertFromDrop\"||t===\"insertParagraph\"||t===\"insertLineBreak\")&&e.preventDefault()}function S(e){e.preventDefault(),L((e.clipboardData?.getData(\"text/plain\")??\"\").replace(/\\r\\n?|\\n/g,\" \"))}function N(e){e.preventDefault()}function R(){l.setTimeout(()=>{i&&!i.done&&(!o.hasFocus()||!i.element.contains(o.activeElement))&&x()},0)}function q(){let e=l.getSelection();if(!e||!e.rangeCount)return;let t=e.getRangeAt(0);t.deleteContents();let n=o.createElement(\"br\");t.insertNode(n),n.nextSibling||n.parentNode?.appendChild(o.createElement(\"br\"));let r=o.createRange();r.setStartAfter(n),r.collapse(!0),e.removeAllRanges(),e.addRange(r)}function w(e){e.done=!0;let t=e.element;t.removeEventListener(\"keydown\",A),t.removeEventListener(\"beforeinput\",T),t.removeEventListener(\"paste\",S),t.removeEventListener(\"drop\",N),t.removeEventListener(\"focusout\",R),t.removeEventListener(\"input\",k),t.removeAttribute(\"contenteditable\"),t.removeAttribute(\"role\"),t.removeAttribute(\"aria-label\"),t.classList.remove(\"ff-editing\"),e.badge?.remove(),i===e&&(i=null)}function x(){let e=i;if(!e||e.done)return;let t=D(e.element);w(e),f({type:\"formfeed:edit-commit\",token:e.token,items:t})}function E(e){let t=i;if(!t||t.done)return;let n=t.element;for(;n.firstChild;)n.removeChild(n.firstChild);for(let r of t.saved)n.appendChild(r);w(t),e&&f({type:\"formfeed:edit-cancel\",token:t.token})}}function D(l){let d=[],m=o=>{let i=d[d.length-1];i?.kind===\"text\"?i.text+=o:o&&d.push({kind:\"text\",text:o})},g=o=>{for(let i of Array.from(o.childNodes))if(i.nodeType===3)m(i.data);else if(i.nodeType===1){let s=i,f=s.getAttribute(\"data-ff-chip\");f!==null?d.push({kind:\"chip\",index:Number(f)}):s.tagName===\"BR\"?d.push({kind:\"break\"}):((s.tagName===\"DIV\"||s.tagName===\"P\")&&d.length&&d.push({kind:\"break\"}),g(s))}};for(g(l);d[d.length-1]?.kind===\"break\";)d.pop();return d}F(window);})();";
3
+ /** Bundled from src/frame/fit.entry.ts. */
4
+ export declare const fitRuntime = "\"use strict\";(()=>{function a(t,e,n){if(e===t)return t.scrollHeight<=t.clientHeight+.5&&t.scrollWidth<=t.clientWidth+.5;let o=n.getComputedStyle(t),i=t.clientHeight-(parseFloat(o.paddingTop)||0)-(parseFloat(o.paddingBottom)||0);return e.scrollHeight<=i+.5&&e.scrollWidth<=e.clientWidth+.5}function m(t,e){let n=t.firstElementChild??t;n.style.fontSize=\"\";let o=parseFloat(e.getComputedStyle(n).fontSize)||16,i=Math.min(o,parseFloat(t.getAttribute(\"data-ff-fit-min\")??\"\")||o/2);if(a(t,n,e))return o;let l=i,s=o;for(let d=0;d<14;d++){let r=(l+s)/2;n.style.fontSize=`${r}px`,a(t,n,e)?l=r:s=r}let f=Math.floor(l*100)/100;return n.style.fontSize=`${f}px`,f}function c(t){let e=()=>{for(let o of Array.from(t.document.querySelectorAll('[data-ff-fit=\"shrink\"]')))m(o,t);t.document.documentElement.setAttribute(\"data-ff-fit\",\"done\")};t.formfeedFit=e;let n=t.document.fonts;n?n.ready.then(e):t.addEventListener(\"load\",e)}c(window);})();";
5
+ /** Bundled from src/frame/stage.entry.ts. */
6
+ export declare const stageRuntime = "\"use strict\";(()=>{var W=`\nhtml.ff-edit-mode [data-ff-edit] { cursor: text; }\nhtml.ff-edit-mode [data-ff-edit]:hover { outline: 1px dashed rgba(37,99,235,.85); outline-offset: 2px; }\nhtml.ff-edit-mode [data-ff-edit=\"t\"]:hover { outline-color: rgba(147,51,234,.9); }\n.ff-editing { outline: 2px solid #2563eb !important; outline-offset: 2px; cursor: text; }\n.ff-editing .ff-chip { background: rgba(37,99,235,.14) !important; box-shadow: inset 0 0 0 1px rgba(37,99,235,.45) !important; border-radius: 3px !important; padding: 0 1px !important; cursor: default; }\n.ff-edit-badge { position: absolute; z-index: 2147483647; font: 500 11px/1.4 system-ui, sans-serif !important; color: #fff !important; background: #2563eb !important; padding: 1px 6px !important; border-radius: 4px !important; pointer-events: none; white-space: nowrap; }\n`;function H(a,l={}){let f=l.clicks!==!1,p=l.live===!0,n=a.document,o=null,d=null,u=e=>{try{a.parent.postMessage(e,\"*\")}catch{}},m=f?n.querySelector('meta[name=\"formfeed:document\"]')?.getAttribute(\"content\")??null:null,s=!1;a.addEventListener(\"blur\",()=>{s=!0}),a.addEventListener(\"focus\",()=>{s=!1});let g=n.createElement(\"style\");g.setAttribute(\"data-formfeed\",\"edit\"),g.setAttribute(\"data-pagedjs-ignore\",\"\"),g.textContent=W,(n.head??n.documentElement).appendChild(g),f&&n.documentElement.classList.add(\"ff-edit-mode\");let x=e=>(e&&typeof e.closest==\"function\"?e:null)?.closest(\"[data-ff-edit]\")??null;n.addEventListener(\"click\",e=>{if(!f)return;if(o&&!o.done&&o.element.contains(e.target)){e.stopImmediatePropagation();return}let t=x(e.target);t&&(e.preventDefault(),e.stopImmediatePropagation(),v(t,{x:e.clientX,y:e.clientY}))},!0);function v(e,t){o&&!o.done&&L();let r=e.getAttribute(\"data-ff-src\")??\"\",i=e.getBoundingClientRect(),b=Array.from(n.querySelectorAll(`[data-ff-src=\"${r.replace(/\"/g,\"\")}\"]`));d={src:r,element:e,point:t},u({type:\"formfeed:edit-request\",src:r,doc:m,edit:e.getAttribute(\"data-ff-edit\"),text:e.textContent??\"\",elements:e.childElementCount,count:b.length,index:Math.max(0,b.indexOf(e)),split:e.hasAttribute(\"data-split-from\")||e.hasAttribute(\"data-split-to\"),rect:{left:i.left,top:i.top,width:i.width,height:i.height}})}n.addEventListener(\"keydown\",e=>{if(!f||o&&!o.done||!(e.ctrlKey||e.metaKey)||e.altKey)return;let t=e.key.toLowerCase();(t===\"z\"||t===\"y\")&&(e.preventDefault(),u({type:t===\"y\"||e.shiftKey?\"formfeed:redo\":\"formfeed:undo\"}))}),a.addEventListener(\"message\",e=>{if(e.source!==a.parent)return;let t=e.data;!t||typeof t.type!=\"string\"||(t.type===\"formfeed:edit-begin\"?B(t):t.type===\"formfeed:edit-refuse\"||t.type===\"formfeed:edit-end\"?(d=null,o&&!o.done&&S(!1)):t.type===\"formfeed:edit-open\"&&E(t))});function E(e){if(!f||typeof e.src!=\"string\"||o&&!o.done)return;let t=Array.from(n.querySelectorAll(`[data-ff-src=\"${e.src.replace(/\"/g,\"\")}\"][data-ff-edit]`)),r=Number.isInteger(e.index)?Number(e.index):0,i=t[r]??t[0];i&&v(i,null)}if(f){let e=()=>u({type:\"formfeed:edit-ready\",doc:m}),t=a;t.PagedConfig?t.formfeedEditReady=e:n.readyState===\"loading\"?n.addEventListener(\"DOMContentLoaded\",e):e()}function B(e){o&&!o.done&&S(!1);let t=e.layer?n.querySelector(`[data-ff-layer=\"${String(e.layer).replace(/\"/g,\"\")}\"] > .ff-text`):d&&d.src===e.src?d.element:n.querySelector(`[data-ff-src=\"${String(e.src).replace(/\"/g,\"\")}\"]`),r=e.at,i=e.layer?r&&Number.isFinite(r.x)&&Number.isFinite(r.y)?{x:Number(r.x),y:Number(r.y)}:null:d&&d.src===e.src?d.point:null;d=null;let b=s&&!n.hasFocus();if(!t||!Array.isArray(e.items)||b){u({type:\"formfeed:edit-cancel\",token:String(e.token)});return}let y=Array.from(t.childNodes),k=n.createDocumentFragment();for(let c of e.items)if(c.kind===\"text\")k.appendChild(n.createTextNode(String(c.text)));else if(c.kind===\"break\")k.appendChild(n.createElement(\"br\"));else if(c.kind===\"chip\"){let h=n.createElement(\"span\");h.className=\"ff-chip\",h.setAttribute(\"data-ff-chip\",String(c.index)),h.setAttribute(\"contenteditable\",\"false\"),c.title&&(h.title=String(c.title)),h.textContent=String(c.text),k.appendChild(h)}for(let c of y)t.removeChild(c);t.appendChild(k),t.contentEditable=\"true\",t.classList.add(\"ff-editing\"),t.setAttribute(\"role\",\"textbox\"),e.label&&t.setAttribute(\"aria-label\",String(e.label)),t.spellcheck=!0,o={token:String(e.token),element:t,saved:y,allowBreaks:e.allowBreaks===!0,badge:e.note?I(t,String(e.note)):null,done:!1},t.addEventListener(\"keydown\",T),t.addEventListener(\"beforeinput\",N),t.addEventListener(\"paste\",w),t.addEventListener(\"drop\",R),t.addEventListener(\"focusout\",F),p&&t.addEventListener(\"input\",C),t.focus(),e.select===\"all\"?q(t):K(t,i),u({type:\"formfeed:edit-started\",token:o.token}),typeof e.insert==\"string\"&&e.insert&&A(e.insert.replace(/\\r\\n?|\\n/g,\" \"))}function A(e){if(typeof n.execCommand==\"function\"&&n.execCommand(\"insertText\",!1,e))return;let t=a.getSelection(),r=t&&t.rangeCount?t.getRangeAt(0):null;r&&(r.deleteContents(),r.insertNode(n.createTextNode(e)),r.collapse(!1),p&&C())}function C(){o&&!o.done&&u({type:\"formfeed:edit-input\",token:o.token,items:D(o.element)})}function I(e,t){let r=n.createElement(\"div\");r.className=\"ff-edit-badge\",r.textContent=t;let i=e.getBoundingClientRect();return r.style.left=`${i.left+a.scrollX}px`,r.style.top=`${Math.max(0,i.top+a.scrollY-22)}px`,n.body.appendChild(r),r}function q(e){let t=a.getSelection();if(!t)return;let r=n.createRange();r.selectNodeContents(e),t.removeAllRanges(),t.addRange(r)}function K(e,t){let r=a.getSelection();if(!r)return;let i=null,b=n;if(t){if(b.caretRangeFromPoint)i=b.caretRangeFromPoint(t.x,t.y);else if(b.caretPositionFromPoint){let y=b.caretPositionFromPoint(t.x,t.y);y&&(i=n.createRange(),i.setStart(y.offsetNode,y.offset))}}if(!i||!e.contains(i.startContainer))i=n.createRange(),i.selectNodeContents(e),i.collapse(!1);else if(t){let y=i.startContainer,c=(y.nodeType===1?y:y.parentElement)?.closest(\"[data-ff-chip]\")??null;if(c&&c!==e&&e.contains(c)){let h=c.getBoundingClientRect();i=n.createRange(),t.x<h.left+h.width/2?i.setStartBefore(c):i.setStartAfter(c),i.collapse(!0)}}r.removeAllRanges(),r.addRange(i)}function T(e){let t=e.key;t===\"Escape\"?(e.preventDefault(),S(!0)):t===\"Enter\"&&!e.shiftKey?(e.preventDefault(),L()):t===\"Enter\"?(e.preventDefault(),o?.allowBreaks&&$()):t===\"Tab\"?(e.preventDefault(),L()):(e.ctrlKey||e.metaKey)&&[\"b\",\"i\",\"u\"].includes(t.toLowerCase())&&(e.preventDefault(),p&&o&&!e.altKey&&u({type:\"formfeed:edit-style\",token:o.token,key:t.toLowerCase()}))}function N(e){let t=e.inputType??\"\";(t.startsWith(\"format\")||t===\"insertFromDrop\"||t===\"insertParagraph\"||t===\"insertLineBreak\")&&e.preventDefault()}function w(e){e.preventDefault(),A((e.clipboardData?.getData(\"text/plain\")??\"\").replace(/\\r\\n?|\\n/g,\" \"))}function R(e){e.preventDefault()}function F(){a.setTimeout(()=>{o&&!o.done&&(!n.hasFocus()||!o.element.contains(n.activeElement))&&L()},0)}function $(){let e=a.getSelection();if(!e||!e.rangeCount)return;let t=e.getRangeAt(0);t.deleteContents();let r=n.createElement(\"br\");t.insertNode(r),r.nextSibling||r.parentNode?.appendChild(n.createElement(\"br\"));let i=n.createRange();i.setStartAfter(r),i.collapse(!0),e.removeAllRanges(),e.addRange(i)}function M(e){e.done=!0;let t=e.element;t.removeEventListener(\"keydown\",T),t.removeEventListener(\"beforeinput\",N),t.removeEventListener(\"paste\",w),t.removeEventListener(\"drop\",R),t.removeEventListener(\"focusout\",F),t.removeEventListener(\"input\",C),t.removeAttribute(\"contenteditable\"),t.removeAttribute(\"role\"),t.removeAttribute(\"aria-label\"),t.classList.remove(\"ff-editing\"),e.badge?.remove(),o===e&&(o=null)}function L(){let e=o;if(!e||e.done)return;let t=D(e.element);M(e),u({type:\"formfeed:edit-commit\",token:e.token,items:t})}function S(e){let t=o;if(!t||t.done)return;let r=t.element;for(;r.firstChild;)r.removeChild(r.firstChild);for(let i of t.saved)r.appendChild(i);M(t),e&&u({type:\"formfeed:edit-cancel\",token:t.token})}}function D(a){let l=[],f=n=>{let o=l[l.length-1];o?.kind===\"text\"?o.text+=n:n&&l.push({kind:\"text\",text:n})},p=n=>{for(let o of Array.from(n.childNodes))if(o.nodeType===3)f(o.data);else if(o.nodeType===1){let d=o,u=d.getAttribute(\"data-ff-chip\");u!==null?l.push({kind:\"chip\",index:Number(u)}):d.tagName===\"BR\"?l.push({kind:\"break\"}):((d.tagName===\"DIV\"||d.tagName===\"P\")&&l.length&&l.push({kind:\"break\"}),p(d))}};for(p(a);l[l.length-1]?.kind===\"break\";)l.pop();return l}function O(a,l){return Array.from(a.querySelectorAll(\"[data-ff-layer]\")).map(f=>{let p=f.querySelector(\":scope > .ff-text\"),n=!1;if(p&&f.style.height!==\"auto\"){let o=l.getComputedStyle(f),d=f.clientHeight-(parseFloat(o.paddingTop)||0)-(parseFloat(o.paddingBottom)||0);n=o.overflow===\"hidden\"&&(p.scrollHeight>d+1||p.scrollWidth>p.clientWidth+1)}return{id:f.getAttribute(\"data-ff-layer\")??\"\",width:f.offsetWidth,height:f.offsetHeight,overflow:n}})}function P(a){let l=a.document,f=m=>{try{a.parent.postMessage(m,\"*\")}catch{}},p=m=>typeof m==\"string\"?l.querySelector(`[data-ff-layer=\"${m.replace(/\"/g,\"\")}\"]`):null,n=()=>{for(let m of Array.from(l.querySelectorAll(\"[data-ff-layer]\")))for(let s of[\"left\",\"top\",\"width\",\"height\",\"transform\"])m.style.removeProperty(s)},o=()=>{a.formfeedFit?.(),f({type:\"formfeed:ready\",layers:O(l,a)})};a.addEventListener(\"message\",m=>{if(m.source!==a.parent)return;let s=m.data;if(!(!s||typeof s.type!=\"string\")){if(s.type===\"formfeed:layer-style\"){let g=p(s.id);if(!g)return;let x=(v,E)=>{typeof E==\"number\"&&Number.isFinite(E)&&g.style.setProperty(v,`${E}px`)};x(\"left\",s.left),x(\"top\",s.top),x(\"width\",s.width),x(\"height\",s.height),typeof s.rotation==\"number\"&&Number.isFinite(s.rotation)&&g.style.setProperty(\"transform\",s.rotation?`rotate(${s.rotation}deg)`:\"none\")}else if(s.type===\"formfeed:layer-style-clear\")n();else if(s.type===\"formfeed:css\"&&typeof s.css==\"string\"){let g=l.querySelector('style[data-formfeed=\"template\"]');g&&(g.textContent=s.css),n(),o()}}}),H(a,{clicks:!1,live:!0});let d=l.fonts,u=()=>d?void d.ready.then(o):o();l.readyState===\"complete\"?u():a.addEventListener(\"load\",u)}P(window);})();";
@@ -0,0 +1,6 @@
1
+ /** Bundled from src/frame/text-edit.entry.ts. */
2
+ export declare const textEditRuntime = "\"use strict\";(()=>{var O=`\nhtml.ff-edit-mode [data-ff-edit] { cursor: text; }\nhtml.ff-edit-mode [data-ff-edit]:hover { outline: 1px dashed rgba(37,99,235,.85); outline-offset: 2px; }\nhtml.ff-edit-mode [data-ff-edit=\"t\"]:hover { outline-color: rgba(147,51,234,.9); }\n.ff-editing { outline: 2px solid #2563eb !important; outline-offset: 2px; cursor: text; }\n.ff-editing .ff-chip { background: rgba(37,99,235,.14) !important; box-shadow: inset 0 0 0 1px rgba(37,99,235,.45) !important; border-radius: 3px !important; padding: 0 1px !important; cursor: default; }\n.ff-edit-badge { position: absolute; z-index: 2147483647; font: 500 11px/1.4 system-ui, sans-serif !important; color: #fff !important; background: #2563eb !important; padding: 1px 6px !important; border-radius: 4px !important; pointer-events: none; white-space: nowrap; }\n`;function F(l,d={}){let m=d.clicks!==!1,g=d.live===!0,o=l.document,i=null,s=null,f=e=>{try{l.parent.postMessage(e,\"*\")}catch{}},v=m?o.querySelector('meta[name=\"formfeed:document\"]')?.getAttribute(\"content\")??null:null,h=!1;l.addEventListener(\"blur\",()=>{h=!0}),l.addEventListener(\"focus\",()=>{h=!1});let y=o.createElement(\"style\");y.setAttribute(\"data-formfeed\",\"edit\"),y.setAttribute(\"data-pagedjs-ignore\",\"\"),y.textContent=O,(o.head??o.documentElement).appendChild(y),m&&o.documentElement.classList.add(\"ff-edit-mode\");let M=e=>(e&&typeof e.closest==\"function\"?e:null)?.closest(\"[data-ff-edit]\")??null;o.addEventListener(\"click\",e=>{if(!m)return;if(i&&!i.done&&i.element.contains(e.target)){e.stopImmediatePropagation();return}let t=M(e.target);t&&(e.preventDefault(),e.stopImmediatePropagation(),C(t,{x:e.clientX,y:e.clientY}))},!0);function C(e,t){i&&!i.done&&x();let n=e.getAttribute(\"data-ff-src\")??\"\",r=e.getBoundingClientRect(),u=Array.from(o.querySelectorAll(`[data-ff-src=\"${n.replace(/\"/g,\"\")}\"]`));s={src:n,element:e,point:t},f({type:\"formfeed:edit-request\",src:n,doc:v,edit:e.getAttribute(\"data-ff-edit\"),text:e.textContent??\"\",elements:e.childElementCount,count:u.length,index:Math.max(0,u.indexOf(e)),split:e.hasAttribute(\"data-split-from\")||e.hasAttribute(\"data-split-to\"),rect:{left:r.left,top:r.top,width:r.width,height:r.height}})}o.addEventListener(\"keydown\",e=>{if(!m||i&&!i.done||!(e.ctrlKey||e.metaKey)||e.altKey)return;let t=e.key.toLowerCase();(t===\"z\"||t===\"y\")&&(e.preventDefault(),f({type:t===\"y\"||e.shiftKey?\"formfeed:redo\":\"formfeed:undo\"}))}),l.addEventListener(\"message\",e=>{if(e.source!==l.parent)return;let t=e.data;!t||typeof t.type!=\"string\"||(t.type===\"formfeed:edit-begin\"?P(t):t.type===\"formfeed:edit-refuse\"||t.type===\"formfeed:edit-end\"?(s=null,i&&!i.done&&E(!1)):t.type===\"formfeed:edit-open\"&&B(t))});function B(e){if(!m||typeof e.src!=\"string\"||i&&!i.done)return;let t=Array.from(o.querySelectorAll(`[data-ff-src=\"${e.src.replace(/\"/g,\"\")}\"][data-ff-edit]`)),n=Number.isInteger(e.index)?Number(e.index):0,r=t[n]??t[0];r&&C(r,null)}if(m){let e=()=>f({type:\"formfeed:edit-ready\",doc:v}),t=l;t.PagedConfig?t.formfeedEditReady=e:o.readyState===\"loading\"?o.addEventListener(\"DOMContentLoaded\",e):e()}function P(e){i&&!i.done&&E(!1);let t=e.layer?o.querySelector(`[data-ff-layer=\"${String(e.layer).replace(/\"/g,\"\")}\"] > .ff-text`):s&&s.src===e.src?s.element:o.querySelector(`[data-ff-src=\"${String(e.src).replace(/\"/g,\"\")}\"]`),n=e.at,r=e.layer?n&&Number.isFinite(n.x)&&Number.isFinite(n.y)?{x:Number(n.x),y:Number(n.y)}:null:s&&s.src===e.src?s.point:null;s=null;let u=h&&!o.hasFocus();if(!t||!Array.isArray(e.items)||u){f({type:\"formfeed:edit-cancel\",token:String(e.token)});return}let c=Array.from(t.childNodes),b=o.createDocumentFragment();for(let a of e.items)if(a.kind===\"text\")b.appendChild(o.createTextNode(String(a.text)));else if(a.kind===\"break\")b.appendChild(o.createElement(\"br\"));else if(a.kind===\"chip\"){let p=o.createElement(\"span\");p.className=\"ff-chip\",p.setAttribute(\"data-ff-chip\",String(a.index)),p.setAttribute(\"contenteditable\",\"false\"),a.title&&(p.title=String(a.title)),p.textContent=String(a.text),b.appendChild(p)}for(let a of c)t.removeChild(a);t.appendChild(b),t.contentEditable=\"true\",t.classList.add(\"ff-editing\"),t.setAttribute(\"role\",\"textbox\"),e.label&&t.setAttribute(\"aria-label\",String(e.label)),t.spellcheck=!0,i={token:String(e.token),element:t,saved:c,allowBreaks:e.allowBreaks===!0,badge:e.note?H(t,String(e.note)):null,done:!1},t.addEventListener(\"keydown\",A),t.addEventListener(\"beforeinput\",T),t.addEventListener(\"paste\",S),t.addEventListener(\"drop\",N),t.addEventListener(\"focusout\",R),g&&t.addEventListener(\"input\",k),t.focus(),e.select===\"all\"?I(t):K(t,r),f({type:\"formfeed:edit-started\",token:i.token}),typeof e.insert==\"string\"&&e.insert&&L(e.insert.replace(/\\r\\n?|\\n/g,\" \"))}function L(e){if(typeof o.execCommand==\"function\"&&o.execCommand(\"insertText\",!1,e))return;let t=l.getSelection(),n=t&&t.rangeCount?t.getRangeAt(0):null;n&&(n.deleteContents(),n.insertNode(o.createTextNode(e)),n.collapse(!1),g&&k())}function k(){i&&!i.done&&f({type:\"formfeed:edit-input\",token:i.token,items:D(i.element)})}function H(e,t){let n=o.createElement(\"div\");n.className=\"ff-edit-badge\",n.textContent=t;let r=e.getBoundingClientRect();return n.style.left=`${r.left+l.scrollX}px`,n.style.top=`${Math.max(0,r.top+l.scrollY-22)}px`,o.body.appendChild(n),n}function I(e){let t=l.getSelection();if(!t)return;let n=o.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n)}function K(e,t){let n=l.getSelection();if(!n)return;let r=null,u=o;if(t){if(u.caretRangeFromPoint)r=u.caretRangeFromPoint(t.x,t.y);else if(u.caretPositionFromPoint){let c=u.caretPositionFromPoint(t.x,t.y);c&&(r=o.createRange(),r.setStart(c.offsetNode,c.offset))}}if(!r||!e.contains(r.startContainer))r=o.createRange(),r.selectNodeContents(e),r.collapse(!1);else if(t){let c=r.startContainer,a=(c.nodeType===1?c:c.parentElement)?.closest(\"[data-ff-chip]\")??null;if(a&&a!==e&&e.contains(a)){let p=a.getBoundingClientRect();r=o.createRange(),t.x<p.left+p.width/2?r.setStartBefore(a):r.setStartAfter(a),r.collapse(!0)}}n.removeAllRanges(),n.addRange(r)}function A(e){let t=e.key;t===\"Escape\"?(e.preventDefault(),E(!0)):t===\"Enter\"&&!e.shiftKey?(e.preventDefault(),x()):t===\"Enter\"?(e.preventDefault(),i?.allowBreaks&&q()):t===\"Tab\"?(e.preventDefault(),x()):(e.ctrlKey||e.metaKey)&&[\"b\",\"i\",\"u\"].includes(t.toLowerCase())&&(e.preventDefault(),g&&i&&!e.altKey&&f({type:\"formfeed:edit-style\",token:i.token,key:t.toLowerCase()}))}function T(e){let t=e.inputType??\"\";(t.startsWith(\"format\")||t===\"insertFromDrop\"||t===\"insertParagraph\"||t===\"insertLineBreak\")&&e.preventDefault()}function S(e){e.preventDefault(),L((e.clipboardData?.getData(\"text/plain\")??\"\").replace(/\\r\\n?|\\n/g,\" \"))}function N(e){e.preventDefault()}function R(){l.setTimeout(()=>{i&&!i.done&&(!o.hasFocus()||!i.element.contains(o.activeElement))&&x()},0)}function q(){let e=l.getSelection();if(!e||!e.rangeCount)return;let t=e.getRangeAt(0);t.deleteContents();let n=o.createElement(\"br\");t.insertNode(n),n.nextSibling||n.parentNode?.appendChild(o.createElement(\"br\"));let r=o.createRange();r.setStartAfter(n),r.collapse(!0),e.removeAllRanges(),e.addRange(r)}function w(e){e.done=!0;let t=e.element;t.removeEventListener(\"keydown\",A),t.removeEventListener(\"beforeinput\",T),t.removeEventListener(\"paste\",S),t.removeEventListener(\"drop\",N),t.removeEventListener(\"focusout\",R),t.removeEventListener(\"input\",k),t.removeAttribute(\"contenteditable\"),t.removeAttribute(\"role\"),t.removeAttribute(\"aria-label\"),t.classList.remove(\"ff-editing\"),e.badge?.remove(),i===e&&(i=null)}function x(){let e=i;if(!e||e.done)return;let t=D(e.element);w(e),f({type:\"formfeed:edit-commit\",token:e.token,items:t})}function E(e){let t=i;if(!t||t.done)return;let n=t.element;for(;n.firstChild;)n.removeChild(n.firstChild);for(let r of t.saved)n.appendChild(r);w(t),e&&f({type:\"formfeed:edit-cancel\",token:t.token})}}function D(l){let d=[],m=o=>{let i=d[d.length-1];i?.kind===\"text\"?i.text+=o:o&&d.push({kind:\"text\",text:o})},g=o=>{for(let i of Array.from(o.childNodes))if(i.nodeType===3)m(i.data);else if(i.nodeType===1){let s=i,f=s.getAttribute(\"data-ff-chip\");f!==null?d.push({kind:\"chip\",index:Number(f)}):s.tagName===\"BR\"?d.push({kind:\"break\"}):((s.tagName===\"DIV\"||s.tagName===\"P\")&&d.length&&d.push({kind:\"break\"}),g(s))}};for(g(l);d[d.length-1]?.kind===\"break\";)d.pop();return d}F(window);})();";
3
+ /** Bundled from src/frame/fit.entry.ts. */
4
+ export declare const fitRuntime = "\"use strict\";(()=>{function a(t,e,n){if(e===t)return t.scrollHeight<=t.clientHeight+.5&&t.scrollWidth<=t.clientWidth+.5;let o=n.getComputedStyle(t),i=t.clientHeight-(parseFloat(o.paddingTop)||0)-(parseFloat(o.paddingBottom)||0);return e.scrollHeight<=i+.5&&e.scrollWidth<=e.clientWidth+.5}function m(t,e){let n=t.firstElementChild??t;n.style.fontSize=\"\";let o=parseFloat(e.getComputedStyle(n).fontSize)||16,i=Math.min(o,parseFloat(t.getAttribute(\"data-ff-fit-min\")??\"\")||o/2);if(a(t,n,e))return o;let l=i,s=o;for(let d=0;d<14;d++){let r=(l+s)/2;n.style.fontSize=`${r}px`,a(t,n,e)?l=r:s=r}let f=Math.floor(l*100)/100;return n.style.fontSize=`${f}px`,f}function c(t){let e=()=>{for(let o of Array.from(t.document.querySelectorAll('[data-ff-fit=\"shrink\"]')))m(o,t);t.document.documentElement.setAttribute(\"data-ff-fit\",\"done\")};t.formfeedFit=e;let n=t.document.fonts;n?n.ready.then(e):t.addEventListener(\"load\",e)}c(window);})();";
5
+ /** Bundled from src/frame/stage.entry.ts. */
6
+ export declare const stageRuntime = "\"use strict\";(()=>{var W=`\nhtml.ff-edit-mode [data-ff-edit] { cursor: text; }\nhtml.ff-edit-mode [data-ff-edit]:hover { outline: 1px dashed rgba(37,99,235,.85); outline-offset: 2px; }\nhtml.ff-edit-mode [data-ff-edit=\"t\"]:hover { outline-color: rgba(147,51,234,.9); }\n.ff-editing { outline: 2px solid #2563eb !important; outline-offset: 2px; cursor: text; }\n.ff-editing .ff-chip { background: rgba(37,99,235,.14) !important; box-shadow: inset 0 0 0 1px rgba(37,99,235,.45) !important; border-radius: 3px !important; padding: 0 1px !important; cursor: default; }\n.ff-edit-badge { position: absolute; z-index: 2147483647; font: 500 11px/1.4 system-ui, sans-serif !important; color: #fff !important; background: #2563eb !important; padding: 1px 6px !important; border-radius: 4px !important; pointer-events: none; white-space: nowrap; }\n`;function H(a,l={}){let f=l.clicks!==!1,p=l.live===!0,n=a.document,o=null,d=null,u=e=>{try{a.parent.postMessage(e,\"*\")}catch{}},m=f?n.querySelector('meta[name=\"formfeed:document\"]')?.getAttribute(\"content\")??null:null,s=!1;a.addEventListener(\"blur\",()=>{s=!0}),a.addEventListener(\"focus\",()=>{s=!1});let g=n.createElement(\"style\");g.setAttribute(\"data-formfeed\",\"edit\"),g.setAttribute(\"data-pagedjs-ignore\",\"\"),g.textContent=W,(n.head??n.documentElement).appendChild(g),f&&n.documentElement.classList.add(\"ff-edit-mode\");let x=e=>(e&&typeof e.closest==\"function\"?e:null)?.closest(\"[data-ff-edit]\")??null;n.addEventListener(\"click\",e=>{if(!f)return;if(o&&!o.done&&o.element.contains(e.target)){e.stopImmediatePropagation();return}let t=x(e.target);t&&(e.preventDefault(),e.stopImmediatePropagation(),v(t,{x:e.clientX,y:e.clientY}))},!0);function v(e,t){o&&!o.done&&L();let r=e.getAttribute(\"data-ff-src\")??\"\",i=e.getBoundingClientRect(),b=Array.from(n.querySelectorAll(`[data-ff-src=\"${r.replace(/\"/g,\"\")}\"]`));d={src:r,element:e,point:t},u({type:\"formfeed:edit-request\",src:r,doc:m,edit:e.getAttribute(\"data-ff-edit\"),text:e.textContent??\"\",elements:e.childElementCount,count:b.length,index:Math.max(0,b.indexOf(e)),split:e.hasAttribute(\"data-split-from\")||e.hasAttribute(\"data-split-to\"),rect:{left:i.left,top:i.top,width:i.width,height:i.height}})}n.addEventListener(\"keydown\",e=>{if(!f||o&&!o.done||!(e.ctrlKey||e.metaKey)||e.altKey)return;let t=e.key.toLowerCase();(t===\"z\"||t===\"y\")&&(e.preventDefault(),u({type:t===\"y\"||e.shiftKey?\"formfeed:redo\":\"formfeed:undo\"}))}),a.addEventListener(\"message\",e=>{if(e.source!==a.parent)return;let t=e.data;!t||typeof t.type!=\"string\"||(t.type===\"formfeed:edit-begin\"?B(t):t.type===\"formfeed:edit-refuse\"||t.type===\"formfeed:edit-end\"?(d=null,o&&!o.done&&S(!1)):t.type===\"formfeed:edit-open\"&&E(t))});function E(e){if(!f||typeof e.src!=\"string\"||o&&!o.done)return;let t=Array.from(n.querySelectorAll(`[data-ff-src=\"${e.src.replace(/\"/g,\"\")}\"][data-ff-edit]`)),r=Number.isInteger(e.index)?Number(e.index):0,i=t[r]??t[0];i&&v(i,null)}if(f){let e=()=>u({type:\"formfeed:edit-ready\",doc:m}),t=a;t.PagedConfig?t.formfeedEditReady=e:n.readyState===\"loading\"?n.addEventListener(\"DOMContentLoaded\",e):e()}function B(e){o&&!o.done&&S(!1);let t=e.layer?n.querySelector(`[data-ff-layer=\"${String(e.layer).replace(/\"/g,\"\")}\"] > .ff-text`):d&&d.src===e.src?d.element:n.querySelector(`[data-ff-src=\"${String(e.src).replace(/\"/g,\"\")}\"]`),r=e.at,i=e.layer?r&&Number.isFinite(r.x)&&Number.isFinite(r.y)?{x:Number(r.x),y:Number(r.y)}:null:d&&d.src===e.src?d.point:null;d=null;let b=s&&!n.hasFocus();if(!t||!Array.isArray(e.items)||b){u({type:\"formfeed:edit-cancel\",token:String(e.token)});return}let y=Array.from(t.childNodes),k=n.createDocumentFragment();for(let c of e.items)if(c.kind===\"text\")k.appendChild(n.createTextNode(String(c.text)));else if(c.kind===\"break\")k.appendChild(n.createElement(\"br\"));else if(c.kind===\"chip\"){let h=n.createElement(\"span\");h.className=\"ff-chip\",h.setAttribute(\"data-ff-chip\",String(c.index)),h.setAttribute(\"contenteditable\",\"false\"),c.title&&(h.title=String(c.title)),h.textContent=String(c.text),k.appendChild(h)}for(let c of y)t.removeChild(c);t.appendChild(k),t.contentEditable=\"true\",t.classList.add(\"ff-editing\"),t.setAttribute(\"role\",\"textbox\"),e.label&&t.setAttribute(\"aria-label\",String(e.label)),t.spellcheck=!0,o={token:String(e.token),element:t,saved:y,allowBreaks:e.allowBreaks===!0,badge:e.note?I(t,String(e.note)):null,done:!1},t.addEventListener(\"keydown\",T),t.addEventListener(\"beforeinput\",N),t.addEventListener(\"paste\",w),t.addEventListener(\"drop\",R),t.addEventListener(\"focusout\",F),p&&t.addEventListener(\"input\",C),t.focus(),e.select===\"all\"?q(t):K(t,i),u({type:\"formfeed:edit-started\",token:o.token}),typeof e.insert==\"string\"&&e.insert&&A(e.insert.replace(/\\r\\n?|\\n/g,\" \"))}function A(e){if(typeof n.execCommand==\"function\"&&n.execCommand(\"insertText\",!1,e))return;let t=a.getSelection(),r=t&&t.rangeCount?t.getRangeAt(0):null;r&&(r.deleteContents(),r.insertNode(n.createTextNode(e)),r.collapse(!1),p&&C())}function C(){o&&!o.done&&u({type:\"formfeed:edit-input\",token:o.token,items:D(o.element)})}function I(e,t){let r=n.createElement(\"div\");r.className=\"ff-edit-badge\",r.textContent=t;let i=e.getBoundingClientRect();return r.style.left=`${i.left+a.scrollX}px`,r.style.top=`${Math.max(0,i.top+a.scrollY-22)}px`,n.body.appendChild(r),r}function q(e){let t=a.getSelection();if(!t)return;let r=n.createRange();r.selectNodeContents(e),t.removeAllRanges(),t.addRange(r)}function K(e,t){let r=a.getSelection();if(!r)return;let i=null,b=n;if(t){if(b.caretRangeFromPoint)i=b.caretRangeFromPoint(t.x,t.y);else if(b.caretPositionFromPoint){let y=b.caretPositionFromPoint(t.x,t.y);y&&(i=n.createRange(),i.setStart(y.offsetNode,y.offset))}}if(!i||!e.contains(i.startContainer))i=n.createRange(),i.selectNodeContents(e),i.collapse(!1);else if(t){let y=i.startContainer,c=(y.nodeType===1?y:y.parentElement)?.closest(\"[data-ff-chip]\")??null;if(c&&c!==e&&e.contains(c)){let h=c.getBoundingClientRect();i=n.createRange(),t.x<h.left+h.width/2?i.setStartBefore(c):i.setStartAfter(c),i.collapse(!0)}}r.removeAllRanges(),r.addRange(i)}function T(e){let t=e.key;t===\"Escape\"?(e.preventDefault(),S(!0)):t===\"Enter\"&&!e.shiftKey?(e.preventDefault(),L()):t===\"Enter\"?(e.preventDefault(),o?.allowBreaks&&$()):t===\"Tab\"?(e.preventDefault(),L()):(e.ctrlKey||e.metaKey)&&[\"b\",\"i\",\"u\"].includes(t.toLowerCase())&&(e.preventDefault(),p&&o&&!e.altKey&&u({type:\"formfeed:edit-style\",token:o.token,key:t.toLowerCase()}))}function N(e){let t=e.inputType??\"\";(t.startsWith(\"format\")||t===\"insertFromDrop\"||t===\"insertParagraph\"||t===\"insertLineBreak\")&&e.preventDefault()}function w(e){e.preventDefault(),A((e.clipboardData?.getData(\"text/plain\")??\"\").replace(/\\r\\n?|\\n/g,\" \"))}function R(e){e.preventDefault()}function F(){a.setTimeout(()=>{o&&!o.done&&(!n.hasFocus()||!o.element.contains(n.activeElement))&&L()},0)}function $(){let e=a.getSelection();if(!e||!e.rangeCount)return;let t=e.getRangeAt(0);t.deleteContents();let r=n.createElement(\"br\");t.insertNode(r),r.nextSibling||r.parentNode?.appendChild(n.createElement(\"br\"));let i=n.createRange();i.setStartAfter(r),i.collapse(!0),e.removeAllRanges(),e.addRange(i)}function M(e){e.done=!0;let t=e.element;t.removeEventListener(\"keydown\",T),t.removeEventListener(\"beforeinput\",N),t.removeEventListener(\"paste\",w),t.removeEventListener(\"drop\",R),t.removeEventListener(\"focusout\",F),t.removeEventListener(\"input\",C),t.removeAttribute(\"contenteditable\"),t.removeAttribute(\"role\"),t.removeAttribute(\"aria-label\"),t.classList.remove(\"ff-editing\"),e.badge?.remove(),o===e&&(o=null)}function L(){let e=o;if(!e||e.done)return;let t=D(e.element);M(e),u({type:\"formfeed:edit-commit\",token:e.token,items:t})}function S(e){let t=o;if(!t||t.done)return;let r=t.element;for(;r.firstChild;)r.removeChild(r.firstChild);for(let i of t.saved)r.appendChild(i);M(t),e&&u({type:\"formfeed:edit-cancel\",token:t.token})}}function D(a){let l=[],f=n=>{let o=l[l.length-1];o?.kind===\"text\"?o.text+=n:n&&l.push({kind:\"text\",text:n})},p=n=>{for(let o of Array.from(n.childNodes))if(o.nodeType===3)f(o.data);else if(o.nodeType===1){let d=o,u=d.getAttribute(\"data-ff-chip\");u!==null?l.push({kind:\"chip\",index:Number(u)}):d.tagName===\"BR\"?l.push({kind:\"break\"}):((d.tagName===\"DIV\"||d.tagName===\"P\")&&l.length&&l.push({kind:\"break\"}),p(d))}};for(p(a);l[l.length-1]?.kind===\"break\";)l.pop();return l}function O(a,l){return Array.from(a.querySelectorAll(\"[data-ff-layer]\")).map(f=>{let p=f.querySelector(\":scope > .ff-text\"),n=!1;if(p&&f.style.height!==\"auto\"){let o=l.getComputedStyle(f),d=f.clientHeight-(parseFloat(o.paddingTop)||0)-(parseFloat(o.paddingBottom)||0);n=o.overflow===\"hidden\"&&(p.scrollHeight>d+1||p.scrollWidth>p.clientWidth+1)}return{id:f.getAttribute(\"data-ff-layer\")??\"\",width:f.offsetWidth,height:f.offsetHeight,overflow:n}})}function P(a){let l=a.document,f=m=>{try{a.parent.postMessage(m,\"*\")}catch{}},p=m=>typeof m==\"string\"?l.querySelector(`[data-ff-layer=\"${m.replace(/\"/g,\"\")}\"]`):null,n=()=>{for(let m of Array.from(l.querySelectorAll(\"[data-ff-layer]\")))for(let s of[\"left\",\"top\",\"width\",\"height\",\"transform\"])m.style.removeProperty(s)},o=()=>{a.formfeedFit?.(),f({type:\"formfeed:ready\",layers:O(l,a)})};a.addEventListener(\"message\",m=>{if(m.source!==a.parent)return;let s=m.data;if(!(!s||typeof s.type!=\"string\")){if(s.type===\"formfeed:layer-style\"){let g=p(s.id);if(!g)return;let x=(v,E)=>{typeof E==\"number\"&&Number.isFinite(E)&&g.style.setProperty(v,`${E}px`)};x(\"left\",s.left),x(\"top\",s.top),x(\"width\",s.width),x(\"height\",s.height),typeof s.rotation==\"number\"&&Number.isFinite(s.rotation)&&g.style.setProperty(\"transform\",s.rotation?`rotate(${s.rotation}deg)`:\"none\")}else if(s.type===\"formfeed:layer-style-clear\")n();else if(s.type===\"formfeed:css\"&&typeof s.css==\"string\"){let g=l.querySelector('style[data-formfeed=\"template\"]');g&&(g.textContent=s.css),n(),o()}}}),H(a,{clicks:!1,live:!0});let d=l.fonts,u=()=>d?void d.ready.then(o):o();l.readyState===\"complete\"?u():a.addEventListener(\"load\",u)}P(window);})();";
@@ -22,6 +22,20 @@ export declare function paperOf(settings: TemplateSettings): {
22
22
  * the element stays so its styling applies.
23
23
  */
24
24
  export declare const pageNumberSpans: (html: string, page: string, total: string) => string;
25
+ /** Options of the flow and paged previews. */
26
+ export interface PreviewOptions {
27
+ /**
28
+ * The editor's edit mode: text in elements marked `data-ff-edit` (`annotateSourcePositions` with
29
+ * `editable`) can be edited in place, and the frame talks to the editor about it by message.
30
+ */
31
+ editing?: boolean;
32
+ /**
33
+ * A name the editor gives this document, which the edit session's messages carry back
34
+ * (`formfeed:document` in the head). The editor has the next document ready a moment before the
35
+ * frame takes it; with the name it can tell a click that still came from the one before.
36
+ */
37
+ document?: string;
38
+ }
25
39
  /** What the preview frame reports about content wider than the page, or `null` when nothing is. */
26
40
  export interface PreviewOverflow {
27
41
  /** How far the widest element reaches past the right edge of the page's content area. */
@@ -43,8 +57,14 @@ export interface PreviewOverflow {
43
57
  * The office quick preview's frame uses the same script.
44
58
  */
45
59
  export declare const zoomGestureScript = "<script>\n(function () {\n var say = function (message) { try { parent.postMessage(message, '*'); } catch (e) {} };\n window.addEventListener('wheel', function (event) {\n if (!event.ctrlKey && !event.metaKey) return;\n event.preventDefault();\n say({ type: 'formfeed:zoom', deltaY: event.deltaY, deltaMode: event.deltaMode });\n }, { passive: false });\n window.addEventListener('keydown', function (event) {\n if (!(event.ctrlKey || event.metaKey) || event.altKey) return;\n var step = event.key === '+' || event.key === '=' ? 'in' : event.key === '-' ? 'out' : event.key === '0' ? 'reset' : null;\n if (!step) return;\n event.preventDefault();\n say({ type: 'formfeed:zoom', step: step });\n });\n})();\n</script>";
46
- export declare function flowDocument(draft: RenderedDraft): string;
47
- export interface PagedOptions {
60
+ export declare function flowDocument(draft: RenderedDraft, options?: PreviewOptions): string;
61
+ /**
62
+ * The design stage's document (plan 16 §4.6): the assembled image template exactly as rendered, with
63
+ * no preview chrome around it (the stage draws its own background), and the stage runtime, which
64
+ * measures layers and takes drag styles and stylesheet patches by message.
65
+ */
66
+ export declare function canvasDocument(draft: RenderedDraft): string;
67
+ export interface PagedOptions extends PreviewOptions {
48
68
  /** URL of the Paged.js polyfill the frame can load. */
49
69
  pagedScriptUrl: string;
50
70
  }
@@ -22,6 +22,20 @@ export declare function paperOf(settings: TemplateSettings): {
22
22
  * the element stays so its styling applies.
23
23
  */
24
24
  export declare const pageNumberSpans: (html: string, page: string, total: string) => string;
25
+ /** Options of the flow and paged previews. */
26
+ export interface PreviewOptions {
27
+ /**
28
+ * The editor's edit mode: text in elements marked `data-ff-edit` (`annotateSourcePositions` with
29
+ * `editable`) can be edited in place, and the frame talks to the editor about it by message.
30
+ */
31
+ editing?: boolean;
32
+ /**
33
+ * A name the editor gives this document, which the edit session's messages carry back
34
+ * (`formfeed:document` in the head). The editor has the next document ready a moment before the
35
+ * frame takes it; with the name it can tell a click that still came from the one before.
36
+ */
37
+ document?: string;
38
+ }
25
39
  /** What the preview frame reports about content wider than the page, or `null` when nothing is. */
26
40
  export interface PreviewOverflow {
27
41
  /** How far the widest element reaches past the right edge of the page's content area. */
@@ -43,8 +57,14 @@ export interface PreviewOverflow {
43
57
  * The office quick preview's frame uses the same script.
44
58
  */
45
59
  export declare const zoomGestureScript = "<script>\n(function () {\n var say = function (message) { try { parent.postMessage(message, '*'); } catch (e) {} };\n window.addEventListener('wheel', function (event) {\n if (!event.ctrlKey && !event.metaKey) return;\n event.preventDefault();\n say({ type: 'formfeed:zoom', deltaY: event.deltaY, deltaMode: event.deltaMode });\n }, { passive: false });\n window.addEventListener('keydown', function (event) {\n if (!(event.ctrlKey || event.metaKey) || event.altKey) return;\n var step = event.key === '+' || event.key === '=' ? 'in' : event.key === '-' ? 'out' : event.key === '0' ? 'reset' : null;\n if (!step) return;\n event.preventDefault();\n say({ type: 'formfeed:zoom', step: step });\n });\n})();\n</script>";
46
- export declare function flowDocument(draft: RenderedDraft): string;
47
- export interface PagedOptions {
60
+ export declare function flowDocument(draft: RenderedDraft, options?: PreviewOptions): string;
61
+ /**
62
+ * The design stage's document (plan 16 §4.6): the assembled image template exactly as rendered, with
63
+ * no preview chrome around it (the stage draws its own background), and the stage runtime, which
64
+ * measures layers and takes drag styles and stylesheet patches by message.
65
+ */
66
+ export declare function canvasDocument(draft: RenderedDraft): string;
67
+ export interface PagedOptions extends PreviewOptions {
48
68
  /** URL of the Paged.js polyfill the frame can load. */
49
69
  pagedScriptUrl: string;
50
70
  }
@@ -0,0 +1,117 @@
1
+ import type { EngineId } from './types.cjs';
2
+ /**
3
+ * Editing text from the preview (plan 16 §3). An element whose content is literal text, output tags,
4
+ * inline children and line breaks — nothing that decides what is printed — is an *editable region*:
5
+ * the preview shows its text editable and everything else as atomic chips, and the edit comes back
6
+ * here to be written into the source. Text the user did not change keeps its source bytes, so
7
+ * indentation, line breaks and character references survive a one-word edit; changed text is
8
+ * HTML-escaped, and a `{` that could open template syntax is written as `&#123;`. Every result is
9
+ * parsed again and compared with what the user typed before it is returned.
10
+ */
11
+ export type RegionRefusal = 'not-an-element' | 'dynamic-tag' | 'void' | 'raw-text' | 'control-flow' | 'block-child' | 'unclosed' | 'no-text' | 'too-large';
12
+ export type ChipKind = 'expression' | 'element' | 'comment' | 'entity';
13
+ export type RegionPart = {
14
+ kind: 'text';
15
+ start: number;
16
+ end: number;
17
+ } | {
18
+ kind: 'break';
19
+ start: number;
20
+ end: number;
21
+ } | {
22
+ kind: 'chip';
23
+ start: number;
24
+ end: number;
25
+ chip: ChipKind;
26
+ label: string;
27
+ inner?: string;
28
+ };
29
+ export interface EditableRegion {
30
+ /** `t`: the whole content is one `t()` call, and the edit goes into the dictionary. */
31
+ kind: 'text' | 't';
32
+ tag: string;
33
+ /** Offset of the start tag's `<`. */
34
+ tagStart: number;
35
+ /** First character of the content, and the `<` of the end tag. */
36
+ start: number;
37
+ end: number;
38
+ /** After the end tag's `>`. */
39
+ outerEnd: number;
40
+ parts: RegionPart[];
41
+ /** `t` regions: the dictionary key and each parameter's expression by name. */
42
+ key?: string;
43
+ params?: Record<string, string>;
44
+ }
45
+ /** What the preview shows and sends back: text, a chip by its index among the region's chips, a line break. */
46
+ export type EditItem = {
47
+ kind: 'text';
48
+ text: string;
49
+ } | {
50
+ kind: 'chip';
51
+ index: number;
52
+ } | {
53
+ kind: 'break';
54
+ };
55
+ export interface RegionChip {
56
+ index: number;
57
+ kind: ChipKind;
58
+ /** What the chip stands for: the expression, `<strong>`, a character reference. */
59
+ label: string;
60
+ source: string;
61
+ }
62
+ export type ApplyResult = {
63
+ source: string;
64
+ } | {
65
+ error: 'chips' | 'invalid';
66
+ };
67
+ /** A region, or why the element at that place is none. */
68
+ export type RegionLookup = EditableRegion | {
69
+ reason: RegionRefusal;
70
+ };
71
+ /** The region whose start tag's `<` is at `line`/`column` (1-based, as `data-ff-src` names it). */
72
+ export declare function editableRegion(source: string, engine: EngineId, location: {
73
+ line: number;
74
+ column: number;
75
+ }): RegionLookup;
76
+ /** The region whose start tag's `<` is at `at`. */
77
+ export declare function editableRegionAt(source: string, engine: EngineId, at: number): RegionLookup;
78
+ /**
79
+ * The region again after the source changed around it (someone typed in the code editor while the
80
+ * preview was being edited): found by its unique original markup, or null.
81
+ */
82
+ export declare function findRegionAgain(source: string, engine: EngineId, outer: string): EditableRegion | null;
83
+ /** Where a region's start tag is, as `data-ff-src` names it: line and column, both 1-based. */
84
+ export declare function regionPosition(source: string, region: EditableRegion): {
85
+ line: number;
86
+ column: number;
87
+ };
88
+ /** The chips of a region in order, with what they stand for. */
89
+ export declare function regionChips(source: string, region: EditableRegion): RegionChip[];
90
+ /** What the preview shows while editing: decoded text (whitespace as written), chips and breaks. */
91
+ export declare function regionItems(source: string, region: EditableRegion): EditItem[];
92
+ /**
93
+ * Writes edited items back into the region. Chips may be deleted, never reordered or repeated. Text
94
+ * between the same two chips is diffed against what it was, so only the changed stretch is
95
+ * rewritten; if the result does not read back as the items (a kept `{` meeting a typed `%`), the
96
+ * whole content is written anew with every brace escaped.
97
+ */
98
+ export declare function applyRegionEdit(source: string, engine: EngineId, region: EditableRegion, items: EditItem[]): ApplyResult;
99
+ /** A dictionary text as items: `{name}` placeholders become chips, in order of appearance. */
100
+ export declare function translationItems(text: string): {
101
+ items: EditItem[];
102
+ names: string[];
103
+ };
104
+ /** Edited dictionary items back into text: chips become their placeholders again, breaks spaces. */
105
+ export declare function translationText(items: EditItem[], names: string[]): string;
106
+ /**
107
+ * The value each chip shows while editing, read off the element's rendered text: the text between
108
+ * the chips must appear in it in order, and exactly one way of placing them must exist. Null when
109
+ * there is none or more than one (an empty value, a value that repeats a literal): the chips then
110
+ * show their labels.
111
+ */
112
+ export declare function chipValues(rendered: string, items: EditItem[]): string[] | null;
113
+ /**
114
+ * Literal text for a template's HTML, as the design emitter writes it: escaped like an edit from the
115
+ * preview, so a `{` that could open template syntax is written as `&#123;`.
116
+ */
117
+ export declare function encodeTemplateText(text: string): string;
@@ -0,0 +1,117 @@
1
+ import type { EngineId } from './types.js';
2
+ /**
3
+ * Editing text from the preview (plan 16 §3). An element whose content is literal text, output tags,
4
+ * inline children and line breaks — nothing that decides what is printed — is an *editable region*:
5
+ * the preview shows its text editable and everything else as atomic chips, and the edit comes back
6
+ * here to be written into the source. Text the user did not change keeps its source bytes, so
7
+ * indentation, line breaks and character references survive a one-word edit; changed text is
8
+ * HTML-escaped, and a `{` that could open template syntax is written as `&#123;`. Every result is
9
+ * parsed again and compared with what the user typed before it is returned.
10
+ */
11
+ export type RegionRefusal = 'not-an-element' | 'dynamic-tag' | 'void' | 'raw-text' | 'control-flow' | 'block-child' | 'unclosed' | 'no-text' | 'too-large';
12
+ export type ChipKind = 'expression' | 'element' | 'comment' | 'entity';
13
+ export type RegionPart = {
14
+ kind: 'text';
15
+ start: number;
16
+ end: number;
17
+ } | {
18
+ kind: 'break';
19
+ start: number;
20
+ end: number;
21
+ } | {
22
+ kind: 'chip';
23
+ start: number;
24
+ end: number;
25
+ chip: ChipKind;
26
+ label: string;
27
+ inner?: string;
28
+ };
29
+ export interface EditableRegion {
30
+ /** `t`: the whole content is one `t()` call, and the edit goes into the dictionary. */
31
+ kind: 'text' | 't';
32
+ tag: string;
33
+ /** Offset of the start tag's `<`. */
34
+ tagStart: number;
35
+ /** First character of the content, and the `<` of the end tag. */
36
+ start: number;
37
+ end: number;
38
+ /** After the end tag's `>`. */
39
+ outerEnd: number;
40
+ parts: RegionPart[];
41
+ /** `t` regions: the dictionary key and each parameter's expression by name. */
42
+ key?: string;
43
+ params?: Record<string, string>;
44
+ }
45
+ /** What the preview shows and sends back: text, a chip by its index among the region's chips, a line break. */
46
+ export type EditItem = {
47
+ kind: 'text';
48
+ text: string;
49
+ } | {
50
+ kind: 'chip';
51
+ index: number;
52
+ } | {
53
+ kind: 'break';
54
+ };
55
+ export interface RegionChip {
56
+ index: number;
57
+ kind: ChipKind;
58
+ /** What the chip stands for: the expression, `<strong>`, a character reference. */
59
+ label: string;
60
+ source: string;
61
+ }
62
+ export type ApplyResult = {
63
+ source: string;
64
+ } | {
65
+ error: 'chips' | 'invalid';
66
+ };
67
+ /** A region, or why the element at that place is none. */
68
+ export type RegionLookup = EditableRegion | {
69
+ reason: RegionRefusal;
70
+ };
71
+ /** The region whose start tag's `<` is at `line`/`column` (1-based, as `data-ff-src` names it). */
72
+ export declare function editableRegion(source: string, engine: EngineId, location: {
73
+ line: number;
74
+ column: number;
75
+ }): RegionLookup;
76
+ /** The region whose start tag's `<` is at `at`. */
77
+ export declare function editableRegionAt(source: string, engine: EngineId, at: number): RegionLookup;
78
+ /**
79
+ * The region again after the source changed around it (someone typed in the code editor while the
80
+ * preview was being edited): found by its unique original markup, or null.
81
+ */
82
+ export declare function findRegionAgain(source: string, engine: EngineId, outer: string): EditableRegion | null;
83
+ /** Where a region's start tag is, as `data-ff-src` names it: line and column, both 1-based. */
84
+ export declare function regionPosition(source: string, region: EditableRegion): {
85
+ line: number;
86
+ column: number;
87
+ };
88
+ /** The chips of a region in order, with what they stand for. */
89
+ export declare function regionChips(source: string, region: EditableRegion): RegionChip[];
90
+ /** What the preview shows while editing: decoded text (whitespace as written), chips and breaks. */
91
+ export declare function regionItems(source: string, region: EditableRegion): EditItem[];
92
+ /**
93
+ * Writes edited items back into the region. Chips may be deleted, never reordered or repeated. Text
94
+ * between the same two chips is diffed against what it was, so only the changed stretch is
95
+ * rewritten; if the result does not read back as the items (a kept `{` meeting a typed `%`), the
96
+ * whole content is written anew with every brace escaped.
97
+ */
98
+ export declare function applyRegionEdit(source: string, engine: EngineId, region: EditableRegion, items: EditItem[]): ApplyResult;
99
+ /** A dictionary text as items: `{name}` placeholders become chips, in order of appearance. */
100
+ export declare function translationItems(text: string): {
101
+ items: EditItem[];
102
+ names: string[];
103
+ };
104
+ /** Edited dictionary items back into text: chips become their placeholders again, breaks spaces. */
105
+ export declare function translationText(items: EditItem[], names: string[]): string;
106
+ /**
107
+ * The value each chip shows while editing, read off the element's rendered text: the text between
108
+ * the chips must appear in it in order, and exactly one way of placing them must exist. Null when
109
+ * there is none or more than one (an empty value, a value that repeats a literal): the chips then
110
+ * show their labels.
111
+ */
112
+ export declare function chipValues(rendered: string, items: EditItem[]): string[] | null;
113
+ /**
114
+ * Literal text for a template's HTML, as the design emitter writes it: escaped like an edit from the
115
+ * preview, so a `{` that could open template syntax is written as `&#123;`.
116
+ */
117
+ export declare function encodeTemplateText(text: string): string;
@@ -5,16 +5,21 @@ import type { EngineId } from './types.cjs';
5
5
  * rendered element says where it came from instead of the editor searching the template for it.
6
6
  * Elements from a loop all point at the loop body, which is the line that wrote them.
7
7
  *
8
+ * With `editable`, a start tag whose content is a region the preview can edit (plan 16 §3.1,
9
+ * `editableRegionAt`) also gets `data-ff-edit="text"`, or `data-ff-edit="t"` when its whole content
10
+ * is one `t()` call.
11
+ *
8
12
  * The annotation must never change what the template means: tags inside template syntax, in
9
13
  * blocks whose output is captured or filtered as a string (`{% set %}…{% endset %}`, `{% filter %}`,
10
14
  * `{% capture %}`), in raw and comment blocks, in `<script>`/`<style>`/`<textarea>`/`<title>` and
11
15
  * HTML comments, closing tags, declarations, tags whose name is built by template syntax and tags
12
- * that already carry the attribute stay untouched. Removing the attribute from the rendered output
16
+ * that already carry the attribute stay untouched. Removing the attributes from the rendered output
13
17
  * gives the document of the original source. Preview only: saved versions, API renders and the
14
- * render-worker never see it.
18
+ * render-worker never see them.
15
19
  */
16
20
  export type SourceFile = 'body' | 'header' | 'footer';
17
21
  export declare const sourceAttribute = "data-ff-src";
22
+ export declare const editAttribute = "data-ff-edit";
18
23
  export interface SourceLocation {
19
24
  file: SourceFile;
20
25
  /** 1-based, as Monaco counts. */
@@ -22,6 +27,10 @@ export interface SourceLocation {
22
27
  /** 1-based UTF-16 column of the tag's `<`. */
23
28
  column: number;
24
29
  }
30
+ export interface AnnotateOptions {
31
+ /** Mark editable regions with `data-ff-edit` as well (the preview's edit mode). */
32
+ editable?: boolean;
33
+ }
25
34
  /** Parses a `data-ff-src` value; null when it is not one. */
26
35
  export declare function parseSourceAttribute(value: string | null | undefined): SourceLocation | null;
27
- export declare function annotateSourcePositions(source: string, engine: EngineId, file: SourceFile): string;
36
+ export declare function annotateSourcePositions(source: string, engine: EngineId, file: SourceFile, options?: AnnotateOptions): string;
@@ -5,16 +5,21 @@ import type { EngineId } from './types.js';
5
5
  * rendered element says where it came from instead of the editor searching the template for it.
6
6
  * Elements from a loop all point at the loop body, which is the line that wrote them.
7
7
  *
8
+ * With `editable`, a start tag whose content is a region the preview can edit (plan 16 §3.1,
9
+ * `editableRegionAt`) also gets `data-ff-edit="text"`, or `data-ff-edit="t"` when its whole content
10
+ * is one `t()` call.
11
+ *
8
12
  * The annotation must never change what the template means: tags inside template syntax, in
9
13
  * blocks whose output is captured or filtered as a string (`{% set %}…{% endset %}`, `{% filter %}`,
10
14
  * `{% capture %}`), in raw and comment blocks, in `<script>`/`<style>`/`<textarea>`/`<title>` and
11
15
  * HTML comments, closing tags, declarations, tags whose name is built by template syntax and tags
12
- * that already carry the attribute stay untouched. Removing the attribute from the rendered output
16
+ * that already carry the attribute stay untouched. Removing the attributes from the rendered output
13
17
  * gives the document of the original source. Preview only: saved versions, API renders and the
14
- * render-worker never see it.
18
+ * render-worker never see them.
15
19
  */
16
20
  export type SourceFile = 'body' | 'header' | 'footer';
17
21
  export declare const sourceAttribute = "data-ff-src";
22
+ export declare const editAttribute = "data-ff-edit";
18
23
  export interface SourceLocation {
19
24
  file: SourceFile;
20
25
  /** 1-based, as Monaco counts. */
@@ -22,6 +27,10 @@ export interface SourceLocation {
22
27
  /** 1-based UTF-16 column of the tag's `<`. */
23
28
  column: number;
24
29
  }
30
+ export interface AnnotateOptions {
31
+ /** Mark editable regions with `data-ff-edit` as well (the preview's edit mode). */
32
+ editable?: boolean;
33
+ }
25
34
  /** Parses a `data-ff-src` value; null when it is not one. */
26
35
  export declare function parseSourceAttribute(value: string | null | undefined): SourceLocation | null;
27
- export declare function annotateSourcePositions(source: string, engine: EngineId, file: SourceFile): string;
36
+ export declare function annotateSourcePositions(source: string, engine: EngineId, file: SourceFile, options?: AnnotateOptions): string;
@@ -0,0 +1,61 @@
1
+ import type { EngineId } from './types.cjs';
2
+ /**
3
+ * A template source read as HTML with template constructs in it: the scanner that finds start tags
4
+ * for click-to-source (`source-positions.ts`) and the regions text can be edited in from the preview
5
+ * (`source-edit.ts`). It knows each engine's delimiters, string literals inside expressions, raw and
6
+ * comment blocks, and blocks whose output is captured as a string. Internal to the engine.
7
+ */
8
+ export declare const tagName: RegExp;
9
+ /** Elements whose content the HTML parser reads as text, so a `<b>` inside is not an element. */
10
+ export declare const rawTextElements: Set<string>;
11
+ /**
12
+ * What a template construct is, for a reader that has to tell output from control flow: `output` is
13
+ * a value printed in place (`{{ x }}`, `{{{ x }}}`, `{{t 'k'}}`), `comment` prints nothing, and
14
+ * `statement` is everything that decides what is printed (`{% if %}`, `{{#each}}`, `{{else}}`,
15
+ * `{{> partial}}`, raw blocks).
16
+ */
17
+ export type TemplateConstruct = {
18
+ type: 'output';
19
+ end: number;
20
+ inner: string;
21
+ } | {
22
+ type: 'comment';
23
+ end: number;
24
+ } | {
25
+ type: 'statement';
26
+ end: number;
27
+ keyword?: string;
28
+ };
29
+ export declare class Scanner {
30
+ private readonly source;
31
+ private readonly engine;
32
+ private readonly n;
33
+ private readonly escapes;
34
+ constructor(source: string, engine: EngineId);
35
+ /** End of the template construct starting at `at` (with a capturing block's body), or null. */
36
+ skipTemplate(at: number): number | null;
37
+ /** The construct starting at `at` and what kind it is, or null when `{` starts none. */
38
+ classify(at: number): TemplateConstruct | null;
39
+ /** Index after `close`, stepping over template constructs; the end of the source when missing. */
40
+ skipTo(from: number, close: string): number;
41
+ /** Index after the `>` that ends a tag, stepping over quoted values and template constructs. */
42
+ tagEnd(from: number): number;
43
+ /** Index of the `</name` that closes a raw text element. */
44
+ skipToClosingTag(from: number, name: string): number;
45
+ private captures;
46
+ private blockEnd;
47
+ private templateTag;
48
+ /** `{{{{raw}}}} … {{{{/raw}}}}`: the content is never parsed. */
49
+ private handlebarsRawBlock;
50
+ private indexAfter;
51
+ /** End of an expression or statement; a `close` inside a string literal does not end it. */
52
+ private expressionEnd;
53
+ }
54
+ /** Offsets where lines start; `\r\n`, `\n` and a lone `\r` all end a line, as in Monaco. */
55
+ export declare function lineStarts(source: string): number[];
56
+ export declare function locate(starts: number[], offset: number): {
57
+ line: number;
58
+ column: number;
59
+ };
60
+ /** The offset of a 1-based line and column, or null when the source has no such place. */
61
+ export declare function offsetOf(starts: number[], sourceLength: number, line: number, column: number): number | null;
@@ -0,0 +1,61 @@
1
+ import type { EngineId } from './types.js';
2
+ /**
3
+ * A template source read as HTML with template constructs in it: the scanner that finds start tags
4
+ * for click-to-source (`source-positions.ts`) and the regions text can be edited in from the preview
5
+ * (`source-edit.ts`). It knows each engine's delimiters, string literals inside expressions, raw and
6
+ * comment blocks, and blocks whose output is captured as a string. Internal to the engine.
7
+ */
8
+ export declare const tagName: RegExp;
9
+ /** Elements whose content the HTML parser reads as text, so a `<b>` inside is not an element. */
10
+ export declare const rawTextElements: Set<string>;
11
+ /**
12
+ * What a template construct is, for a reader that has to tell output from control flow: `output` is
13
+ * a value printed in place (`{{ x }}`, `{{{ x }}}`, `{{t 'k'}}`), `comment` prints nothing, and
14
+ * `statement` is everything that decides what is printed (`{% if %}`, `{{#each}}`, `{{else}}`,
15
+ * `{{> partial}}`, raw blocks).
16
+ */
17
+ export type TemplateConstruct = {
18
+ type: 'output';
19
+ end: number;
20
+ inner: string;
21
+ } | {
22
+ type: 'comment';
23
+ end: number;
24
+ } | {
25
+ type: 'statement';
26
+ end: number;
27
+ keyword?: string;
28
+ };
29
+ export declare class Scanner {
30
+ private readonly source;
31
+ private readonly engine;
32
+ private readonly n;
33
+ private readonly escapes;
34
+ constructor(source: string, engine: EngineId);
35
+ /** End of the template construct starting at `at` (with a capturing block's body), or null. */
36
+ skipTemplate(at: number): number | null;
37
+ /** The construct starting at `at` and what kind it is, or null when `{` starts none. */
38
+ classify(at: number): TemplateConstruct | null;
39
+ /** Index after `close`, stepping over template constructs; the end of the source when missing. */
40
+ skipTo(from: number, close: string): number;
41
+ /** Index after the `>` that ends a tag, stepping over quoted values and template constructs. */
42
+ tagEnd(from: number): number;
43
+ /** Index of the `</name` that closes a raw text element. */
44
+ skipToClosingTag(from: number, name: string): number;
45
+ private captures;
46
+ private blockEnd;
47
+ private templateTag;
48
+ /** `{{{{raw}}}} … {{{{/raw}}}}`: the content is never parsed. */
49
+ private handlebarsRawBlock;
50
+ private indexAfter;
51
+ /** End of an expression or statement; a `close` inside a string literal does not end it. */
52
+ private expressionEnd;
53
+ }
54
+ /** Offsets where lines start; `\r\n`, `\n` and a lone `\r` all end a line, as in Monaco. */
55
+ export declare function lineStarts(source: string): number[];
56
+ export declare function locate(starts: number[], offset: number): {
57
+ line: number;
58
+ column: number;
59
+ };
60
+ /** The offset of a 1-based line and column, or null when the source has no such place. */
61
+ export declare function offsetOf(starts: number[], sourceLength: number, line: number, column: number): number | null;