@mathzetta/inlinemath 0.1.0 → 0.2.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 +64 -20
- package/dist/cas.external.js +2 -2
- package/dist/cas.js +2 -2
- package/dist/chunks/calculate-Cz87Lt0N.js +2 -0
- package/dist/chunks/draw-Bev17BJJ.js +2 -0
- package/dist/chunks/edit-C65xXzo8.js +2 -0
- package/dist/chunks/edit-M68aRA5o.js +2 -0
- package/dist/chunks/{html-CvuSyhzk.js → html-BimAqn7x.js} +2 -2
- package/dist/chunks/html-CupluJSh.js +2 -0
- package/dist/chunks/lite-3Fb-OHbt.js +2 -0
- package/dist/inlinemath-cas.external.global.min.js +2 -2
- package/dist/inlinemath-cas.global.min.js +2 -2
- package/dist/inlinemath-lite-calc.global.min.js +2 -2
- package/dist/inlinemath-lite.external.global.min.js +2 -2
- package/dist/inlinemath-lite.global.min.js +2 -2
- package/dist/inlinemath.css +32 -1
- package/dist/inlinemath.external.global.min.js +2 -2
- package/dist/inlinemath.external.js +2 -2
- package/dist/inlinemath.global.min.js +2 -2
- package/dist/inlinemath.js +2 -2
- package/dist/lite-calc.js +2 -2
- package/dist/lite.external.js +2 -2
- package/dist/lite.js +2 -2
- package/dist/markdown.external.js +2 -2
- package/dist/markdown.js +2 -2
- package/inlinemath.css +32 -1
- package/package.json +3 -3
- package/src/cas.js +25 -15
- package/src/edit.js +96 -0
- package/src/glyphs.js +2 -0
- package/src/index.d.ts +2 -2
- package/src/index.js +1 -1
- package/src/layout.js +55 -11
- package/src/markdown.d.ts +2 -2
- package/src/markdown.js +354 -39
- package/src/mathzetta.js +2 -1
- package/src/types.d.ts +77 -6
- package/src/variables.js +228 -0
- package/src/view.js +226 -6
- package/dist/chunks/calculate-BX9lJ7Ff.js +0 -2
- package/dist/chunks/draw-Cm4exbg7.js +0 -2
- package/dist/chunks/html-DWtfytjA.js +0 -2
- package/dist/chunks/lite-Bj_L6w2g.js +0 -2
package/dist/inlinemath.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/* Inline Math 0.
|
|
2
|
-
import{t}from"./chunks/html-
|
|
1
|
+
/* Inline Math 0.2.0 — MIT licence; includes mathzetta (and @mathzetta/cas, for the CAS) */
|
|
2
|
+
import{t}from"./chunks/html-CupluJSh.js";export{a as toHTML}from"./chunks/html-CupluJSh.js";import{l as e,a as s,t as i,s as r,p as n,n as o,b as h,c as l}from"./chunks/lite-3Fb-OHbt.js";export{D as DEFAULTS,P as PATHS,d as numberTree}from"./chunks/lite-3Fb-OHbt.js";import{o as c,r as u}from"./chunks/edit-M68aRA5o.js";import"./chunks/calculate-Cz87Lt0N.js";class f{constructor(t,e,s={}){this.element=t,this.options=s,this.p=s.prefix||"mv",this.handlers=[],this.clicks=[],this.active=null,this.live=p(t,s.announce,this.p),this.set(e)}set(i,{animate:r=!1,duration:n=600,easing:o="ease-in-out"}={}){const h=m(r)&&this.tree?this.snapshot():null,a=void 0!==this.tree;return this.tree=t(i,this.options),this.element.innerHTML=e(this.tree,s(this.tree,this.options)).html,this.root=this.element.firstElementChild,this.handlers.length&&this.root.classList.add(`${this.p}-clickable`),this.editing&&this.root.classList.add(`${this.p}-editable`),this.active=null,(this.clicks.length||this.editing)&&this.focusable(),h&&this.morph(h,{duration:n,easing:o}),a&&this.live&&this.announce(this.spoken()),this}spoken(){const t=this.root&&this.root.getAttribute&&this.root.getAttribute("aria-label");if(t)return t;try{return i(this.tree)}catch{return""}}announce(t){return this.say(this.live,t)}say(t,e){if(!t)return this;t.textContent="";const s=()=>{t.textContent=e};return"function"==typeof requestAnimationFrame?requestAnimationFrame(()=>requestAnimationFrame(s)):setTimeout(s,50),this}nodes(t){return r(this.tree,t)}elements(t){return this.nodes(t).map(t=>this.elementOf(t)).filter(Boolean)}elementOf(t){return void 0===t.id?null:this.root.querySelector(`[data-node="${t.id}"]`)}highlight(t,e=`${this.p}-hl`){return this.elements(t).forEach(t=>t.classList.add(e)),this}unhighlight(t=null,e=`${this.p}-hl`){return(null===t?this.root.querySelectorAll(`.${e}`):this.elements(t)).forEach(t=>t.classList.remove(e)),this}color(t,e){return this.elements(t).forEach(t=>{t.style.color=e||""}),this}on(t,e){const s=t=>{const s=t.target.closest?.("[data-node]");if(!s||!this.root.contains(s))return;const i=Number(s.dataset.node),o=r(this.tree,i)[0];e({node:o,id:i,path:n(this.tree,i),element:s,event:t})};return this.element.addEventListener(t,s),this.handlers.push([t,s]),this.root.classList.add(`${this.p}-clickable`),"click"===t&&(this.clicks.push(e),this.keyboard()),()=>{this.element.removeEventListener(t,s),this.clicks=this.clicks.filter(t=>t!==e)}}editable({toText:t,onEdit:e}={}){if("function"!=typeof t)throw new Error("editable needs { toText } (import { toText } from 'mathzetta/text')");return this.editing={toText:t,onEdit:e},this.root&&this.root.classList&&this.root.classList.add(`${this.p}-editable`),this.keyboard(),!this.editOn&&this.element.addEventListener&&(this.editOn=!0,this.element.addEventListener("dblclick",t=>{const e=t.target.closest?.("[data-node]");e&&this.root.contains(e)&&(t.preventDefault(),this.edit(r(this.tree,Number(e.dataset.node))[0]))})),this}edit(e=this.tree,{returnFocus:s=!1}={}){if(!this.editing)throw new Error("call editable({ toText }) first");const r="object"==typeof e&&e&&e.type?e:this.nodes(e)[0];if(!r)return null;const h=n(this.tree,r.id)||[],a=this.elementOf(r)||this.root;let l="Edit";try{l=`Edit ${i(r)}`}catch{}const d=()=>{s&&this.root.focus&&this.root.focus()};return c(a,this.editing.toText(r),{label:l,parse:e=>t(e,this.options),commit:(t,e)=>{this.set(u(this.tree,h,t),{animate:!0});const i=o(this.tree,h);s&&i&&this.focusPart(i===this.tree?null:i),d(),this.editing.onEdit&&this.editing.onEdit({tree:this.tree,text:this.editing.toText(this.tree),path:h,part:e})},cancel:d})}focusable(){this.root&&this.root.setAttribute&&(this.root.setAttribute("tabindex","0"),this.root.getAttribute("aria-label")||(this.root.setAttribute("role","math"),this.root.setAttribute("aria-label",this.spoken())),this.root.setAttribute("aria-description",this.editing?"Arrow keys move between parts, F2 edits one.":"Arrow keys move between parts, Enter selects one."))}keyboard(){this.focusable(),!this.keysOn&&this.element.addEventListener&&(this.keysOn=!0,this.partsLive=this.live||p(this.element,!0,this.p),this.element.addEventListener("keydown",t=>this.key(t)))}key(t){if(!this.root||!this.root.contains(t.target))return;const e=this.active;let s;switch(t.key){case"ArrowDown":s=e?this.partsOf(e)[0]:this.partsOf(this.tree)[0];break;case"ArrowUp":s=e?this.outerOf(e):void 0;break;case"ArrowRight":s=e?this.neighbour(e,1):this.partsOf(this.tree)[0];break;case"ArrowLeft":s=e?this.neighbour(e,-1):void 0;break;case"Home":case"Escape":s=null;break;case"F2":if(!this.editing)return;return t.preventDefault(),void this.edit(e||this.tree,{returnFocus:!0});case"Enter":case" ":{t.preventDefault();const s=e||this.tree,i=this.elementOf(s)||this.root,r={node:s,id:s.id,path:n(this.tree,s.id),element:i,event:t};for(const t of this.clicks)t(r);return}default:return}t.preventDefault(),void 0!==s&&this.focusPart(s)}focusPart(t){const e=`${this.p}-focus`;this.root.querySelectorAll(`.${e}`).forEach(t=>t.classList.remove(e)),this.active=t;const s=t&&this.elementOf(t);s&&s.classList.add(e);let r="";try{r=t?i(t):this.spoken()}catch{r=""}return this.say(this.partsLive,r),this}partsOf(t){const e=[],s=t=>{this.elementOf(t)?e.push(t):"op"===t.type&&t.args.forEach(s)};return t&&"op"===t.type&&t.args.forEach(s),e}outerOf(t){const e=n(this.tree,t.id);for(let t=e?e.length-1:-1;t>0;t--){const s=o(this.tree,e.slice(0,t));if(s&&this.elementOf(s))return s}return null}neighbour(t,e){const s=this.partsOf(this.outerOf(t)||this.tree),i=s.indexOf(t);return i<0?void 0:s[i+e]}segments(t={}){return h(this.tree,t)}showSegment(t,e=`${this.p}-hl`){return this.unhighlight(null,e),t&&void 0!==t.id&&this.highlight(t.id,e),this}snapshot(){const t=new Map,e=s=>{const i=this.elementOf(s);if(i){const e=l(s);t.has(e)||t.set(e,[]),t.get(e).push(i.getBoundingClientRect())}"op"===s.type&&s.args.forEach(e)};return e(this.tree),t}morph(t,{duration:e,easing:s}){if("undefined"==typeof Element||!Element.prototype.animate)return;const i=r=>{const n=this.elementOf(r),o=n&&t.get(l(r));if(o&&o.length){const t=o.shift(),i=n.getBoundingClientRect(),r=t.left-i.left,h=t.top-i.top,a=i.width?t.width/i.width:1,l=i.height?t.height/i.height:1;return void((Math.abs(r)+Math.abs(h)>.5||Math.abs(a-1)+Math.abs(l-1)>.01)&&n.animate([{transformOrigin:"0 0",transform:`translate(${r}px, ${h}px) scale(${a}, ${l})`},{transformOrigin:"0 0",transform:"none"}],{duration:e,easing:s}))}"op"===r.type?r.args.forEach(i):n&&n.animate([{opacity:0},{opacity:0},{opacity:1}],{duration:e,easing:s})};i(this.tree)}}function p(t,e,s){if(!e)return null;if("object"==typeof e&&1===e.nodeType)return e;if("undefined"==typeof document||!t.insertAdjacentElement)return null;const i=document.createElement("span");return i.className=`${s}-sr-only`,i.setAttribute("aria-live","polite"),i.setAttribute("aria-atomic","true"),t.insertAdjacentElement("afterend",i),i}function m(t){return!!t&&("always"===t||!("function"==typeof matchMedia&&matchMedia("(prefers-reduced-motion: reduce)").matches))}function g(t,e,s={}){return new f(t,e,s)}export{f as View,e as layout,o as nodeAt,n as pathOf,g as render,r as select,m as shouldAnimate,l as signature,t as treeOf};
|
package/dist/lite-calc.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/* Inline Math 0.
|
|
2
|
-
import{c
|
|
1
|
+
/* Inline Math 0.2.0 — MIT licence; includes mathzetta (and @mathzetta/cas, for the CAS) */
|
|
2
|
+
import{c}from"./chunks/calculate-Cz87Lt0N.js";export{a as calculate}from"./chunks/calculate-Cz87Lt0N.js";import{e as o,f as e}from"./chunks/lite-3Fb-OHbt.js";export{D as DEFAULTS,l as layout,d as numberTree,s as select}from"./chunks/lite-3Fb-OHbt.js";const t=(s,a={})=>o(s,{...a,blocks:a.blocks??c}),r=(s,a={})=>e(s,{...a,blocks:a.blocks??c});export{c as calculateBlock,t as toHTML,r as treeOf};
|
package/dist/lite.external.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/* Inline Math 0.
|
|
2
|
-
export{D as DEFAULTS,l as layout,n as numberTree,s as select,t as toHTML,a as treeOf}from"./chunks/draw-
|
|
1
|
+
/* Inline Math 0.2.0 — MIT licence; MathZetta not included: map mathzetta, mathzetta/speech and mathzetta/calculate with an import map */
|
|
2
|
+
export{D as DEFAULTS,l as layout,n as numberTree,s as select,t as toHTML,a as treeOf}from"./chunks/draw-Bev17BJJ.js";import"mathzetta";import"mathzetta/speech";
|
package/dist/lite.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/* Inline Math 0.
|
|
2
|
-
export{D as DEFAULTS,l as layout,
|
|
1
|
+
/* Inline Math 0.2.0 — MIT licence; includes mathzetta (and @mathzetta/cas, for the CAS) */
|
|
2
|
+
export{D as DEFAULTS,l as layout,d as numberTree,s as select,e as toHTML,f as treeOf}from"./chunks/lite-3Fb-OHbt.js";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/* Inline Math 0.
|
|
2
|
-
import{a as t}from"./chunks/html-CvuSyhzk.js";import{calculate as e}from"mathzetta/calculate";import"./chunks/draw-Cm4exbg7.js";import"mathzetta";import"mathzetta/speech";const n=new RegExp("(\\d+)","g");function s(t,{delimiters:e=["$$","$","\\[","\\("]}={}){const n=[];let s="",i=0;const r=String(t),l=t=>0===t||"\n"===r[t-1],o=(t,e,s)=>(n.push({source:t,display:e,raw:s}),`${n.length-1}`);for(;i<r.length;){if(l(i)){const t=/^( {0,3})(`{3,}|~{3,})([^\n]*)\n?/.exec(r.slice(i));if(t){const e=t[2],n=new RegExp(`\\n {0,3}${"`"===e[0]?"`":"~"}{${e.length},}[ \\t]*(?=\\n|$)`),c=r.slice(i+t[0].length),l=n.exec(`\n${c}`),a=l?c.slice(0,Math.max(0,l.index-1)):c,p=t[0].length+(l?l.index-1+l[0].length:c.length),h=r.slice(i,i+p);"math"===t[3].trim()?s+=o(a,!0,h):s+=h,i+=p;continue}}const t=r[i];if("`"===t){const t=/^`+/.exec(r.slice(i))[0],e=r.indexOf(t,i+t.length);if(e>-1){s+=r.slice(i,e+t.length),i=e+t.length;continue}s+=t,i+=t.length;continue}if("\\"===t){const t=r.slice(i,i+2),n="\\["===t?"\\]":"\\("===t?"\\)":null;if(n&&e.includes(t)){const e=r.indexOf(n,i+2);if(e>-1){s+=o(r.slice(i+2,e),"\\["===t,r.slice(i,e+2)),i=e+2;continue}}s+=t,i+=2;continue}if("$"===t)if("$"===r[i+1]&&e.includes("$$")){const t=r.indexOf("$$",i+2);if(t>-1){s+=o(r.slice(i+2,t),!0,r.slice(i,t+2)),i=t+2;continue}}else if(e.includes("$")&&r[i+1]&&!/\s/.test(r[i+1])){const t=c(r,i+1);if(t>-1){s+=o(r.slice(i+1,t),!1,r.slice(i,t+1)),i=t+1;continue}}s+=t,i++}return{text:s,math:n}}function c(t,e){for(let n=e;n<t.length;n++){const e=t[n];if("\\"!==e){if("`"===e)return-1;if("\n"===e&&/^\n[ \t]*\n/.test(t.slice(n)))return-1;if("$"===e&&!/\s/.test(t[n-1])&&!/\d/.test(t[n+1]??"")&&"$"!==t[n+1])return n}else n++}return-1}const i=t=>String(t).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""),r=/^\s*([A-Za-zͰ-Ͽ](?:_\{?\w+\}?)?)\s*(?::=|=)\s*([^=<>≤≥]+)$/;function l(n,s,c){const{source:l,display:o}=n;try{const n=t(l,{...s.math,display:o,blocks:s.blocks,scope:c});return!1!==s.define&&function(t,n){const s=r.exec(t);if(!s||/\{\{/.test(s[2]))return;try{const t=e(s[2],n);"number"!=typeof t.value&&"bigint"!=typeof t.value||(n[s[1].replace(/[{}]/g,"")]=t.exact?t.text:t.value)}catch{}}(l,c),o?`<span class="mv-md-display">${n}</span>`:`<span class="mv-md-math">${n}</span>`}catch(t){return`<span class="mv-md-error" title="${i(t.message)}"><code>${i(n.raw)}</code></span>`}}const o=/^(https?:|mailto:|#|\/|\.{0,2}\/|[^:]*$)/i,a=t=>o.test(t.trim())?i(t.trim()):"#";function p(t,e,n){const s=[],c=t=>(s.push(t),`${s.length-1}`);let r=t;return r=r.replace(/(`+)([\s\S]*?[^`])\1(?!`)/g,(t,e,s)=>c(`<code>${i(n(s.trim()))}</code>`)),r=r.replace(/\\([\\`*_{}[\]()#+\-.!|~$<>"'])/g,(t,e)=>c(i(e))),r=r.replace(/<((?:https?:\/\/|mailto:)[^\s>]+)>/g,(t,e)=>c(`<a href="${a(e)}">${i(e)}</a>`)),e.html&&(r=r.replace(/<\/?[A-Za-z][^>]*>/g,t=>c(t))),r=r.replace(/!\[([^\]]*)\]\(\s*((?:[^\s()]|\([^\s()]*\))+)(?:\s+"([^"]*)")?\s*\)/g,(t,e,n,s)=>c(`<img src="${a(n)}" alt="${i(e)}"${s?` title="${i(s)}"`:""}>`)),r=r.replace(/\[([^\]]+)\]\(\s*((?:[^\s()]|\([^\s()]*\))+)(?:\s+"([^"]*)")?\s*\)/g,(t,s,r,l)=>c(`<a href="${a(r)}"${l?` title="${i(l)}"`:""}>${p(s,e,n)}</a>`)),r=i(r),r=r.replace(/(\*\*|__)(?=\S)([\s\S]*?\S)\1/g,"<strong>$2</strong>"),r=r.replace(/(^|[^*\w])\*(?=\S)([\s\S]*?\S)\*(?!\*)/g,"$1<em>$2</em>"),r=r.replace(/(^|[^_\w])_(?=\S)([\s\S]*?\S)_(?![_\w])/g,"$1<em>$2</em>"),r=r.replace(/~~(?=\S)([\s\S]*?\S)~~/g,"<del>$1</del>"),r=r.replace(/( {2,}|\\)\n/g,"<br>\n"),r.replace(/(\d+)/g,(t,e)=>s[Number(e)])}const h=/^( {0,3})(#{1,6}\s|>|```|~~~|([-*+]|\d{1,9}[.)])\s|(\*[ \t]*){3,}$|(-[ \t]*){3,}$|(_[ \t]*){3,}$)/,u=/^( {0,3})([-*+]|\d{1,9}[.)])(\s+|$)/,$=/^\s*\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?\s*$/;function g(t,e,n){const s=[];let c=0;const r=t=>p(t,e,n);for(;c<t.length;){const l=t[c];if(!l.trim()){c++;continue}const o=/^ {0,3}(`{3,}|~{3,})\s*([^\s`]*)/.exec(l);if(o){const e=[];for(c++;c<t.length&&!new RegExp(`^ {0,3}${"`"===o[1][0]?"`":"~"}{${o[1].length},}\\s*$`).test(t[c]);)e.push(t[c++]);c++;const r=o[2]?` class="language-${i(o[2])}"`:"";s.push(`<pre><code${r}>${i(n(e.join("\n")))}</code></pre>`);continue}const a=/^ {0,3}(#{1,6})\s+(.*?)\s*#*\s*$/.exec(l);if(a){s.push(`<h${a[1].length}>${r(a[2])}</h${a[1].length}>`),c++;continue}if(/^ {0,3}((\*[ \t]*){3,}|(-[ \t]*){3,}|(_[ \t]*){3,})$/.test(l)){s.push("<hr>"),c++;continue}if(/^ {0,3}>/.test(l)){const i=[];for(;c<t.length&&t[c].trim()&&(/^ {0,3}>/.test(t[c])||i.length);)i.push(t[c].replace(/^ {0,3}> ?/,"")),c++;s.push(`<blockquote>\n${g(i,e,n)}\n</blockquote>`);continue}const p=u.exec(l);if(p){const i=/\d/.test(p[2]),r=i?parseInt(p[2],10):1,l=[];let o=!1;for(;c<t.length;){const e=u.exec(t[c]);if(!e||/\d/.test(e[2])!==i)break;const n=e[0].length,s=[t[c].slice(n)];for(c++;c<t.length;){const e=t[c];if(!e.trim()){const e=t[c+1];if(void 0!==e&&e.startsWith(" ".repeat(Math.min(n,4)))&&e.trim()){s.push(""),o=!0,c++;continue}void 0!==e&&u.test(e)&&(o=!0);break}if(e.startsWith(" ".repeat(Math.min(n,4))))s.push(e.slice(Math.min(n,4)));else{if(u.test(e)||h.test(e))break;s.push(e)}c++}for(l.push(s);c<t.length&&!t[c].trim()&&void 0!==t[c+1]&&u.test(t[c+1]);)c++}const a=i?"ol":"ul",$=l.map(t=>{let s=g(t,e,n);return o||(s=s.replace(/^<p>([\s\S]*?)<\/p>/,"$1").replace(/\n<p>([\s\S]*?)<\/p>/g,"\n$1")),`<li>${s}</li>`});s.push(`<${a}${i&&1!==r?` start="${r}"`:""}>\n${$.join("\n")}\n</${a}>`);continue}if(l.includes("|")&&void 0!==t[c+1]&&$.test(t[c+1])&&t[c+1].includes("-")){const e=t=>t.trim().replace(/^\|/,"").replace(/\|$/,"").split(/(?<!\\)\|/).map(t=>t.trim()),n=e(t[c+1]).map(t=>t.startsWith(":")&&t.endsWith(":")?"center":t.endsWith(":")?"right":t.startsWith(":")?"left":""),i=(t,e,s)=>`<${t}${n[s]?` style="text-align:${n[s]}"`:""}>${r(e)}</${t}>`,o=e(l);c+=2;const a=[];for(;c<t.length&&t[c].trim()&&t[c].includes("|");)a.push(e(t[c++]));s.push(`<table>\n<thead><tr>${o.map((t,e)=>i("th",t,e)).join("")}</tr></thead>\n<tbody>\n${a.map(t=>`<tr>${o.map((e,n)=>i("td",t[n]??"",n)).join("")}</tr>`).join("\n")}\n</tbody>\n</table>`);continue}if(/^( {4}|\t)/.test(l)){const e=[];for(;c<t.length&&(/^( {4}|\t)/.test(t[c])||!t[c].trim());)e.push(t[c++].replace(/^( {4}|\t)/,""));for(;e.length&&!e[e.length-1].trim();)e.pop();s.push(`<pre><code>${i(n(e.join("\n")))}</code></pre>`);continue}const m=[];for(;c<t.length&&t[c].trim()&&(!m.length||!h.test(t[c])||/^ {0,3}[-=]+\s*$/.test(t[c]));){if(m.length&&/^ {0,3}(=+|-+)\s*$/.test(t[c])){const e="="===t[c].trim()[0]?1:2;s.push(`<h${e}>${r(m.join("\n"))}</h${e}>`),m.length=0,c++;break}m.push(t[c].replace(/^ {0,3}/,"")),c++}m.length&&s.push(`<p>${r(m.join("\n"))}</p>`)}return s.join("\n")}function m(t,e={},n=t=>t){return g(String(t).replace(/\r\n?/g,"\n").split("\n"),e,n)}function f(t,e={}){const{text:c,math:i}=s(t,e),r={...e.scope??{}},o=i.map(t=>l(t,e,r));return(e.render?e.render(c):m(c,e,t=>t.replace(n,(t,e)=>i[Number(e)].raw))).replace(new RegExp("<p>\\s*(\\d+)\\s*</p>","g"),(t,e)=>i[Number(e)].display?`<div class="mv-md-block">${o[Number(e)]}</div>`:t).replace(n,(t,e)=>o[Number(e)])}function d(t,e,n={}){return t.innerHTML=f(e,n),t}export{s as extractMath,f as markdownToHTML,m as renderMarkdown,d as renderMarkdownInto};
|
|
1
|
+
/* Inline Math 0.2.0 — MIT licence; MathZetta not included: map mathzetta, mathzetta/speech and mathzetta/calculate with an import map */
|
|
2
|
+
import{t as e,a as t}from"./chunks/html-BimAqn7x.js";import{calculate as n}from"mathzetta/calculate";import{v as s,o as r,r as a,u as i,s as o,E as l,b as u,n as d,i as p}from"./chunks/edit-C65xXzo8.js";export{V as Variables,c as createVariables}from"./chunks/edit-C65xXzo8.js";import{toPostfix as m}from"mathzetta";import"mathzetta/speech";import{p as h,c as f,n as $}from"./chunks/draw-Bev17BJJ.js";const g=new RegExp("(\\d+)","g");function v(e,{delimiters:t=["$$","$","\\[","\\("]}={}){const n=[];let s="",r=0;const a=String(e),i=e=>0===e||"\n"===a[e-1],o=(e,t,s)=>(n.push({source:e,display:t,raw:s,start:r,end:r+s.length}),`${n.length-1}`);for(;r<a.length;){if(i(r)){const e=/^( {0,3})(`{3,}|~{3,})([^\n]*)\n?/.exec(a.slice(r));if(e){const t=e[2],n=new RegExp(`\\n {0,3}${"`"===t[0]?"`":"~"}{${t.length},}[ \\t]*(?=\\n|$)`),i=a.slice(r+e[0].length),c=n.exec(`\n${i}`),l=c?i.slice(0,Math.max(0,c.index-1)):i,u=e[0].length+(c?c.index-1+c[0].length:i.length),d=a.slice(r,r+u);"math"===e[3].trim()?s+=o(l,!0,d):s+=d,r+=u;continue}}const e=a[r];if("`"===e){const e=/^`+/.exec(a.slice(r))[0],t=a.indexOf(e,r+e.length);if(t>-1){s+=a.slice(r,t+e.length),r=t+e.length;continue}s+=e,r+=e.length;continue}if("\\"===e){const e=a.slice(r,r+2),n="\\["===e?"\\]":"\\("===e?"\\)":null;if(n&&t.includes(e)){const t=a.indexOf(n,r+2);if(t>-1){s+=o(a.slice(r+2,t),"\\["===e,a.slice(r,t+2)),r=t+2;continue}}s+=e,r+=2;continue}if("$"===e)if("$"===a[r+1]&&t.includes("$$")){const e=a.indexOf("$$",r+2);if(e>-1){s+=o(a.slice(r+2,e),!0,a.slice(r,e+2)),r=e+2;continue}}else if(t.includes("$")&&a[r+1]&&!/\s/.test(a[r+1])){const e=b(a,r+1);if(e>-1){s+=o(a.slice(r+1,e),!1,a.slice(r,e+1)),r=e+1;continue}}s+=e,r++}return{text:s,math:n}}function b(e,t){for(let n=t;n<e.length;n++){const t=e[n];if("\\"!==t){if("`"===t)return-1;if("\n"===t&&/^\n[ \t]*\n/.test(e.slice(n)))return-1;if("$"===t&&!/\s/.test(e[n-1])&&!/\d/.test(e[n+1]??"")&&"$"!==e[n+1])return n}else n++}return-1}const x=e=>String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""),y=/^\s*([A-Za-z\u0370-\u03ff](?:_\{?\w+\}?)?)\s*=\s*([^=<>≤≥]+)$/;function k(s,r,a,i){const{text:c,math:h}=v(s,r),f=a?a.definitions(i):new Map,g=e=>a?a.textOf(e):e.text,b={...r.scope??{}},k={},w=new Map,S=new Set,E=[],j=()=>{for(const e of Object.keys(k))delete k[e];Object.assign(k,b);for(const e of f.keys())delete k[e];let e=[...f.values()];for(;e.length;){const t=e.filter(e=>{try{const t=n(g(e),k);if("number"==typeof t.value||"bigint"==typeof t.value||Array.isArray(t.value))return k[e.name]=t.exact?t.text:t.value,!1}catch{}return!0});if(t.length===e.length)break;e=t}const t={},s=_({});for(const e of f.keys()){const n=s(e);if(n)try{t[e]=m(o(n,t=>t===e?null:s(t)).tree)}catch{}}k[l]=t},_=t=>{const n=new Map;return s=>{const r=f.get(s);if(!r)return null;if(!n.has(s)){let a=null;try{a=e(g(r),t)}catch{}n.set(s,a)}return n.get(s)}};j();const M=h.map((s,a)=>{const{source:i,display:c}=s,l=c?"mv-md-display":"mv-md-math",m=(e,t="")=>`<span class="${l}${t}" data-mv-md="${a}">${e}</span>`;try{const l={...r.math,display:c,blocks:r.blocks,scope:k},h=function(t){let n=t.trim();const s=n.startsWith("_");s&&(n=n.slice(1).trimStart());let r=n.indexOf(":="),a=2;r<0&&s&&(r=n.search(/(?<![<>!≤≥=])=(?!=)/),a=1);const i=s?{error:"a hidden $_…$ saves a variable: $_A := 2+2$"}:null;if(r<=0)return i;const o=n.slice(0,r).trim(),c=n.slice(r+a).trim();let l=null;try{l=/\{\{/.test(o)?null:d(e(o))}catch{}return null!==l&&c?{hidden:s,lhs:o,name:l,rhs:c,input:p(c)}:i}(i);if(h&&h.error)throw new Error(h.error);if(h){const{name:n,input:r,hidden:i}=h,c=r?{name:n,text:r.default,input:r,key:`input:${JSON.stringify(r)}`}:{name:n,text:h.rhs,input:null,key:`expr:${h.rhs}`,start:s.start,end:s.end};let d="";if(r){const e=function(e,t){const{input:n,name:s}=e,r=`class="mv-md-input mv-md-${n.kind}" data-mv-var="${x(s)}" aria-label="${x(s)}"`;if("dropdown"===n.kind)return`<select ${r}>${n.options.map(e=>`<option value="${x(e)}"${e===t?" selected":""}>${x(e)}</option>`).join("")}</select>`;return"slider"===n.kind?`<input type="range" ${r} min="${n.min}" max="${n.max}" step="${n.step}" value="${x(t)}"><output class="mv-md-output" data-mv-out="${x(s)}">${x(t)}</output>`:`<input type="text" ${r} value="${x(t)}" size="${Math.max(4,t.length+1)}" spellcheck="false" autocomplete="off">`}(c,g(c));d=i?e:`${t(h.lhs,l)}<span class="mv-md-assign" aria-hidden="true">≔</span>${e}`,S.add(a)}else{const n=o(e(h.rhs,l),_(l)).tree;if(!i){const s=$({type:"op",op:"=",args:[u(e(h.lhs)),void 0===n.id?n:u(n)]});E[a]=s,d=function(e){return e.replace('<span class="mv-rel">=</span>','<span class="mv-rel mv-rel-def">≔</span>').replace(/(aria-label="[^"]*?) equals /,"$1 is defined as ").replace("<mo>=</mo>","<mo>≔</mo>")}(t(s,l))}}return f.delete(n),f.set(n,c),w.set(n,c),j(),i&&!r?"":m(d,r?" mv-md-input-def":"")}const{tree:v,changed:M}=o(e(i,l),_(l));M&&$(v),E[a]=v;const O=t(v,l);return!M&&!1!==r.define&&function(e,t,s){const r=y.exec(e);if(!r||/\{\{/.test(r[2]))return!1;const a=r[1].replace(/[{}]/g,"");if(s.has(a))return!1;try{const e=n(r[2],t);if("number"==typeof e.value||"bigint"==typeof e.value||Array.isArray(e.value))return t[a]=e.exact?e.text:e.value,!0}catch{}return!1}(i,b,f)&&j(),m(O)}catch(e){return`<span class="mv-md-error" data-mv-md="${a}" title="${x(e.message)}"><code>${x(s.raw)}</code></span>`}});return{text:c,math:h,drawn:M,defs:w,inputs:S,trees:E}}const w=/^(https?:|mailto:|#|\/|\.{0,2}\/|[^:]*$)/i,S=e=>w.test(e.trim())?x(e.trim()):"#";function E(e,t,n){const s=[],r=e=>(s.push(e),`${s.length-1}`);let a=e;return a=a.replace(/(`+)([\s\S]*?[^`])\1(?!`)/g,(e,t,s)=>r(`<code>${x(n(s.trim()))}</code>`)),a=a.replace(/\\([\\`*_{}[\]()#+\-.!|~$<>"'])/g,(e,t)=>r(x(t))),a=a.replace(/<((?:https?:\/\/|mailto:)[^\s>]+)>/g,(e,t)=>r(`<a href="${S(t)}">${x(t)}</a>`)),t.html&&(a=a.replace(/<\/?[A-Za-z][^>]*>/g,e=>r(e))),a=a.replace(/!\[([^\]]*)\]\(\s*((?:[^\s()]|\([^\s()]*\))+)(?:\s+"([^"]*)")?\s*\)/g,(e,t,n,s)=>r(`<img src="${S(n)}" alt="${x(t)}"${s?` title="${x(s)}"`:""}>`)),a=a.replace(/\[([^\]]+)\]\(\s*((?:[^\s()]|\([^\s()]*\))+)(?:\s+"([^"]*)")?\s*\)/g,(e,s,a,i)=>r(`<a href="${S(a)}"${i?` title="${x(i)}"`:""}>${E(s,t,n)}</a>`)),a=x(a),a=a.replace(/(\*\*|__)(?=\S)([\s\S]*?\S)\1/g,"<strong>$2</strong>"),a=a.replace(/(^|[^*\w])\*(?=\S)([\s\S]*?\S)\*(?!\*)/g,"$1<em>$2</em>"),a=a.replace(/(^|[^_\w])_(?=\S)([\s\S]*?\S)_(?![_\w])/g,"$1<em>$2</em>"),a=a.replace(/~~(?=\S)([\s\S]*?\S)~~/g,"<del>$1</del>"),a=a.replace(/( {2,}|\\)\n/g,"<br>\n"),a.replace(/(\d+)/g,(e,t)=>s[Number(t)])}const j=/^( {0,3})(#{1,6}\s|>|```|~~~|([-*+]|\d{1,9}[.)])\s|(\*[ \t]*){3,}$|(-[ \t]*){3,}$|(_[ \t]*){3,}$)/,_=/^( {0,3})([-*+]|\d{1,9}[.)])(\s+|$)/,M=/^\s*\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?\s*$/;function O(e,t,n){const s=[];let r=0;const a=e=>E(e,t,n);for(;r<e.length;){const i=e[r];if(!i.trim()){r++;continue}const o=/^ {0,3}(`{3,}|~{3,})\s*([^\s`]*)/.exec(i);if(o){const t=[];for(r++;r<e.length&&!new RegExp(`^ {0,3}${"`"===o[1][0]?"`":"~"}{${o[1].length},}\\s*$`).test(e[r]);)t.push(e[r++]);r++;const a=o[2]?` class="language-${x(o[2])}"`:"";s.push(`<pre><code${a}>${x(n(t.join("\n")))}</code></pre>`);continue}const c=/^ {0,3}(#{1,6})\s+(.*?)\s*#*\s*$/.exec(i);if(c){s.push(`<h${c[1].length}>${a(c[2])}</h${c[1].length}>`),r++;continue}if(/^ {0,3}((\*[ \t]*){3,}|(-[ \t]*){3,}|(_[ \t]*){3,})$/.test(i)){s.push("<hr>"),r++;continue}if(/^ {0,3}>/.test(i)){const a=[];for(;r<e.length&&e[r].trim()&&(/^ {0,3}>/.test(e[r])||a.length);)a.push(e[r].replace(/^ {0,3}> ?/,"")),r++;s.push(`<blockquote>\n${O(a,t,n)}\n</blockquote>`);continue}const l=_.exec(i);if(l){const a=/\d/.test(l[2]),i=a?parseInt(l[2],10):1,o=[];let c=!1;for(;r<e.length;){const t=_.exec(e[r]);if(!t||/\d/.test(t[2])!==a)break;const n=t[0].length,s=[e[r].slice(n)];for(r++;r<e.length;){const t=e[r];if(!t.trim()){const t=e[r+1];if(void 0!==t&&t.startsWith(" ".repeat(Math.min(n,4)))&&t.trim()){s.push(""),c=!0,r++;continue}void 0!==t&&_.test(t)&&(c=!0);break}if(t.startsWith(" ".repeat(Math.min(n,4))))s.push(t.slice(Math.min(n,4)));else{if(_.test(t)||j.test(t))break;s.push(t)}r++}for(o.push(s);r<e.length&&!e[r].trim()&&void 0!==e[r+1]&&_.test(e[r+1]);)r++}const u=a?"ol":"ul",d=o.map(e=>{let s=O(e,t,n);return c||(s=s.replace(/^<p>([\s\S]*?)<\/p>/,"$1").replace(/\n<p>([\s\S]*?)<\/p>/g,"\n$1")),`<li>${s}</li>`});s.push(`<${u}${a&&1!==i?` start="${i}"`:""}>\n${d.join("\n")}\n</${u}>`);continue}if(i.includes("|")&&void 0!==e[r+1]&&M.test(e[r+1])&&e[r+1].includes("-")){const t=e=>e.trim().replace(/^\|/,"").replace(/\|$/,"").split(/(?<!\\)\|/).map(e=>e.trim()),n=t(e[r+1]).map(e=>e.startsWith(":")&&e.endsWith(":")?"center":e.endsWith(":")?"right":e.startsWith(":")?"left":""),o=(e,t,s)=>`<${e}${n[s]?` style="text-align:${n[s]}"`:""}>${a(t)}</${e}>`,c=t(i);r+=2;const l=[];for(;r<e.length&&e[r].trim()&&e[r].includes("|");)l.push(t(e[r++]));s.push(`<table>\n<thead><tr>${c.map((e,t)=>o("th",e,t)).join("")}</tr></thead>\n<tbody>\n${l.map(e=>`<tr>${c.map((t,n)=>o("td",e[n]??"",n)).join("")}</tr>`).join("\n")}\n</tbody>\n</table>`);continue}if(/^( {4}|\t)/.test(i)){const t=[];for(;r<e.length&&(/^( {4}|\t)/.test(e[r])||!e[r].trim());)t.push(e[r++].replace(/^( {4}|\t)/,""));for(;t.length&&!t[t.length-1].trim();)t.pop();s.push(`<pre><code>${x(n(t.join("\n")))}</code></pre>`);continue}const u=[];for(;r<e.length&&e[r].trim()&&(!u.length||!j.test(e[r])||/^ {0,3}[-=]+\s*$/.test(e[r]));){if(u.length&&/^ {0,3}(=+|-+)\s*$/.test(e[r])){const t="="===e[r].trim()[0]?1:2;s.push(`<h${t}>${a(u.join("\n"))}</h${t}>`),u.length=0,r++;break}u.push(e[r].replace(/^ {0,3}/,"")),r++}u.length&&s.push(`<p>${a(u.join("\n"))}</p>`)}return s.join("\n")}function A(e,t={},n=e=>e){return O(String(e).replace(/\r\n?/g,"\n").split("\n"),t,n)}function N({text:e,math:t,drawn:n},s){return(s.render?s.render(e):A(e,s,e=>e.replace(g,(e,n)=>t[Number(n)].raw))).replace(new RegExp("<p>\\s*(\\d+)\\s*</p>","g"),(e,s)=>t[Number(s)].display&&n[Number(s)]?`<div class="mv-md-block">${n[Number(s)]}</div>`:e).replace(g,(e,t)=>n[Number(t)]).replace(/<p>\s*<\/p>\n?/g,"")}function L(e,t={}){return N(k(e,t,t.variables||null),t)}const W=new WeakMap,q=new Set;function z(){for(const e of q)e.connected()&&!e.element.isConnected&&e.stop(!0)}function C(t,n,o={}){const c=void 0===o.variables?s:o.variables||null;z();const l=W.get(t);l&&l.stop(l.store!==c);let u=k(n,o,c,t);if(t.innerHTML=N(u,o),!c)return W.delete(t),t;c.own(t,u.defs);let d=t.isConnected;const p=n=>{const s=n.target,r=s&&s.dataset&&s.dataset.mvVar;if(void 0!==r&&t.contains(s)){if("text"===s.type)try{e(s.value,{blocks:o.blocks,scope:{}}),s.removeAttribute("aria-invalid")}catch{return void s.setAttribute("aria-invalid","true")}c.set(r,s.value)}},m=s=>{const l=s.target.closest?.("[data-node]"),d=l&&l.closest("[data-mv-md]");if(!d||!t.contains(d))return;const p=Number(d.dataset.mvMd),m=u.trees[p];if(!m)return;const $=Number(l.dataset.node),g=h(m,$)||[];let v=null;for(let e=g.length;e>=0&&!v;e--){const t=f(m,g.slice(0,e));t&&void 0!==t.from&&(v={node:t,depth:e})}const b=v&&c.definitions().get(v.node.from);if(b&&b.input&&"textbox"===b.input.kind){s.preventDefault();const n=b.name,u=t.ownerDocument.querySelector(`[data-mv-var="${CSS.escape(n)}"]`),d=o.editable&&o.editable.toText;if(!d)return void(u&&(u.focus(),u.select()));const p=t=>e(t),h=f(m,g);return void r(l,d(i(h,p)),{label:`Edit ${n}`,parse:t=>e(t,{blocks:o.blocks}),commit:e=>{const t=a(i(v.node,p),g.slice(v.depth),e);c.set(n,d(t))}})}const x=b&&u.defs.get(b.name),y=x&&x.key===b.key&&void 0!==x.start?{...u.math[p],start:x.start,end:x.end,raw:n.slice(x.start,x.end)}:u.math[p];t.dispatchEvent(new CustomEvent("inlinemath:select",{bubbles:!0,detail:{index:p,start:y.start,end:y.end,raw:y.raw,source:y.source,id:$,path:g}}))};t.addEventListener("input",p),t.addEventListener("change",p),t.addEventListener("dblclick",m);const $=c.subscribe(e=>{e!==t&&(t.isConnected?(d=!0,z(),(()=>{const e=k(n,o,c,t);e.drawn.forEach((n,s)=>{if(n===u.drawn[s]||e.inputs.has(s))return;const r=t.querySelector(`[data-mv-md="${s}"]`);r&&(r.outerHTML=n)});for(const n of t.querySelectorAll("[data-mv-var], [data-mv-out]")){const t=e.defs.get(n.dataset.mvVar??n.dataset.mvOut);if(!t)continue;const s=c.textOf(t);void 0!==n.dataset.mvOut?n.textContent=s:n.value!==s&&n!==n.ownerDocument?.activeElement&&(n.value=s)}u=e})()):d&&g(!0))});function g(e){$(),t.removeEventListener("input",p),t.removeEventListener("change",p),t.removeEventListener("dblclick",m),q.delete(v),W.delete(t),e&&c.own(t,null)}const v={element:t,store:c,stop:g,connected:()=>d};return q.add(v),W.set(t,v),t}export{v as extractMath,L as markdownToHTML,A as renderMarkdown,C as renderMarkdownInto,s as variables};
|
package/dist/markdown.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/* Inline Math 0.
|
|
2
|
-
import{a as e}from"./chunks/html-DWtfytjA.js";import{a as t}from"./chunks/calculate-BX9lJ7Ff.js";import"./chunks/lite-Bj_L6w2g.js";const n=new RegExp("(\\d+)","g");function s(e,{delimiters:t=["$$","$","\\[","\\("]}={}){const n=[];let s="",i=0;const r=String(e),l=e=>0===e||"\n"===r[e-1],o=(e,t,s)=>(n.push({source:e,display:t,raw:s}),`${n.length-1}`);for(;i<r.length;){if(l(i)){const e=/^( {0,3})(`{3,}|~{3,})([^\n]*)\n?/.exec(r.slice(i));if(e){const t=e[2],n=new RegExp(`\\n {0,3}${"`"===t[0]?"`":"~"}{${t.length},}[ \\t]*(?=\\n|$)`),c=r.slice(i+e[0].length),l=n.exec(`\n${c}`),a=l?c.slice(0,Math.max(0,l.index-1)):c,p=e[0].length+(l?l.index-1+l[0].length:c.length),h=r.slice(i,i+p);"math"===e[3].trim()?s+=o(a,!0,h):s+=h,i+=p;continue}}const e=r[i];if("`"===e){const e=/^`+/.exec(r.slice(i))[0],t=r.indexOf(e,i+e.length);if(t>-1){s+=r.slice(i,t+e.length),i=t+e.length;continue}s+=e,i+=e.length;continue}if("\\"===e){const e=r.slice(i,i+2),n="\\["===e?"\\]":"\\("===e?"\\)":null;if(n&&t.includes(e)){const t=r.indexOf(n,i+2);if(t>-1){s+=o(r.slice(i+2,t),"\\["===e,r.slice(i,t+2)),i=t+2;continue}}s+=e,i+=2;continue}if("$"===e)if("$"===r[i+1]&&t.includes("$$")){const e=r.indexOf("$$",i+2);if(e>-1){s+=o(r.slice(i+2,e),!0,r.slice(i,e+2)),i=e+2;continue}}else if(t.includes("$")&&r[i+1]&&!/\s/.test(r[i+1])){const e=c(r,i+1);if(e>-1){s+=o(r.slice(i+1,e),!1,r.slice(i,e+1)),i=e+1;continue}}s+=e,i++}return{text:s,math:n}}function c(e,t){for(let n=t;n<e.length;n++){const t=e[n];if("\\"!==t){if("`"===t)return-1;if("\n"===t&&/^\n[ \t]*\n/.test(e.slice(n)))return-1;if("$"===t&&!/\s/.test(e[n-1])&&!/\d/.test(e[n+1]??"")&&"$"!==e[n+1])return n}else n++}return-1}const i=e=>String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""),r=/^\s*([A-Za-zͰ-Ͽ](?:_\{?\w+\}?)?)\s*(?::=|=)\s*([^=<>≤≥]+)$/;function l(n,s,c){const{source:l,display:o}=n;try{const n=e(l,{...s.math,display:o,blocks:s.blocks,scope:c});return!1!==s.define&&function(e,n){const s=r.exec(e);if(!s||/\{\{/.test(s[2]))return;try{const e=t(s[2],n);"number"!=typeof e.value&&"bigint"!=typeof e.value||(n[s[1].replace(/[{}]/g,"")]=e.exact?e.text:e.value)}catch{}}(l,c),o?`<span class="mv-md-display">${n}</span>`:`<span class="mv-md-math">${n}</span>`}catch(e){return`<span class="mv-md-error" title="${i(e.message)}"><code>${i(n.raw)}</code></span>`}}const o=/^(https?:|mailto:|#|\/|\.{0,2}\/|[^:]*$)/i,a=e=>o.test(e.trim())?i(e.trim()):"#";function p(e,t,n){const s=[],c=e=>(s.push(e),`${s.length-1}`);let r=e;return r=r.replace(/(`+)([\s\S]*?[^`])\1(?!`)/g,(e,t,s)=>c(`<code>${i(n(s.trim()))}</code>`)),r=r.replace(/\\([\\`*_{}[\]()#+\-.!|~$<>"'])/g,(e,t)=>c(i(t))),r=r.replace(/<((?:https?:\/\/|mailto:)[^\s>]+)>/g,(e,t)=>c(`<a href="${a(t)}">${i(t)}</a>`)),t.html&&(r=r.replace(/<\/?[A-Za-z][^>]*>/g,e=>c(e))),r=r.replace(/!\[([^\]]*)\]\(\s*((?:[^\s()]|\([^\s()]*\))+)(?:\s+"([^"]*)")?\s*\)/g,(e,t,n,s)=>c(`<img src="${a(n)}" alt="${i(t)}"${s?` title="${i(s)}"`:""}>`)),r=r.replace(/\[([^\]]+)\]\(\s*((?:[^\s()]|\([^\s()]*\))+)(?:\s+"([^"]*)")?\s*\)/g,(e,s,r,l)=>c(`<a href="${a(r)}"${l?` title="${i(l)}"`:""}>${p(s,t,n)}</a>`)),r=i(r),r=r.replace(/(\*\*|__)(?=\S)([\s\S]*?\S)\1/g,"<strong>$2</strong>"),r=r.replace(/(^|[^*\w])\*(?=\S)([\s\S]*?\S)\*(?!\*)/g,"$1<em>$2</em>"),r=r.replace(/(^|[^_\w])_(?=\S)([\s\S]*?\S)_(?![_\w])/g,"$1<em>$2</em>"),r=r.replace(/~~(?=\S)([\s\S]*?\S)~~/g,"<del>$1</del>"),r=r.replace(/( {2,}|\\)\n/g,"<br>\n"),r.replace(/(\d+)/g,(e,t)=>s[Number(t)])}const h=/^( {0,3})(#{1,6}\s|>|```|~~~|([-*+]|\d{1,9}[.)])\s|(\*[ \t]*){3,}$|(-[ \t]*){3,}$|(_[ \t]*){3,}$)/,u=/^( {0,3})([-*+]|\d{1,9}[.)])(\s+|$)/,$=/^\s*\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?\s*$/;function g(e,t,n){const s=[];let c=0;const r=e=>p(e,t,n);for(;c<e.length;){const l=e[c];if(!l.trim()){c++;continue}const o=/^ {0,3}(`{3,}|~{3,})\s*([^\s`]*)/.exec(l);if(o){const t=[];for(c++;c<e.length&&!new RegExp(`^ {0,3}${"`"===o[1][0]?"`":"~"}{${o[1].length},}\\s*$`).test(e[c]);)t.push(e[c++]);c++;const r=o[2]?` class="language-${i(o[2])}"`:"";s.push(`<pre><code${r}>${i(n(t.join("\n")))}</code></pre>`);continue}const a=/^ {0,3}(#{1,6})\s+(.*?)\s*#*\s*$/.exec(l);if(a){s.push(`<h${a[1].length}>${r(a[2])}</h${a[1].length}>`),c++;continue}if(/^ {0,3}((\*[ \t]*){3,}|(-[ \t]*){3,}|(_[ \t]*){3,})$/.test(l)){s.push("<hr>"),c++;continue}if(/^ {0,3}>/.test(l)){const i=[];for(;c<e.length&&e[c].trim()&&(/^ {0,3}>/.test(e[c])||i.length);)i.push(e[c].replace(/^ {0,3}> ?/,"")),c++;s.push(`<blockquote>\n${g(i,t,n)}\n</blockquote>`);continue}const p=u.exec(l);if(p){const i=/\d/.test(p[2]),r=i?parseInt(p[2],10):1,l=[];let o=!1;for(;c<e.length;){const t=u.exec(e[c]);if(!t||/\d/.test(t[2])!==i)break;const n=t[0].length,s=[e[c].slice(n)];for(c++;c<e.length;){const t=e[c];if(!t.trim()){const t=e[c+1];if(void 0!==t&&t.startsWith(" ".repeat(Math.min(n,4)))&&t.trim()){s.push(""),o=!0,c++;continue}void 0!==t&&u.test(t)&&(o=!0);break}if(t.startsWith(" ".repeat(Math.min(n,4))))s.push(t.slice(Math.min(n,4)));else{if(u.test(t)||h.test(t))break;s.push(t)}c++}for(l.push(s);c<e.length&&!e[c].trim()&&void 0!==e[c+1]&&u.test(e[c+1]);)c++}const a=i?"ol":"ul",$=l.map(e=>{let s=g(e,t,n);return o||(s=s.replace(/^<p>([\s\S]*?)<\/p>/,"$1").replace(/\n<p>([\s\S]*?)<\/p>/g,"\n$1")),`<li>${s}</li>`});s.push(`<${a}${i&&1!==r?` start="${r}"`:""}>\n${$.join("\n")}\n</${a}>`);continue}if(l.includes("|")&&void 0!==e[c+1]&&$.test(e[c+1])&&e[c+1].includes("-")){const t=e=>e.trim().replace(/^\|/,"").replace(/\|$/,"").split(/(?<!\\)\|/).map(e=>e.trim()),n=t(e[c+1]).map(e=>e.startsWith(":")&&e.endsWith(":")?"center":e.endsWith(":")?"right":e.startsWith(":")?"left":""),i=(e,t,s)=>`<${e}${n[s]?` style="text-align:${n[s]}"`:""}>${r(t)}</${e}>`,o=t(l);c+=2;const a=[];for(;c<e.length&&e[c].trim()&&e[c].includes("|");)a.push(t(e[c++]));s.push(`<table>\n<thead><tr>${o.map((e,t)=>i("th",e,t)).join("")}</tr></thead>\n<tbody>\n${a.map(e=>`<tr>${o.map((t,n)=>i("td",e[n]??"",n)).join("")}</tr>`).join("\n")}\n</tbody>\n</table>`);continue}if(/^( {4}|\t)/.test(l)){const t=[];for(;c<e.length&&(/^( {4}|\t)/.test(e[c])||!e[c].trim());)t.push(e[c++].replace(/^( {4}|\t)/,""));for(;t.length&&!t[t.length-1].trim();)t.pop();s.push(`<pre><code>${i(n(t.join("\n")))}</code></pre>`);continue}const f=[];for(;c<e.length&&e[c].trim()&&(!f.length||!h.test(e[c])||/^ {0,3}[-=]+\s*$/.test(e[c]));){if(f.length&&/^ {0,3}(=+|-+)\s*$/.test(e[c])){const t="="===e[c].trim()[0]?1:2;s.push(`<h${t}>${r(f.join("\n"))}</h${t}>`),f.length=0,c++;break}f.push(e[c].replace(/^ {0,3}/,"")),c++}f.length&&s.push(`<p>${r(f.join("\n"))}</p>`)}return s.join("\n")}function f(e,t={},n=e=>e){return g(String(e).replace(/\r\n?/g,"\n").split("\n"),t,n)}function m(e,t={}){const{text:c,math:i}=s(e,t),r={...t.scope??{}},o=i.map(e=>l(e,t,r));return(t.render?t.render(c):f(c,t,e=>e.replace(n,(e,t)=>i[Number(t)].raw))).replace(new RegExp("<p>\\s*(\\d+)\\s*</p>","g"),(e,t)=>i[Number(t)].display?`<div class="mv-md-block">${o[Number(t)]}</div>`:e).replace(n,(e,t)=>o[Number(t)])}function d(e,t,n={}){return e.innerHTML=m(t,n),e}export{s as extractMath,m as markdownToHTML,f as renderMarkdown,d as renderMarkdownInto};
|
|
1
|
+
/* Inline Math 0.2.0 — MIT licence; includes mathzetta (and @mathzetta/cas, for the CAS) */
|
|
2
|
+
import{t as e,a as t}from"./chunks/html-CupluJSh.js";import{a as n}from"./chunks/calculate-Cz87Lt0N.js";import{v as s,o as r,r as a,u as i,s as o,E as l,b as u,n as d,i as p}from"./chunks/edit-M68aRA5o.js";export{V as Variables,c as createVariables}from"./chunks/edit-M68aRA5o.js";import{p as m,n as f,g as h,d as $}from"./chunks/lite-3Fb-OHbt.js";const g=new RegExp("(\\d+)","g");function v(e,{delimiters:t=["$$","$","\\[","\\("]}={}){const n=[];let s="",r=0;const a=String(e),i=e=>0===e||"\n"===a[e-1],o=(e,t,s)=>(n.push({source:e,display:t,raw:s,start:r,end:r+s.length}),`${n.length-1}`);for(;r<a.length;){if(i(r)){const e=/^( {0,3})(`{3,}|~{3,})([^\n]*)\n?/.exec(a.slice(r));if(e){const t=e[2],n=new RegExp(`\\n {0,3}${"`"===t[0]?"`":"~"}{${t.length},}[ \\t]*(?=\\n|$)`),i=a.slice(r+e[0].length),c=n.exec(`\n${i}`),l=c?i.slice(0,Math.max(0,c.index-1)):i,u=e[0].length+(c?c.index-1+c[0].length:i.length),d=a.slice(r,r+u);"math"===e[3].trim()?s+=o(l,!0,d):s+=d,r+=u;continue}}const e=a[r];if("`"===e){const e=/^`+/.exec(a.slice(r))[0],t=a.indexOf(e,r+e.length);if(t>-1){s+=a.slice(r,t+e.length),r=t+e.length;continue}s+=e,r+=e.length;continue}if("\\"===e){const e=a.slice(r,r+2),n="\\["===e?"\\]":"\\("===e?"\\)":null;if(n&&t.includes(e)){const t=a.indexOf(n,r+2);if(t>-1){s+=o(a.slice(r+2,t),"\\["===e,a.slice(r,t+2)),r=t+2;continue}}s+=e,r+=2;continue}if("$"===e)if("$"===a[r+1]&&t.includes("$$")){const e=a.indexOf("$$",r+2);if(e>-1){s+=o(a.slice(r+2,e),!0,a.slice(r,e+2)),r=e+2;continue}}else if(t.includes("$")&&a[r+1]&&!/\s/.test(a[r+1])){const e=b(a,r+1);if(e>-1){s+=o(a.slice(r+1,e),!1,a.slice(r,e+1)),r=e+1;continue}}s+=e,r++}return{text:s,math:n}}function b(e,t){for(let n=t;n<e.length;n++){const t=e[n];if("\\"!==t){if("`"===t)return-1;if("\n"===t&&/^\n[ \t]*\n/.test(e.slice(n)))return-1;if("$"===t&&!/\s/.test(e[n-1])&&!/\d/.test(e[n+1]??"")&&"$"!==e[n+1])return n}else n++}return-1}const x=e=>String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""),y=/^\s*([A-Za-z\u0370-\u03ff](?:_\{?\w+\}?)?)\s*=\s*([^=<>≤≥]+)$/;function k(s,r,a,i){const{text:c,math:m}=v(s,r),f=a?a.definitions(i):new Map,g=e=>a?a.textOf(e):e.text,b={...r.scope??{}},k={},w=new Map,S=new Set,j=[],E=()=>{for(const e of Object.keys(k))delete k[e];Object.assign(k,b);for(const e of f.keys())delete k[e];let e=[...f.values()];for(;e.length;){const t=e.filter(e=>{try{const t=n(g(e),k);if("number"==typeof t.value||"bigint"==typeof t.value||Array.isArray(t.value))return k[e.name]=t.exact?t.text:t.value,!1}catch{}return!0});if(t.length===e.length)break;e=t}const t={},s=_({});for(const e of f.keys()){const n=s(e);if(n)try{t[e]=h(o(n,t=>t===e?null:s(t)).tree)}catch{}}k[l]=t},_=t=>{const n=new Map;return s=>{const r=f.get(s);if(!r)return null;if(!n.has(s)){let a=null;try{a=e(g(r),t)}catch{}n.set(s,a)}return n.get(s)}};E();const M=m.map((s,a)=>{const{source:i,display:c}=s,l=c?"mv-md-display":"mv-md-math",m=(e,t="")=>`<span class="${l}${t}" data-mv-md="${a}">${e}</span>`;try{const l={...r.math,display:c,blocks:r.blocks,scope:k},h=function(t){let n=t.trim();const s=n.startsWith("_");s&&(n=n.slice(1).trimStart());let r=n.indexOf(":="),a=2;r<0&&s&&(r=n.search(/(?<![<>!≤≥=])=(?!=)/),a=1);const i=s?{error:"a hidden $_…$ saves a variable: $_A := 2+2$"}:null;if(r<=0)return i;const o=n.slice(0,r).trim(),c=n.slice(r+a).trim();let l=null;try{l=/\{\{/.test(o)?null:d(e(o))}catch{}return null!==l&&c?{hidden:s,lhs:o,name:l,rhs:c,input:p(c)}:i}(i);if(h&&h.error)throw new Error(h.error);if(h){const{name:n,input:r,hidden:i}=h,c=r?{name:n,text:r.default,input:r,key:`input:${JSON.stringify(r)}`}:{name:n,text:h.rhs,input:null,key:`expr:${h.rhs}`,start:s.start,end:s.end};let d="";if(r){const e=function(e,t){const{input:n,name:s}=e,r=`class="mv-md-input mv-md-${n.kind}" data-mv-var="${x(s)}" aria-label="${x(s)}"`;if("dropdown"===n.kind)return`<select ${r}>${n.options.map(e=>`<option value="${x(e)}"${e===t?" selected":""}>${x(e)}</option>`).join("")}</select>`;return"slider"===n.kind?`<input type="range" ${r} min="${n.min}" max="${n.max}" step="${n.step}" value="${x(t)}"><output class="mv-md-output" data-mv-out="${x(s)}">${x(t)}</output>`:`<input type="text" ${r} value="${x(t)}" size="${Math.max(4,t.length+1)}" spellcheck="false" autocomplete="off">`}(c,g(c));d=i?e:`${t(h.lhs,l)}<span class="mv-md-assign" aria-hidden="true">≔</span>${e}`,S.add(a)}else{const n=o(e(h.rhs,l),_(l)).tree;if(!i){const s=$({type:"op",op:"=",args:[u(e(h.lhs)),void 0===n.id?n:u(n)]});j[a]=s,d=function(e){return e.replace('<span class="mv-rel">=</span>','<span class="mv-rel mv-rel-def">≔</span>').replace(/(aria-label="[^"]*?) equals /,"$1 is defined as ").replace("<mo>=</mo>","<mo>≔</mo>")}(t(s,l))}}return f.delete(n),f.set(n,c),w.set(n,c),E(),i&&!r?"":m(d,r?" mv-md-input-def":"")}const{tree:v,changed:M}=o(e(i,l),_(l));M&&$(v),j[a]=v;const O=t(v,l);return!M&&!1!==r.define&&function(e,t,s){const r=y.exec(e);if(!r||/\{\{/.test(r[2]))return!1;const a=r[1].replace(/[{}]/g,"");if(s.has(a))return!1;try{const e=n(r[2],t);if("number"==typeof e.value||"bigint"==typeof e.value||Array.isArray(e.value))return t[a]=e.exact?e.text:e.value,!0}catch{}return!1}(i,b,f)&&E(),m(O)}catch(e){return`<span class="mv-md-error" data-mv-md="${a}" title="${x(e.message)}"><code>${x(s.raw)}</code></span>`}});return{text:c,math:m,drawn:M,defs:w,inputs:S,trees:j}}const w=/^(https?:|mailto:|#|\/|\.{0,2}\/|[^:]*$)/i,S=e=>w.test(e.trim())?x(e.trim()):"#";function j(e,t,n){const s=[],r=e=>(s.push(e),`${s.length-1}`);let a=e;return a=a.replace(/(`+)([\s\S]*?[^`])\1(?!`)/g,(e,t,s)=>r(`<code>${x(n(s.trim()))}</code>`)),a=a.replace(/\\([\\`*_{}[\]()#+\-.!|~$<>"'])/g,(e,t)=>r(x(t))),a=a.replace(/<((?:https?:\/\/|mailto:)[^\s>]+)>/g,(e,t)=>r(`<a href="${S(t)}">${x(t)}</a>`)),t.html&&(a=a.replace(/<\/?[A-Za-z][^>]*>/g,e=>r(e))),a=a.replace(/!\[([^\]]*)\]\(\s*((?:[^\s()]|\([^\s()]*\))+)(?:\s+"([^"]*)")?\s*\)/g,(e,t,n,s)=>r(`<img src="${S(n)}" alt="${x(t)}"${s?` title="${x(s)}"`:""}>`)),a=a.replace(/\[([^\]]+)\]\(\s*((?:[^\s()]|\([^\s()]*\))+)(?:\s+"([^"]*)")?\s*\)/g,(e,s,a,i)=>r(`<a href="${S(a)}"${i?` title="${x(i)}"`:""}>${j(s,t,n)}</a>`)),a=x(a),a=a.replace(/(\*\*|__)(?=\S)([\s\S]*?\S)\1/g,"<strong>$2</strong>"),a=a.replace(/(^|[^*\w])\*(?=\S)([\s\S]*?\S)\*(?!\*)/g,"$1<em>$2</em>"),a=a.replace(/(^|[^_\w])_(?=\S)([\s\S]*?\S)_(?![_\w])/g,"$1<em>$2</em>"),a=a.replace(/~~(?=\S)([\s\S]*?\S)~~/g,"<del>$1</del>"),a=a.replace(/( {2,}|\\)\n/g,"<br>\n"),a.replace(/(\d+)/g,(e,t)=>s[Number(t)])}const E=/^( {0,3})(#{1,6}\s|>|```|~~~|([-*+]|\d{1,9}[.)])\s|(\*[ \t]*){3,}$|(-[ \t]*){3,}$|(_[ \t]*){3,}$)/,_=/^( {0,3})([-*+]|\d{1,9}[.)])(\s+|$)/,M=/^\s*\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?\s*$/;function O(e,t,n){const s=[];let r=0;const a=e=>j(e,t,n);for(;r<e.length;){const i=e[r];if(!i.trim()){r++;continue}const o=/^ {0,3}(`{3,}|~{3,})\s*([^\s`]*)/.exec(i);if(o){const t=[];for(r++;r<e.length&&!new RegExp(`^ {0,3}${"`"===o[1][0]?"`":"~"}{${o[1].length},}\\s*$`).test(e[r]);)t.push(e[r++]);r++;const a=o[2]?` class="language-${x(o[2])}"`:"";s.push(`<pre><code${a}>${x(n(t.join("\n")))}</code></pre>`);continue}const c=/^ {0,3}(#{1,6})\s+(.*?)\s*#*\s*$/.exec(i);if(c){s.push(`<h${c[1].length}>${a(c[2])}</h${c[1].length}>`),r++;continue}if(/^ {0,3}((\*[ \t]*){3,}|(-[ \t]*){3,}|(_[ \t]*){3,})$/.test(i)){s.push("<hr>"),r++;continue}if(/^ {0,3}>/.test(i)){const a=[];for(;r<e.length&&e[r].trim()&&(/^ {0,3}>/.test(e[r])||a.length);)a.push(e[r].replace(/^ {0,3}> ?/,"")),r++;s.push(`<blockquote>\n${O(a,t,n)}\n</blockquote>`);continue}const l=_.exec(i);if(l){const a=/\d/.test(l[2]),i=a?parseInt(l[2],10):1,o=[];let c=!1;for(;r<e.length;){const t=_.exec(e[r]);if(!t||/\d/.test(t[2])!==a)break;const n=t[0].length,s=[e[r].slice(n)];for(r++;r<e.length;){const t=e[r];if(!t.trim()){const t=e[r+1];if(void 0!==t&&t.startsWith(" ".repeat(Math.min(n,4)))&&t.trim()){s.push(""),c=!0,r++;continue}void 0!==t&&_.test(t)&&(c=!0);break}if(t.startsWith(" ".repeat(Math.min(n,4))))s.push(t.slice(Math.min(n,4)));else{if(_.test(t)||E.test(t))break;s.push(t)}r++}for(o.push(s);r<e.length&&!e[r].trim()&&void 0!==e[r+1]&&_.test(e[r+1]);)r++}const u=a?"ol":"ul",d=o.map(e=>{let s=O(e,t,n);return c||(s=s.replace(/^<p>([\s\S]*?)<\/p>/,"$1").replace(/\n<p>([\s\S]*?)<\/p>/g,"\n$1")),`<li>${s}</li>`});s.push(`<${u}${a&&1!==i?` start="${i}"`:""}>\n${d.join("\n")}\n</${u}>`);continue}if(i.includes("|")&&void 0!==e[r+1]&&M.test(e[r+1])&&e[r+1].includes("-")){const t=e=>e.trim().replace(/^\|/,"").replace(/\|$/,"").split(/(?<!\\)\|/).map(e=>e.trim()),n=t(e[r+1]).map(e=>e.startsWith(":")&&e.endsWith(":")?"center":e.endsWith(":")?"right":e.startsWith(":")?"left":""),o=(e,t,s)=>`<${e}${n[s]?` style="text-align:${n[s]}"`:""}>${a(t)}</${e}>`,c=t(i);r+=2;const l=[];for(;r<e.length&&e[r].trim()&&e[r].includes("|");)l.push(t(e[r++]));s.push(`<table>\n<thead><tr>${c.map((e,t)=>o("th",e,t)).join("")}</tr></thead>\n<tbody>\n${l.map(e=>`<tr>${c.map((t,n)=>o("td",e[n]??"",n)).join("")}</tr>`).join("\n")}\n</tbody>\n</table>`);continue}if(/^( {4}|\t)/.test(i)){const t=[];for(;r<e.length&&(/^( {4}|\t)/.test(e[r])||!e[r].trim());)t.push(e[r++].replace(/^( {4}|\t)/,""));for(;t.length&&!t[t.length-1].trim();)t.pop();s.push(`<pre><code>${x(n(t.join("\n")))}</code></pre>`);continue}const u=[];for(;r<e.length&&e[r].trim()&&(!u.length||!E.test(e[r])||/^ {0,3}[-=]+\s*$/.test(e[r]));){if(u.length&&/^ {0,3}(=+|-+)\s*$/.test(e[r])){const t="="===e[r].trim()[0]?1:2;s.push(`<h${t}>${a(u.join("\n"))}</h${t}>`),u.length=0,r++;break}u.push(e[r].replace(/^ {0,3}/,"")),r++}u.length&&s.push(`<p>${a(u.join("\n"))}</p>`)}return s.join("\n")}function A(e,t={},n=e=>e){return O(String(e).replace(/\r\n?/g,"\n").split("\n"),t,n)}function N({text:e,math:t,drawn:n},s){return(s.render?s.render(e):A(e,s,e=>e.replace(g,(e,n)=>t[Number(n)].raw))).replace(new RegExp("<p>\\s*(\\d+)\\s*</p>","g"),(e,s)=>t[Number(s)].display&&n[Number(s)]?`<div class="mv-md-block">${n[Number(s)]}</div>`:e).replace(g,(e,t)=>n[Number(t)]).replace(/<p>\s*<\/p>\n?/g,"")}function L(e,t={}){return N(k(e,t,t.variables||null),t)}const W=new WeakMap,q=new Set;function C(){for(const e of q)e.connected()&&!e.element.isConnected&&e.stop(!0)}function R(t,n,o={}){const c=void 0===o.variables?s:o.variables||null;C();const l=W.get(t);l&&l.stop(l.store!==c);let u=k(n,o,c,t);if(t.innerHTML=N(u,o),!c)return W.delete(t),t;c.own(t,u.defs);let d=t.isConnected;const p=n=>{const s=n.target,r=s&&s.dataset&&s.dataset.mvVar;if(void 0!==r&&t.contains(s)){if("text"===s.type)try{e(s.value,{blocks:o.blocks,scope:{}}),s.removeAttribute("aria-invalid")}catch{return void s.setAttribute("aria-invalid","true")}c.set(r,s.value)}},h=s=>{const l=s.target.closest?.("[data-node]"),d=l&&l.closest("[data-mv-md]");if(!d||!t.contains(d))return;const p=Number(d.dataset.mvMd),h=u.trees[p];if(!h)return;const $=Number(l.dataset.node),g=m(h,$)||[];let v=null;for(let e=g.length;e>=0&&!v;e--){const t=f(h,g.slice(0,e));t&&void 0!==t.from&&(v={node:t,depth:e})}const b=v&&c.definitions().get(v.node.from);if(b&&b.input&&"textbox"===b.input.kind){s.preventDefault();const n=b.name,u=t.ownerDocument.querySelector(`[data-mv-var="${CSS.escape(n)}"]`),d=o.editable&&o.editable.toText;if(!d)return void(u&&(u.focus(),u.select()));const p=t=>e(t),m=f(h,g);return void r(l,d(i(m,p)),{label:`Edit ${n}`,parse:t=>e(t,{blocks:o.blocks}),commit:e=>{const t=a(i(v.node,p),g.slice(v.depth),e);c.set(n,d(t))}})}const x=b&&u.defs.get(b.name),y=x&&x.key===b.key&&void 0!==x.start?{...u.math[p],start:x.start,end:x.end,raw:n.slice(x.start,x.end)}:u.math[p];t.dispatchEvent(new CustomEvent("inlinemath:select",{bubbles:!0,detail:{index:p,start:y.start,end:y.end,raw:y.raw,source:y.source,id:$,path:g}}))};t.addEventListener("input",p),t.addEventListener("change",p),t.addEventListener("dblclick",h);const $=c.subscribe(e=>{e!==t&&(t.isConnected?(d=!0,C(),(()=>{const e=k(n,o,c,t);e.drawn.forEach((n,s)=>{if(n===u.drawn[s]||e.inputs.has(s))return;const r=t.querySelector(`[data-mv-md="${s}"]`);r&&(r.outerHTML=n)});for(const n of t.querySelectorAll("[data-mv-var], [data-mv-out]")){const t=e.defs.get(n.dataset.mvVar??n.dataset.mvOut);if(!t)continue;const s=c.textOf(t);void 0!==n.dataset.mvOut?n.textContent=s:n.value!==s&&n!==n.ownerDocument?.activeElement&&(n.value=s)}u=e})()):d&&g(!0))});function g(e){$(),t.removeEventListener("input",p),t.removeEventListener("change",p),t.removeEventListener("dblclick",h),q.delete(v),W.delete(t),e&&c.own(t,null)}const v={element:t,store:c,stop:g,connected:()=>d};return q.add(v),W.set(t,v),t}export{v as extractMath,L as markdownToHTML,A as renderMarkdown,R as renderMarkdownInto,s as variables};
|
package/inlinemath.css
CHANGED
|
@@ -98,19 +98,42 @@ span.mv-delim { width: 0.16em; border: 0 solid currentColor; box-sizing: border-
|
|
|
98
98
|
/* ---- piecewise ------------------------------------------------------------- */
|
|
99
99
|
.mv-cases { display: inline-grid; grid-template-columns: auto auto; column-gap: 1em; row-gap: 0.25em; align-items: baseline; text-align: left; margin: 0 0.1em; }
|
|
100
100
|
.mv-case-value, .mv-case-cond { display: block; }
|
|
101
|
+
.mv-matrix { display: inline-grid; column-gap: 0.8em; row-gap: 0.3em; align-items: baseline; justify-items: center; margin: 0 0.15em; }
|
|
102
|
+
.mv-matrix-row { display: contents; }
|
|
103
|
+
.mv-matrix-cell { display: block; }
|
|
101
104
|
|
|
102
105
|
/* ---- decorations: \boxed \cancel \overline \vec … --------------------------- */
|
|
103
106
|
.mv-boxed { display: inline-block; border: 0.06em solid currentColor; padding: 0.16em 0.2em; }
|
|
104
107
|
.mv-over { display: inline-block; border-top: 0.06em solid currentColor; padding-top: 0.08em; }
|
|
105
108
|
.mv-underline { display: inline-block; border-bottom: 0.06em solid currentColor; padding-bottom: 0.06em; }
|
|
106
|
-
.mv-cancel { display: inline-block;
|
|
109
|
+
.mv-cancel { display: inline-block; position: relative; }
|
|
110
|
+
.mv-cancel-line { position: absolute; left: 0; top: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
|
|
107
111
|
.mv-accent { display: inline-block; position: relative; padding-top: 0.3em; }
|
|
108
112
|
.mv-accent-mark { position: absolute; top: 0; left: 0; right: 0; text-align: center; font-size: 0.7em; line-height: 0.6; }
|
|
109
113
|
|
|
110
114
|
/* ---- interaction -------------------------------------------------------------- */
|
|
111
115
|
.mv-hl { background: var(--mv-hl, rgba(255, 200, 0, 0.35)); box-shadow: 0 0 0 0.08em var(--mv-hl, rgba(255, 200, 0, 0.35)); }
|
|
116
|
+
/* Windows high contrast (and other forced colours) drops backgrounds and shadows: outline a highlight instead */
|
|
117
|
+
@media (forced-colors: active) {
|
|
118
|
+
.mv-hl { outline: 0.08em solid Highlight; outline-offset: 0.04em; }
|
|
119
|
+
}
|
|
112
120
|
.mv-clickable .mv-n { cursor: pointer; }
|
|
121
|
+
.mv-editable .mv-n:hover { outline: 1px dashed rgba(0, 0, 0, 0.25); }
|
|
122
|
+
/* the box editing a part in place (view.editable, or a Markdown textbox variable) */
|
|
123
|
+
.mv-edit { transform: translateY(-50%); z-index: 1000; box-sizing: content-box; padding: 0.1em 0.35em; font-family: inherit;
|
|
124
|
+
border: 1px solid #1a5fb4; border-radius: 0.25em; background: #fff; color: #111; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18); }
|
|
125
|
+
.mv-edit[aria-invalid="true"] { border-color: #c33; outline: 2px solid #c33; }
|
|
126
|
+
/* the live region a view announces steps through ({ announce: true }): read, never seen */
|
|
127
|
+
.mv-sr-only, .mv-sr-math { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
|
|
113
128
|
.mv-clickable .mv-n:hover { outline: 1px dashed rgba(0, 0, 0, 0.25); }
|
|
129
|
+
/* the keyboard: the expression is one tab stop, and the part the arrow keys are on is ringed */
|
|
130
|
+
.mv[tabindex]:focus-visible { outline: 0.1em solid #1a5fb4; outline-offset: 0.12em; }
|
|
131
|
+
.mv[tabindex]:focus .mv-focus { outline: 0.1em solid #1a5fb4; outline-offset: 0.06em; border-radius: 0.1em; }
|
|
132
|
+
/* while a part is ringed, the whole expression's ring steps back so the part is the one that stands out */
|
|
133
|
+
.mv[tabindex]:focus-visible:has(.mv-focus) { outline: 1px dashed #1a5fb4; }
|
|
134
|
+
@media (forced-colors: active) {
|
|
135
|
+
.mv[tabindex]:focus-visible, .mv[tabindex]:focus .mv-focus { outline-color: Highlight; }
|
|
136
|
+
}
|
|
114
137
|
|
|
115
138
|
/* ---- steps (stepsHTML from '@mathzetta/inlinemath/cas') ---------------------------------------- */
|
|
116
139
|
.mv-steps { margin: 0; padding-left: 1.6em; }
|
|
@@ -125,3 +148,11 @@ span.mv-delim { width: 0.16em; border: 0 solid currentColor; box-sizing: border-
|
|
|
125
148
|
.mv-md-display { display: block; text-align: center; margin: 0.6em 0; overflow-x: auto; }
|
|
126
149
|
.mv-md-block { margin: 0.8em 0; }
|
|
127
150
|
.mv-md-error code { background: rgba(200, 60, 0, 0.08); color: #a33; border-bottom: 1px dotted #a33; }
|
|
151
|
+
/* saved variables: $A := 2+2$ draws A ≔ 2 + 2; $A := [[…]]$ an input that sets A */
|
|
152
|
+
.mv-md-input-def { display: inline-flex; align-items: center; gap: 0.3em; }
|
|
153
|
+
.mv-md-assign { margin: 0 0.1em; }
|
|
154
|
+
.mv-md-input { font: inherit; font-size: 0.9em; }
|
|
155
|
+
input.mv-md-textbox { font-family: inherit; padding: 0.05em 0.3em; field-sizing: content; min-width: 3ch; }
|
|
156
|
+
input.mv-md-textbox[aria-invalid="true"] { outline: 2px solid #c33; outline-offset: 1px; }
|
|
157
|
+
input.mv-md-slider { vertical-align: middle; }
|
|
158
|
+
.mv-md-output { font-variant-numeric: tabular-nums; min-width: 2ch; }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mathzetta/inlinemath",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Draw calculus-level maths as HTML and CSS from anything MathZetta reads, with every part addressable.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"@mathzetta/cas": "^0.1.0",
|
|
50
|
-
"mathzetta": "^1.
|
|
50
|
+
"mathzetta": "^1.1.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@rollup/plugin-terser": "^0.4.4",
|
|
54
54
|
"@mathzetta/cas": "^0.1.0",
|
|
55
|
-
"mathzetta": "^1.
|
|
55
|
+
"mathzetta": "^1.1.0",
|
|
56
56
|
"rollup": "^4.65.0"
|
|
57
57
|
},
|
|
58
58
|
"license": "MIT",
|
package/src/cas.js
CHANGED
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
* toHTML('{{solve(x^2 - 5x + 6 = 0, x)}}', { blocks: casBlocks() }) // x = 2 or x = 3
|
|
10
10
|
* stepsHTML(mathCAS().diff('x^2 sin x', 'x', { steps: 'brief' }).steps)
|
|
11
11
|
*
|
|
12
|
-
* Block functions: simplify, expand, factor, cancel, diff(f, x[, n])
|
|
13
|
-
* solve(equation, x), approx(expr[, digits]);
|
|
14
|
-
* too.
|
|
12
|
+
* Block functions: simplify, expand, factor, cancel, diff(f, x[, n]) (or der, derivative,
|
|
13
|
+
* differentiate), integrate(f, x[, a, b]) (or integral), solve(equation, x), approx(expr[, digits]);
|
|
14
|
+
* d/dx … and ∫ … without limits go to the CAS too. In Markdown, saved variables ($_f := x^3$)
|
|
15
|
+
* stand for their expressions: {{diff(f, x)}}. Everything else is MathZetta's calculator (calculateBlock), as without this.
|
|
15
16
|
*
|
|
16
17
|
* Needs @mathzetta/cas (a peer dependency, like mathzetta).
|
|
17
18
|
*/
|
|
@@ -24,6 +25,8 @@ import { calculateBlock } from './calculator.js';
|
|
|
24
25
|
import { toText } from 'mathzetta/text';
|
|
25
26
|
import { toHTML } from './html.js';
|
|
26
27
|
|
|
28
|
+
const EXPRESSIONS = Symbol.for('inlinemath.expressions'); // as variables.js
|
|
29
|
+
|
|
27
30
|
const shared = new Map();
|
|
28
31
|
|
|
29
32
|
/** How the complex functions are written for MathZetta: Re z, Im z, z̄ (an overline), arg z. */
|
|
@@ -69,13 +72,17 @@ export function mathCAS(options = {}) {
|
|
|
69
72
|
}
|
|
70
73
|
|
|
71
74
|
const CALLS = new Set(['simplify', 'expand', 'factor', 'cancel', 'diff', 'integrate', 'solve', 'approx']);
|
|
75
|
+
// other names people write for them
|
|
76
|
+
const ALIASES = { integral: 'integrate', differentiate: 'diff', approximate: 'approx', simp: 'simplify' };
|
|
72
77
|
|
|
73
78
|
/**
|
|
74
79
|
* A `{{…}}` handler: pass it as toHTML(input, { blocks: casBlocks() }).
|
|
75
|
-
* @param {object} [options] { cas } a CAS of your own (mathCAS({ rules }))
|
|
80
|
+
* @param {object} [options] { cas } a CAS of your own (mathCAS({ rules })); { steps } how much working each call
|
|
81
|
+
* keeps (the CAS's steps option: true, 'brief', false), read from the handler's `last` after a block
|
|
76
82
|
*/
|
|
77
83
|
export function casBlocks(options = {}) {
|
|
78
84
|
const cas = options.cas ?? mathCAS();
|
|
85
|
+
const how = options.steps === undefined ? {} : { steps: options.steps };
|
|
79
86
|
const handler = (text, scope) => {
|
|
80
87
|
let tokens;
|
|
81
88
|
try {
|
|
@@ -83,8 +90,11 @@ export function casBlocks(options = {}) {
|
|
|
83
90
|
} catch {
|
|
84
91
|
return calculateBlock(text, scope);
|
|
85
92
|
}
|
|
93
|
+
// saved variables ($_f := x^3$ in Markdown) stand for their expressions: {{diff(f, x)}}
|
|
94
|
+
const saved = scope && scope[EXPRESSIONS];
|
|
95
|
+
if (saved) tokens = tokens.flatMap((t) => (Object.hasOwn(saved, t) ? saved[t] : [t]));
|
|
86
96
|
const head = tokens[tokens.length - 1];
|
|
87
|
-
const name = head?.startsWith('\\:') ? head.slice(2) : null;
|
|
97
|
+
const name = head?.startsWith('\\:') ? (ALIASES[head.slice(2)] ?? head.slice(2)) : null;
|
|
88
98
|
const symbolic = name && CALLS.has(name);
|
|
89
99
|
// d/dx …, ∫ … dx and ∫ from a to b … dx (MathZetta writes the limits as int's 3rd and 4th operands)
|
|
90
100
|
const calculus = head === 'der' || head === 'int';
|
|
@@ -95,16 +105,16 @@ export function casBlocks(options = {}) {
|
|
|
95
105
|
let r;
|
|
96
106
|
try {
|
|
97
107
|
switch (symbolic ? name : head === 'der' ? 'derivative' : 'antiderivative') {
|
|
98
|
-
case 'simplify': r = cas.simplify(args[0]); break;
|
|
99
|
-
case 'expand': r = cas.expand(args[0]); break;
|
|
100
|
-
case 'factor': r = cas.factor(args[0]); break;
|
|
101
|
-
case 'cancel': r = cas.cancel(args[0]); break;
|
|
102
|
-
case 'diff': r = cas.diff(args[0], word(args[1]), { order: args[2] ? Number(args[2].s) : 1 }); break;
|
|
103
|
-
case 'integrate': r = cas.integrate(args[0], word(args[1]), args[3] ? { from: args[2].s, to: args[3].s } : {}); break;
|
|
104
|
-
case 'solve': r = cas.solve(args[0], word(args[1])); break;
|
|
105
|
-
case 'approx': r = cas.approximate(args[0], { digits: args[1] ? Number(args[1].s) : 15 }); break;
|
|
106
|
-
case 'derivative': r = cas.diff(node.args[0], node.args[1].s); break;
|
|
107
|
-
default: r = cas.integrate(node); break;
|
|
108
|
+
case 'simplify': r = cas.simplify(args[0], how); break;
|
|
109
|
+
case 'expand': r = cas.expand(args[0], how); break;
|
|
110
|
+
case 'factor': r = cas.factor(args[0], how); break;
|
|
111
|
+
case 'cancel': r = cas.cancel(args[0], how); break;
|
|
112
|
+
case 'diff': r = cas.diff(args[0], word(args[1]), { ...how, order: args[2] ? Number(args[2].s) : 1 }); break;
|
|
113
|
+
case 'integrate': r = cas.integrate(args[0], word(args[1]), { ...how, ...(args[3] ? { from: args[2].s, to: args[3].s } : {}) }); break;
|
|
114
|
+
case 'solve': r = cas.solve(args[0], word(args[1]), how); break;
|
|
115
|
+
case 'approx': r = cas.approximate(args[0], { ...how, digits: args[1] ? Number(args[1].s) : 15 }); break;
|
|
116
|
+
case 'derivative': r = cas.diff(node.args[0], node.args[1].s, how); break;
|
|
117
|
+
default: r = cas.integrate(node, undefined, how); break;
|
|
108
118
|
}
|
|
109
119
|
} catch (error) {
|
|
110
120
|
// no answer: leave it as written, as calculateBlock does
|
package/src/edit.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Editing a part of a drawn expression in place: a text box opens over the part, holding the
|
|
3
|
+
* part as text; Enter puts what was typed back into the expression, Escape (or leaving it with
|
|
4
|
+
* something that doesn't read) changes nothing. Used by View.editable() and by the Markdown
|
|
5
|
+
* pages' textbox variables.
|
|
6
|
+
*
|
|
7
|
+
* The part is written as text by MathZetta's toText, which the caller passes in (import it
|
|
8
|
+
* from 'mathzetta/text'): Inline Math's core imports only 'mathzetta', 'mathzetta/speech' and
|
|
9
|
+
* 'mathzetta/calculate', so a buildless page's import map stays the same.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { bare } from './variables.js';
|
|
13
|
+
|
|
14
|
+
/** A copy of `tree` (ids dropped) with the node at `path` replaced by `part`. */
|
|
15
|
+
export function replaceAt(tree, path, part) {
|
|
16
|
+
const visit = (n, k) => (k === path.length
|
|
17
|
+
? part
|
|
18
|
+
: { ...n, args: n.args.map((a, j) => (j === path[k] ? visit(a, k + 1) : a)) });
|
|
19
|
+
return bare(visit(tree, 0));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Open a text box over `element` holding `text`.
|
|
24
|
+
* @param {Element} element the drawn part
|
|
25
|
+
* @param {string} text what the box starts with
|
|
26
|
+
* @param {object} how
|
|
27
|
+
* @param {(text: string) => object} how.parse the typed text → a tree (throws if it doesn't read)
|
|
28
|
+
* @param {(tree: object, text: string) => void} how.commit called with the new part
|
|
29
|
+
* @param {() => void} [how.cancel] called when nothing changed
|
|
30
|
+
* @param {string} [how.label] the box's accessible name
|
|
31
|
+
* @returns {HTMLInputElement|null}
|
|
32
|
+
*/
|
|
33
|
+
export function openEditor(element, text, { parse, commit, cancel, label = 'Edit' }) {
|
|
34
|
+
const doc = element.ownerDocument;
|
|
35
|
+
if (!doc || !doc.body) return null;
|
|
36
|
+
const view = doc.defaultView;
|
|
37
|
+
const r = element.getBoundingClientRect();
|
|
38
|
+
const input = doc.createElement('input');
|
|
39
|
+
input.type = 'text';
|
|
40
|
+
input.className = 'mv-edit';
|
|
41
|
+
input.value = text;
|
|
42
|
+
input.spellcheck = false;
|
|
43
|
+
input.autocomplete = 'off';
|
|
44
|
+
input.setAttribute('aria-label', label);
|
|
45
|
+
const fit = () => { input.style.width = `${Math.max(4, input.value.length + 2)}ch`; };
|
|
46
|
+
const font = view.getComputedStyle(element);
|
|
47
|
+
Object.assign(input.style, {
|
|
48
|
+
position: 'absolute',
|
|
49
|
+
left: `${r.left + view.scrollX}px`,
|
|
50
|
+
top: `${r.top + view.scrollY + r.height / 2}px`,
|
|
51
|
+
minWidth: `${Math.max(r.width, 32)}px`,
|
|
52
|
+
fontSize: font.fontSize,
|
|
53
|
+
});
|
|
54
|
+
fit();
|
|
55
|
+
doc.body.appendChild(input);
|
|
56
|
+
view.getSelection?.()?.removeAllRanges(); // the double-click selected a word of the page
|
|
57
|
+
input.focus();
|
|
58
|
+
input.select();
|
|
59
|
+
|
|
60
|
+
let done = false;
|
|
61
|
+
const close = () => {
|
|
62
|
+
done = true;
|
|
63
|
+
input.remove();
|
|
64
|
+
};
|
|
65
|
+
const finish = (keep) => {
|
|
66
|
+
if (done) return true;
|
|
67
|
+
if (!keep || input.value === text) {
|
|
68
|
+
close();
|
|
69
|
+
if (cancel) cancel();
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
let tree;
|
|
73
|
+
try {
|
|
74
|
+
tree = parse(input.value);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
input.setAttribute('aria-invalid', 'true');
|
|
77
|
+
input.title = error.message;
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
close();
|
|
81
|
+
commit(tree, input.value);
|
|
82
|
+
return true;
|
|
83
|
+
};
|
|
84
|
+
input.addEventListener('keydown', (event) => {
|
|
85
|
+
event.stopPropagation(); // the view's arrow keys are not for the box
|
|
86
|
+
if (event.key === 'Enter') { event.preventDefault(); finish(true); }
|
|
87
|
+
if (event.key === 'Escape') { event.preventDefault(); finish(false); }
|
|
88
|
+
});
|
|
89
|
+
input.addEventListener('input', () => {
|
|
90
|
+
fit();
|
|
91
|
+
input.removeAttribute('aria-invalid');
|
|
92
|
+
input.removeAttribute('title');
|
|
93
|
+
});
|
|
94
|
+
input.addEventListener('blur', () => { if (!finish(true)) finish(false); });
|
|
95
|
+
return input;
|
|
96
|
+
}
|
package/src/glyphs.js
CHANGED
|
@@ -18,6 +18,8 @@ export const PATHS = {
|
|
|
18
18
|
'}': { fill: 'M0,0 C0.55,0 0.5,0.05 0.5,0.2 L0.5,0.38 C0.5,0.46 0.65,0.49 0.95,0.5 C0.65,0.51 0.5,0.54 0.5,0.62 L0.5,0.8 C0.5,0.95 0.55,1 0,1 L0,0.985 C0.32,0.985 0.36,0.95 0.36,0.8 L0.36,0.62 C0.36,0.53 0.45,0.505 0.7,0.5 C0.45,0.495 0.36,0.47 0.36,0.38 L0.36,0.2 C0.36,0.05 0.32,0.015 0,0.015 Z' },
|
|
19
19
|
// Radical: short tick, long down-stroke, long up-stroke to the top right.
|
|
20
20
|
'sqrt': { stroke: 'M0,0.62 L0.18,0.55 L0.45,0.97 L0.98,0.015' },
|
|
21
|
+
// \cancel: one stroke, bottom left to top right, stretched over what it crosses out.
|
|
22
|
+
'cancel': { stroke: 'M0,1 L1,0' },
|
|
21
23
|
// Integral: an S slanted to the right with small hooks at each end.
|
|
22
24
|
'int': { stroke: 'M0.95,0.09 C0.9,0.01 0.72,0 0.66,0.12 C0.6,0.25 0.42,0.75 0.34,0.88 C0.28,0.99 0.1,0.99 0.05,0.91' },
|
|
23
25
|
'sum': { fill: 'M0.04,0 L0.94,0 L0.98,0.24 L0.94,0.24 C0.9,0.1 0.8,0.07 0.62,0.07 L0.24,0.07 L0.58,0.5 L0.2,0.93 L0.64,0.93 C0.82,0.93 0.92,0.9 0.95,0.76 L0.99,0.76 L0.94,1 L0.02,1 L0.47,0.47 Z' },
|
package/src/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// '@mathzetta/inlinemath' — drawing, the live view, selection. See types.d.ts.
|
|
2
|
-
export type { Input, Node, Target, LayoutOptions, DrawOptions, ClickInfo } from './types.js';
|
|
3
|
-
export { toHTML, treeOf, layout, DEFAULTS, View, render, select, signature, nodeAt, pathOf, numberTree, PATHS } from './types.js';
|
|
2
|
+
export type { Input, Node, Target, LayoutOptions, DrawOptions, ViewOptions, ClickInfo } from './types.js';
|
|
3
|
+
export { toHTML, treeOf, layout, DEFAULTS, View, render, shouldAnimate, select, signature, nodeAt, pathOf, numberTree, PATHS } from './types.js';
|
package/src/index.js
CHANGED
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
|
|
13
13
|
export { toHTML, treeOf } from './html.js';
|
|
14
14
|
export { layout, DEFAULTS } from './layout.js';
|
|
15
|
-
export { View, render } from './view.js';
|
|
15
|
+
export { View, render, shouldAnimate } from './view.js';
|
|
16
16
|
export { select, signature, nodeAt, pathOf, numberTree } from './select.js';
|
|
17
17
|
export { PATHS } from './glyphs.js';
|
package/src/layout.js
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
import {
|
|
22
22
|
GREEK, needsBrackets, unaryNeedsBrackets, isMinusOneTimes, isImplicitProduct, isVariable,
|
|
23
23
|
firstLeaf, customName, derivativeOrder, bracketedSides, bracketOp, firstVariable,
|
|
24
|
-
isCustomFunction, precedenceOf,
|
|
24
|
+
isCustomFunction, precedenceOf, toAudioSpeech, MATRICES, matrixRows,
|
|
25
25
|
} from './mathzetta.js';
|
|
26
26
|
import { svg } from './glyphs.js';
|
|
27
27
|
|
|
@@ -42,6 +42,7 @@ const OP_CLASS = {
|
|
|
42
42
|
'&': 'and', '|': 'or', '\\not': 'not', '\\xor': 'xor', '\\nand': 'nand', '\\nor': 'nor', '?:': 'cases',
|
|
43
43
|
'()': 'tuple', '[]': 'list', '{}': 'set', '(]': 'interval', '[)': 'interval',
|
|
44
44
|
'\\sumidx': 'sum', '\\prodidx': 'prod', 'mod': 'mod', 'pmod': 'pmod',
|
|
45
|
+
pmatrix: 'matrix', bmatrix: 'matrix', vmatrix: 'matrix',
|
|
45
46
|
};
|
|
46
47
|
|
|
47
48
|
const RELATIONS = {
|
|
@@ -54,7 +55,7 @@ const BINARY = { '±': '±', '∪': '∪', '∩': '∩', 'mod': 'mod' };
|
|
|
54
55
|
const TRIG = ['sin', 'cos', 'tan', 'csc', 'sec', 'cot', 'sinh', 'cosh', 'tanh'];
|
|
55
56
|
const INVERSE = { arcsin: 'sin', arccos: 'cos', arctan: 'tan', arcsinh: 'sinh', arccosh: 'cosh', arctanh: 'tanh' };
|
|
56
57
|
/** Functions written with a name and, when the argument is simple, no brackets: sin x, ln x. */
|
|
57
|
-
const NAMED = [...TRIG, ...Object.keys(INVERSE), 'ln'];
|
|
58
|
+
const NAMED = [...TRIG, ...Object.keys(INVERSE), 'ln', 'det'];
|
|
58
59
|
/** Functions always written with brackets: max(a, b). */
|
|
59
60
|
const CALLS = { atan2: 'atan2', max: 'max', min: 'min', gcd: 'gcd', mean: 'mean', round: 'round', fixed: 'fixed', expm1: 'expm1', random: 'random' };
|
|
60
61
|
|
|
@@ -74,7 +75,8 @@ export const DEFAULTS = {
|
|
|
74
75
|
derivativeBrackets: '[', // d/dx [x² + 1], or '(' for d/dx (x² + 1)
|
|
75
76
|
scriptFractions: 'slash',// x^{1/2} written x^{1/2} with a slash; 'stack' stacks it
|
|
76
77
|
cases: true, // c ? a : b drawn as a piecewise brace
|
|
77
|
-
label: true, // accessible name of the whole expression: true = the
|
|
78
|
+
label: true, // accessible name of the whole expression: true = MathZetta's toAudioSpeech (the grouping in the words), a string, (tree) => string, or false
|
|
79
|
+
mathml: null, // MathZetta's toMathML (import it from 'mathzetta/mathml'): also write the expression as visually hidden MathML, which screen readers can step through and show in math braille; it replaces the label
|
|
78
80
|
attributes: null, // (node) => ({ ... }) extra attributes for a node's element
|
|
79
81
|
style: null, // (node) => 'css' inline style for a node's element
|
|
80
82
|
};
|
|
@@ -102,18 +104,34 @@ export function layout(tree, options = {}) {
|
|
|
102
104
|
const r = new Layout({ ...DEFAULTS, ...options });
|
|
103
105
|
const b = r.render(tree, { level: 0 });
|
|
104
106
|
const cls = `${r.p}${r.o.display ? ` ${r.p}-display` : ''}`;
|
|
105
|
-
// Screen readers get the expression
|
|
106
|
-
|
|
107
|
-
const
|
|
107
|
+
// Screen readers get the expression as MathML they can walk (mathml: true), or read as a teacher would (the
|
|
108
|
+
// label); the spans and glyphs of the drawing are never read piecemeal.
|
|
109
|
+
const mathml = typeof r.o.mathml === 'function' ? assistiveMathML(r.o.mathml, tree, r.p, r.o.display) : '';
|
|
110
|
+
const label = mathml ? null : accessibleName(tree, r.o.label);
|
|
111
|
+
const body = label === null && !mathml ? b.html : b.html.replace(/^<span /, '<span aria-hidden="true" ');
|
|
108
112
|
const attrs = label === null ? '' : ` role="math" aria-label="${escape(label)}"`;
|
|
109
|
-
return { html: `<span class="${cls}"${attrs}>${body}</span>`, h: b.h, d: b.d };
|
|
113
|
+
return { html: `<span class="${cls}"${attrs}>${body}${mathml}</span>`, h: b.h, d: b.d };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The expression as MathML for assistive technology: no ids (two drawings on a page must not share them), hidden
|
|
118
|
+
* from sight. The page passes MathZetta's toMathML, so Inline Math itself imports only what every page maps.
|
|
119
|
+
*/
|
|
120
|
+
function assistiveMathML(toMathML, tree, prefix, display) {
|
|
121
|
+
try {
|
|
122
|
+
return String(toMathML(tree)).replace(/ id="mz-\d+"/g, '')
|
|
123
|
+
.replace(/^<math>/, `<math class="${prefix}-sr-math"${display ? ' display="block"' : ''}>`);
|
|
124
|
+
} catch {
|
|
125
|
+
return ''; // nothing MathZetta can write as MathML: the label stands in
|
|
126
|
+
}
|
|
110
127
|
}
|
|
111
128
|
|
|
112
129
|
function accessibleName(tree, label) {
|
|
113
130
|
if (label === false || label === null) return null;
|
|
114
131
|
if (typeof label === 'string') return label;
|
|
115
132
|
try {
|
|
116
|
-
|
|
133
|
+
// a screen reader is speech with no drawing in view: the grouping has to be in the words
|
|
134
|
+
return typeof label === 'function' ? label(tree) : toAudioSpeech(tree);
|
|
117
135
|
} catch {
|
|
118
136
|
return null;
|
|
119
137
|
}
|
|
@@ -199,6 +217,8 @@ class Layout {
|
|
|
199
217
|
if (NAMED.includes(op) || op === 'log') return wrap(this.named(node, ctx));
|
|
200
218
|
if (CALLS[op]) return wrap(row(this.word(CALLS[op]), this.fence(this.list(args, ctx))));
|
|
201
219
|
if (isCustomFunction(op)) return wrap(this.custom(node, ctx));
|
|
220
|
+
const rows = matrixRows(node); // pmatrix, bmatrix, vmatrix, and [[1, 2], [3, 4]]
|
|
221
|
+
if (rows) return wrap(this.matrix(node, rows, ctx));
|
|
202
222
|
if (GROUPS[op]) return wrap(this.fence(this.list(args, ctx), ...GROUPS[op]));
|
|
203
223
|
if (RELATIONS[op] && args.length === 2) return wrap(row(side(a, 'left'), this.rel(RELATIONS[op]), side(b, 'right')));
|
|
204
224
|
if (BINARY[op] && args.length === 2) return wrap(row(side(a, 'left'), this.bin(BINARY[op]), side(b, 'right')));
|
|
@@ -325,7 +345,8 @@ class Layout {
|
|
|
325
345
|
decorate(name, b) {
|
|
326
346
|
switch (name) {
|
|
327
347
|
case 'boxed': return box(this.el('boxed', b.html), b.h + 0.22, b.d + 0.22);
|
|
328
|
-
|
|
348
|
+
// a drawn stroke, not a background: Windows high contrast drops backgrounds, and a cancelled term would look kept
|
|
349
|
+
case 'cancel': return box(this.el('cancel', b.html + svg('cancel', `${this.p}-cancel-line`)), b.h, b.d);
|
|
329
350
|
case 'underline': return box(this.el('underline', b.html), b.h, b.d + 0.12);
|
|
330
351
|
case 'overline': case 'bar': return box(this.el('over', b.html), b.h + 0.14, b.d);
|
|
331
352
|
default: return box(this.el('accent', this.el('accent-mark', ACCENTS[name]) + b.html), b.h + 0.3, b.d);
|
|
@@ -557,6 +578,28 @@ class Layout {
|
|
|
557
578
|
return row(op, body);
|
|
558
579
|
}
|
|
559
580
|
|
|
581
|
+
/**
|
|
582
|
+
* A matrix: a grid of entries, centred on the maths axis, in brackets as tall as it is. Each
|
|
583
|
+
* row that is a list in the tree is an element of its own (display: contents), so a row can
|
|
584
|
+
* be pointed at like any part.
|
|
585
|
+
*/
|
|
586
|
+
matrix(node, rows, ctx) {
|
|
587
|
+
const ROWGAP = 0.3;
|
|
588
|
+
const cells = rows.map((r) => r.map((c) => this.render(c, ctx)));
|
|
589
|
+
const heights = cells.map((r) => ({ h: Math.max(LH, ...r.map((b) => b.h)), d: Math.max(LD, ...r.map((b) => b.d)) }));
|
|
590
|
+
const total = heights.reduce((s, x) => s + x.h + x.d, 0) + ROWGAP * (rows.length - 1);
|
|
591
|
+
const lift = AXIS + total / 2 - heights[0].h; // the first row's baseline
|
|
592
|
+
const html = cells.map((r, i) => {
|
|
593
|
+
const inner = r.map((b) => this.el('matrix-cell', b.html)).join('');
|
|
594
|
+
const tree = node.args[i];
|
|
595
|
+
return tree && tree.type === 'op' && tree.op === '[]' ? this.wrap(tree, ['op', 'op-list', 'matrix-row'], box(inner)).html : inner;
|
|
596
|
+
}).join('');
|
|
597
|
+
const columns = rows[0].length;
|
|
598
|
+
const grid = box(this.el('matrix', html, `grid-template-columns:repeat(${columns},auto);vertical-align:${em(lift)}`), AXIS + total / 2, total / 2 - AXIS);
|
|
599
|
+
const [open, close] = MATRICES[node.op] ?? ['[', ']'];
|
|
600
|
+
return this.fence(grid, open, close);
|
|
601
|
+
}
|
|
602
|
+
|
|
560
603
|
/** c ? a : b → a brace with "a if c", "b otherwise". Nested ternaries add rows. */
|
|
561
604
|
cases(node, ctx) {
|
|
562
605
|
const rows = [];
|
|
@@ -565,7 +608,8 @@ class Layout {
|
|
|
565
608
|
rows.push([this.render(n.args[1], ctx), row(this.word('if'), this.text('space', ''), this.render(n.args[0], ctx))]);
|
|
566
609
|
n = n.args[2];
|
|
567
610
|
}
|
|
568
|
-
|
|
611
|
+
// a case nobody wrote (`unchanged`: no else, no otherwise row) is not drawn
|
|
612
|
+
if (!(n.type === 'symbol' && n.value === 'unchanged')) rows.push([this.render(n, ctx), this.word('otherwise')]);
|
|
569
613
|
const ROWGAP = 0.25;
|
|
570
614
|
const heights = rows.map(([v, c]) => ({ h: Math.max(v.h, c.h), d: Math.max(v.d, c.d) }));
|
|
571
615
|
const total = heights.reduce((s, x) => s + x.h + x.d, 0) + ROWGAP * (rows.length - 1);
|
|
@@ -583,7 +627,7 @@ function isSimpleArgument(node, inScript = false) {
|
|
|
583
627
|
if (node.type === 'number') return !node.value.startsWith('-') || inScript;
|
|
584
628
|
if (node.type === 'symbol') return true;
|
|
585
629
|
if (node.type !== 'op') return false;
|
|
586
|
-
if (node.op === 'abs') return !inScript;
|
|
630
|
+
if (node.op === 'abs' || matrixRows(node)) return !inScript; // |x| and a matrix bring their own brackets
|
|
587
631
|
if (inScript && (node.op === 'neg' || node.op === '^')) return isSimpleArgument(node.args[0], true) && (node.op === 'neg' || isSimpleArgument(node.args[1], true));
|
|
588
632
|
if (node.op === '*' && !isMinusOneTimes(node)) {
|
|
589
633
|
return node.args.every((c) => (c.type === 'number' && !c.value.startsWith('-')) || isShortSymbol(c) || (c.op === '*' && isSimpleArgument(c, inScript)));
|