@malloy-publisher/app 0.9.14 → 0.9.15

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/index.html CHANGED
@@ -16,7 +16,7 @@ SPDX-License-Identifier: MIT
16
16
  href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
17
17
  />
18
18
  <title>Malloy Publisher</title>
19
- <script type="module" crossorigin src="/assets/index-B_gOHtqJ.js"></script>
19
+ <script type="module" crossorigin src="/assets/index-JQs0UPrG.js"></script>
20
20
  <link rel="stylesheet" crossorigin href="/assets/index-DUqldpo0.css">
21
21
  </head>
22
22
  <body>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@malloy-publisher/app",
3
3
  "description": "Malloy Publisher Console (the built-in web UI)",
4
- "version": "0.9.14",
4
+ "version": "0.9.15",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs.js",
7
7
  "module": "dist/index.es.js",
@@ -42,7 +42,7 @@
42
42
  "test:playwright:headed": "bunx playwright test --config=playwright.config.ts --headed"
43
43
  },
44
44
  "dependencies": {
45
- "@malloy-publisher/sdk": "^0.9.14",
45
+ "@malloy-publisher/sdk": "^0.9.15",
46
46
  "@mui/icons-material": "^7.0.2",
47
47
  "@mui/material": "^7.0.2",
48
48
  "@tanstack/react-query": "^5.59.16",
@@ -1 +0,0 @@
1
- import{D as m,c as g,r as u,a9 as l,j as n,ab as p,ax as x}from"./index-B_gOHtqJ.js";import{d}from"./documentRoutes-e6eAjpuN.js";function j(){const{environmentName:e,packageName:a}=m(),s=g(),r=u.useMemo(()=>l({environmentName:e??"",packageName:a??""}),[e,a]);if(e)if(a){const t=p({environmentName:e,packageName:a});return n.jsx(x,{onClickPackageFile:s,onOpenDocument:({path:o,mode:i},c)=>s(d(e,a,o,i),c),resourceUri:t,onEvent:r})}else return n.jsx("div",{children:n.jsx("h2",{children:"Missing package name"})});else return n.jsx("div",{children:n.jsx("h2",{children:"Missing environment name"})})}export{j as default};
@@ -1,153 +0,0 @@
1
- import{ae as ce,j as $,I as ae,r as p,aU as he,V as ue,aV as me,aH as be,aW as W,aX as ye,aY as pe,aZ as fe,a_ as ge,a$ as ve,b0 as we,b1 as oe}from"./index-B_gOHtqJ.js";const v=ce.drillCell;function ke(e,t){const r=new Set;let l;try{l=e.getMetadata()?.getAllFields()??[]}catch{return r}const o=new Set;for(const a of l)!a||t(a)||a.tag?.tag("hidden")===void 0&&o.add(a.tag?.text("label")??a.name);for(const a of l){if(!a||!t(a))continue;const n=a.tag?.text("label")??a.name;o.has(n)||r.add(n)}return r}function D(e){const t=/^\s*(\d+)/.exec(e.style?.gridColumn??"");return t?t[1]:void 0}function xe(e,t){if(t.size!==0)for(const r of e.querySelectorAll(".malloy-table")){const l=n=>n.closest(".malloy-table")===r,o=new Set;for(const n of r.querySelectorAll(".column-cell.th")){if(!l(n))continue;const i=(n.textContent??"").replace(/\u200b/g,"").trim(),b=D(n);b&&t.has(i)&&o.add(b)}if(o.size===0)continue;const a=new Set;for(const n of r.querySelectorAll(`.${v}[tabindex="0"]`)){if(!l(n))continue;const i=D(n);i&&(a.has(i)?n.tabIndex=-1:a.add(i))}for(const n of r.querySelectorAll(".column-cell.td")){if(!l(n))continue;const i=D(n),b=!n.querySelector(".value-null")&&(n.textContent??"").trim()!=="";if(i&&b&&o.has(i)&&!n.querySelector(".malloy-table")){if(n.classList.add(v),n.tabIndex===0)a.add(i);else{const f=a.has(i);f||a.add(i),n.tabIndex=f?-1:0}n.setAttribute("role","button")}}}}function Ce(e){const t=e.closest(".malloy-table"),r=D(e);return!t||!r?[]:Array.from(t.querySelectorAll(`.${v}`)).filter(l=>l.closest(".malloy-table")===t&&D(l)===r)}function ne(e,t){const r=Ce(e),l=r.indexOf(e);if(l===-1)return;const o=t==="first"?r[0]:t==="last"?r[r.length-1]:r[Math.min(Math.max(l+t,0),r.length-1)];if(o){for(const a of r)a.tabIndex=a===o?0:-1;return o}}function Ae(e){return{background:e.dashboardRoot,tableBackground:e.tableBackground,tableHeaderColor:e.tableHeader,tableBodyColor:e.tableBody,tableBorder:e.border,tablePinnedBackground:e.tableHeaderBackground,tablePinnedBorder:e.pinnedBorder,tableFontSize:`${e.font.size}px`,fontFamily:e.font.family,mapColor:e.mapColor}}function Se(e){const{foreground:t,axisFaint:r,gridline:l,font:o}=e,a={background:e.background,font:o.family,title:{color:t,font:o.family},axis:{labelColor:t,titleColor:t,domainColor:r,tickColor:r,gridColor:l,labelFont:o.family,titleFont:o.family},legend:{labelColor:t,titleColor:t,labelFont:o.family,titleFont:o.family},header:{labelColor:t,titleColor:t},range:{category:e.series}},n={...a,legend:{...a.legend,orient:"bottom"}};return i=>i==="shape_map"?n:a}function Ee(e){if(!e)return;const t=e.tag("theme");if(!t)return;const r={},l=t.tag("palette");if(l){const a={},n=l.textArray("series");n&&n.length>0&&(a.series=n);for(const i of he){const b=l.tag(i);if(!b)continue;const f={},x=b.text("light"),w=b.text("dark");x&&(f.light=x),w&&(f.dark=w),Object.keys(f).length>0&&(a[i]=f)}Object.keys(a).length>0&&(r.palette=a)}const o=t.tag("font");if(o){const a={},n=o.text("family");n&&(a.family=n);const i=o.numeric("size");typeof i=="number"&&Number.isFinite(i)&&(a.size=i),Object.keys(a).length>0&&(r.font=a)}return Object.keys(r).length>0?r:void 0}const B="data-publisher-fill",ze=async(e,t)=>{if(typeof window>"u")throw new Error("MalloyRenderer can only be used in browser environment");const{MalloyRenderer:r}=await pe();return new r({onClick:t,vegaConfigOverride:Se(e),theme:Ae(e),onError:l=>{console.error("Error rendering visualization:",typeof l,l)}}).createViz()};async function Me(e){if(!e||typeof e!="object")return;const t=e,r=[...Array.isArray(t.model_annotations)?t.model_annotations:[],...Array.isArray(t.source_annotations)?t.source_annotations:[],...Array.isArray(t.annotations)?t.annotations:[]].map(o=>typeof o?.value=="string"?o.value:void 0).filter(o=>!!o);if(r.length===0)return;let l;try{({parseAnnotation:l}=await ye())}catch{return}try{const{tag:o}=l(r);return Ee(o)}catch(o){console.warn("Failed to parse # theme.* annotations; chart will render with the shell theme.",{error:o,lines:r});return}}function Re(e,t,r){const l=fe(t,r);for(const[o,a]of Object.entries(l))e.style.setProperty(o,a)}const Te=`
2
- /* Card geometry, through the renderer's OWN theme vars rather than over the top
3
- of them. It declares --malloy-theme--dashboard-* on .malloy-render itself and
4
- passes each through to the --malloy-render--* the card CSS reads, so a value
5
- inherited from our wrapper loses to that declaration however early it is set:
6
- this has to be a rule on the same element, at higher specificity. Doubling the
7
- class does that, and then no !important is needed — which matters, because
8
- !important here also lands on .dashboard-item-borderless and repaints a card
9
- the author asked to have no card. */
10
- .malloy-render.malloy-render {
11
- --malloy-theme--dashboard-card-radius: var(--publisher-dashboard-card-radius);
12
- --malloy-theme--dashboard-card-padding: var(--publisher-dashboard-card-padding);
13
- }
14
- /* dashboard.css hardcodes background: #f7f9fc on .malloy-dashboard
15
- and .dashboard-row-header, which would paint light grey in dark
16
- mode and also bleed an operator-picked palette.background across
17
- the panel chrome in light. Both surfaces use
18
- --malloy-render--background here, which buildMalloyExplicitTheme
19
- wires to dashboardRoot: a mode-keyed neutral that stays decoupled
20
- from palette.background (the chart canvas) on purpose. Selectors
21
- are duplicated at higher specificity to beat the renderer s own
22
- scoped rules. */
23
- .malloy-render .malloy-dashboard,
24
- .malloy-render.malloy-render .malloy-dashboard,
25
- div.malloy-render .malloy-dashboard {
26
- /* --publisher-dashboard-root is set on the outer Publisher wrapper
27
- (see buildTableCssVars) and stays decoupled from
28
- --malloy-render--background, which gets shadowed inside the
29
- renderer when a theme.background annotation is present. The
30
- dedicated var means the panel between tiles always paints the
31
- operator neutral dashboardRoot regardless of annotations. */
32
- background: var(--publisher-dashboard-root) !important;
33
- background-color: var(--publisher-dashboard-root) !important;
34
- color: var(--malloy-render--table-body-color) !important;
35
- }
36
- .malloy-render .malloy-dashboard .dashboard-row,
37
- .malloy-render .malloy-dashboard .dashboard-row-body,
38
- .malloy-render .malloy-dashboard .dashboard-row-header,
39
- .malloy-render.malloy-render .malloy-dashboard .dashboard-row-header,
40
- div.malloy-render .malloy-dashboard .dashboard-row-header {
41
- /* Belt + suspenders: dashboard.css hardcodes .dashboard-row-header
42
- to #f7f9fc, and row / row-body have no explicit background but
43
- get caught in any annotation-driven inline writes. Force all of
44
- them to the neutral panel colour. */
45
- background: var(--publisher-dashboard-root) !important;
46
- background-color: var(--publisher-dashboard-root) !important;
47
- }
48
- .malloy-render .malloy-dashboard .dashboard-item:not(.dashboard-item-borderless) {
49
- /* Tile padding around each chart / table. Uses our custom
50
- --malloy-render--tile-background so the operator can theme the
51
- tile separately from the table header row (which paints from
52
- --malloy-render--table-pinned-background below).
53
-
54
- A flat bordered card rather than the renderer's shadow ring, which is what
55
- makes it match the composite tile's Paper. :not(borderless) because
56
- # borderless asks for no card at all, and an !important background and
57
- border drew one anyway. */
58
- background: var(--malloy-render--tile-background) !important;
59
- color: var(--malloy-render--table-body-color) !important;
60
- box-shadow: none !important;
61
- /* The card edge, not the table gridline: --publisher-dashboard-card-border,
62
- the same value TileCard paints, so the renderer's card and the composite
63
- one are outlined identically. */
64
- border: var(--publisher-dashboard-card-border) !important;
65
- }
66
- /* The renderer's big-value card — the small card a "# big_value" measure sits
67
- in, several to a row inside one tile. (No backticks in here: this is inside
68
- a template literal.) Its own CSS gives it a 0.55px edge in
69
- #e5e7eb: a sub-pixel width, and a grey off the slate ramp everything else on
70
- the page is on. It is a dashboard card like any other, so it takes the card
71
- edge and stops being the one card outlined in a hairline nobody can see. */
72
- .malloy-render .malloy-big-value-card {
73
- border: var(--publisher-dashboard-card-border) !important;
74
- /* Its shadow is a four-layer Tailwind stack, and only two of those layers
75
- are a shadow: the other is "0 0 0 1px #e5e7eb", a spread ring drawn as a
76
- second border OVER the real one. So the border above was landing
77
- underneath a ring in the renderer's own grey, and the card kept both a
78
- lifted look the flat cards around it do not have and an edge we did not
79
- pick. Dropped whole rather than rebuilt layer by layer: the ring's job is
80
- the border's job, and the border is already doing it. */
81
- box-shadow: none !important;
82
- }
83
- /* The strip of big-value cards as a grid, so cards share a width and the last one does not wrap
84
- alone. The renderer's wrapping flex row sizes each card to its own text. The 250px floor is the
85
- widest realistic value: it is nowrap at 32px in an overflow:visible card, so a narrower track
86
- would spill it onto its neighbour. Embedded (a nested big_value) is left as the renderer draws it. */
87
- .malloy-render .malloy-big-value:not(.malloy-big-value--embedded) {
88
- display: grid;
89
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
90
- }
91
- .malloy-render .malloy-big-value-card:not(.malloy-big-value-card--embedded) {
92
- width: auto;
93
- max-width: none;
94
- }
95
- .malloy-render .malloy-dashboard .dashboard-row-header-separator {
96
- background: var(--malloy-render--table-border) !important;
97
- }
98
- /* !important because the malloy-explorer stylesheet pins these same properties with it. */
99
- [${B}] .malloy-table.root {
100
- height: 100% !important;
101
- align-content: start !important;
102
- grid-template-columns: repeat(var(--total-header-size), minmax(max-content, 1fr)) !important;
103
- }
104
- .malloy-render .malloy-table .th.column-cell {
105
- /* Non-pinned tables have no header background in the renderer's
106
- own CSS (only pinned scrolled tables paint the pinned-header
107
- with this var). Force the same value here so every table has a
108
- visible header band reflecting the operator's choice. */
109
- background: var(--malloy-render--table-pinned-background) !important;
110
- }
111
- .malloy-render .dashboard-item-title,
112
- .malloy-render .dashboard-dimension-name {
113
- color: var(--malloy-render--label-color) !important;
114
- }
115
- .malloy-render .dashboard-item-value,
116
- .malloy-render .dashboard-item-value-measure,
117
- .malloy-render .dashboard-dimension-value {
118
- color: var(--malloy-render--value-color) !important;
119
- }
120
- .malloy-render .malloy-table,
121
- .malloy-render .malloy-list {
122
- color: var(--malloy-render--table-body-color) !important;
123
- }
124
- .malloy-render .column-cell.th,
125
- .malloy-render .cell-content.header {
126
- color: var(--malloy-render--table-header-color) !important;
127
- }
128
- /* A cell whose column declares a "# drill" this surface can honor, marked
129
- by markDrillableCells. Ordinary text with a pointer cursor until hovered,
130
- then it reads as a link: the same affordance Malloyyo gives the same tag,
131
- and the only thing that tells a reader a cell navigates. Kept off the
132
- resting state deliberately: a column painted blue competes with the data.
133
- (No backticks in here: this is inside a template literal.) */
134
- .malloy-render .${v} {
135
- cursor: pointer;
136
- }
137
- .malloy-render .${v}:hover > .cell-content {
138
- color: var(--publisher-drill-link) !important;
139
- text-decoration: underline;
140
- }
141
- /* Keyboard focus reads the same as hover, plus a ring: a hover colour is not
142
- something a keyboard user can produce, and a focus ring is not something a
143
- mouse user sees. focus-visible rather than focus, so a click does not leave a
144
- ring behind it. (No backticks in here: this is inside a template literal.) */
145
- .malloy-render .${v}:focus-visible {
146
- outline: 2px solid var(--publisher-drill-link);
147
- outline-offset: -2px;
148
- }
149
- .malloy-render .${v}:focus-visible > .cell-content {
150
- color: var(--publisher-drill-link) !important;
151
- text-decoration: underline;
152
- }
153
- `,le="publisher-malloy-renderer-overrides";function je(){if(typeof document>"u"||document.getElementById(le))return;const e=document.createElement("style");e.id=le,e.textContent=Te,document.head.appendChild(e)}function Fe({result:e,height:t,drill:r,onSizeChange:l,onSizing:o,fill:a}){const n=p.useRef(null),i=p.useRef(r);i.current=r;const b=p.useCallback(c=>{i.current?.onClick(c)},[]),f=r!==void 0,x=p.useRef(!1),w=p.useRef(null),P=p.useRef(0),{theme:I,layers:Y,mode:J}=ue(),X=p.useMemo(()=>({radius:I.ui.radius.tile,padding:`${me}px`}),[I.ui.radius.tile]);return p.useEffect(()=>()=>{P.current+=1;const c=w.current;c?.viz.remove(),c?.node.remove(),w.current=null},[]),p.useLayoutEffect(()=>{if(!n.current||!e)return;je();const c=n.current,se=P.current+=1;let H=!1;const V=()=>!H&&se===P.current;let d,m,_=null,K=0,L=null,N=null,q=null,R=null,T=null,j=null,Z=null,G=0,A=null;x.current=!1;let g,S;const U=k=>{if(H||!k.firstElementChild||W(g,S)==="container")return;const F=ge(g,S);if(x.current&&!F)return;const O=c.hasAttribute(B);O&&c.removeAttribute(B);const E=ve(k,oe(g));O&&c.setAttribute(B,""),E>0&&(x.current=!0,l&&E!==G&&(G=E,l(E)));const h=we(k,oe(g));F&&h&&Z!==h&&(Z=h,j?.disconnect(),j=new ResizeObserver(()=>U(k)),j.observe(h))};return(async()=>{let k;try{k=JSON.parse(e)}catch(y){console.error("Error parsing visualization result:",y);return}const F=await Me(k),O=F?be([...Y,F],J):I;if(!V())return;try{m=await ze(O,b)}catch(y){console.error("Failed to create renderer:",y);return}if(!V()){m.remove(),m=void 0;return}const E=w.current;d=document.createElement("div"),d.style.width="100%",d.style.height="100%",Re(d,O,X),c.childElementCount>0&&(c.style.position="relative",d.style.position="absolute",d.style.inset="0",d.style.visibility="hidden"),c.appendChild(d);const h=d;R=new MutationObserver(()=>{T&&clearTimeout(T),T=setTimeout(()=>{U(h),x.current&&R?.disconnect()},100)}),R.observe(d,{childList:!0,subtree:!0,attributes:!0});const ie=m;let Q=!1;const ee=()=>{if(!(Q||!V())){Q=!0,A&&(clearTimeout(A),A=null),E?.viz.remove();for(const y of Array.from(c.children))y!==h&&c.removeChild(y);h.style.position="",h.style.inset="",h.style.visibility="",c.style.position="",w.current={viz:ie,node:h},U(h)}};try{m.setResult(k);try{const C=m.getMetadata(),z=C?.getRootField();g=z?.renderAs(),S=z?C?.getPluginsForField(z.key)?.[0]?.sizingStrategy:void 0}catch{g=void 0,S=void 0}o?.(W(g,S)),d.dataset.malloyRenderAs=g??"unknown",d.dataset.malloySizing=W(g,S),m.render(d);const y=i.current;try{if(y){const C=ke(m,y.canDrill),z=()=>{try{xe(h,C)}catch(s){console.warn("Drill affordance skipped:",s)}};z();const te=s=>{const u=s.querySelector(".cell-content")??s,M=u.getBoundingClientRect();u.dispatchEvent(new MouseEvent("click",{bubbles:!0,cancelable:!0,view:u.ownerDocument.defaultView,clientX:Math.round(M.left+M.width/2),clientY:Math.round(M.bottom)}))},re=s=>s.target?.closest?.(`.${v}`)??null,de=(s,u)=>{ne(s,u)?.focus()};L=s=>{const u=re(s);if(!u)return;const M=s.key==="ArrowDown"?1:s.key==="ArrowUp"?-1:s.key==="Home"?"first":s.key==="End"?"last":void 0;if(M!==void 0){s.preventDefault(),de(u,M);return}s.key==="Enter"?(s.preventDefault(),te(u)):s.key===" "&&s.preventDefault()},N=s=>{if(s.key!==" ")return;const u=re(s);u&&(s.preventDefault(),te(u))},q=s=>{const u=s.target?.closest?.(`.${v}`);u&&ne(u,0)},h.addEventListener("keydown",L),h.addEventListener("keyup",N),h.addEventListener("focusin",q),C.size>0&&typeof MutationObserver<"u"&&(_=new MutationObserver(()=>{cancelAnimationFrame(K),K=requestAnimationFrame(z)}),_.observe(h,{childList:!0,subtree:!0}))}}catch(C){console.warn("Drill affordance skipped:",C)}m.onReady(ee),A=setTimeout(ee,1e4)}catch(y){console.error("Error rendering visualization:",y),R?.disconnect(),j?.disconnect(),_?.disconnect(),m.remove(),m=void 0,h.parentNode===c&&c.removeChild(h)}})(),()=>{H=!0,R?.disconnect(),j?.disconnect(),T&&clearTimeout(T),A&&clearTimeout(A),d&&w.current?.node!==d&&(L&&d.removeEventListener("keydown",L),N&&d.removeEventListener("keyup",N),q&&d.removeEventListener("focusin",q),_?.disconnect(),cancelAnimationFrame(K),m?.remove(),d.parentNode===c&&c.removeChild(d),c.style.position="")}},[e,b,f,l,o,I,Y,J,X]),$.jsx("div",{ref:n,...a?{[B]:""}:{},style:{width:"100%",height:t?`${t}px`:"400px"}})}function Oe(e){return typeof window>"u"?$.jsx(ae,{sx:{width:"100%",height:e.height?`${e.height}px`:"100%",display:"flex",alignItems:"center",justifyContent:"center",color:"text.secondary"},children:"Loading..."}):$.jsx(p.Suspense,{fallback:$.jsx(ae,{sx:{width:"100%",height:e.height?`${e.height}px`:"100%",display:"flex",alignItems:"center",justifyContent:"center",color:"text.secondary"},children:"Loading visualization..."}),children:$.jsx(Fe,{...e})})}const Be=Object.freeze(Object.defineProperty({__proto__:null,default:Oe},Symbol.toStringTag,{value:"Module"}));export{v as D,Oe as R,Se as a,Ae as b,Be as c,ke as d,xe as m,Ee as r};