@livx.cc/bare-v3 0.1.0-alpha.86 → 0.1.0-alpha.87
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/dist/manifest.json
CHANGED
|
@@ -42,6 +42,14 @@ export declare const isNum: (s: unknown) => boolean;
|
|
|
42
42
|
export declare const directives: Record<string, DirectiveRenderer>;
|
|
43
43
|
/** Built-in fence renderers by language: (text, ctx) => html. Unlisted languages render as code. */
|
|
44
44
|
export declare const fences: Record<string, FenceRenderer>;
|
|
45
|
+
/**
|
|
46
|
+
* Opt-in ```chart renderer that also takes JSON (a dependency-free SVG bar/line/pie chart); a body that is not JSON
|
|
47
|
+
* falls back to the built-in bars. Enable with `new MarkdownStream({ fences: { chart: jsonChart } })` and pass the same
|
|
48
|
+
* `fences` to promptGuide(). JSON: an array of rows (`[{"month":"Jan","sales":3}]`), or `{ type?: bar|line|pie,
|
|
49
|
+
* title?, x?, y?, data: rows }`, or `{ series: { name: { label: value } } }`. The label column is the first
|
|
50
|
+
* non-numeric one; every numeric column is a series. An unfinished JSON body (still streaming) shows a placeholder.
|
|
51
|
+
*/
|
|
52
|
+
export declare const jsonChart: FenceRenderer;
|
|
45
53
|
/**
|
|
46
54
|
* A system-prompt snippet teaching a model what this renderer turns into components. Generated from
|
|
47
55
|
* the same options the stream uses, so custom directives/fences (with a `.doc`) and tones are included.
|
package/dist/markdown-stream.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
var
|
|
2
|
-
`).filter((
|
|
3
|
-
`).map((t)=>t.split(":")).filter((t)=>t.length>1&&!isNaN(parseFloat(t[1]))),
|
|
4
|
-
`)}var
|
|
5
|
-
`),t=[];while(
|
|
6
|
-
`)?t:t.slice(0,-1),
|
|
7
|
-
`);if(
|
|
1
|
+
var q=Symbol.for("bare-v3.styles");function R(e,n,a){if(!e?.head||e.getElementById(n))return;let t=e[q]??=new Set;if(t.has(n))return;let r=e.defaultView;if(r&&"adoptedStyleSheets"in e&&"replaceSync"in r.CSSStyleSheet.prototype){let i=new r.CSSStyleSheet;i.replaceSync(a),e.adoptedStyleSheets=[...e.adoptedStyleSheets,i],t.add(n);return}let s=e.createElement("style");s.id=n,s.textContent=a,e.head.append(s)}var b=(e)=>String(e).replace(/[&<>"]/g,(n)=>({"&":"&","<":"<",">":">",'"':"""})[n]),P=(e)=>Object.fromEntries([...(e||"").matchAll(/(\w+)=(?:"([^"]*)"|(\S+))/g)].map((n)=>[n[1],n[2]??n[3]])),B=(e)=>/^[-+$€£]?[\d,.]+%?$/.test(String(e).trim()),z=(e)=>e?` data-b3-tone="${b(e)}"`:"",T={callout(e,n){let a=e.attrs.title?`<strong>${b(e.attrs.title)}</strong>`:"";return`<div class="b3-alert"${z(e.attrs.tone)}><div>${a}${n.parse(e.tokens)}</div></div>`},stats(e,n){let a=n?.inline??b;return`<div class="b3-md-stats">${e.body.split(`
|
|
2
|
+
`).filter((r)=>r.trim()).map((r)=>{let[s="",i,o=""]=r.replace(/^\s*\|/,"").replace(/\|\s*$/,"").split("|").map((c)=>c.trim()),l=/^[↑+]/.test(o)?"success":/^[↓-]/.test(o)?"danger":"";return`<div class="b3-stat b3-surface"><span class="b3-label">${a(s)}</span><strong class="b3-stat-value">${i?a(i.replace(/^\*\*(.*)\*\*$/,"$1")):"…"}</strong>${o?`<span class="b3-badge"${z(l)}>${a(o)}</span>`:""}</div>`}).join("")}</div>`}},S={chart(e){let n=e.split(`
|
|
3
|
+
`).map((t)=>t.split(":")).filter((t)=>t.length>1&&!isNaN(parseFloat(t[1]))),a=Math.max(...n.map((t)=>parseFloat(t[1])),1);return`<figure class="b3-md-bars b3-surface">${n.map(([t="",r=""])=>`<div class="b3-md-bar"><span>${b(t.trim())}</span><i style="inline-size:${Math.max(parseFloat(r),0)/a*100}%"></i><b>${b(r.trim())}</b></div>`).join("")}</figure>`}},U=(e,n)=>{let a=e.trim();if(!/^[[{]/.test(a))return S.chart(e,n);let t;try{t=JSON.parse(a)}catch{return(a.match(/[[{]/g)?.length??0)>(a.match(/[\]}]/g)?.length??0)?'<figure class="b3-md-chart b3-surface b3-md-pending"><div class="b3-skeleton"></div></figure>':j(e,"json")}let r=_(t);return r?Y(r):j(e,"json")};U.doc='```chart fence with JSON — `{"type":"bar|line|pie","title":"…","data":[{"label":"Jan","sales":120,"costs":80}]}` (numbers, not strings; every numeric field is a series; type is optional) — for trends over time (line), comparing groups/series (bar) or shares of a whole (pie). For a few single values, one `Label: number` per line gives simple bars.';var M=(e)=>typeof e==="number"&&Number.isFinite(e);function _(e){let n=Array.isArray(e)?{data:e}:e&&typeof e==="object"?e:null;if(!n)return null;let a=n.data??n.rows,t=n.series??n.values;if(!a&&t&&typeof t==="object"&&!Array.isArray(t)){let c=Object.keys(t);a=[...new Set(c.flatMap((p)=>Object.keys(t[p]||{})))].map((p)=>({label:p,...Object.fromEntries(c.map((g)=>[g,Number(t[g]?.[p]??0)]))}))}if(!Array.isArray(a)||!a.length||!a.every((c)=>c&&typeof c==="object"&&!Array.isArray(c)))return null;let r=[...new Set(a.flatMap((c)=>Object.keys(c)))],s=typeof n.x==="string"?n.x:r.find((c)=>a.some((d)=>d[c]!=null&&!M(d[c])))??"",i=n.y?[n.y].flat().map(String):r.filter((c)=>c!==s&&a.some((d)=>M(d[c])));if(!i.length)return null;let o=a.some((c)=>/^\d{4}-\d{2}/.test(String(c[s]??""))),l=["bar","line","pie"].includes(n.type)?n.type:o||a.length>12?"line":"bar";return{type:l,title:String(n.title??""),x:s,ys:l==="pie"?i.slice(0,1):i.slice(0,8),rows:a.slice(0,500)}}var A=(e)=>{try{return new Intl.NumberFormat(void 0,{notation:"compact",maximumFractionDigits:1}).format(e)}catch{return String(e)}};function Y({type:e,title:n,x:a,ys:t,rows:r}){let s=(m,u)=>M(m[u])?m[u]:0,i=(m,u)=>String(a?m[a]??"":u+1),o=(m,u,h)=>`<title>${b(i(m,u))} · ${b(h)}: ${b(m[h]??"")}</title>`,l=n?`<figcaption>${b(n)}</figcaption>`:"",c=(m)=>`<div class="b3-md-legend">${m.map((u,h)=>`<span><i class="b3-md-c${h%8}"></i>${b(u)}</span>`).join("")}</div>`;if(e==="pie"){let m=t[0],u=r.map((v)=>Math.max(s(v,m),0)),h=u.reduce((v,w)=>v+w,0)||1,f=0,E=r.map((v,w)=>{let x=f+u[w]/h*Math.PI*2,C=(O)=>`${(16+15*Math.sin(O)).toFixed(3)} ${(16-15*Math.cos(O)).toFixed(3)}`,N=u[w]>=h?"M16 1a15 15 0 1 1 0 30a15 15 0 1 1 0-30Z":`M16 16L${C(f)}A15 15 0 ${x-f>Math.PI?1:0} 1 ${C(x)}Z`;return f=x,`<path class="b3-md-c${w%8}" d="${N}">${o(v,w,m)}</path>`});return`<figure class="b3-md-chart b3-surface">${l}<div class="b3-md-pie"><svg viewBox="0 0 32 32" role="img" aria-label="${b(n||m)}">${E.join("")}</svg>${c(r.map(i))}</div></figure>`}let d=r.flatMap((m)=>t.map((u)=>s(m,u))),p=Math.min(0,...d),g=Math.max(0,...d),H=g-p||1,k=(m)=>(100-(m-p)/H*100).toFixed(2),y=r.length,I=e==="line"?t.map((m,u)=>`<polyline class="b3-md-c${u%8}" vector-effect="non-scaling-stroke" points="${r.map((h,f)=>`${(y>1?f/(y-1)*100:50).toFixed(2)},${k(s(h,m))}`).join(" ")}"><title>${b(m)}</title></polyline>`).join(""):r.map((m,u)=>t.map((h,f)=>{let E=100/y*0.8/t.length,v=100/y*(u+0.1)+E*f,w=s(m,h),x=Math.min(+k(w),+k(0));return`<rect class="b3-md-c${f%8}" x="${v.toFixed(2)}" y="${x.toFixed(2)}" width="${E.toFixed(2)}" height="${Math.max(Math.abs(+k(w)-+k(0)),0.4).toFixed(2)}">${o(m,u,h)}</rect>`}).join("")).join(""),D=y>2?[0,Math.floor((y-1)/2),y-1]:[...Array(y).keys()];return`<figure class="b3-md-chart b3-surface">${l}<div class="b3-md-plot"><div class="b3-md-y"><span>${A(g)}</span><span>${A(p)}</span></div><svg viewBox="0 0 100 100" preserveAspectRatio="none" role="img" aria-label="${b(n||t.join(", "))}">${I}</svg><div class="b3-md-x">${D.map((m)=>`<span>${b(i(r[m],m))}</span>`).join("")}</div></div>${t.length>1?c(t):""}</figure>`}T.callout.doc='`:::callout{tone=info|success|warning|danger title="Short title"}` newline, markdown body, newline `:::` — a highlighted note, tip, warning or recommendation.';T.stats.doc="`:::stats` newline, one card per line `Label | Value | note`, newline `:::` — headline numbers; a note starting with ↑ or + shows as good, ↓ or - as bad.";S.chart.doc="```chart fence, one bar per line `Label: number` (plain number, no units) — a horizontal bar chart for comparing a few values.";function X(e={}){let n={...T,...e.directives,...S,...e.fences},a=Object.entries(e.tones??new L().tones).reduce((t,[r,s])=>((t[s]??=[]).push(r),t),{});return["Your replies are Markdown rendered live into UI components. Use GitHub-flavoured Markdown (headings, **bold**, lists, links, `inline code`, fenced code with a language, > quotes) plus:",`- Tables: GFM pipe tables with a header row and a \`| --- |\` delimiter row. Never add a Status column the data does not already have. Only when a row really has one of these states (e.g. an invoice that is paid), write the plain word alone in the cell and it is shown as a coloured badge automatically (no images, emoji or badge URLs): ${Object.entries(a).map(([t,r])=>`${r.join(", ")} (${t})`).join("; ")}. Numeric columns align right.`,"- Task lists: `- [x] done` and `- [ ] to do`.",...Object.values(n).filter((t)=>t?.doc).map((t)=>`- ${t.doc}`),"Use a component only when it makes the answer clearer; plain prose is fine. Put every block on its own lines with a blank line around it, always close ::: and ``` blocks, and never write raw HTML."].join(`
|
|
4
|
+
`)}var j=(e,n)=>`<div class="b3-md-code"><header><span class="b3-muted">${b(n||"text")}</span><button type="button" class="b3-button" data-b3-emphasis="quiet" data-b3-md-copy>Copy</button></header><pre><code>${b(e)}</code></pre></div>`;function V(e){let n=e,a=n.split(`
|
|
5
|
+
`),t=[];while(a.length&&/^\s*\|/.test(a.at(-1)))t.unshift(a.pop());let r=e.endsWith(`
|
|
6
|
+
`)?t:t.slice(0,-1),s=!1;if(t.length&&!r.some((c)=>/^\s*\|?\s*:?-{2,}/.test(c)))s=!0,n=a.join(`
|
|
7
|
+
`);if(n=n.replace(/(^|\n) {0,3}(`{3}[^\n]*|~{3}[^\n]*|:{3}[^\n]*|`{1,2}|~{1,2}|:{1,2})$/,"$1"),(n.match(/^ {0,3}(`{3}|~{3})/gm)||[]).length%2)return{src:n,pendingTable:s};n=n.replace(/\[([^\]\n]*)\]?\([^)\n]*$/,"$1").replace(/\[([^\]\n]*)$/,"$1").replace(/(\*{1,3}|_{1,3}|~{1,2}|`)$/,"");let i=[...n.matchAll(/^ {0,3}(`{3}|~{3})[^\n]*\n?/gm)].at(-1),o=n.slice(Math.max(n.lastIndexOf(`
|
|
8
8
|
|
|
9
|
-
`)+1,
|
|
9
|
+
`)+1,i?i.index+i[0].length:0)),l="";for(let c of["`","~~"])if(o.split(c).length%2===0)l=c+l;return l+=G(o),{src:l?n.trimEnd()+l:n,pendingTable:s}}function G(e){let n=e.replace(/`[^`\n]*`?/g,"").replace(/\\[*_]/g,"").replace(/\]\([^)\n]*\)?|https?:\/\/\S*/g,"]"),a=[];for(let{0:t,index:r}of n.matchAll(/\*+|_+/g)){let s=n[r-1]??" ",i=n[r+t.length]??" ",o=t.length;if(/\S/.test(s)&&(t[0]==="*"||!/\w/.test(i)))while(o&&a.at(-1)?.[0]===t[0]){let c=a.pop(),d=Math.min(o,c.length);if(o-=d,c.length>d)a.push(c.slice(d))}let l=/[\p{L}\p{N}]/u.test(i)||t.length>1&&/\s/.test(s)&&/^[^\s\w*_-]\S*$/.test(n.slice(r+t.length));if(o&&l&&!(/\w/.test(s)&&(t[0]==="_"||o===1)))a.push(t.slice(0,o))}return a.reverse().join("")}var F={note:"info",info:"info",tip:"success",important:"info",warning:"warning",caution:"danger",danger:"danger"},J="b3-markdown-stream-style",W=`
|
|
10
10
|
.b3-prose > :is(.b3-md-stats,.b3-table-wrap,.b3-alert,.b3-md-code,.b3-md-bars){margin-block:1rem;}
|
|
11
11
|
.b3-prose > :first-child{margin-block-start:0;}
|
|
12
12
|
.b3-md-appear{animation:b3-md-in var(--b3-duration,.2s) ease-out;}
|
|
@@ -21,6 +21,24 @@ var y=Symbol.for("bare-v3.styles");function f(e,s,l){if(!e?.head||e.getElementBy
|
|
|
21
21
|
.b3-md-bar>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
|
22
22
|
.b3-md-bar>i{display:block;block-size:.7rem;border-radius:999px;background:var(--b3-color-accent);transition:inline-size var(--b3-duration,.2s);}
|
|
23
23
|
.b3-md-bar>b{text-align:end;font-variant-numeric:tabular-nums;}
|
|
24
|
+
.b3-prose > .b3-md-chart{margin-block:1rem;}
|
|
25
|
+
.b3-md-chart{display:grid;gap:.5rem;margin-inline:0;padding:var(--b3-space,1rem);font-size:.8rem;}
|
|
26
|
+
.b3-md-chart>figcaption{font-weight:600;font-size:.9rem;}
|
|
27
|
+
.b3-md-plot{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:.25rem .5rem;}
|
|
28
|
+
.b3-md-plot>svg{block-size:10rem;inline-size:100%;overflow:visible;border-block-end:1px solid var(--b3-color-border);}
|
|
29
|
+
.b3-md-y{display:flex;flex-direction:column;justify-content:space-between;text-align:end;}
|
|
30
|
+
.b3-md-x{grid-column:2;display:flex;justify-content:space-between;gap:.5rem;}
|
|
31
|
+
.b3-md-x>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
|
32
|
+
.b3-md-x>span:only-child{margin-inline:auto;}
|
|
33
|
+
:is(.b3-md-y,.b3-md-x,.b3-md-legend){color:var(--b3-color-muted);font-variant-numeric:tabular-nums;}
|
|
34
|
+
.b3-md-chart rect,.b3-md-chart path{fill:var(--c);stroke:none;}
|
|
35
|
+
.b3-md-chart polyline{fill:none;stroke:var(--c);stroke-width:2;stroke-linejoin:round;}
|
|
36
|
+
.b3-md-pie{display:flex;flex-wrap:wrap;align-items:center;gap:1rem;}
|
|
37
|
+
.b3-md-pie>svg{inline-size:8rem;block-size:8rem;flex:none;}
|
|
38
|
+
.b3-md-legend{display:flex;flex-wrap:wrap;gap:.25rem .75rem;}
|
|
39
|
+
.b3-md-legend i{display:inline-block;inline-size:.6rem;block-size:.6rem;border-radius:2px;margin-inline-end:.3rem;background:var(--c);}
|
|
40
|
+
.b3-md-c0{--c:var(--b3-color-accent);}.b3-md-c1{--c:#f59e0b;}.b3-md-c2{--c:#10b981;}.b3-md-c3{--c:#ef4444;}.b3-md-c4{--c:#8b5cf6;}.b3-md-c5{--c:#ec4899;}.b3-md-c6{--c:#14b8a6;}.b3-md-c7{--c:#f97316;}
|
|
41
|
+
.b3-md-chart.b3-md-pending>.b3-skeleton{block-size:10rem;}
|
|
24
42
|
.b3-md-stats{display:grid;gap:.75rem;grid-template-columns:repeat(auto-fit,minmax(min(10rem,100%),1fr));}
|
|
25
43
|
.b3-md-stats>.b3-stat{container-type:inline-size;}
|
|
26
44
|
.b3-md-stats .b3-stat-value{font-size:clamp(1.5rem,18cqi,3rem);}
|
|
@@ -34,8 +52,8 @@ var y=Symbol.for("bare-v3.styles");function f(e,s,l){if(!e?.head||e.getElementBy
|
|
|
34
52
|
.b3-md-pending>.b3-skeleton{block-size:1.5rem;}
|
|
35
53
|
.b3-md-pending>.b3-skeleton+.b3-skeleton{inline-size:80%;}
|
|
36
54
|
@media (prefers-reduced-motion:reduce){.b3-md-appear,.b3-md-caret{animation:none;}}
|
|
37
|
-
`;class
|
|
38
|
-
`),
|
|
39
|
-
`).replace(/\n$/,""),c=
|
|
40
|
-
`)+(c&&
|
|
41
|
-
`:""),name:
|
|
55
|
+
`;class L{Marked=null;sanitize=null;directives=T;fences=S;code=j;tones={paid:"success",done:"success",ok:"success",active:"success",pending:"warning",overdue:"danger",failed:"danger",blocked:"danger",draft:"info"};html="escape";images="alt";markedOptions={}}class Z{el=null;buf="";nodes=[];ended=!1;options;#e;#t=(e)=>this.#n(e);constructor(e){this.options={...new L,...e},this.options.directives={...T,...e?.directives},this.options.fences={...S,...e?.fences};let{Marked:n,sanitize:a}=this.options;if(typeof n!=="function")throw TypeError('MarkdownStream: options.Marked (from "marked") is required');if(typeof a!=="function")throw TypeError("MarkdownStream: options.sanitize is required (e.g. html => DOMPurify.sanitize(html))");this.#e=this.#s()}attach(e){return this.detach(),this.el=e,e.replaceChildren(),this.buf="",this.nodes=[],this.ended=!1,R(e.ownerDocument,J,W),e.addEventListener("click",this.#t),this}detach(){this.el?.removeEventListener("click",this.#t),this.el=null}push(e){if(this.ended){console.warn("MarkdownStream: push() after end() ignored; call attach(el) to start a new stream");return}this.buf+=e,this.render(!0)}end(e){if(e!==void 0)this.buf=String(e);this.ended=!0,this.render(!1)}toHtml(e){return this.options.sanitize(this.#e.parse(e))}render(e){let{el:n}=this;if(!n)throw Error("MarkdownStream: call attach(el) before push()");let a=n.ownerDocument,{src:t,pendingTable:r}=e?V(this.buf):{src:this.buf,pendingTable:!1},s=this.#e.lexer(t).filter((i)=>i.type!=="space");if(s.forEach((i,o)=>{let l=this.nodes[o];if(l&&l.raw===i.raw)return;let c=a.createElement("div");c.innerHTML=this.options.sanitize(this.#e.parser([i]));let p=(c.childElementCount===1&&[...c.childNodes].every((g)=>g.nodeType===1||!g.textContent.trim())?c.firstElementChild:null)??c;if(!l)p.classList.add("b3-md-appear");l?l.el.replaceWith(p):n.append(p),this.nodes[o]={raw:i.raw,el:p}}),this.nodes.splice(s.length).forEach((i)=>i.el.remove()),n.querySelector(":scope .b3-md-caret, :scope > .b3-md-pending")?.remove(),r)n.insertAdjacentHTML("beforeend",'<div class="b3-md-pending" aria-hidden="true"><div class="b3-skeleton"></div><div class="b3-skeleton"></div></div>');else if(e){let i=this.nodes.at(-1)?.el;((i?.matches("p, li, td, th, pre"))?i:i?.querySelector("p:last-of-type, li:last-child, td:last-child")||i||n).insertAdjacentHTML("beforeend",'<span class="b3-md-caret" aria-hidden="true"></span>')}}#n(e){let n=e.target.closest?.("[data-b3-md-copy]");if(!n||!this.el?.contains(n))return;let a=n.closest(".b3-md-code")?.querySelector("code")?.textContent??"",t=(i)=>{n.textContent=i,setTimeout(()=>{n.textContent="Copy"},1200)},r=(i)=>{console.warn("MarkdownStream: copy failed",i),t("Copy failed")},s=this.el.ownerDocument.defaultView?.navigator?.clipboard;if(s?.writeText)s.writeText(a).then(()=>t("Copied"),r);else r(Error("navigator.clipboard is unavailable (insecure context?)"))}#s(){let e=this.options,n={name:"directive",level:"block",start:(t)=>t.match(/^:::/m)?.index,tokenizer(t){let r=/^:::(\w+)(?:\{([^}\n]*)\})?[^\n]*(?:\n|$)/.exec(t);if(!r)return;let s=t.slice(r[0].length).split(`
|
|
56
|
+
`),i=null,o=s.length;for(let p=0;p<s.length;p++){let g=/^ {0,3}(`{3,}|~{3,})/.exec(s[p])?.[1];if(i){if(g&&g[0]===i[0]&&g.length>=i.length&&!s[p].trim().slice(g.length))i=null}else if(g)i=g;else if(/^:::[^\S\n]*$/.test(s[p])){o=p;break}}let l=s.slice(0,o).join(`
|
|
57
|
+
`).replace(/\n$/,""),c=o<s.length;return{type:"directive",raw:r[0]+s.slice(0,c?o+1:o).join(`
|
|
58
|
+
`)+(c&&o+1<s.length?`
|
|
59
|
+
`:""),name:r[1],attrs:P(r[2]),body:l,tokens:this.lexer.blockTokens(l,[])}},renderer(t){return(e.directives[t.name]??e.directives.callout)(t,{parse:(s)=>this.parser.parse(s),parseInline:(s)=>this.parser.parseInline(s),inline:(s)=>a.parseInline(s),esc:b})}},a=new e.Marked({gfm:!0,extensions:[n]});if(a.use({renderer:{blockquote(t){let r=/^\s*(?:\[!(\w+)\][^\S\n]*\n?|\*\*(\w+):?\*\*:?[^\S\n]*)/.exec(t.text),s=(r?.[1]??r?.[2])?.toLowerCase();if(!s||!r||!Object.hasOwn(F,s))return!1;let i=s[0].toUpperCase()+s.slice(1);return e.directives.callout({attrs:{tone:F[s],title:i},tokens:a.lexer(t.text.slice(r[0].length))},{parse:(o)=>this.parser.parse(o),parseInline:(o)=>this.parser.parseInline(o),inline:(o)=>a.parseInline(o),esc:b})},table(t){let r=t.header.map((i,o)=>t.rows.length>0&&t.rows.every((l)=>B(l[o]?.text||"0"))),s=(i,o,l)=>{let c=this.parser.parseInline(i.tokens),d=l==="td"&&e.tones[i.text.trim().toLowerCase()],p=d?`<span class="b3-badge" data-b3-tone="${b(d)}">${c}</span>`:c;return`<${l}${l==="th"?' scope="col"':""}${r[o]?' class="b3-md-num"':""}>${p}</${l}>`};return`<div class="b3-table-wrap" tabindex="0" role="region" aria-label="Table"><table class="b3-table b3-md-table"><thead><tr>${t.header.map((i,o)=>s(i,o,"th")).join("")}</tr></thead><tbody>${t.rows.map((i)=>`<tr>${i.map((o,l)=>s(o,l,"td")).join("")}</tr>`).join("")}</tbody></table></div>`},code({text:t,lang:r}){let s=(r||"").trim().split(/\s/)[0],i=Object.hasOwn(e.fences,s)?e.fences[s]:null;return i?i(t,{esc:b,lang:s}):e.code(t,s)},html(t){return e.html==="render"?!1:t.block?`<p>${b(t.text.trim())}</p>`:b(t.text)},image({href:t,text:r}){return e.images==="render"||typeof e.images==="function"&&e.images(t??"")?!1:b(r)},list(t){if(!t.items.some((r)=>r.task))return!1;return`<ul class="b3-md-tasks">${t.items.map((r)=>{let s=r.tokens.filter((l)=>l.type!=="checkbox"),i=s.find((l)=>l.type==="text"||l.type==="paragraph");if(i?.tokens)i.tokens=i.tokens.filter((l)=>l.type!=="checkbox");let o=s.map((l)=>l.type==="text"&&!r.loose?this.parser.parseInline(l.tokens??[l]):this.parser.parse([l])).join("");return`<li><input type="checkbox" disabled${r.checked?" checked":""}>${o}</li>`}).join("")}</ul>`}}}),e.markedOptions&&Object.keys(e.markedOptions).length)a.use(e.markedOptions);return a}}function ee(e=document.scrollingElement,{threshold:n=80}={}){let a=e.ownerDocument,t=a.defaultView,r=e===a.scrollingElement?t:e,s=!0,i=e.scrollTop,o=()=>{let d=e.scrollTop;if(e.scrollHeight-d-e.clientHeight>=n)s=!1;else if(d>=i)s=!0;i=d},l=(d)=>{if(d.target?.closest?.('input, textarea, select, [contenteditable]:not([contenteditable="false"])'))return;if(e.scrollTop>0&&((d.deltaY??0)<0||/^(ArrowUp|PageUp|Home)$/.test(d.key??"")))s=!1},c=[["scroll",o],["wheel",l],["keydown",l]];return c.forEach(([d,p])=>r.addEventListener(d,p,{passive:!0})),{get pinned(){return s},stick(d=!1){if(d||s)e.scrollTop=e.scrollHeight,s=!0},destroy(){c.forEach(([d,p])=>r.removeEventListener(d,p))}}}export{Z as MarkdownStream,L as MarkdownStreamOptions,j as codeBlock,T as directives,b as esc,S as fences,B as isNum,U as jsonChart,P as parseAttrs,X as promptGuide,V as settle,ee as stickToBottom};
|
|
@@ -29,6 +29,7 @@ Any markdown-speaking model works with no prompt: standard markdown is upgraded
|
|
|
29
29
|
| `:::callout{tone=warning title="…"}` … `:::` | `b3-alert` with tone and title; body is markdown |
|
|
30
30
|
| `:::stats` lines `Label \| Value \| ↑ note` `:::` | `b3-stat` cards; `↑`/`+` notes success, `↓`/`-` danger |
|
|
31
31
|
| ```` ```chart ```` lines `Label: number` | horizontal bars scaled to the max |
|
|
32
|
+
| ```` ```chart ```` JSON rows, opt-in: `fences: { chart: jsonChart }` | SVG bar / line / pie (no chart library); unfinished JSON shows a placeholder |
|
|
32
33
|
| ```` ```lang ```` | code block with language label and Copy button |
|
|
33
34
|
| `- [x] task` | list with disabled checkboxes |
|
|
34
35
|
| `> [!NOTE]` / `> [!WARNING]` (GitHub alerts) or `> **Note:** …` | `b3-alert`; note/important → info, tip → success, warning → warning, caution/danger → danger |
|