efficient-easel 0.98.0 → 0.99.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.
- package/README.md +11 -3
- package/dist/{chunk-OGZFDJ6G.js → chunk-JE63JHKO.js} +1 -1
- package/dist/{chunk-CERTFXCV.js → chunk-JYPOOHII.js} +3 -3
- package/dist/chunk-SJQG5ENJ.js +1 -0
- package/dist/{chunk-2LUSK32B.js → chunk-ZT7M24XD.js} +1 -1
- package/dist/copy/index.js +6 -6
- package/dist/gold/index.js +1 -1
- package/dist/markup/index.d.ts +97 -21
- package/dist/markup/index.js +1 -1
- package/dist/strings/catalogue.js +1 -1
- package/dist/strings/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-6OPSJGAI.js +0 -1
package/README.md
CHANGED
|
@@ -214,20 +214,28 @@ email. Framework-free: no React, no DOM, no imports.
|
|
|
214
214
|
| `~~x~~` | strikethrough | yes |
|
|
215
215
|
| `[words](href)` | a link — `http`, `https`, `mailto`, `tel` or no scheme only | yes |
|
|
216
216
|
| `- ` at the start of a line | a bullet line, one level | yes |
|
|
217
|
+
| `1. ` at the start of a line | a numbered line, one level: 1-3 digits, `. `, words; the number is kept as typed | yes |
|
|
218
|
+
| `[x]{underline}`, `[x]{sup}`, `[x]{sub}` | underline, superscript, subscript (tree only) | not yet — `applyMark` writes them; the buttons come with the final text box |
|
|
219
|
+
| `[x]{color=name}` | a theme colour, by name only (`isColorName`; never a hex) (tree only) | not yet — `applyColor` writes it |
|
|
217
220
|
| `@@x@@`, `++x++` | Emphasis, Strong (the storefront's old word styles) | no — read only |
|
|
218
221
|
| `*x*`, `#x#`, `[x]` | legacy accent, bold, italic (per product set) | no — read only |
|
|
219
222
|
|
|
220
223
|
The three names a merchant sees are in `MARK_NAMES`. A run never crosses a line
|
|
221
|
-
break, and
|
|
222
|
-
|
|
224
|
+
break, and runs, spans and links nest up to four levels
|
|
225
|
+
(`[**_[x]{sup}_**]{color=accent}`); a fifth stays as typed. Any block after `]`
|
|
226
|
+
that is not exactly one of the four (`[x]{foo}`, `[x]{color=#f00}`,
|
|
227
|
+
`[x]{{first_name}}`) is plain text. The spans and the numbered line are read by
|
|
228
|
+
`parseMarkup` only: `tokenizeInline` keeps them as text, so a renderer that has
|
|
229
|
+
not learned them prints the delimiters.
|
|
223
230
|
|
|
224
231
|
| Export | Notes |
|
|
225
232
|
|---|---|
|
|
226
233
|
| `parseMarkup(value, rules)` → `MarkupLine[]` | The whole grammar as a tree. Each run keeps the delimiters that were saved. |
|
|
227
|
-
| `serializeMarkup(lines)` | The inverse: `serializeMarkup(parseMarkup(s, rules)) === s`, for every string. Pinned by `tests/markup-round-trip.test.ts` (made-up strings in the shape of saved copy). All 917 saved production strings were checked
|
|
234
|
+
| `serializeMarkup(lines)` | The inverse: `serializeMarkup(parseMarkup(s, rules)) === s`, for every string. Pinned by `tests/markup-round-trip.test.ts` (made-up strings in the shape of saved copy). All 917 saved production strings were checked off-repo on 2026-09-29 (editor-shell #89), and again for the spans and numbered lines on 2026-10-06 (E1). |
|
|
228
235
|
| `isSafeLinkHref(href)` | The link rule. Call it before writing any `href`. |
|
|
229
236
|
| `tokenizeInline(value, rules)`, `stripInline` | The flat reading older renderers use: runs only, no links, no nesting. |
|
|
230
237
|
| `applyMark(text, start, end, style)`, `MARKUP_TOOLS`, `markupTools`, `COPY_FIELD_TOOLS` | The writer behind a toolbar button, and the button descriptors. |
|
|
238
|
+
| `applyColor(text, start, end, name)`, `isColorName`, `spanFor` | A colour carries a name, so it has its own writer: it writes, renames and (`null`) takes off `[x]{color=name}`, and changes nothing for a name `isColorName` refuses. |
|
|
231
239
|
| `STANDARD_MARKUP`, `STOREFRONT_MARKUP`, `CAMPAIGN_MARKUP` | The rule sets. The last two add each product's legacy runs. |
|
|
232
240
|
|
|
233
241
|
## The edit lock — two operators, one document
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DEFAULT_PICK_WORDS as o}from"./chunk-ZAOM6PFH.js";import{DEFAULT_STYLE_CLIPBOARD_WORDS as r}from"./chunk-6WY6ZXJG.js";import{DEFAULT_CANVAS_WORDS as t}from"./chunk-GGTPNGFJ.js";import{DEFAULT_FIELDS_WORDS as m}from"./chunk-SUO5627P.js";import{DEFAULT_TREE_WORDS as n}from"./chunk-H4B72XCJ.js";import{DEFAULT_PANEL_WORDS as c}from"./chunk-7A7O2JWQ.js";import{DEFAULT_NODE_MENU_WORDS as f}from"./chunk-WK3AFPXY.js";import{DEFAULT_SAVE_WORDS as p}from"./chunk-H6DDIBQ4.js";import{DEFAULT_CHROME_WORDS as s,DEFAULT_NOTICE_WORDS as i}from"./chunk-KDIVA6WD.js";import{DEFAULT_LOCK_WORDS as u}from"./chunk-RE4LP46F.js";import{DEFAULT_RAIL_WORDS as e}from"./chunk-2OAZYSWJ.js";import{DEFAULT_COPY_WORDS as k}from"./chunk-
|
|
1
|
+
import{DEFAULT_PICK_WORDS as o}from"./chunk-ZAOM6PFH.js";import{DEFAULT_STYLE_CLIPBOARD_WORDS as r}from"./chunk-6WY6ZXJG.js";import{DEFAULT_CANVAS_WORDS as t}from"./chunk-GGTPNGFJ.js";import{DEFAULT_FIELDS_WORDS as m}from"./chunk-SUO5627P.js";import{DEFAULT_TREE_WORDS as n}from"./chunk-H4B72XCJ.js";import{DEFAULT_PANEL_WORDS as c}from"./chunk-7A7O2JWQ.js";import{DEFAULT_NODE_MENU_WORDS as f}from"./chunk-WK3AFPXY.js";import{DEFAULT_SAVE_WORDS as p}from"./chunk-H6DDIBQ4.js";import{DEFAULT_CHROME_WORDS as s,DEFAULT_NOTICE_WORDS as i}from"./chunk-KDIVA6WD.js";import{DEFAULT_LOCK_WORDS as u}from"./chunk-RE4LP46F.js";import{DEFAULT_RAIL_WORDS as e}from"./chunk-2OAZYSWJ.js";import{DEFAULT_COPY_WORDS as k}from"./chunk-ZT7M24XD.js";import{DEFAULT_DRAG_WORDS as j}from"./chunk-O2NLQBFX.js";var h={notice:i,lock:u,save:p,chrome:s,rail:e,tree:n,panel:c,fields:m,pick:o,drag:j,menu:f,styleClipboard:r,copy:k,canvas:t},l=o=>"object"==typeof o&&null!==o;function a(o,r){const t={};for(const m of Object.keys(o)){const n=o[m],c=r[m];null==c?t[m]=n:l(n)?t[m]=l(c)?a(n,c):n:t[m]=typeof c==typeof n?c:n}return t}function y(o,r){return r?a(o,r):o}export{h as DEFAULT_EDITOR_STRINGS,y as mergeEditorStrings};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{tokenizeInline as e,STANDARD_MARKUP as t}from"./chunk-
|
|
1
|
+
import{tokenizeInline as e,STANDARD_MARKUP as t}from"./chunk-SJQG5ENJ.js";import{jsx as n,jsxs as l}from"react/jsx-runtime";import{useRef as r}from"react";function s(t,n){const l=[];let r=0;for(const s of e(t,n)){if("text"===s.kind){s.text.length>0&&(l.push({kind:"text",text:t.slice(r,r+s.text.length)}),r+=s.text.length);continue}const e=i(t,r,s.kind,s.text,n);if(!e)return[{kind:"text",text:t}];const o=r+e.open.length,c=o+s.text.length,a=c+e.close.length;l.push({kind:"delimiter",text:t.slice(r,o)}),l.push({kind:s.kind,text:t.slice(o,c)}),l.push({kind:"delimiter",text:t.slice(c,a)}),r=a}return l.map(e=>e.text).join("")!==t?[{kind:"text",text:t}]:l}function i(e,t,n,l,r){for(const s of r){if(s.kind!==n)continue;if(!e.startsWith(s.open,t))continue;const r=t+s.open.length;if(e.startsWith(l,r)&&e.startsWith(s.close,r+l.length))return s}return null}function o({value:e,rules:l=t,className:r,layerRef:i}){const o=s(e,l);/* @__PURE__ */
|
|
2
2
|
return n("div",{ref:i,className:["es-gold-layer",r??""].filter(Boolean).join(" "),"aria-hidden":"true",children:o.map((e,t)=>function(e,t){const{kind:l,text:r}=e;switch(l){case"delimiter":/* @__PURE__ */
|
|
3
3
|
return n("span",{className:"es-gold-delim",children:r},t);case"accent":case"highlight":/* @__PURE__ */
|
|
4
4
|
return n("em",{className:"es-gold-mark es-gold-accent",children:r},t);case"bold":/* @__PURE__ */
|
|
@@ -6,8 +6,8 @@ return n("strong",{className:"es-gold-mark es-gold-bold",children:r},t);case"ita
|
|
|
6
6
|
return n("em",{className:"es-gold-mark es-gold-italic",children:r},t);case"strike":/* @__PURE__ */
|
|
7
7
|
return n("s",{className:"es-gold-mark es-gold-strike",children:r},t);case"quiet":/* @__PURE__ */
|
|
8
8
|
return n("span",{className:"es-gold-mark es-gold-quiet",children:r},t);default:/* @__PURE__ */
|
|
9
|
-
return n("span",{className:"es-gold-text",children:r},t)}}(e,t))})}function c({value:e,onInput:s,onCommit:i,onCancel:c,multiline:a=!1,placeholder:u,className:d,rules:f=t,ariaLabel:m,disabled:h=!1,inputRef:g}){const p=r(null),k=r(e),x=r(!1);function
|
|
9
|
+
return n("span",{className:"es-gold-text",children:r},t)}}(e,t))})}function c({value:e,onInput:s,onCommit:i,onCancel:c,multiline:a=!1,placeholder:u,className:d,rules:f=t,ariaLabel:m,disabled:h=!1,inputRef:g}){const p=r(null),k=r(e),x=r(!1);function N(e){x.current&&(x.current=!1,i?.(e))}/* @__PURE__ */
|
|
10
10
|
return l("div",{className:["es-gold",a?"es-gold-is-multiline":"es-gold-is-single",h?"es-gold-is-off":"",d??""].filter(Boolean).join(" "),children:[
|
|
11
11
|
/* @__PURE__ */n(o,{value:e,rules:f,layerRef:p}),u&&""===e?
|
|
12
12
|
/* @__PURE__ */n("div",{className:"es-gold-placeholder","aria-hidden":"true",children:u}):null,
|
|
13
|
-
/* @__PURE__ */n("textarea",{ref:g,className:"es-gold-input",disabled:h,value:e,placeholder:u,"aria-label":m,onChange:function(e){x.current=!0,s(e.currentTarget.value)},onFocus:function(){k.current=e,x.current=!1},onBlur:function(){
|
|
13
|
+
/* @__PURE__ */n("textarea",{ref:g,className:"es-gold-input",disabled:h,value:e,placeholder:u,"aria-label":m,onChange:function(e){x.current=!0,s(e.currentTarget.value)},onFocus:function(){k.current=e,x.current=!1},onBlur:function(){N(e)},onKeyDown:function(t){return"Escape"===t.key?(t.preventDefault(),x.current=!1,void c?.(k.current)):"Enter"!==t.key||a?void 0:(t.preventDefault(),void N(e))},onScroll:function(e){const t=p.current;t&&(t.scrollTop=e.currentTarget.scrollTop,t.scrollLeft=e.currentTarget.scrollLeft)}})]})}export{o as GoldLayer,c as GoldTextInput,s as goldSegments};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e={bold:{open:"**",close:"**",placeholder:"bold text"},italic:{open:"_",close:"_",placeholder:"italic text"},strike:{open:"~~",close:"~~",placeholder:"struck out"},code:{open:"`",close:"`",placeholder:"code"},highlight:{open:"==",close:"==",placeholder:"highlighted text"},quiet:{open:"^^",close:"^^",placeholder:"quiet text"},underline:{open:"[",close:"]{underline}",placeholder:"underlined text"},sup:{open:"[",close:"]{sup}",placeholder:"superscript"},sub:{open:"[",close:"]{sub}",placeholder:"subscript"}};function t(e){return/^[a-z][a-z0-9-]*$/.test(e)}function n(e,t){const n=/^\{(underline|sup|sub|color=([a-z][a-z0-9-]*))\}/.exec(e.slice(t,t+64));return n?void 0===n[2]?{kind:n[1],length:n[0].length}:{kind:"color",color:n[2],length:n[0].length}:null}var l={bold:e.bold.placeholder,italic:e.italic.placeholder,strike:e.strike.placeholder,code:e.code.placeholder,highlight:e.highlight.placeholder,quiet:e.quiet.placeholder,link:"link text",underline:e.underline.placeholder,sup:e.sup.placeholder,sub:e.sub.placeholder,color:"colored text"},o={bullet:()=>"- ",number:e=>`${e+1}. `,quote:()=>"> "};function r(t,n,r,i,c=p,u=l){if("clear"===i)return M(t,n,r,c);const a=t.slice(n,r);if("link"===i){const e=a||u.link,l=`[${e}](https://)`;return{text:t.slice(0,n)+l+t.slice(r),selectionStart:n+e.length+3,selectionEnd:n+l.length-1}}const d=o[i];if(d){const e=t.lastIndexOf("\n",Math.max(n-1,0))+1,l=t.indexOf("\n",r),o=-1===l?t.length:l,i=t.slice(e,o).split("\n"),s=i.every((e,t)=>e.startsWith(d(t))),c=i.map((e,t)=>s?e.slice(d(t).length):d(t)+e).join("\n");return{text:t.slice(0,e)+c+t.slice(o),selectionStart:e,selectionEnd:e+c.length}}const{open:h,close:f}=e[i],k=i,g=u[k]??l[k];if(s(t,n,r,i))return{text:t.slice(0,n-h.length)+a+t.slice(r+f.length),selectionStart:n-h.length,selectionEnd:n-h.length+a.length};const m=a||g;return{text:t.slice(0,n)+h+m+f+t.slice(r),selectionStart:n+h.length,selectionEnd:n+h.length+m.length}}function i(e,o,r,i,s=l){const c={text:e,selectionStart:o,selectionEnd:r};if(null!==i&&!t(i))return c;const u=e.slice(o,r),a=o>=1&&"["===e[o-1]&&"]"===e[r]?n(e,r+1):null;if("color"===a?.kind){const t=o-1,n=e.slice(r+1+a.length);return null===i?{text:e.slice(0,t)+u+n,selectionStart:t,selectionEnd:t+u.length}:{text:`${e.slice(0,r)}]{color=${i}}${n}`,selectionStart:o,selectionEnd:r}}if(null===i)return c;const d=u||(s.color??l.color);return{text:`${e.slice(0,o)}[${d}]{color=${i}}${e.slice(r)}`,selectionStart:o+1,selectionEnd:o+1+d.length}}function s(t,n,l,o){const r=e[o];if(!r)return!1;const{open:i,close:s}=r;return n>=i.length&&t.slice(n-i.length,n)===i&&t.slice(l,l+s.length)===s}function c(e,t,n){const l=0===t?0:e.lastIndexOf("\n",t-1)+1;for(let o=e.lastIndexOf("[",t);o>=l;o=0===o?-1:e.lastIndexOf("[",o-1)){const t=$(e,o);if(t&&n<=t.end)return{start:o,end:t.end,label:t.label,href:t.href}}return null}function u(e,t,n,l){const o=c(e,t,n),r=o?o.start:t,i=o?o.end:n,s=`[${o?o.label:e.slice(t,n)||l}](${l})`,u=r+s.length;return{text:e.slice(0,r)+s+e.slice(i),selectionStart:u,selectionEnd:u}}function a(e,t){return{text:e.slice(0,t.start)+t.label+e.slice(t.end),selectionStart:t.start,selectionEnd:t.start+t.label.length}}var d=[{style:"bold",label:"B",name:"Strong",title:"Strong · **words** · ⌘B",shortcut:"b"},{style:"italic",label:"I",name:"Italic",title:"Italic · _words_ · ⌘I",shortcut:"i"},{style:"strike",label:"S",name:"Strikethrough",title:"Strikethrough · ~~words~~"},{style:"highlight",label:"◆",name:"Emphasis",title:"Emphasis · ==words=="},{style:"quiet",label:"a",name:"Quiet",title:"Quiet · ^^words^^"},{style:"code",label:"‹›",name:"Code",title:"Code"},{style:"link",label:"🔗",name:"Link",title:"Link · [words](https://…) · ⌘K",shortcut:"k"},{style:"bullet",label:"•",name:"Bulleted list",title:"Bulleted list"},{style:"number",label:"1.",name:"Numbered list",title:"Numbered list"},{style:"quote",label:"❝",name:"Quote",title:"Quote"},{style:"clear",label:"T×",name:"Clear marks",title:"Clear marks · ⌘⇧X",shortcut:"shift+x"}],h={bold:"Strong",highlight:"Emphasis",quiet:"Quiet"};function f(e){return d.filter(t=>e.includes(t.style))}var p=[{open:"**",close:"**",kind:"bold"},{open:"==",close:"==",kind:"highlight"},{open:"~~",close:"~~",kind:"strike"},{open:"_",close:"_",kind:"italic",wordBoundary:!0},{open:"^^",close:"^^",kind:"quiet"},{open:"@@",close:"@@",kind:"highlight"},{open:"++",close:"++",kind:"bold"}],k=d.map(e=>e.style).filter(e=>p.some(t=>t.kind===e)),g=[...p,{open:"*",close:"*",kind:"accent"}],m=[...p,{open:"*",close:"*",kind:"accent"},{open:"#",close:"#",kind:"bold",notBefore:"0123456789"},{open:"[",close:"]",kind:"italic",notBefore:"(",notBeforeBlock:!0}];function b(e){return!/\s/.test(e)&&!/[!-\/:-@[-`{-~]/.test(e)}function x(e,t){const n=[];let l="",o=0;for(;o<e.length;){const r=S(e,o,t);r?(n.push({kind:"text",text:l}),l="",n.push({kind:r.rule.kind,text:r.inner}),o=r.end):(l+=e[o],o+=1)}return n.push({kind:"text",text:l}),n}function S(e,t,l){for(const o of l){if(!e.startsWith(o.open,t))continue;if(o.wordBoundary&&t>0&&b(e[t-1]))continue;const l=t+o.open.length,r=e.indexOf(o.close,l);if(r<l+1)continue;const i=e.slice(l,r);if(i.includes(o.close[0]))continue;if(i.includes("\n"))continue;const s=r+o.close.length,c=e[s];if((!o.notBefore||void 0===c||!o.notBefore.includes(c))&&!(o.notBeforeBlock&&n(e,s)||o.wordBoundary&&void 0!==c&&b(c)))return{rule:o,inner:i,end:s}}return null}function y(e,t){return x(e,t).map(e=>e.text).join("")}var v=["http","https","mailto","tel"];function E(e){if(""===e||/[\s\u0000-\u001f\u007f]/.test(e))return!1;const t=/^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(e);return!t||v.includes(t[1].toLowerCase())}function $(e,t){if("["!==e[t])return null;const n=e.indexOf("]",t+1);if(n<t+2||"("!==e[n+1])return null;const l=e.slice(t+1,n);if(l.includes("["))return null;const o=e.indexOf(")",n+2);if(-1===o)return null;const r=e.slice(n+2,o);return E(r)?{label:l,href:r,end:o+1}:null}function B(e,t){if("["!==e[t])return null;let l=0;for(let o=t;o<e.length;o+=1){const r=e[o];if("\n"===r)return null;if("["===r)l+=1;else if("]"===r){if(l-=1,l>0)continue;if(o===t+1)return null;const r=n(e,o+1);return r?{kind:r.kind,color:r.color,label:e.slice(t+1,o),close:e.slice(o,o+1+r.length),end:o+1+r.length}:null}}return null}var w=4;function q(e,t,n){const l=[];let o="";const r=()=>{o&&l.push({kind:"text",text:o}),o=""},i=e=>n+1<w?q(e,t,n+1):[{kind:"text",text:e}];let s=0;for(;s<e.length;){const n=$(e,s);if(n){r(),l.push({kind:"link",href:n.href,children:i(n.label)}),s=n.end;continue}const c=B(e,s);if(c){r(),l.push({kind:c.kind,open:"[",close:c.close,...void 0===c.color?{}:{color:c.color},children:i(c.label)}),s=c.end;continue}const u=S(e,s,t);u?(r(),l.push({kind:u.rule.kind,open:u.rule.open,close:u.rule.close,children:i(u.inner)}),s=u.end):(o+=e[s],s+=1)}return r(),l}function O(e,t){return e.split("\n").map(e=>{const{bullet:n,number:l,rest:o}=function(e){if(e.startsWith("- ")&&""!==e.slice(2).trim())return{bullet:!0,number:null,rest:e.slice(2)};const t=/^([0-9]{1,3})\. /.exec(e);return t&&""!==e.slice(t[0].length).trim()?{bullet:!1,number:t[1],rest:e.slice(t[0].length)}:{bullet:!1,number:null,rest:e}}(e);return{bullet:n,number:l,children:q(o,t,0)}})}function I(e){return null!=e.number?`${e.number}. `:e.bullet?"- ":""}function z(e){return e.map(e=>"text"===e.kind?e.text:"link"===e.kind?`[${z(e.children)}](${e.href})`:e.open+z(e.children)+e.close).join("")}function _(e){return e.map(e=>I(e)+z(e.children)).join("\n")}function C(n,l,o){if("link"===l)return void 0===o?null:{id:n,kind:"link",open:"[",close:`](${o})`,href:o};if("color"===l)return void 0!==o&&t(o)?{id:n,kind:"color",open:"[",close:`]{color=${o}}`,color:o}:null;const r=e[l];return r&&"code"!==l?{id:n,kind:l,open:r.open,close:r.close}:null}function Q(e,t){let n=0,l=0;return e.split("\n").map(e=>{const[o]=O(e,t);let r=l+I(o).length;l+=e.length+1;const i=[],s=(e,t)=>{for(const l of e){if("text"===l.kind){for(const e of l.text)i.push({ch:e,marks:t,at:r}),r+=e.length;continue}const e="link"===l.kind?C(++n,"link",l.href):{id:++n,kind:l.kind,open:l.open,close:l.close,...void 0===l.color?{}:{color:l.color}};r+=e.open.length,s(l.children,[...t,e]),r+=e.close.length}};return s(o.children,[]),{bullet:o.bullet,number:o.number??null,chars:i}})}function j(e){let t="";const n=[];return e.forEach((e,l)=>{l>0&&(t+="\n"),t+=I(e);const o=[],r=[];for(const n of e.chars){let e=0;for(;e<o.length&&e<n.marks.length&&o[e].id===n.marks[e].id;)e+=1;for(;o.length>e;)t+=o.pop().close;for(let l=e;l<n.marks.length;l+=1)t+=n.marks[l].open,o.push(n.marks[l]);r.push(t.length),t+=n.ch}for(;o.length>0;)t+=o.pop().close;n.push(r)}),{text:t,at:n}}function L(e,t){return e.length===t.length&&e.every((e,n)=>{const l=t[n];return e.bullet===l.bullet&&(e.number??null)===(l.number??null)&&(e.chars.length===l.chars.length&&e.chars.every((e,t)=>{const n=l.chars[t];return e.ch===n.ch&&e.marks.length===n.marks.length&&e.marks.every((e,t)=>e.kind===n.marks[t].kind&&e.href===n.marks[t].href&&e.color===n.marks[t].color)}))})}function M(e,t,n,l=p){const o=Q(e,l),r=o.flatMap(e=>e.chars),i={text:e,selectionStart:t,selectionEnd:n},s=e=>o.map(t=>({bullet:t.bullet,number:t.number,chars:t.chars.map(t=>({...t,marks:t.marks.filter(n=>"link"===n.kind||!e(t,n))}))})),c=e=>{const t=j(e);return L(e,Q(t.text,l))?t:null},u=(e,t)=>{let n=r.indexOf(t);for(let t=0;t<e.at.length;t+=1){if(n<e.at[t].length)return e.at[t][n];n-=e.at[t].length}return 0};if(t===n){const e=[...r].reverse().find(e=>e.at<t),n=r.find(e=>e.at>=t),l=new Set([...e?.marks??[],...n?.marks??[]].map(e=>e.id));if(![...l].some(e=>r.some(t=>t.marks.some(t=>t.id===e&&"link"!==t.kind))))return i;const o=c(s((e,t)=>l.has(t.id)));if(!o)return i;const a=n?u(o,n):e?u(o,e)+e.ch.length:0;return{text:o.text,selectionStart:a,selectionEnd:a}}const a=new Set(r.filter(e=>e.at>=t&&e.at<n));if(0===a.size)return i;const d=new Set([...a].flatMap(e=>e.marks.map(e=>e.id))),h=c(s(e=>a.has(e)))??c(s((e,t)=>d.has(t.id)));if(!h)return i;const f=r.find(e=>a.has(e)),k=[...r].reverse().find(e=>a.has(e));return{text:h.text,selectionStart:u(h,f),selectionEnd:u(h,k)+k.ch.length}}export{m as CAMPAIGN_MARKUP,k as COPY_FIELD_TOOLS,d as MARKUP_TOOLS,h as MARK_NAMES,l as MARK_PLACEHOLDERS,p as STANDARD_MARKUP,g as STOREFRONT_MARKUP,i as applyColor,r as applyMark,M as clearMarks,c as findLink,t as isColorName,E as isSafeLinkHref,s as markedAt,Q as markedLines,f as markupTools,O as parseMarkup,a as removeLink,L as sameMarks,_ as serializeMarkup,C as spanFor,y as stripInline,x as tokenizeInline,u as writeLink,j as writeMarkedLines};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{MARKUP_TOOLS as e,MARK_PLACEHOLDERS as t}from"./chunk-
|
|
1
|
+
import{MARKUP_TOOLS as e,MARK_PLACEHOLDERS as t}from"./chunk-SJQG5ENJ.js";var i={formatting:"Formatting",alignment:"Alignment",align:{left:"Left",center:"Center",right:"Right",justify:"Justify"},link:{title:"Link",label:"Link to",placeholder:"https://… or /page",refused:"Use a web address (https://…), a page on this site (/…), mailto: or tel:.",remove:"Remove link",apply:"Apply"},marks:Object.fromEntries(e.map(e=>[e.style,{name:e.name??e.title,title:e.title}])),placeholders:t};export{i as DEFAULT_COPY_WORDS};
|
package/dist/copy/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import{DEFAULT_COPY_WORDS as e}from"../chunk-
|
|
1
|
+
import{DEFAULT_COPY_WORDS as e}from"../chunk-ZT7M24XD.js";import{SettingsSegmented as t}from"../chunk-QB3BZIRA.js";import{GoldTextInput as n}from"../chunk-JYPOOHII.js";import{applyMark as l,STANDARD_MARKUP as r,writeMarkedLines as o,sameMarks as i,markedLines as a,spanFor as s,markupTools as c,findLink as u,markedAt as d,removeLink as p,writeLink as h,isSafeLinkHref as f}from"../chunk-SJQG5ENJ.js";import{useWords as m}from"../chunk-MFIRYGHW.js";import"../chunk-BZ5ASXOL.js";import{AlignSeparateIcon as y,AlignRightIcon as b,AlignCenterIcon as g,AlignLeftIcon as k,ClearMarksIcon as v,LinkIcon as x,QuietIcon as w,EmphasisIcon as C,StrikeIcon as D,ItalicIcon as N,BoldIcon as S}from"../chunk-PI26YXYD.js";import{useRef as j,useLayoutEffect as E,useState as L,useEffect as P,useId as K}from"react";import{jsx as T,jsxs as z,Fragment as $}from"react/jsx-runtime";var A=["left","center","right","justify"],B=e.align,M={left:/* @__PURE__ */T(k,{}),center:/* @__PURE__ */T(g,{}),right:/* @__PURE__ */T(b,{}),justify:/* @__PURE__ */T(y,{})},R={three:{labelsPx:94.5,widestLabelPx:39.94},four:{labelsPx:140,widestLabelPx:44}};function I(e,t=B){return A.filter(t=>e.includes(t)).map(e=>({id:e,label:t[e],icon:M[e],title:t[e]}))}var Y=/[\u1100-\u11ff\u2e80-\u9fff\uac00-\ud7af\uf900-\ufaff\uff00-\uffef]/;function F(e){if(e.every(e=>e.label===B[e.id]))return e.length>3?R.four:R.three;const t=e.map(e=>[...e.label].reduce((e,t)=>e+(Y.test(t)?13:8),0));return{labelsPx:t.reduce((e,t)=>e+t,0),widestLabelPx:Math.max(0,...t)}}function O(e,t){const n=t?.selectionStart??e.length;return{start:n,end:t?.selectionEnd??n}}function Z(e,t,n,r=l){const{start:o,end:i}=O(e,n);return r(e,o,i,t)}function q(e,t,n){const{start:l,end:r}=O(e,n),o=l+t.length;return{text:e.slice(0,l)+t+e.slice(r),selectionStart:o,selectionEnd:o}}var H=1e3;function J(e=200){let t=[],n=[],l=null,r=0;return{record(o,i,a){const s="type"===i&&"type"===l&&a-r<1e3;l=i,r=a,n=[],s||(t.push(o),t.length>e&&t.shift())},undo(e){const r=t.pop();return r?(n.push(e),l=null,r):null},redo(e){const r=n.pop();return r?(t.push(e),l=null,r):null},reset(){t=[],n=[],l=null}}}function X({href:t,editing:n,onApply:l,onRemove:r,onClose:o}){const i=m("copy",e).link,a=K(),[s,c]=L(t),[u,d]=L(!1),p=j(null);P(()=>{p.current?.focus(),p.current?.select()},[]);const h=()=>{const e=s.trim();f(e)?l(e):d(!0)};/* @__PURE__ */
|
|
2
2
|
return z("div",{role:"dialog","aria-label":i.title,className:"es-copy-link",onKeyDown:e=>{"Enter"===e.key?(e.preventDefault(),h()):"Escape"===e.key&&(e.preventDefault(),e.stopPropagation(),o())},children:[
|
|
3
3
|
/* @__PURE__ */T("label",{htmlFor:a,className:"es-copy-link-label",children:i.label}),
|
|
4
4
|
/* @__PURE__ */T("input",{ref:p,id:a,type:"text",className:"es-copy-link-input",value:s,placeholder:i.placeholder,spellCheck:!1,autoComplete:"off","aria-invalid":u||void 0,"aria-describedby":u?`${a}-why`:void 0,onChange:e=>{c(e.target.value),d(!1)}}),u?/* @__PURE__ */T("p",{id:`${a}-why`,role:"alert",className:"es-copy-link-why",children:i.refused}):null,
|
|
5
5
|
/* @__PURE__ */z("div",{className:"es-copy-link-actions",children:[n?/* @__PURE__ */T("button",{type:"button",className:"es-copy-link-btn",onClick:r,children:i.remove}):null,
|
|
6
|
-
/* @__PURE__ */T("button",{type:"button",className:"es-copy-link-btn is-primary",onClick:h,disabled:""===s.trim(),children:i.apply})]})]})}var
|
|
7
|
-
return T("button",{type:"button",onMouseDown:e=>e.preventDefault(),onClick:()=>n(e.style),disabled:l,title:e.title,"aria-label":e.name??e.title,"aria-keyshortcuts":_(e.shortcut),"aria-pressed":s||u?r:void 0,"aria-haspopup":"link"===e.style&&s?"dialog":void 0,"aria-expanded":"link"===e.style&&s?"link"===u:void 0,className:`es-copy-mark${t?" has-glyph":ee[e.style]?` ${ee[e.style]}`:""}${r?" is-active":""}`,children:t??e.label},e.style)}),r?/* @__PURE__ */z(
|
|
8
|
-
/* @__PURE__ */T("span",{className:"es-copy-bar-split","aria-hidden":"true"}),r]}):null,o?/* @__PURE__ */T("span",{className:"es-copy-bar-end",children:o}):null]}):null}function ne({target:e,onChange:t}){const n=j(null);return E(()=>{const t=n.current,l=e.current;t&&l&&l.value===t.text&&(n.current=null,l.focus(),l.setSelectionRange(t.start,t.end))}),l=>{const r=l(e.current);t(r.text),n.current={start:r.selectionStart,end:r.selectionEnd,text:r.text}}}function le({value:o,onChange:i,onCommit:a,onCancel:s,multiline:f=!1,placeholder:y,ariaLabel:b,className:g,readOnly:k=!1,rules:v,tools:x=[],writeMark:
|
|
9
|
-
return z("div",{className:"es-copy"+(g?` ${g}`:""),onFocus:()=>
|
|
10
|
-
/* @__PURE__ */T(n,{value:o,onInput:e=>{
|
|
6
|
+
/* @__PURE__ */T("button",{type:"button",className:"es-copy-link-btn is-primary",onClick:h,disabled:""===s.trim(),children:i.apply})]})]})}var G=/* @__PURE__ */new Set(["script","style","head","title","meta","link","template","noscript","svg","math","object","iframe"]),Q=/* @__PURE__ */new Set(["p","div","li","ul","ol","dl","dt","dd","h1","h2","h3","h4","h5","h6","blockquote","pre","table","thead","tbody","tfoot","tr","section","article","header","footer","aside","nav","figure","figcaption","address","hr"]);function U(e,t){const n=t.rules??r,l=e.html&&""!==e.html.trim()?function(e,t,n){const l=t.createElement("template");l.innerHTML=e;const r=[[]],s=()=>r[r.length-1],c=()=>{const e=s();for(;e.length>0&&" "===e[e.length-1].ch;)e.pop();e.length>0&&r.push([])},u=(e,t,n,l)=>{if(3===e.nodeType){for(const r of e.textContent??""){const e=/\s/.test(r)?" ":r,o=s();(" "!==e||0!==o.length&&" "!==o[o.length-1].ch)&&o.push({ch:e,bold:t,italic:n,href:l})}return}if(1!==e.nodeType&&11!==e.nodeType)return;const o=e,i=1===e.nodeType?o.localName:"";if(G.has(i))return;if("br"===i)return void r.push([]);let a=t,d=n,p=l;if("b"!==i&&"strong"!==i||(a=!0),"i"!==i&&"em"!==i||(d=!0),"a"===i){const e=(o.getAttribute("href")??"").trim();p=f(e)?e:null}const h=1===e.nodeType?o.style:null;if(h){const e=h.fontWeight;"bold"===e||"bolder"===e||Number(e)>=600?a=!0:("normal"===e||"lighter"===e||""!==e&&Number(e)<600)&&(a=!1),"italic"===h.fontStyle||"oblique"===h.fontStyle?d=!0:"normal"===h.fontStyle&&(d=!1)}const m=Q.has(i);m&&c();for(const t of[...e.childNodes])u(t,a,d,p);m&&c()};u(l.content,!1,!1,null);for(;r.length>1&&0===r[r.length-1].length;)r.pop();return r.map(e=>function(e,t){const n=t=>e.map((n,l)=>n[t]&&(" "!==n.ch||Boolean(e[l-1]?.[t])&&Boolean(e[l+1]?.[t]))),l=[{bold:!0,italic:!0,links:!0},{bold:!0,italic:!1,links:!0},{bold:!1,italic:!1,links:!0},{bold:!1,italic:!1,links:!1}];for(const r of l){const l=W(e,r.bold?n("bold"):null,r.italic?n("italic"):null,r.links),s=o([l]).text;if(i([l],a(s,t)))return s}return e.map(e=>e.ch).join("")}(e,n))}(e.html,t.doc,n):(e.text??"").replace(/\r\n?/g,"\n").split("\n");return t.multiline?l.join("\n"):l.map(e=>e.trim()).filter(e=>""!==e).join(" ")}function W(e,t,n,l){let r=0,o=null,i=null,a=null;return{bullet:!1,chars:e.map((e,c)=>{const u=l?e.href:null;return o=null===u?null:o&&o.href===u?o:s(++r,"link",u),i=t?.[c]?i??s(++r,"bold"):null,a=n?.[c]?a??s(++r,"italic"):null,{ch:e.ch,at:-1,marks:[o,i,a].filter(e=>null!==e)}})}}var V={bold:/* @__PURE__ */T(S,{size:16}),italic:/* @__PURE__ */T(N,{size:16}),strike:/* @__PURE__ */T(D,{size:16}),highlight:/* @__PURE__ */T(C,{size:16}),quiet:/* @__PURE__ */T(w,{size:16}),link:/* @__PURE__ */T(x,{size:16}),clear:/* @__PURE__ */T(v,{size:16})};function _(e){if(!e)return;const t=e.split("+"),n=t.pop().toUpperCase();return["Meta",...t.map(e=>e[0].toUpperCase()+e.slice(1)),n].join("+")}var ee={bold:"is-bold",italic:"is-italic",strike:"is-strike"};function te({tools:t,onApply:n,disabled:l=!1,actions:r,align:o,glyphs:i,ariaLabel:a,pressed:s,open:u=null}){const d=m("copy",e),p="string"==typeof t[0]?c(t).map(e=>({...e,...d.marks[e.style]})):t;return 0!==p.length||r||o?/* @__PURE__ */z("div",{className:"es-copy-bar",role:"group","aria-label":a??d.formatting,children:[p.map(e=>{const t=i?.[e.style]??V[e.style],r=u===e.style||Boolean(s?.[e.style]);/* @__PURE__ */
|
|
7
|
+
return T("button",{type:"button",onMouseDown:e=>e.preventDefault(),onClick:()=>n(e.style),disabled:l,title:e.title,"aria-label":e.name??e.title,"aria-keyshortcuts":_(e.shortcut),"aria-pressed":s||u?r:void 0,"aria-haspopup":"link"===e.style&&s?"dialog":void 0,"aria-expanded":"link"===e.style&&s?"link"===u:void 0,className:`es-copy-mark${t?" has-glyph":ee[e.style]?` ${ee[e.style]}`:""}${r?" is-active":""}`,children:t??e.label},e.style)}),r?/* @__PURE__ */z($,{children:[
|
|
8
|
+
/* @__PURE__ */T("span",{className:"es-copy-bar-split","aria-hidden":"true"}),r]}):null,o?/* @__PURE__ */T("span",{className:"es-copy-bar-end",children:o}):null]}):null}function ne({target:e,onChange:t}){const n=j(null);return E(()=>{const t=n.current,l=e.current;t&&l&&l.value===t.text&&(n.current=null,l.focus(),l.setSelectionRange(t.start,t.end))}),l=>{const r=l(e.current);t(r.text),n.current={start:r.selectionStart,end:r.selectionEnd,text:r.text}}}function le({value:o,onChange:i,onCommit:a,onCancel:s,multiline:f=!1,placeholder:y,ariaLabel:b,className:g,readOnly:k=!1,rules:v,tools:x=[],writeMark:w,actions:C,align:D,glyphs:N,barLabel:S,renderFooter:E,inputRef:K,barShows:$="always"}){const A=m("copy",e),B=j(null),M=K??B,[R,Y]=L(!1),[O,H]=L(null),G=j(J()).current,Q=j(null);P(()=>{const e=Q.current;e&&o===e.to?Q.current=null:e&&o===e.from||(Q.current=null,G.reset())},[o,G]);const W=e=>{Q.current={from:Q.current?.from??o,to:e},i(e)},V=e=>({text:o,start:e?.selectionStart??O?.start??o.length,end:e?.selectionEnd??O?.end??o.length}),_=ne({target:M,onChange:W}),ee=e=>(H({start:e.selectionStart,end:e.selectionEnd}),e),le=e=>_(t=>(G.record(V(t),"edit",Date.now()),ee(e(t)))),[re,oe]=L(null),ie=v??r,ae="string"==typeof x[0]?c(x):x,se=ae.map(e=>e.style),ce={};if(O)for(const e of se)ce[e]="link"===e?null!==u(o,O.start,O.end):d(o,O.start,O.end,e);const ue=e=>{if("clear"===e)return void le(t=>Z(o,e,t,(e,t,n)=>l(e,t,n,"clear",ie)));if("link"!==e){const t=w??((e,t,n,o)=>l(e,t,n,o,r,A.placeholders));return void le(n=>Z(o,e,n,t))}const t=M.current,n=t?.selectionStart??o.length,i=t?.selectionEnd??n;oe({start:n,end:i,link:u(o,n,i)})},de=D?I(D.allow,A.align):[];/* @__PURE__ */
|
|
9
|
+
return z("div",{className:"es-copy"+(g?` ${g}`:""),onFocus:()=>Y(!0),onBlur:e=>{e.currentTarget.contains(e.relatedTarget)||Y(!1)},onKeyDown:e=>{if(k||e.target!==M.current)return;if(e.altKey||e.metaKey===e.ctrlKey)return;const t=e.key.toLowerCase(),n="KeyZ"===e.code||"z"===t,l=("KeyY"===e.code||"y"===t)&&!e.shiftKey;if(n||l)return e.preventDefault(),e.stopPropagation(),r=l||e.shiftKey?"redo":"undo",void _(e=>{const t=V(e),n=G[r](t);return ee(n?{text:n.text,selectionStart:n.start,selectionEnd:n.end}:{text:t.text,selectionStart:t.start,selectionEnd:t.end})});var r;const o=`${e.shiftKey?"shift+":""}${t}`,i=ae.find(e=>e.shortcut===o);i&&(e.preventDefault(),e.stopPropagation(),ue(i.style))},onPaste:e=>{const t=M.current;if(k||!t||e.target!==t)return;e.preventDefault();const n=U({html:e.clipboardData.getData("text/html"),text:e.clipboardData.getData("text/plain")},{doc:t.ownerDocument,multiline:f,rules:ie});le(e=>q(o,n,e))},onSelect:()=>{const e=M.current;e&&e.ownerDocument.activeElement===e&&H({start:e.selectionStart??o.length,end:e.selectionEnd??o.length})},children:["always"===$||R||null!==re?/* @__PURE__ */T(te,{tools:x,disabled:k,actions:C,glyphs:N,ariaLabel:S,pressed:ce,open:re?"link":null,onApply:ue,align:D?/* @__PURE__ */T(t,{options:de,value:D.value,onChange:D.onChange,ariaLabel:A.alignment,disabled:k||D.disabled,fit:F(de)}):null}):null,
|
|
10
|
+
/* @__PURE__ */T(n,{value:o,onInput:e=>{G.record(V(null),"type",Date.now()),W(e)},onCommit:a,onCancel:s,multiline:f,placeholder:y,ariaLabel:b,rules:v,disabled:k,inputRef:M,className:"es-copy-box"}),re?/* @__PURE__ */T(X,{href:re.link?.href??"",editing:null!==re.link,onApply:e=>{const t=re;oe(null),le(()=>h(o,t.start,t.end,e))},onRemove:()=>{const e=re.link;oe(null),e&&le(()=>p(o,e))},onClose:()=>{oe(null),M.current?.focus()}}):null,E?E({focused:R,insert:e=>le(t=>q(o,e,t))}):null]})}export{A as COPY_ALIGNS,R as COPY_ALIGN_FIT,M as COPY_ALIGN_GLYPHS,B as COPY_ALIGN_LABELS,le as CopyBox,te as MarkBar,H as TYPING_BURST_MS,_ as ariaShortcut,I as copyAlignOptions,J as createHistory,q as insertSelection,Z as markSelection,U as pasteToMarkup,ne as useCaretEdit};
|
package/dist/gold/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{GoldLayer,GoldTextInput,goldSegments}from"../chunk-
|
|
1
|
+
export{GoldLayer,GoldTextInput,goldSegments}from"../chunk-JYPOOHII.js";import"../chunk-SJQG5ENJ.js";var e={accent:"var(--gold, #c9a461)",quiet:"var(--es-muted, #6b7280)",caret:"var(--es-text, #111827)",placeholder:"var(--es-field-placeholder, #9ca3af)",delimiterOpacity:"0.35",delimiterRestingOpacity:"0.25",boldShadow:"0 0 0.4px currentColor",italicDecoration:"underline dotted",strikeDecoration:"line-through",pad:"0"},t={accent:"--es-gold-accent",quiet:"--es-gold-quiet",caret:"--es-gold-caret",placeholder:"--es-gold-placeholder",delimiterOpacity:"--es-gold-delim-opacity",delimiterRestingOpacity:"--es-gold-delim-resting-opacity",boldShadow:"--es-gold-bold-shadow",italicDecoration:"--es-gold-italic-decoration",strikeDecoration:"--es-gold-strike-decoration",pad:"--es-gold-pad"};export{t as goldCssVars,e as goldTokens};
|
package/dist/markup/index.d.ts
CHANGED
|
@@ -43,7 +43,36 @@
|
|
|
43
43
|
*
|
|
44
44
|
* [words](href) a link — safe addresses only ({@link isSafeLinkHref})
|
|
45
45
|
* - words a bullet line, one level
|
|
46
|
-
*
|
|
46
|
+
* 1. words a numbered line, one level: 1-3 digits, ". ", words
|
|
47
|
+
* **a _b_ a** one run inside another, up to four levels
|
|
48
|
+
*
|
|
49
|
+
* [words]{underline} underline
|
|
50
|
+
* [words]{sup} superscript
|
|
51
|
+
* [words]{sub} subscript
|
|
52
|
+
* [words]{color=name} a theme colour, by NAME ({@link isColorName})
|
|
53
|
+
*
|
|
54
|
+
* THE SPANS AND THE NUMBERED LINE (plan step E1, approved by GG 2026-10-06)
|
|
55
|
+
* are the final text box's marks. One shape for all four, so one reading rule:
|
|
56
|
+
* `[`, words, `]`, then EXACTLY one of those blocks. Anything else after the
|
|
57
|
+
* `]` — `{foo}`, `{color=#ff0000}`, a merge tag's `{{` — is not a span, and the
|
|
58
|
+
* whole thing stays as typed. Two marks on the same words nest
|
|
59
|
+
* (`[[x]{sup}]{color=accent}`); one block never holds two.
|
|
60
|
+
*
|
|
61
|
+
* Why these cannot clash with an old mark: no old rule closes on `]{` (a link
|
|
62
|
+
* needs `](`), and the campaign's legacy `[phrase]` italic steps back from a
|
|
63
|
+
* span block, the way it steps back from a link (`notBeforeBlock`). No inline
|
|
64
|
+
* rule opens on a digit. Production held neither shape when they were chosen:
|
|
65
|
+
* 0 of 24,233 text values contained `]{`, and none had a line starting with a
|
|
66
|
+
* number and `.` or `)`.
|
|
67
|
+
*
|
|
68
|
+
* Not chosen: `^x^` / `~x~` (one character from Quiet `^^` and strike `~~`,
|
|
69
|
+
* and `~20 min` is ordinary copy), `__x__` (pinned as italic below, and
|
|
70
|
+
* CommonMark's bold) and `++x++` (the old Strong).
|
|
71
|
+
*
|
|
72
|
+
* Only the tree ({@link parseMarkup}) reads them. The flat
|
|
73
|
+
* {@link tokenizeInline} — the old renderers' reading — keeps them as text, as
|
|
74
|
+
* it keeps links: an email or a page drawn before its renderer learns them
|
|
75
|
+
* prints the delimiters. No toolbar button writes them yet.
|
|
47
76
|
*
|
|
48
77
|
* EVERY READING IS LINE BY LINE: a run never crosses a line break. The email
|
|
49
78
|
* always read this way; the editor's painter and the storefront used to read
|
|
@@ -87,21 +116,32 @@
|
|
|
87
116
|
*/
|
|
88
117
|
/** A style a toolbar button can apply. The first six are inline marks; then
|
|
89
118
|
* the composer-only affordances (a link and the three line prefixes), which
|
|
90
|
-
* only a renderer that draws block content can honour;
|
|
91
|
-
* writes no mark at all — it takes them off ({@link clearMarks})
|
|
92
|
-
|
|
119
|
+
* only a renderer that draws block content can honour; `clear`, which
|
|
120
|
+
* writes no mark at all — it takes them off ({@link clearMarks}); and the
|
|
121
|
+
* three spans of the final text box (E1), which no button in
|
|
122
|
+
* {@link MARKUP_TOOLS} offers yet. A colour carries a name, so it is written
|
|
123
|
+
* by {@link applyColor}, not here. */
|
|
124
|
+
type MarkStyle = 'bold' | 'italic' | 'strike' | 'code' | 'highlight' | 'quiet' | 'link' | 'bullet' | 'number' | 'quote' | 'clear' | 'underline' | 'sup' | 'sub';
|
|
125
|
+
/** What a span means: `[words]{underline}`, `{sup}`, `{sub}` or
|
|
126
|
+
* `{color=name}`. Only the tree reads these; {@link InlineKind} is the flat
|
|
127
|
+
* reading's, which never makes one. */
|
|
128
|
+
type SpanKind = 'underline' | 'sup' | 'sub' | 'color';
|
|
93
129
|
/** What a parsed run MEANS. `accent` is the storefront/campaign brand colour —
|
|
94
130
|
* the legacy `*phrase*` — and `highlight` is its standard-markdown successor;
|
|
95
131
|
* both resolve to the same paint, which is what makes converting stored copy
|
|
96
132
|
* from one to the other invisible. */
|
|
97
133
|
type InlineKind = 'text' | 'bold' | 'italic' | 'strike' | 'code' | 'highlight' | 'accent' | 'quiet';
|
|
134
|
+
/** A theme colour's name as a span saves it: lowercase letters, digits and
|
|
135
|
+
* `-`, starting with a letter (`accent`, `brand-2`). Never a hex: a colour is
|
|
136
|
+
* the theme's, so changing the theme recolours the words. */
|
|
137
|
+
declare function isColorName(name: string): boolean;
|
|
98
138
|
/**
|
|
99
139
|
* The words a press WRITES when nothing is selected — `**bold text**`, left
|
|
100
140
|
* selected so the next keystroke replaces it. English unless the caller of
|
|
101
141
|
* {@link applyMark} hands in its own (0.95.0: a host in another language).
|
|
102
142
|
* They are words put in the box, not rules: nothing here changes what parses.
|
|
103
143
|
*/
|
|
104
|
-
type MarkPlaceholders = Record<'bold' | 'italic' | 'strike' | 'code' | 'highlight' | 'quiet' | 'link', string
|
|
144
|
+
type MarkPlaceholders = Record<'bold' | 'italic' | 'strike' | 'code' | 'highlight' | 'quiet' | 'link', string> & Partial<Record<'underline' | 'sup' | 'sub' | 'color', string>>;
|
|
105
145
|
declare const MARK_PLACEHOLDERS: MarkPlaceholders;
|
|
106
146
|
interface WrapResult {
|
|
107
147
|
text: string;
|
|
@@ -119,6 +159,17 @@ interface WrapResult {
|
|
|
119
159
|
* and the campaign designer, where the asterisk means colour, not slant.
|
|
120
160
|
*/
|
|
121
161
|
declare function applyMark(text: string, start: number, end: number, style: MarkStyle, rules?: readonly InlineRule[], placeholders?: MarkPlaceholders): WrapResult;
|
|
162
|
+
/**
|
|
163
|
+
* Colour `text[start:end]` with the theme colour `name`, writing
|
|
164
|
+
* `[words]{color=name}` and leaving the words selected. On words that are
|
|
165
|
+
* already exactly one colour span it changes the name; `null` takes the colour
|
|
166
|
+
* off. A name {@link isColorName} refuses changes nothing — a hex or a typo is
|
|
167
|
+
* never saved as a block the reader would print as text.
|
|
168
|
+
*
|
|
169
|
+
* Separate from {@link applyMark} because a colour carries a value, as a link
|
|
170
|
+
* does ({@link writeLink}).
|
|
171
|
+
*/
|
|
172
|
+
declare function applyColor(text: string, start: number, end: number, name: string | null, placeholders?: MarkPlaceholders): WrapResult;
|
|
122
173
|
/**
|
|
123
174
|
* True when `text[start:end]` is ALREADY wrapped in `style`'s own fence — the
|
|
124
175
|
* very test {@link applyMark} uses to decide that a press unwraps. So a button
|
|
@@ -226,6 +277,14 @@ interface InlineRule {
|
|
|
226
277
|
* more rule field and no new branch in {@link tokenizeInline}.
|
|
227
278
|
*/
|
|
228
279
|
readonly notBefore?: string;
|
|
280
|
+
/**
|
|
281
|
+
* True when the run may not close right before a span block (`{sup}`,
|
|
282
|
+
* `{color=accent}`, …). The campaign's legacy `[phrase]` needs it for the
|
|
283
|
+
* reason it needs `notBefore: '('`: without it `[x]{sup}` would read as an
|
|
284
|
+
* italic `x` followed by a printed `{sup}`. Only the four exact blocks count,
|
|
285
|
+
* so `[x]{{first_name}}` and `[x]{foo}` read as they always did.
|
|
286
|
+
*/
|
|
287
|
+
readonly notBeforeBlock?: boolean;
|
|
229
288
|
}
|
|
230
289
|
/**
|
|
231
290
|
* The standard-markdown marks, shared by every product.
|
|
@@ -322,12 +381,14 @@ interface MarkupText {
|
|
|
322
381
|
text: string;
|
|
323
382
|
}
|
|
324
383
|
/** A delimited run. `open` and `close` are the delimiters that were actually
|
|
325
|
-
* saved — `#` for a legacy campaign bold, `**` for the standard one
|
|
326
|
-
* tree writes back the same bytes it was read
|
|
384
|
+
* saved — `#` for a legacy campaign bold, `**` for the standard one, `[` and
|
|
385
|
+
* `]{sup}` for a span — so the tree writes back the same bytes it was read
|
|
386
|
+
* from. `color` is the theme colour's name, on a `color` span only. */
|
|
327
387
|
interface MarkupRun {
|
|
328
|
-
kind: InlineRule['kind'];
|
|
388
|
+
kind: InlineRule['kind'] | SpanKind;
|
|
329
389
|
open: string;
|
|
330
390
|
close: string;
|
|
391
|
+
color?: string;
|
|
331
392
|
children: MarkupNode[];
|
|
332
393
|
}
|
|
333
394
|
/** `[words](href)`. Only made when {@link isSafeLinkHref} passes. */
|
|
@@ -338,9 +399,12 @@ interface MarkupLink {
|
|
|
338
399
|
}
|
|
339
400
|
type MarkupNode = MarkupText | MarkupRun | MarkupLink;
|
|
340
401
|
/** One line of the saved string. `bullet` means it was saved as `- words`;
|
|
341
|
-
* `
|
|
402
|
+
* `number` holds the digits of a line saved as `12. words`, as typed (`01`
|
|
403
|
+
* stays `01`), and is null on every other line. `children` hold what follows
|
|
404
|
+
* the prefix. A line built by hand may leave `number` out: it means null. */
|
|
342
405
|
interface MarkupLine {
|
|
343
406
|
bullet: boolean;
|
|
407
|
+
number?: string | null;
|
|
344
408
|
children: MarkupNode[];
|
|
345
409
|
}
|
|
346
410
|
/**
|
|
@@ -361,10 +425,14 @@ declare function isSafeLinkHref(href: string): boolean;
|
|
|
361
425
|
* - A run never crosses a line break.
|
|
362
426
|
* - A line that starts with `- ` and has words after it is a bullet. One level
|
|
363
427
|
* only: an indented ` - ` is plain text.
|
|
428
|
+
* - A line that starts with 1-3 digits, `. ` and words is numbered, the digits
|
|
429
|
+
* kept as typed. One level only, as bullets.
|
|
364
430
|
* - `[words](href)` is a link when {@link isSafeLinkHref} passes; otherwise the
|
|
365
431
|
* whole thing stays plain text.
|
|
366
|
-
* -
|
|
367
|
-
*
|
|
432
|
+
* - `[words]{underline}`, `{sup}`, `{sub}` and `{color=name}` are spans; any
|
|
433
|
+
* other block stays plain text.
|
|
434
|
+
* - A run's words are read again, so `**bold _with italic_**` is italic inside
|
|
435
|
+
* bold. Four levels: a fifth stays as typed.
|
|
368
436
|
*
|
|
369
437
|
* Nothing is lost: {@link serializeMarkup} writes back the exact bytes.
|
|
370
438
|
*/
|
|
@@ -378,22 +446,25 @@ declare function serializeMarkup(lines: readonly MarkupLine[]): string;
|
|
|
378
446
|
*
|
|
379
447
|
* `open` and `close` are the delimiters that were saved (`#` for a legacy
|
|
380
448
|
* campaign bold), or, for a run made in the editor, the toolbar's own fence.
|
|
381
|
-
* A link's `close` is `](href)`.
|
|
449
|
+
* A link's `close` is `](href)`, a span's `]{sup}` or `]{color=name}`.
|
|
382
450
|
*/
|
|
383
451
|
interface MarkSpan {
|
|
384
452
|
id: number;
|
|
385
|
-
kind: InlineRule['kind'] | 'link';
|
|
453
|
+
kind: InlineRule['kind'] | SpanKind | 'link';
|
|
386
454
|
open: string;
|
|
387
455
|
close: string;
|
|
388
456
|
href?: string;
|
|
457
|
+
color?: string;
|
|
389
458
|
}
|
|
390
459
|
/**
|
|
391
460
|
* A NEW run, as the toolbar writes it: `**` for bold, `_` for italic, and so on
|
|
392
|
-
* ({@link applyMark}'s own fences),
|
|
393
|
-
*
|
|
394
|
-
*
|
|
461
|
+
* ({@link applyMark}'s own fences), a link to `value`, or a colour span named
|
|
462
|
+
* `value` ({@link isColorName}). Null for a style that writes no run (a line
|
|
463
|
+
* prefix, clear) and for a link or colour with no usable value. A paste filter
|
|
464
|
+
* or an editor making a run asks here, so no delimiter is spelled outside this
|
|
465
|
+
* module (E8).
|
|
395
466
|
*/
|
|
396
|
-
declare function spanFor(id: number, style: MarkStyle,
|
|
467
|
+
declare function spanFor(id: number, style: MarkStyle | 'color', value?: string): MarkSpan | null;
|
|
397
468
|
/** One character of the words — never a delimiter — with the runs it sits in,
|
|
398
469
|
* outside first, and its offset in the saved string. */
|
|
399
470
|
interface MarkedChar {
|
|
@@ -401,9 +472,12 @@ interface MarkedChar {
|
|
|
401
472
|
marks: readonly MarkSpan[];
|
|
402
473
|
at: number;
|
|
403
474
|
}
|
|
404
|
-
/** One line: its bullet flag (the `- `
|
|
475
|
+
/** One line: its bullet flag or its number (the `- ` and the `12. ` are not
|
|
476
|
+
* characters) and its words. `number` left out means null, as on
|
|
477
|
+
* {@link MarkupLine}. */
|
|
405
478
|
interface MarkedLine {
|
|
406
479
|
bullet: boolean;
|
|
480
|
+
number?: string | null;
|
|
407
481
|
chars: MarkedChar[];
|
|
408
482
|
}
|
|
409
483
|
/**
|
|
@@ -433,12 +507,14 @@ declare function writeMarkedLines(lines: readonly MarkedLine[]): {
|
|
|
433
507
|
at: number[][];
|
|
434
508
|
};
|
|
435
509
|
/** True when two readings hold the same words wearing the same marks — the
|
|
436
|
-
* kinds and
|
|
510
|
+
* kinds, addresses, colours and list numbers, not which run or which
|
|
511
|
+
* delimiter. */
|
|
437
512
|
declare function sameMarks(a: readonly MarkedLine[], b: readonly MarkedLine[]): boolean;
|
|
438
513
|
/**
|
|
439
514
|
* Take every mark off `text[start:end]`, keeping the words and any link (a
|
|
440
515
|
* link has its own Remove). A run the selection only partly covers is split,
|
|
441
|
-
* so the rest of it keeps its mark. Bullets stay: they are lines,
|
|
516
|
+
* so the rest of it keeps its mark. Bullets and numbers stay: they are lines,
|
|
517
|
+
* not marks.
|
|
442
518
|
*
|
|
443
519
|
* With nothing selected, the runs the caret touches — the characters either
|
|
444
520
|
* side of it — come off whole.
|
|
@@ -449,4 +525,4 @@ declare function sameMarks(a: readonly MarkedLine[], b: readonly MarkedLine[]):
|
|
|
449
525
|
*/
|
|
450
526
|
declare function clearMarks(text: string, start: number, end: number, rules?: readonly InlineRule[]): WrapResult;
|
|
451
527
|
|
|
452
|
-
export { CAMPAIGN_MARKUP, COPY_FIELD_TOOLS, type InlineKind, type InlineRule, type InlineToken, type LinkSpan, MARKUP_TOOLS, MARK_NAMES, MARK_PLACEHOLDERS, type MarkPlaceholders, type MarkSpan, type MarkStyle, type MarkedChar, type MarkedLine, type MarkupLine, type MarkupLink, type MarkupNode, type MarkupRun, type MarkupText, type MarkupTool, STANDARD_MARKUP, STOREFRONT_MARKUP, type WrapResult, applyMark, clearMarks, findLink, isSafeLinkHref, markedAt, markedLines, markupTools, parseMarkup, removeLink, sameMarks, serializeMarkup, spanFor, stripInline, tokenizeInline, writeLink, writeMarkedLines };
|
|
528
|
+
export { CAMPAIGN_MARKUP, COPY_FIELD_TOOLS, type InlineKind, type InlineRule, type InlineToken, type LinkSpan, MARKUP_TOOLS, MARK_NAMES, MARK_PLACEHOLDERS, type MarkPlaceholders, type MarkSpan, type MarkStyle, type MarkedChar, type MarkedLine, type MarkupLine, type MarkupLink, type MarkupNode, type MarkupRun, type MarkupText, type MarkupTool, STANDARD_MARKUP, STOREFRONT_MARKUP, type SpanKind, type WrapResult, applyColor, applyMark, clearMarks, findLink, isColorName, isSafeLinkHref, markedAt, markedLines, markupTools, parseMarkup, removeLink, sameMarks, serializeMarkup, spanFor, stripInline, tokenizeInline, writeLink, writeMarkedLines };
|
package/dist/markup/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{CAMPAIGN_MARKUP,COPY_FIELD_TOOLS,MARKUP_TOOLS,MARK_NAMES,MARK_PLACEHOLDERS,STANDARD_MARKUP,STOREFRONT_MARKUP,applyMark,clearMarks,findLink,isSafeLinkHref,markedAt,markedLines,markupTools,parseMarkup,removeLink,sameMarks,serializeMarkup,spanFor,stripInline,tokenizeInline,writeLink,writeMarkedLines}from"../chunk-
|
|
1
|
+
export{CAMPAIGN_MARKUP,COPY_FIELD_TOOLS,MARKUP_TOOLS,MARK_NAMES,MARK_PLACEHOLDERS,STANDARD_MARKUP,STOREFRONT_MARKUP,applyColor,applyMark,clearMarks,findLink,isColorName,isSafeLinkHref,markedAt,markedLines,markupTools,parseMarkup,removeLink,sameMarks,serializeMarkup,spanFor,stripInline,tokenizeInline,writeLink,writeMarkedLines}from"../chunk-SJQG5ENJ.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{DEFAULT_EDITOR_STRINGS,mergeEditorStrings}from"../chunk-
|
|
1
|
+
export{DEFAULT_EDITOR_STRINGS,mergeEditorStrings}from"../chunk-JE63JHKO.js";import"../chunk-ZAOM6PFH.js";import"../chunk-6WY6ZXJG.js";import"../chunk-GGTPNGFJ.js";import"../chunk-SUO5627P.js";import"../chunk-H4B72XCJ.js";import"../chunk-7A7O2JWQ.js";import"../chunk-WK3AFPXY.js";import"../chunk-H6DDIBQ4.js";import"../chunk-KDIVA6WD.js";import"../chunk-RE4LP46F.js";import"../chunk-2OAZYSWJ.js";import"../chunk-ZT7M24XD.js";import"../chunk-SJQG5ENJ.js";import"../chunk-O2NLQBFX.js";
|
package/dist/strings/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{DEFAULT_EDITOR_STRINGS as r,mergeEditorStrings as n}from"../chunk-
|
|
1
|
+
import{DEFAULT_EDITOR_STRINGS as r,mergeEditorStrings as n}from"../chunk-JE63JHKO.js";export{DEFAULT_EDITOR_STRINGS,mergeEditorStrings}from"../chunk-JE63JHKO.js";import"../chunk-ZAOM6PFH.js";import"../chunk-6WY6ZXJG.js";import"../chunk-GGTPNGFJ.js";import"../chunk-SUO5627P.js";import"../chunk-H4B72XCJ.js";import"../chunk-7A7O2JWQ.js";import"../chunk-WK3AFPXY.js";import"../chunk-H6DDIBQ4.js";import"../chunk-KDIVA6WD.js";import"../chunk-RE4LP46F.js";import"../chunk-2OAZYSWJ.js";import"../chunk-ZT7M24XD.js";import"../chunk-SJQG5ENJ.js";import{stringsContext as o}from"../chunk-MFIRYGHW.js";import"../chunk-O2NLQBFX.js";import{useContext as t,useMemo as i}from"react";import{jsx as c}from"react/jsx-runtime";function s({value:s,locale:u,children:m}){const e=o(),p=t(e),h=p?.strings??r,j=u??p?.locale??"en",k=i(()=>({strings:n(h,s),locale:j}),[h,s,j]);/* @__PURE__ */
|
|
2
2
|
return c(e.Provider,{value:k,children:m})}function u(){return t(o())?.strings??r}function m(){return t(o())?.locale??"en"}export{s as EditorStringsProvider,m as useEditorLocale,u as useEditorStrings};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "efficient-easel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.99.0",
|
|
4
4
|
"description": "Efficient Easel: the EFFICIENT editors' shared engine and chrome: the saved document as pure functions, the published renderer, and the editor frame, panels, Layers tree, text grammar and type-in-place box. Published as editor-shell up to 0.66.0 and as efficient-editor up to 0.95.0.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "Efficient Pty Ltd",
|
package/dist/chunk-6OPSJGAI.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var e={bold:{fence:"**",placeholder:"bold text"},italic:{fence:"_",placeholder:"italic text"},strike:{fence:"~~",placeholder:"struck out"},code:{fence:"`",placeholder:"code"},highlight:{fence:"==",placeholder:"highlighted text"},quiet:{fence:"^^",placeholder:"quiet text"}},t={bold:e.bold.placeholder,italic:e.italic.placeholder,strike:e.strike.placeholder,code:e.code.placeholder,highlight:e.highlight.placeholder,quiet:e.quiet.placeholder,link:"link text"},n={bullet:()=>"- ",number:e=>`${e+1}. `,quote:()=>"> "};function l(l,i,r,s,o=u,c=t){if("clear"===s)return Q(l,i,r,o);const a=l.slice(i,r);if("link"===s){const e=a||c.link,t=`[${e}](https://)`;return{text:l.slice(0,i)+t+l.slice(r),selectionStart:i+e.length+3,selectionEnd:i+t.length-1}}const h=n[s];if(h){const e=l.lastIndexOf("\n",Math.max(i-1,0))+1,t=l.indexOf("\n",r),n=-1===t?l.length:t,s=l.slice(e,n).split("\n"),o=s.every((e,t)=>e.startsWith(h(t))),c=s.map((e,t)=>o?e.slice(h(t).length):h(t)+e).join("\n");return{text:l.slice(0,e)+c+l.slice(n),selectionStart:e,selectionEnd:e+c.length}}const{fence:d}=e[s],f=c[s],k=l.slice(Math.max(0,i-d.length),i),p=l.slice(r,r+d.length);if(k===d&&p===d)return{text:l.slice(0,i-d.length)+a+l.slice(r+d.length),selectionStart:i-d.length,selectionEnd:i-d.length+a.length};const g=a||f;return{text:l.slice(0,i)+d+g+d+l.slice(r),selectionStart:i+d.length,selectionEnd:i+d.length+g.length}}function i(t,n,l,i){const r=e[i];if(!r)return!1;const{fence:s}=r;return n>=s.length&&t.slice(n-s.length,n)===s&&t.slice(l,l+s.length)===s}function r(e,t,n){const l=0===t?0:e.lastIndexOf("\n",t-1)+1;for(let i=e.lastIndexOf("[",t);i>=l;i=0===i?-1:e.lastIndexOf("[",i-1)){const t=S(e,i);if(t&&n<=t.end)return{start:i,end:t.end,label:t.label,href:t.href}}return null}function s(e,t,n,l){const i=r(e,t,n),s=i?i.start:t,o=i?i.end:n,c=`[${i?i.label:e.slice(t,n)||l}](${l})`,a=s+c.length;return{text:e.slice(0,s)+c+e.slice(o),selectionStart:a,selectionEnd:a}}function o(e,t){return{text:e.slice(0,t.start)+t.label+e.slice(t.end),selectionStart:t.start,selectionEnd:t.start+t.label.length}}var c=[{style:"bold",label:"B",name:"Strong",title:"Strong · **words** · ⌘B",shortcut:"b"},{style:"italic",label:"I",name:"Italic",title:"Italic · _words_ · ⌘I",shortcut:"i"},{style:"strike",label:"S",name:"Strikethrough",title:"Strikethrough · ~~words~~"},{style:"highlight",label:"◆",name:"Emphasis",title:"Emphasis · ==words=="},{style:"quiet",label:"a",name:"Quiet",title:"Quiet · ^^words^^"},{style:"code",label:"‹›",name:"Code",title:"Code"},{style:"link",label:"🔗",name:"Link",title:"Link · [words](https://…) · ⌘K",shortcut:"k"},{style:"bullet",label:"•",name:"Bulleted list",title:"Bulleted list"},{style:"number",label:"1.",name:"Numbered list",title:"Numbered list"},{style:"quote",label:"❝",name:"Quote",title:"Quote"},{style:"clear",label:"T×",name:"Clear marks",title:"Clear marks · ⌘⇧X",shortcut:"shift+x"}],a={bold:"Strong",highlight:"Emphasis",quiet:"Quiet"};function h(e){return c.filter(t=>e.includes(t.style))}var u=[{open:"**",close:"**",kind:"bold"},{open:"==",close:"==",kind:"highlight"},{open:"~~",close:"~~",kind:"strike"},{open:"_",close:"_",kind:"italic",wordBoundary:!0},{open:"^^",close:"^^",kind:"quiet"},{open:"@@",close:"@@",kind:"highlight"},{open:"++",close:"++",kind:"bold"}],d=c.map(e=>e.style).filter(e=>u.some(t=>t.kind===e)),f=[...u,{open:"*",close:"*",kind:"accent"}],k=[...u,{open:"*",close:"*",kind:"accent"},{open:"#",close:"#",kind:"bold",notBefore:"0123456789"},{open:"[",close:"]",kind:"italic",notBefore:"("}];function p(e){return!/\s/.test(e)&&!/[!-\/:-@[-`{-~]/.test(e)}function g(e,t){const n=[];let l="",i=0;for(;i<e.length;){const r=m(e,i,t);r?(n.push({kind:"text",text:l}),l="",n.push({kind:r.rule.kind,text:r.inner}),i=r.end):(l+=e[i],i+=1)}return n.push({kind:"text",text:l}),n}function m(e,t,n){for(const l of n){if(!e.startsWith(l.open,t))continue;if(l.wordBoundary&&t>0&&p(e[t-1]))continue;const n=t+l.open.length,i=e.indexOf(l.close,n);if(i<n+1)continue;const r=e.slice(n,i);if(r.includes(l.close[0]))continue;if(r.includes("\n"))continue;const s=i+l.close.length,o=e[s];if((!l.notBefore||void 0===o||!l.notBefore.includes(o))&&(!l.wordBoundary||void 0===o||!p(o)))return{rule:l,inner:r,end:s}}return null}function x(e,t){return g(e,t).map(e=>e.text).join("")}var b=["http","https","mailto","tel"];function y(e){if(""===e||/[\s\u0000-\u001f\u007f]/.test(e))return!1;const t=/^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(e);return!t||b.includes(t[1].toLowerCase())}function S(e,t){if("["!==e[t])return null;const n=e.indexOf("]",t+1);if(n<t+2||"("!==e[n+1])return null;const l=e.slice(t+1,n);if(l.includes("["))return null;const i=e.indexOf(")",n+2);if(-1===i)return null;const r=e.slice(n+2,i);return y(r)?{label:l,href:r,end:i+1}:null}var v=2;function w(e,t,n){const l=[];let i="";const r=()=>{i&&l.push({kind:"text",text:i}),i=""},s=e=>n+1<v?w(e,t,n+1):[{kind:"text",text:e}];let o=0;for(;o<e.length;){const n=S(e,o);if(n){r(),l.push({kind:"link",href:n.href,children:s(n.label)}),o=n.end;continue}const c=m(e,o,t);c?(r(),l.push({kind:c.rule.kind,open:c.rule.open,close:c.rule.close,children:s(c.inner)}),o=c.end):(i+=e[o],o+=1)}return r(),l}function E(e,t){return e.split("\n").map(e=>{const n=e.startsWith("- ")&&""!==e.slice(2).trim();return{bullet:n,children:w(n?e.slice(2):e,t,0)}})}function B(e){return e.map(e=>"text"===e.kind?e.text:"link"===e.kind?`[${B(e.children)}](${e.href})`:e.open+B(e.children)+e.close).join("")}function q(e){return e.map(e=>(e.bullet?"- ":"")+B(e.children)).join("\n")}function O(t,n,l){if("link"===n)return void 0===l?null:{id:t,kind:"link",open:"[",close:`](${l})`,href:l};const i=e[n];return i&&"code"!==n?{id:t,kind:n,open:i.fence,close:i.fence}:null}function I(e,t){let n=0,l=0;return e.split("\n").map(e=>{const[i]=E(e,t);let r=l+(i.bullet?2:0);l+=e.length+1;const s=[],o=(e,t)=>{for(const l of e){if("text"===l.kind){for(const e of l.text)s.push({ch:e,marks:t,at:r}),r+=e.length;continue}const e="link"===l.kind?O(++n,"link",l.href):{id:++n,kind:l.kind,open:l.open,close:l.close};r+=e.open.length,o(l.children,[...t,e]),r+=e.close.length}};return o(i.children,[]),{bullet:i.bullet,chars:s}})}function $(e){let t="";const n=[];return e.forEach((e,l)=>{l>0&&(t+="\n"),e.bullet&&(t+="- ");const i=[],r=[];for(const n of e.chars){let e=0;for(;e<i.length&&e<n.marks.length&&i[e].id===n.marks[e].id;)e+=1;for(;i.length>e;)t+=i.pop().close;for(let l=e;l<n.marks.length;l+=1)t+=n.marks[l].open,i.push(n.marks[l]);r.push(t.length),t+=n.ch}for(;i.length>0;)t+=i.pop().close;n.push(r)}),{text:t,at:n}}function C(e,t){return e.length===t.length&&e.every((e,n)=>{const l=t[n];return e.bullet===l.bullet&&e.chars.length===l.chars.length&&e.chars.every((e,t)=>{const n=l.chars[t];return e.ch===n.ch&&e.marks.length===n.marks.length&&e.marks.every((e,t)=>e.kind===n.marks[t].kind&&e.href===n.marks[t].href)})})}function Q(e,t,n,l=u){const i=I(e,l),r=i.flatMap(e=>e.chars),s={text:e,selectionStart:t,selectionEnd:n},o=e=>i.map(t=>({bullet:t.bullet,chars:t.chars.map(t=>({...t,marks:t.marks.filter(n=>"link"===n.kind||!e(t,n))}))})),c=e=>{const t=$(e);return C(e,I(t.text,l))?t:null},a=(e,t)=>{let n=r.indexOf(t);for(let t=0;t<e.at.length;t+=1){if(n<e.at[t].length)return e.at[t][n];n-=e.at[t].length}return 0};if(t===n){const e=[...r].reverse().find(e=>e.at<t),n=r.find(e=>e.at>=t),l=new Set([...e?.marks??[],...n?.marks??[]].map(e=>e.id));if(![...l].some(e=>r.some(t=>t.marks.some(t=>t.id===e&&"link"!==t.kind))))return s;const i=c(o((e,t)=>l.has(t.id)));if(!i)return s;const h=n?a(i,n):e?a(i,e)+e.ch.length:0;return{text:i.text,selectionStart:h,selectionEnd:h}}const h=new Set(r.filter(e=>e.at>=t&&e.at<n));if(0===h.size)return s;const d=new Set([...h].flatMap(e=>e.marks.map(e=>e.id))),f=c(o(e=>h.has(e)))??c(o((e,t)=>d.has(t.id)));if(!f)return s;const k=r.find(e=>h.has(e)),p=[...r].reverse().find(e=>h.has(e));return{text:f.text,selectionStart:a(f,k),selectionEnd:a(f,p)+p.ch.length}}export{k as CAMPAIGN_MARKUP,d as COPY_FIELD_TOOLS,c as MARKUP_TOOLS,a as MARK_NAMES,t as MARK_PLACEHOLDERS,u as STANDARD_MARKUP,f as STOREFRONT_MARKUP,l as applyMark,Q as clearMarks,r as findLink,y as isSafeLinkHref,i as markedAt,I as markedLines,h as markupTools,E as parseMarkup,o as removeLink,C as sameMarks,q as serializeMarkup,O as spanFor,x as stripInline,g as tokenizeInline,s as writeLink,$ as writeMarkedLines};
|