plotleaf 0.3.1 → 0.4.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 CHANGED
@@ -4,44 +4,31 @@ Beautiful, interactive reports from Markdown and prepared JSON. Built for coding
4
4
 
5
5
  **The agent does the thinking. We do the rendering.**
6
6
 
7
- [Source](https://github.com/LoueeD/plotleaf) · [Issues](https://github.com/LoueeD/plotleaf/issues) · [Verification](https://github.com/LoueeD/plotleaf/actions/workflows/ci.yml) · [Contributing](https://github.com/LoueeD/plotleaf/blob/main/CONTRIBUTING.md)
7
+ [Website](https://plotleaf-site.loueed.workers.dev) · [Docs](https://plotleaf-site.loueed.workers.dev/docs/) · [Examples](https://plotleaf-site.loueed.workers.dev/examples/) · [Playground](https://plotleaf-site.loueed.workers.dev/playground/) · [Source](https://github.com/LoueeD/plotleaf) · [Issues](https://github.com/LoueeD/plotleaf/issues) · [Verification](https://github.com/LoueeD/plotleaf/actions/workflows/ci.yml) · [Contributing](https://github.com/LoueeD/plotleaf/blob/main/CONTRIBUTING.md)
8
8
 
9
9
  A report is one Markdown file, optionally accompanied by local JSON datasets. No application, configuration file, account, database or hosted service. Export one HTML file that keeps working offline.
10
10
 
11
11
  ## Start with your coding agent
12
12
 
13
- Copy this into your agent and replace the report brief:
13
+ Copy this into your coding agent and describe your report:
14
14
 
15
15
  ```text
16
- Create a polished, interactive report with plotleaf.
17
-
18
- Report brief: [Describe the report and point to the data you want to use.]
19
-
20
- Use Node 22+ and npx; no app scaffolding, Bun or account is needed.
21
- First run `npx --yes plotleaf --help`. If it lists `guide`, read
22
- `npx --yes plotleaf guide`. Otherwise read the authoring guide at:
23
- https://raw.githubusercontent.com/LoueeD/plotleaf/v0.3.0/skills/plotleaf/SKILL.md
24
- Then run `npx --yes plotleaf schema` for the installed component API.
25
-
26
- Use the data I provide; don't invent values or findings. If the brief or
27
- data is missing, ask for what's needed. Prepare one report.md and any local
28
- JSON/assets it needs, following the guide and installed schema.
29
-
30
- Run `npx --yes plotleaf validate report.md --json` and fix all errors.
31
- Start `npx --yes plotleaf dev report.md --no-open` and give me the preview URL.
32
- Build `npx --yes plotleaf build report.md --out report.html` and give me
33
- the source and portable HTML paths, with any data limitations.
16
+ Build a beautiful, interactive report with Plotleaf.
17
+ Here's what I want to explore: [Your brief and data]
18
+ Follow https://plotleaf-site.loueed.workers.dev/agent and give me a preview and a standalone HTML report.
34
19
  ```
35
20
 
36
- The `guide` command is available in **0.3.1 or newer**. The prompt also works with 0.3.0 through the linked authoring guide.
37
-
38
21
  ## Status
39
22
 
23
+ **0.4.0** adds scoped interactive explorations: dropdowns, segmented choices, toggles, literal text/number inputs and supported date ranges select complete agent-prepared views. Metrics, charts, funnels, tables and data alternatives update together, including offline HTML. Unsupported selections show an unavailable state; no analytics or arbitrary queries run in reports.
24
+
25
+ **0.3.2** adds the website links and updated agent setup prompt. Read the [docs](https://plotleaf-site.loueed.workers.dev/docs/), explore [example reports](https://plotleaf-site.loueed.workers.dev/examples/), or try the [browser playground](https://plotleaf-site.loueed.workers.dev/playground/) without installing anything. The playground supports Markdown and JSON; local image imports and larger reports use the CLI.
26
+
40
27
  The initial MVP includes validation, live preview/reload, self-contained HTML export and a generated component specification. All bundled examples use fictional data.
41
28
 
42
29
  **0.3.0** adds local PNG/JPEG image cells, static sparklines and a cumulative example report. Donut charts and prepared funnel/progress views are available since 0.2.0. Check your installed CLI version or schema before using newer components.
43
30
 
44
- Implemented components: responsive grids, metrics/comparisons, line/area/bar/donut charts, prepared funnel/progress stages, literal chart targets, sortable/formatted tables and callouts. Reports support light/dark system preference, native chart-data disclosures and responsive layouts. Filters, maps, subtotals and reusable compositions remain planned increments.
31
+ Implemented components: responsive grids, metrics/comparisons, line/area/bar/donut charts, prepared funnel/progress stages, literal chart targets, sortable/formatted tables and callouts. Reports support light/dark system preference, native chart-data disclosures and responsive layouts. Scoped prepared-view controls are supported. Arbitrary row queries, maps, subtotals and reusable compositions remain planned increments.
45
32
 
46
33
  ## Quick start
47
34
 
@@ -184,3 +171,24 @@ Bun builds a Node-target ESM executable and browser-target IIFE assets. The brow
184
171
  MIT licensed. Bundled chart licenses/notices are retained in the package and exported HTML.
185
172
 
186
173
  See [CONTRIBUTING.md](https://github.com/LoueeD/plotleaf/blob/main/CONTRIBUTING.md) for the platform matrix and contribution workflow. The `v0.1.0` source tag reproduces the published npm archive; subsequent source changes require a new package version before release. Renderer releases require the owner's manual visual review of the running preview, in addition to automated checks.
174
+
175
+
176
+ ## Interactive prepared views
177
+
178
+ ```markdown
179
+ ::explore{data="./regional-views.json" title="Regional performance"}
180
+ ```
181
+
182
+ The JSON bundle declares native `inputs`, their defaults/supported values and
183
+ complete `views`. Every view binds all input IDs through `when` and contains
184
+ Markdown using the existing components plus optional inline JSON `datasets`.
185
+ The agent prepares every value and denominator; Plotleaf selects the matching
186
+ view without recalculating analytics. Controls affect only their exploration;
187
+ static prose and metrics outside it stay fixed. Reset restores defaults and an
188
+ unsupported combination hides stale results.
189
+
190
+ See the [interactive example](https://plotleaf-site.loueed.workers.dev/playground/?example=interactions),
191
+ [authoring guide](https://plotleaf-site.loueed.workers.dev/docs/) and `npx plotleaf schema`
192
+ for the exact contract and limits. All selectable data remains readable in the
193
+ HTML file; hidden views are not redaction. Native controls need JavaScript, while
194
+ the default view and data alternatives remain readable without it.
@@ -1 +1 @@
1
- (()=>{var d=new Intl.Collator("en-GB",{numeric:!0,sensitivity:"base"});for(let a of document.querySelectorAll("table[data-plotleaf-table]")){let r=a.tBodies[0];if(!r)continue;let i=[...r.rows],u=-1,n=!1;for(let o of a.querySelectorAll("thead button[data-column]"))o.disabled=!1,o.addEventListener("click",()=>{let s=Number(o.dataset.column);n=u===s?!n:!1,u=s;let c=i.map((e,t)=>({row:e,index:t,value:JSON.parse(e.cells[s]?.dataset.raw??"null")}));c.sort((e,t)=>{if(e.value===null||t.value===null)return e.value===t.value?e.index-t.index:e.value===null?1:-1;let l=typeof e.value==="number"&&typeof t.value==="number"?e.value-t.value:d.compare(String(e.value),String(t.value));return(n?-l:l)||e.index-t.index}),r.replaceChildren(...c.map((e)=>e.row)),a.querySelectorAll("thead th[aria-sort]").forEach((e)=>{let t=e.contains(o);e.setAttribute("aria-sort",t?n?"descending":"ascending":"none");let l=e.querySelector(".sort-indicator");if(l)l.textContent=t?n?"↓":"↑":"↕"})})}})();
1
+ (()=>{var u=(l)=>typeof l==="object"?`${l.start}/${l.end}`:`${typeof l}:${String(l)}`;var b=JSON.parse(document.getElementById("plotleaf-data")?.textContent??"{}");for(let l of b.explorations??[]){let s=function(){let t=new Map,e=!0;for(let n of l.inputs){let i=f(n.id),m=i[0],p;if(n.type==="select")p=n.options[Number(m.value)]?.value??"\x00";else if(n.type==="segmented")p=n.options[Number(i.find((r)=>r.checked)?.value??-1)]?.value??"\x00";else if(n.type==="toggle")p=m.checked;else if(n.type==="date-range")p={start:i.find((r)=>r.dataset.rangePart==="start").value,end:i.find((r)=>r.dataset.rangePart==="end").value};else p=n.type==="number"?m.value===""?NaN:Number(m.value):m.value;let y=u(p);t.set(n.id,y);let g=n.type==="toggle"||n.options.some((r)=>u(r.value)===y);for(let r of i)r.setAttribute("aria-invalid",String(!g));e&&=g}let o=e?l.views.find((n)=>l.inputs.every((i)=>t.get(i.id)===u(n.when[i.id]))):void 0;for(let n of a.querySelectorAll("[data-plotleaf-view]"))n.hidden=n.dataset.plotleafView!==o?.id;v.textContent=o?`Showing ${o.label} · Prepared view`:"No prepared view for these selections. Choose supported values or reset.",a.dispatchEvent(new Event("plotleaf:viewchange",{bubbles:!0}))},d=function(){for(let t of l.inputs)for(let e of f(t.id))if(t.type==="toggle")e.checked=t.default;else if(t.type==="date-range")e.value=t.default[e.dataset.rangePart];else if(t.type==="segmented")e.checked=u(t.options[Number(e.value)].value)===u(t.default);else if(t.type==="select")e.value=String(t.options.findIndex((o)=>u(o.value)===u(t.default)));else e.value=String(t.default);s()},a=document.getElementById(`${l.id}-title`)?.parentElement;if(!a)continue;let f=(t)=>[...a.querySelectorAll("[data-plotleaf-input]")].filter((e)=>e.dataset.plotleafInput===t),v=a.querySelector("[data-plotleaf-status]");for(let t of l.inputs)for(let e of f(t.id))e.disabled=!1,e.addEventListener("input",s),e.addEventListener("change",s);let c=a.querySelector("[data-plotleaf-reset]");c.disabled=!1,c.addEventListener("click",d),s()}var E=new Intl.Collator("en-GB",{numeric:!0,sensitivity:"base"});for(let l of document.querySelectorAll("table[data-plotleaf-table]")){let a=l.tBodies[0];if(!a)continue;let f=[...a.rows],v=-1,s=!1;for(let d of l.querySelectorAll("thead button[data-column]"))d.disabled=!1,d.addEventListener("click",()=>{let c=Number(d.dataset.column);s=v===c?!s:!1,v=c;let t=f.map((e,o)=>({row:e,index:o,value:JSON.parse(e.cells[c]?.dataset.raw??"null")}));t.sort((e,o)=>{if(e.value===null||o.value===null)return e.value===o.value?e.index-o.index:e.value===null?1:-1;let n=typeof e.value==="number"&&typeof o.value==="number"?e.value-o.value:E.compare(String(e.value),String(o.value));return(s?-n:n)||e.index-o.index}),a.replaceChildren(...t.map((e)=>e.row)),l.querySelectorAll("thead th[aria-sort]").forEach((e)=>{let o=e.contains(d);e.setAttribute("aria-sort",o?s?"descending":"ascending":"none");let n=e.querySelector(".sort-indicator");if(n)n.textContent=o?s?"↓":"↑":"↕"})})}})();