From 800989419b526584118504fdd1136fb5364c6754 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 15 Jan 2023 22:50:56 +0100 Subject: [PATCH 1/2] catch all query errors by default --- packages/core/pattern.mjs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index 5e8bc786..c12cf2b0 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -334,7 +334,12 @@ export class Pattern { * silence */ queryArc(begin, end) { - return this.query(new State(new TimeSpan(begin, end))); + try { + return this.query(new State(new TimeSpan(begin, end))); + } catch (err) { + logger(`[query]: ${err.message}`, 'error'); + return []; + } } /** From 5aa983b45bc9335bf5dc91837f5cb88dbe59272a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 15 Jan 2023 23:11:49 +0100 Subject: [PATCH 2/2] do less work when not drawing --- packages/core/euclid.mjs | 2 +- packages/react/dist/index.cjs.js | 2 +- packages/react/dist/index.es.js | 550 +++++++++---------- packages/react/src/hooks/usePatternFrame.mjs | 4 +- packages/react/src/hooks/useStrudel.mjs | 7 +- 5 files changed, 283 insertions(+), 282 deletions(-) diff --git a/packages/core/euclid.mjs b/packages/core/euclid.mjs index 6aa2283d..d8560c8e 100644 --- a/packages/core/euclid.mjs +++ b/packages/core/euclid.mjs @@ -46,7 +46,7 @@ const _bjork = function (n, x) { return Math.min(ons, offs) <= 1 ? [n, x] : _bjork(...(ons > offs ? left(n, x) : right(n, x))); }; -const bjork = function (ons, steps) { +export const bjork = function (ons, steps) { const offs = steps - ons; const x = Array(ons).fill([1]); const y = Array(offs).fill([0]); diff --git a/packages/react/dist/index.cjs.js b/packages/react/dist/index.cjs.js index 9e5132ee..6837f4d8 100644 --- a/packages/react/dist/index.cjs.js +++ b/packages/react/dist/index.cjs.js @@ -1 +1 @@ -"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const t=require("react"),ue=require("@uiw/react-codemirror"),w=require("@codemirror/view"),O=require("@codemirror/state"),de=require("@codemirror/lang-javascript"),i=require("@lezer/highlight"),fe=require("@uiw/codemirror-themes"),Z=require("@strudel.cycles/webaudio"),ge=require("react-hook-inview"),T=require("@strudel.cycles/core"),me=require("@strudel.cycles/transpiler"),ee=e=>e&&typeof e=="object"&&"default"in e?e:{default:e},u=ee(t),he=ee(ue),pe=fe.createTheme({theme:"dark",settings:{background:"#222",foreground:"#75baff",caret:"#ffcc00",selection:"rgba(128, 203, 196, 0.5)",selectionMatch:"#036dd626",lineHighlight:"#00000050",gutterBackground:"transparent",gutterForeground:"#8a919966"},styles:[{tag:i.tags.keyword,color:"#c792ea"},{tag:i.tags.operator,color:"#89ddff"},{tag:i.tags.special(i.tags.variableName),color:"#eeffff"},{tag:i.tags.typeName,color:"#c3e88d"},{tag:i.tags.atom,color:"#f78c6c"},{tag:i.tags.number,color:"#c3e88d"},{tag:i.tags.definition(i.tags.variableName),color:"#82aaff"},{tag:i.tags.string,color:"#c3e88d"},{tag:i.tags.special(i.tags.string),color:"#c3e88d"},{tag:i.tags.comment,color:"#7d8799"},{tag:i.tags.variableName,color:"#c792ea"},{tag:i.tags.tagName,color:"#c3e88d"},{tag:i.tags.bracket,color:"#525154"},{tag:i.tags.meta,color:"#ffcb6b"},{tag:i.tags.attributeName,color:"#c792ea"},{tag:i.tags.propertyName,color:"#c792ea"},{tag:i.tags.className,color:"#decb6b"},{tag:i.tags.invalid,color:"#ffffff"}]});const $=O.StateEffect.define(),ve=O.StateField.define({create(){return w.Decoration.none},update(e,o){try{for(let r of o.effects)if(r.is($))if(r.value){const n=w.Decoration.mark({attributes:{style:"background-color: #FFCA2880"}});e=w.Decoration.set([n.range(0,o.newDoc.length)])}else e=w.Decoration.set([]);return e}catch(r){return console.warn("flash error",r),e}},provide:e=>w.EditorView.decorations.from(e)}),te=e=>{e.dispatch({effects:$.of(!0)}),setTimeout(()=>{e.dispatch({effects:$.of(!1)})},200)},V=O.StateEffect.define(),be=O.StateField.define({create(){return w.Decoration.none},update(e,o){try{for(let r of o.effects)if(r.is(V)){const n=r.value.map(l=>(l.context.locations||[]).map(({start:m,end:d})=>{const a=l.context.color||"#FFCA28";let s=o.newDoc.line(m.line).from+m.column,p=o.newDoc.line(d.line).from+d.column;const E=o.newDoc.length;return s>E||p>E?void 0:w.Decoration.mark({attributes:{style:`outline: 1.5px solid ${a};`}}).range(s,p)})).flat().filter(Boolean)||[];e=w.Decoration.set(n,!0)}return e}catch{return w.Decoration.set([])}},provide:e=>w.EditorView.decorations.from(e)}),Ee=[de.javascript(),pe,be,ve];function re({value:e,onChange:o,onViewChanged:r,onSelectionChange:n,options:l,editorDidMount:m}){const d=t.useCallback(p=>{o?.(p)},[o]),a=t.useCallback(p=>{r?.(p)},[r]),s=t.useCallback(p=>{p.selectionSet&&n&&n?.(p.state.selection)},[n]);return u.default.createElement(u.default.Fragment,null,u.default.createElement(he.default,{value:e,onChange:d,onCreateEditor:a,onUpdate:s,extensions:Ee}))}function J(...e){return e.filter(Boolean).join(" ")}function oe({view:e,pattern:o,active:r,getTime:n}){const l=t.useRef([]),m=t.useRef(0);t.useEffect(()=>{if(e)if(o&&r){m.current=0;let d=requestAnimationFrame(function a(){try{const s=n(),E=[Math.max(m.current??s,s-1/10,-.01),s+1/60];m.current=E[1],l.current=l.current.filter(h=>h.whole.end>s);const c=o.queryArc(...E).filter(h=>h.hasOnset());l.current=l.current.concat(c),e.dispatch({effects:V.of(l.current)})}catch{e.dispatch({effects:V.of([])})}d=requestAnimationFrame(a)});return()=>{cancelAnimationFrame(d)}}else l.current=[],e.dispatch({effects:V.of([])})},[o,r,e])}function ye(e,o=!1){const r=t.useRef(),n=t.useRef(),l=a=>{if(n.current!==void 0){const s=a-n.current;e(a,s)}n.current=a,r.current=requestAnimationFrame(l)},m=()=>{r.current=requestAnimationFrame(l)},d=()=>{r.current&&cancelAnimationFrame(r.current),delete r.current};return t.useEffect(()=>{r.current&&(d(),m())},[e]),t.useEffect(()=>(o&&m(),d),[]),{start:m,stop:d}}function we({pattern:e,started:o,getTime:r,onDraw:n,drawTime:l=[-2,2]}){let[m,d]=l;m=Math.abs(m);let a=t.useRef([]),s=t.useRef(null);t.useEffect(()=>{if(e){const c=r(),h=e.queryArc(Math.max(c,0),c+d+.1);a.current=a.current.filter(b=>b.whole.begin{const c=r()+d;if(s.current===null){s.current=c;return}const h=e.queryArc(Math.max(s.current,c-1/10),c);s.current=c,a.current=(a.current||[]).filter(b=>b.whole.end>=c-m-d).concat(h.filter(b=>b.hasOnset())),n(e,c-d,a.current,l)},[e]));return t.useEffect(()=>{o?p():(a.current=[],E())},[o]),{clear:()=>{a.current=[]}}}function ne(e){return t.useEffect(()=>(window.addEventListener("message",e),()=>window.removeEventListener("message",e)),[e]),t.useCallback(o=>window.postMessage(o,"*"),[])}function ae({defaultOutput:e,interval:o,getTime:r,evalOnMount:n=!1,initialCode:l="",autolink:m=!1,beforeEval:d,afterEval:a,editPattern:s,onEvalError:p,onToggle:E,canvasId:c,drawContext:h,drawTime:b=[-2,2]}){const D=t.useMemo(()=>ke(),[]);c=c||`canvas-${D}`;const[q,R]=t.useState(),[N,L]=t.useState(),[y,x]=t.useState(l),[H,S]=t.useState(),[A,j]=t.useState(),[C,P]=t.useState(!1),B=y!==H,{scheduler:_,evaluate:F,start:f,stop:v,pause:G}=t.useMemo(()=>T.repl({interval:o,defaultOutput:e,onSchedulerError:R,onEvalError:g=>{L(g),p?.(g)},getTime:r,drawContext:h,transpiler:me.transpiler,editPattern:s,beforeEval:({code:g})=>{x(g),d?.()},afterEval:({pattern:g,code:k})=>{S(k),j(g),L(),R(),m&&(window.location.hash="#"+encodeURIComponent(btoa(k))),a?.()},onToggle:g=>{P(g),E?.(g)}}),[e,o,r]),I=ne(({data:{from:g,type:k}})=>{k==="start"&&g!==D&&v()}),Q=t.useCallback(async(g=!0)=>{const k=await F(y,g);return I({type:"start",from:D}),k},[F,y]),z=t.useCallback((g,k,U,W)=>{const{onPaint:le}=g.context||{},ie=typeof h=="function"?h(c):h;le?.(ie,k,U,W)},[h,c]),K=t.useCallback(g=>{if(h&&z){const[k,U]=b,W=g.queryArc(0,U);z(g,-.001,W,b)}},[h,b,z]),X=t.useRef();t.useEffect(()=>{!X.current&&n&&y&&(X.current=!0,F(y,!1).then(g=>K(g)))},[n,y,F,K]),t.useEffect(()=>()=>{_.stop()},[_]);const se=async()=>{C?(_.stop(),K(A)):await Q()},ce=q||N;return we({pattern:A,started:h&&C,getTime:()=>_.now(),drawTime:b,onDraw:z}),{id:D,canvasId:c,code:y,setCode:x,error:ce,schedulerError:q,scheduler:_,evalError:N,evaluate:F,activateCode:Q,activeCode:H,isDirty:B,pattern:A,started:C,start:f,stop:v,pause:G,togglePlay:se}}function ke(){return Math.floor((1+Math.random())*65536).toString(16).substring(1)}function Y({type:e}){return u.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",className:"sc-h-5 sc-w-5",viewBox:"0 0 20 20",fill:"currentColor"},{refresh:u.default.createElement("path",{fillRule:"evenodd",d:"M4 2a1 1 0 011 1v2.101a7.002 7.002 0 0111.601 2.566 1 1 0 11-1.885.666A5.002 5.002 0 005.999 7H9a1 1 0 010 2H4a1 1 0 01-1-1V3a1 1 0 011-1zm.008 9.057a1 1 0 011.276.61A5.002 5.002 0 0014.001 13H11a1 1 0 110-2h5a1 1 0 011 1v5a1 1 0 11-2 0v-2.101a7.002 7.002 0 01-11.601-2.566 1 1 0 01.61-1.276z",clipRule:"evenodd"}),play:u.default.createElement("path",{fillRule:"evenodd",d:"M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z",clipRule:"evenodd"}),pause:u.default.createElement("path",{fillRule:"evenodd",d:"M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z",clipRule:"evenodd"}),stop:u.default.createElement("path",{fillRule:"evenodd",d:"M2 10a8 8 0 1116 0 8 8 0 01-16 0zm5-2.25A.75.75 0 017.75 7h4.5a.75.75 0 01.75.75v4.5a.75.75 0 01-.75.75h-4.5a.75.75 0 01-.75-.75v-4.5z",clipRule:"evenodd"})}[e])}const _e="_container_3i85k_1",Me="_header_3i85k_5",Ce="_buttons_3i85k_9",Fe="_button_3i85k_9",De="_buttonDisabled_3i85k_17",Re="_error_3i85k_21",qe="_body_3i85k_25",M={container:_e,header:Me,buttons:Ce,button:Fe,buttonDisabled:De,error:Re,body:qe},Se=()=>Z.getAudioContext().currentTime;function Ae({tune:e,hideOutsideView:o=!1,enableKeyboard:r,drawTime:n,punchcard:l,canvasHeight:m=200}){n=n||(l?[0,4]:void 0);const d=!!n,a=t.useCallback(n?f=>document.querySelector("#"+f)?.getContext("2d"):null,[n]),{code:s,setCode:p,evaluate:E,activateCode:c,error:h,isDirty:b,activeCode:D,pattern:q,started:R,scheduler:N,togglePlay:L,stop:y,canvasId:x,id:H}=ae({initialCode:e,defaultOutput:Z.webaudioOutput,editPattern:f=>l?f.punchcard():f,getTime:Se,evalOnMount:d,drawContext:a,drawTime:n}),[S,A]=t.useState(),[j,C]=ge.useInView({threshold:.01}),P=t.useRef(),B=t.useMemo(()=>((C||!o)&&(P.current=!0),C||P.current),[C,o]);oe({view:S,pattern:q,active:R&&!D?.includes("strudel disable-highlighting"),getTime:()=>N.now()}),t.useLayoutEffect(()=>{if(r){const f=async v=>{(v.ctrlKey||v.altKey)&&(v.code==="Enter"?(v.preventDefault(),te(S),await c()):v.code==="Period"&&(y(),v.preventDefault()))};return window.addEventListener("keydown",f,!0),()=>window.removeEventListener("keydown",f,!0)}},[r,q,s,E,y,S]);const[_,F]=t.useState([]);return Ne(t.useCallback(f=>{const{data:v}=f.detail;v?.hap?.context?.id===H&&F(I=>I.concat([f.detail]).slice(-10))},[])),u.default.createElement("div",{className:M.container,ref:j},u.default.createElement("div",{className:M.header},u.default.createElement("div",{className:M.buttons},u.default.createElement("button",{className:J(M.button,R?"sc-animate-pulse":""),onClick:()=>L()},u.default.createElement(Y,{type:R?"stop":"play"})),u.default.createElement("button",{className:J(b?M.button:M.buttonDisabled),onClick:()=>c()},u.default.createElement(Y,{type:"refresh"}))),h&&u.default.createElement("div",{className:M.error},h.message)),u.default.createElement("div",{className:M.body},B&&u.default.createElement(re,{value:s,onChange:p,onViewChanged:A})),n&&u.default.createElement("canvas",{id:x,className:"w-full pointer-events-none",height:m,ref:f=>{f&&f.width!==f.clientWidth&&(f.width=f.clientWidth)}}),!!_.length&&u.default.createElement("div",{className:"sc-bg-gray-800 sc-rounded-md sc-p-2"},_.map(({message:f},v)=>u.default.createElement("div",{key:v},f))))}function Ne(e){Le(T.logger.key,e)}function Le(e,o,r=!1){t.useEffect(()=>(document.addEventListener(e,o,r),()=>{document.removeEventListener(e,o,r)}),[o])}const xe=e=>t.useLayoutEffect(()=>(window.addEventListener("keydown",e,!0),()=>window.removeEventListener("keydown",e,!0)),[e]);exports.CodeMirror=re;exports.MiniRepl=Ae;exports.cx=J;exports.flash=te;exports.useHighlighting=oe;exports.useKeydown=xe;exports.usePostMessage=ne;exports.useStrudel=ae; +"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const t=require("react"),de=require("@uiw/react-codemirror"),w=require("@codemirror/view"),V=require("@codemirror/state"),fe=require("@codemirror/lang-javascript"),d=require("@lezer/highlight"),ge=require("@uiw/codemirror-themes"),Z=require("@strudel.cycles/webaudio"),me=require("react-hook-inview"),T=require("@strudel.cycles/core"),he=require("@strudel.cycles/transpiler"),ee=e=>e&&typeof e=="object"&&"default"in e?e:{default:e},f=ee(t),pe=ee(de),ve=ge.createTheme({theme:"dark",settings:{background:"#222",foreground:"#75baff",caret:"#ffcc00",selection:"rgba(128, 203, 196, 0.5)",selectionMatch:"#036dd626",lineHighlight:"#00000050",gutterBackground:"transparent",gutterForeground:"#8a919966"},styles:[{tag:d.tags.keyword,color:"#c792ea"},{tag:d.tags.operator,color:"#89ddff"},{tag:d.tags.special(d.tags.variableName),color:"#eeffff"},{tag:d.tags.typeName,color:"#c3e88d"},{tag:d.tags.atom,color:"#f78c6c"},{tag:d.tags.number,color:"#c3e88d"},{tag:d.tags.definition(d.tags.variableName),color:"#82aaff"},{tag:d.tags.string,color:"#c3e88d"},{tag:d.tags.special(d.tags.string),color:"#c3e88d"},{tag:d.tags.comment,color:"#7d8799"},{tag:d.tags.variableName,color:"#c792ea"},{tag:d.tags.tagName,color:"#c3e88d"},{tag:d.tags.bracket,color:"#525154"},{tag:d.tags.meta,color:"#ffcb6b"},{tag:d.tags.attributeName,color:"#c792ea"},{tag:d.tags.propertyName,color:"#c792ea"},{tag:d.tags.className,color:"#decb6b"},{tag:d.tags.invalid,color:"#ffffff"}]});const J=V.StateEffect.define(),be=V.StateField.define({create(){return w.Decoration.none},update(e,r){try{for(let o of r.effects)if(o.is(J))if(o.value){const n=w.Decoration.mark({attributes:{style:"background-color: #FFCA2880"}});e=w.Decoration.set([n.range(0,r.newDoc.length)])}else e=w.Decoration.set([]);return e}catch(o){return console.warn("flash error",o),e}},provide:e=>w.EditorView.decorations.from(e)}),te=e=>{e.dispatch({effects:J.of(!0)}),setTimeout(()=>{e.dispatch({effects:J.of(!1)})},200)},z=V.StateEffect.define(),Ee=V.StateField.define({create(){return w.Decoration.none},update(e,r){try{for(let o of r.effects)if(o.is(z)){const n=o.value.map(u=>(u.context.locations||[]).map(({start:m,end:g})=>{const s=u.context.color||"#FFCA28";let l=r.newDoc.line(m.line).from+m.column,p=r.newDoc.line(g.line).from+g.column;const E=r.newDoc.length;return l>E||p>E?void 0:w.Decoration.mark({attributes:{style:`outline: 1.5px solid ${s};`}}).range(l,p)})).flat().filter(Boolean)||[];e=w.Decoration.set(n,!0)}return e}catch{return w.Decoration.set([])}},provide:e=>w.EditorView.decorations.from(e)}),ye=[fe.javascript(),ve,Ee,be];function re({value:e,onChange:r,onViewChanged:o,onSelectionChange:n,options:u,editorDidMount:m}){const g=t.useCallback(p=>{r?.(p)},[r]),s=t.useCallback(p=>{o?.(p)},[o]),l=t.useCallback(p=>{p.selectionSet&&n&&n?.(p.state.selection)},[n]);return f.default.createElement(f.default.Fragment,null,f.default.createElement(pe.default,{value:e,onChange:g,onCreateEditor:s,onUpdate:l,extensions:ye}))}function G(...e){return e.filter(Boolean).join(" ")}function oe({view:e,pattern:r,active:o,getTime:n}){const u=t.useRef([]),m=t.useRef(0);t.useEffect(()=>{if(e)if(r&&o){m.current=0;let g=requestAnimationFrame(function s(){try{const l=n(),E=[Math.max(m.current??l,l-1/10,-.01),l+1/60];m.current=E[1],u.current=u.current.filter(h=>h.whole.end>l);const i=r.queryArc(...E).filter(h=>h.hasOnset());u.current=u.current.concat(i),e.dispatch({effects:z.of(u.current)})}catch{e.dispatch({effects:z.of([])})}g=requestAnimationFrame(s)});return()=>{cancelAnimationFrame(g)}}else u.current=[],e.dispatch({effects:z.of([])})},[r,o,e])}function we(e,r=!1){const o=t.useRef(),n=t.useRef(),u=s=>{if(n.current!==void 0){const l=s-n.current;e(s,l)}n.current=s,o.current=requestAnimationFrame(u)},m=()=>{o.current=requestAnimationFrame(u)},g=()=>{o.current&&cancelAnimationFrame(o.current),delete o.current};return t.useEffect(()=>{o.current&&(g(),m())},[e]),t.useEffect(()=>(r&&m(),g),[]),{start:m,stop:g}}function ke({pattern:e,started:r,getTime:o,onDraw:n,drawTime:u=[-2,2]}){let[m,g]=u;m=Math.abs(m);let s=t.useRef([]),l=t.useRef(null);t.useEffect(()=>{if(e&&r){const i=o(),h=e.queryArc(Math.max(i,0),i+g+.1);s.current=s.current.filter(v=>v.whole.begin{const i=o()+g;if(l.current===null){l.current=i;return}const h=e.queryArc(Math.max(l.current,i-1/10),i);l.current=i,s.current=(s.current||[]).filter(v=>v.whole.end>=i-m-g).concat(h.filter(v=>v.hasOnset())),n(e,i-g,s.current,u)},[e]));return t.useEffect(()=>{r?p():(s.current=[],E())},[r]),{clear:()=>{s.current=[]}}}function ne(e){return t.useEffect(()=>(window.addEventListener("message",e),()=>window.removeEventListener("message",e)),[e]),t.useCallback(r=>window.postMessage(r,"*"),[])}function ae({defaultOutput:e,interval:r,getTime:o,evalOnMount:n=!1,initialCode:u="",autolink:m=!1,beforeEval:g,afterEval:s,editPattern:l,onEvalError:p,onToggle:E,canvasId:i,drawContext:h,drawTime:v=[-2,2]}){const F=t.useMemo(()=>_e(),[]);i=i||`canvas-${F}`;const[S,D]=t.useState(),[N,x]=t.useState(),[y,L]=t.useState(u),[P,A]=t.useState(),[R,O]=t.useState(),[M,H]=t.useState(!1),j=y!==P,q=t.useCallback(c=>!!(c?.context?.onPaint&&h),[h]),{scheduler:C,evaluate:a,start:b,stop:B,pause:I}=t.useMemo(()=>T.repl({interval:r,defaultOutput:e,onSchedulerError:D,onEvalError:c=>{x(c),p?.(c)},getTime:o,drawContext:h,transpiler:he.transpiler,editPattern:l,beforeEval:({code:c})=>{L(c),g?.()},afterEval:({pattern:c,code:k})=>{A(k),O(c),x(),D(),m&&(window.location.hash="#"+encodeURIComponent(btoa(k))),s?.()},onToggle:c=>{H(c),E?.(c)}}),[e,r,o]),se=ne(({data:{from:c,type:k}})=>{k==="start"&&c!==F&&B()}),Q=t.useCallback(async(c=!0)=>{const k=await a(y,c);return se({type:"start",from:F}),k},[a,y]),K=t.useCallback((c,k,W,$)=>{const{onPaint:ie}=c.context||{},ue=typeof h=="function"?h(i):h;ie?.(ue,k,W,$)},[h,i]),U=t.useCallback(c=>{if(q(c)){const[k,W]=v,$=c.queryArc(0,W);K(c,-.001,$,v)}},[v,K,q]),X=t.useRef();t.useEffect(()=>{!X.current&&n&&y&&(X.current=!0,a(y,!1).then(c=>U(c)))},[n,y,a,U]),t.useEffect(()=>()=>{C.stop()},[C]);const ce=async()=>{M?(C.stop(),U(R)):await Q()},le=S||N;return ke({pattern:R,started:q(R)&&M,getTime:()=>C.now(),drawTime:v,onDraw:K}),{id:F,canvasId:i,code:y,setCode:L,error:le,schedulerError:S,scheduler:C,evalError:N,evaluate:a,activateCode:Q,activeCode:P,isDirty:j,pattern:R,started:M,start:b,stop:B,pause:I,togglePlay:ce}}function _e(){return Math.floor((1+Math.random())*65536).toString(16).substring(1)}function Y({type:e}){return f.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",className:"sc-h-5 sc-w-5",viewBox:"0 0 20 20",fill:"currentColor"},{refresh:f.default.createElement("path",{fillRule:"evenodd",d:"M4 2a1 1 0 011 1v2.101a7.002 7.002 0 0111.601 2.566 1 1 0 11-1.885.666A5.002 5.002 0 005.999 7H9a1 1 0 010 2H4a1 1 0 01-1-1V3a1 1 0 011-1zm.008 9.057a1 1 0 011.276.61A5.002 5.002 0 0014.001 13H11a1 1 0 110-2h5a1 1 0 011 1v5a1 1 0 11-2 0v-2.101a7.002 7.002 0 01-11.601-2.566 1 1 0 01.61-1.276z",clipRule:"evenodd"}),play:f.default.createElement("path",{fillRule:"evenodd",d:"M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z",clipRule:"evenodd"}),pause:f.default.createElement("path",{fillRule:"evenodd",d:"M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z",clipRule:"evenodd"}),stop:f.default.createElement("path",{fillRule:"evenodd",d:"M2 10a8 8 0 1116 0 8 8 0 01-16 0zm5-2.25A.75.75 0 017.75 7h4.5a.75.75 0 01.75.75v4.5a.75.75 0 01-.75.75h-4.5a.75.75 0 01-.75-.75v-4.5z",clipRule:"evenodd"})}[e])}const Me="_container_3i85k_1",Ce="_header_3i85k_5",Fe="_buttons_3i85k_9",De="_button_3i85k_9",Re="_buttonDisabled_3i85k_17",qe="_error_3i85k_21",Se="_body_3i85k_25",_={container:Me,header:Ce,buttons:Fe,button:De,buttonDisabled:Re,error:qe,body:Se},Ae=()=>Z.getAudioContext().currentTime;function Ne({tune:e,hideOutsideView:r=!1,enableKeyboard:o,drawTime:n,punchcard:u,canvasHeight:m=200}){n=n||(u?[0,4]:void 0);const g=!!n,s=t.useCallback(n?a=>document.querySelector("#"+a)?.getContext("2d"):null,[n]),{code:l,setCode:p,evaluate:E,activateCode:i,error:h,isDirty:v,activeCode:F,pattern:S,started:D,scheduler:N,togglePlay:x,stop:y,canvasId:L,id:P}=ae({initialCode:e,defaultOutput:Z.webaudioOutput,editPattern:a=>u?a.punchcard():a,getTime:Ae,evalOnMount:g,drawContext:s,drawTime:n}),[A,R]=t.useState(),[O,M]=me.useInView({threshold:.01}),H=t.useRef(),j=t.useMemo(()=>((M||!r)&&(H.current=!0),M||H.current),[M,r]);oe({view:A,pattern:S,active:D&&!F?.includes("strudel disable-highlighting"),getTime:()=>N.now()}),t.useLayoutEffect(()=>{if(o){const a=async b=>{(b.ctrlKey||b.altKey)&&(b.code==="Enter"?(b.preventDefault(),te(A),await i()):b.code==="Period"&&(y(),b.preventDefault()))};return window.addEventListener("keydown",a,!0),()=>window.removeEventListener("keydown",a,!0)}},[o,S,l,E,y,A]);const[q,C]=t.useState([]);return xe(t.useCallback(a=>{const{data:b}=a.detail;b?.hap?.context?.id===P&&C(I=>I.concat([a.detail]).slice(-10))},[])),f.default.createElement("div",{className:_.container,ref:O},f.default.createElement("div",{className:_.header},f.default.createElement("div",{className:_.buttons},f.default.createElement("button",{className:G(_.button,D?"sc-animate-pulse":""),onClick:()=>x()},f.default.createElement(Y,{type:D?"stop":"play"})),f.default.createElement("button",{className:G(v?_.button:_.buttonDisabled),onClick:()=>i()},f.default.createElement(Y,{type:"refresh"}))),h&&f.default.createElement("div",{className:_.error},h.message)),f.default.createElement("div",{className:_.body},j&&f.default.createElement(re,{value:l,onChange:p,onViewChanged:R})),n&&f.default.createElement("canvas",{id:L,className:"w-full pointer-events-none",height:m,ref:a=>{a&&a.width!==a.clientWidth&&(a.width=a.clientWidth)}}),!!q.length&&f.default.createElement("div",{className:"sc-bg-gray-800 sc-rounded-md sc-p-2"},q.map(({message:a},b)=>f.default.createElement("div",{key:b},a))))}function xe(e){Le(T.logger.key,e)}function Le(e,r,o=!1){t.useEffect(()=>(document.addEventListener(e,r,o),()=>{document.removeEventListener(e,r,o)}),[r])}const Pe=e=>t.useLayoutEffect(()=>(window.addEventListener("keydown",e,!0),()=>window.removeEventListener("keydown",e,!0)),[e]);exports.CodeMirror=re;exports.MiniRepl=Ne;exports.cx=G;exports.flash=te;exports.useHighlighting=oe;exports.useKeydown=Pe;exports.usePostMessage=ne;exports.useStrudel=ae; diff --git a/packages/react/dist/index.es.js b/packages/react/dist/index.es.js index b0152c74..4aecb645 100644 --- a/packages/react/dist/index.es.js +++ b/packages/react/dist/index.es.js @@ -1,15 +1,15 @@ -import l, { useCallback as y, useRef as N, useEffect as k, useMemo as J, useState as M, useLayoutEffect as te } from "react"; -import le from "@uiw/react-codemirror"; -import { Decoration as A, EditorView as re } from "@codemirror/view"; +import d, { useCallback as E, useRef as A, useEffect as k, useMemo as Q, useState as _, useLayoutEffect as te } from "react"; +import ue from "@uiw/react-codemirror"; +import { Decoration as M, EditorView as re } from "@codemirror/view"; import { StateEffect as ne, StateField as oe } from "@codemirror/state"; -import { javascript as ue } from "@codemirror/lang-javascript"; -import { tags as i } from "@lezer/highlight"; -import { createTheme as de } from "@uiw/codemirror-themes"; -import { webaudioOutput as fe, getAudioContext as me } from "@strudel.cycles/webaudio"; -import { useInView as he } from "react-hook-inview"; -import { repl as ge, logger as pe } from "@strudel.cycles/core"; -import { transpiler as ve } from "@strudel.cycles/transpiler"; -const be = de({ +import { javascript as de } from "@codemirror/lang-javascript"; +import { tags as u } from "@lezer/highlight"; +import { createTheme as fe } from "@uiw/codemirror-themes"; +import { webaudioOutput as me, getAudioContext as he } from "@strudel.cycles/webaudio"; +import { useInView as ge } from "react-hook-inview"; +import { repl as pe, logger as ve } from "@strudel.cycles/core"; +import { transpiler as be } from "@strudel.cycles/transpiler"; +const Ee = fe({ theme: "dark", settings: { background: "#222", @@ -22,421 +22,421 @@ const be = de({ gutterForeground: "#8a919966" }, styles: [ - { tag: i.keyword, color: "#c792ea" }, - { tag: i.operator, color: "#89ddff" }, - { tag: i.special(i.variableName), color: "#eeffff" }, - { tag: i.typeName, color: "#c3e88d" }, - { tag: i.atom, color: "#f78c6c" }, - { tag: i.number, color: "#c3e88d" }, - { tag: i.definition(i.variableName), color: "#82aaff" }, - { tag: i.string, color: "#c3e88d" }, - { tag: i.special(i.string), color: "#c3e88d" }, - { tag: i.comment, color: "#7d8799" }, - { tag: i.variableName, color: "#c792ea" }, - { tag: i.tagName, color: "#c3e88d" }, - { tag: i.bracket, color: "#525154" }, - { tag: i.meta, color: "#ffcb6b" }, - { tag: i.attributeName, color: "#c792ea" }, - { tag: i.propertyName, color: "#c792ea" }, - { tag: i.className, color: "#decb6b" }, - { tag: i.invalid, color: "#ffffff" } + { tag: u.keyword, color: "#c792ea" }, + { tag: u.operator, color: "#89ddff" }, + { tag: u.special(u.variableName), color: "#eeffff" }, + { tag: u.typeName, color: "#c3e88d" }, + { tag: u.atom, color: "#f78c6c" }, + { tag: u.number, color: "#c3e88d" }, + { tag: u.definition(u.variableName), color: "#82aaff" }, + { tag: u.string, color: "#c3e88d" }, + { tag: u.special(u.string), color: "#c3e88d" }, + { tag: u.comment, color: "#7d8799" }, + { tag: u.variableName, color: "#c792ea" }, + { tag: u.tagName, color: "#c3e88d" }, + { tag: u.bracket, color: "#525154" }, + { tag: u.meta, color: "#ffcb6b" }, + { tag: u.attributeName, color: "#c792ea" }, + { tag: u.propertyName, color: "#c792ea" }, + { tag: u.className, color: "#decb6b" }, + { tag: u.invalid, color: "#ffffff" } ] }); -const Q = ne.define(), Ee = oe.define({ +const X = ne.define(), ye = oe.define({ create() { - return A.none; + return M.none; }, - update(e, r) { + update(e, t) { try { - for (let t of r.effects) - if (t.is(Q)) - if (t.value) { - const n = A.mark({ attributes: { style: "background-color: #FFCA2880" } }); - e = A.set([n.range(0, r.newDoc.length)]); + for (let r of t.effects) + if (r.is(X)) + if (r.value) { + const n = M.mark({ attributes: { style: "background-color: #FFCA2880" } }); + e = M.set([n.range(0, t.newDoc.length)]); } else - e = A.set([]); + e = M.set([]); return e; - } catch (t) { - return console.warn("flash error", t), e; + } catch (r) { + return console.warn("flash error", r), e; } }, provide: (e) => re.decorations.from(e) -}), ye = (e) => { - e.dispatch({ effects: Q.of(!0) }), setTimeout(() => { - e.dispatch({ effects: Q.of(!1) }); +}), we = (e) => { + e.dispatch({ effects: X.of(!0) }), setTimeout(() => { + e.dispatch({ effects: X.of(!1) }); }, 200); -}, I = ne.define(), we = oe.define({ +}, B = ne.define(), ke = oe.define({ create() { - return A.none; + return M.none; }, - update(e, r) { + update(e, t) { try { - for (let t of r.effects) - if (t.is(I)) { - const n = t.value.map( - (s) => (s.context.locations || []).map(({ start: m, end: u }) => { - const o = s.context.color || "#FFCA28"; - let c = r.newDoc.line(m.line).from + m.column, g = r.newDoc.line(u.line).from + u.column; - const b = r.newDoc.length; - return c > b || g > b ? void 0 : A.mark({ attributes: { style: `outline: 1.5px solid ${o};` } }).range(c, g); + for (let r of t.effects) + if (r.is(B)) { + const n = r.value.map( + (l) => (l.context.locations || []).map(({ start: m, end: f }) => { + const c = l.context.color || "#FFCA28"; + let s = t.newDoc.line(m.line).from + m.column, g = t.newDoc.line(f.line).from + f.column; + const b = t.newDoc.length; + return s > b || g > b ? void 0 : M.mark({ attributes: { style: `outline: 1.5px solid ${c};` } }).range(s, g); }) ).flat().filter(Boolean) || []; - e = A.set(n, !0); + e = M.set(n, !0); } return e; } catch { - return A.set([]); + return M.set([]); } }, provide: (e) => re.decorations.from(e) -}), ke = [ue(), be, we, Ee]; -function Fe({ value: e, onChange: r, onViewChanged: t, onSelectionChange: n, options: s, editorDidMount: m }) { - const u = y( - (g) => { - r?.(g); - }, - [r] - ), o = y( +}), Fe = [de(), Ee, ke, ye]; +function _e({ value: e, onChange: t, onViewChanged: r, onSelectionChange: n, options: l, editorDidMount: m }) { + const f = E( (g) => { t?.(g); }, [t] - ), c = y( + ), c = E( + (g) => { + r?.(g); + }, + [r] + ), s = E( (g) => { g.selectionSet && n && n?.(g.state.selection); }, [n] ); - return /* @__PURE__ */ l.createElement(l.Fragment, null, /* @__PURE__ */ l.createElement(le, { + return /* @__PURE__ */ d.createElement(d.Fragment, null, /* @__PURE__ */ d.createElement(ue, { value: e, - onChange: u, - onCreateEditor: o, - onUpdate: c, - extensions: ke + onChange: f, + onCreateEditor: c, + onUpdate: s, + extensions: Fe })); } function T(...e) { return e.filter(Boolean).join(" "); } -function _e({ view: e, pattern: r, active: t, getTime: n }) { - const s = N([]), m = N(0); +function Me({ view: e, pattern: t, active: r, getTime: n }) { + const l = A([]), m = A(0); k(() => { if (e) - if (r && t) { + if (t && r) { m.current = 0; - let u = requestAnimationFrame(function o() { + let f = requestAnimationFrame(function c() { try { - const c = n(), b = [Math.max(m.current ?? c, c - 1 / 10, -0.01), c + 1 / 60]; - m.current = b[1], s.current = s.current.filter((h) => h.whole.end > c); - const a = r.queryArc(...b).filter((h) => h.hasOnset()); - s.current = s.current.concat(a), e.dispatch({ effects: I.of(s.current) }); + const s = n(), b = [Math.max(m.current ?? s, s - 1 / 10, -0.01), s + 1 / 60]; + m.current = b[1], l.current = l.current.filter((h) => h.whole.end > s); + const i = t.queryArc(...b).filter((h) => h.hasOnset()); + l.current = l.current.concat(i), e.dispatch({ effects: B.of(l.current) }); } catch { - e.dispatch({ effects: I.of([]) }); + e.dispatch({ effects: B.of([]) }); } - u = requestAnimationFrame(o); + f = requestAnimationFrame(c); }); return () => { - cancelAnimationFrame(u); + cancelAnimationFrame(f); }; } else - s.current = [], e.dispatch({ effects: I.of([]) }); - }, [r, t, e]); + l.current = [], e.dispatch({ effects: B.of([]) }); + }, [t, r, e]); } -function Me(e, r = !1) { - const t = N(), n = N(), s = (o) => { +function Ae(e, t = !1) { + const r = A(), n = A(), l = (c) => { if (n.current !== void 0) { - const c = o - n.current; - e(o, c); + const s = c - n.current; + e(c, s); } - n.current = o, t.current = requestAnimationFrame(s); + n.current = c, r.current = requestAnimationFrame(l); }, m = () => { - t.current = requestAnimationFrame(s); - }, u = () => { - t.current && cancelAnimationFrame(t.current), delete t.current; + r.current = requestAnimationFrame(l); + }, f = () => { + r.current && cancelAnimationFrame(r.current), delete r.current; }; return k(() => { - t.current && (u(), m()); - }, [e]), k(() => (r && m(), u), []), { + r.current && (f(), m()); + }, [e]), k(() => (t && m(), f), []), { start: m, - stop: u + stop: f }; } -function Ae({ pattern: e, started: r, getTime: t, onDraw: n, drawTime: s = [-2, 2] }) { - let [m, u] = s; +function Ne({ pattern: e, started: t, getTime: r, onDraw: n, drawTime: l = [-2, 2] }) { + let [m, f] = l; m = Math.abs(m); - let o = N([]), c = N(null); + let c = A([]), s = A(null); k(() => { - if (e) { - const a = t(), h = e.queryArc(Math.max(a, 0), a + u + 0.1); - o.current = o.current.filter((v) => v.whole.begin < a), o.current = o.current.concat(h); + if (e && t) { + const i = r(), h = e.queryArc(Math.max(i, 0), i + f + 0.1); + c.current = c.current.filter((p) => p.whole.begin < i), c.current = c.current.concat(h); } - }, [e]); - const { start: g, stop: b } = Me( - y(() => { - const a = t() + u; - if (c.current === null) { - c.current = a; + }, [e, t]); + const { start: g, stop: b } = Ae( + E(() => { + const i = r() + f; + if (s.current === null) { + s.current = i; return; } - const h = e.queryArc(Math.max(c.current, a - 1 / 10), a); - c.current = a, o.current = (o.current || []).filter((v) => v.whole.end >= a - m - u).concat(h.filter((v) => v.hasOnset())), n(e, a - u, o.current, s); + const h = e.queryArc(Math.max(s.current, i - 1 / 10), i); + s.current = i, c.current = (c.current || []).filter((p) => p.whole.end >= i - m - f).concat(h.filter((p) => p.hasOnset())), n(e, i - f, c.current, l); }, [e]) ); return k(() => { - r ? g() : (o.current = [], b()); - }, [r]), { + t ? g() : (c.current = [], b()); + }, [t]), { clear: () => { - o.current = []; + c.current = []; } }; } -function Ne(e) { - return k(() => (window.addEventListener("message", e), () => window.removeEventListener("message", e)), [e]), y((r) => window.postMessage(r, "*"), []); +function Ce(e) { + return k(() => (window.addEventListener("message", e), () => window.removeEventListener("message", e)), [e]), E((t) => window.postMessage(t, "*"), []); } function De({ defaultOutput: e, - interval: r, - getTime: t, + interval: t, + getTime: r, evalOnMount: n = !1, - initialCode: s = "", + initialCode: l = "", autolink: m = !1, - beforeEval: u, - afterEval: o, - editPattern: c, + beforeEval: f, + afterEval: c, + editPattern: s, onEvalError: g, onToggle: b, - canvasId: a, + canvasId: i, drawContext: h, - drawTime: v = [-2, 2] + drawTime: p = [-2, 2] }) { - const R = J(() => Ce(), []); - a = a || `canvas-${R}`; - const [L, x] = M(), [H, P] = M(), [E, S] = M(s), [V, q] = M(), [z, K] = M(), [D, O] = M(!1), j = E !== V, { scheduler: F, evaluate: C, start: d, stop: p, pause: X } = J( - () => ge({ - interval: r, + const D = Q(() => Re(), []); + i = i || `canvas-${D}`; + const [P, R] = _(), [z, H] = _(), [y, S] = _(l), [V, q] = _(), [x, I] = _(), [N, O] = _(!1), K = y !== V, L = E((a) => !!(a?.context?.onPaint && h), [h]), { scheduler: C, evaluate: o, start: v, stop: j, pause: U } = Q( + () => pe({ + interval: t, defaultOutput: e, - onSchedulerError: x, - onEvalError: (f) => { - P(f), g?.(f); + onSchedulerError: R, + onEvalError: (a) => { + H(a), g?.(a); }, - getTime: t, + getTime: r, drawContext: h, - transpiler: ve, - editPattern: c, - beforeEval: ({ code: f }) => { - S(f), u?.(); + transpiler: be, + editPattern: s, + beforeEval: ({ code: a }) => { + S(a), f?.(); }, - afterEval: ({ pattern: f, code: w }) => { - q(w), K(f), P(), x(), m && (window.location.hash = "#" + encodeURIComponent(btoa(w))), o?.(); + afterEval: ({ pattern: a, code: w }) => { + q(w), I(a), H(), R(), m && (window.location.hash = "#" + encodeURIComponent(btoa(w))), c?.(); }, - onToggle: (f) => { - O(f), b?.(f); + onToggle: (a) => { + O(a), b?.(a); } }), - [e, r, t] - ), U = Ne(({ data: { from: f, type: w } }) => { - w === "start" && f !== R && p(); - }), Y = y( - async (f = !0) => { - const w = await C(E, f); - return U({ type: "start", from: R }), w; + [e, t, r] + ), ce = Ce(({ data: { from: a, type: w } }) => { + w === "start" && a !== D && j(); + }), Y = E( + async (a = !0) => { + const w = await o(y, a); + return ce({ type: "start", from: D }), w; }, - [C, E] - ), B = y( - (f, w, $, G) => { - const { onPaint: se } = f.context || {}, ie = typeof h == "function" ? h(a) : h; - se?.(ie, w, $, G); + [o, y] + ), W = E( + (a, w, G, J) => { + const { onPaint: ie } = a.context || {}, le = typeof h == "function" ? h(i) : h; + ie?.(le, w, G, J); }, - [h, a] - ), W = y( - (f) => { - if (h && B) { - const [w, $] = v, G = f.queryArc(0, $); - B(f, -1e-3, G, v); + [h, i] + ), $ = E( + (a) => { + if (L(a)) { + const [w, G] = p, J = a.queryArc(0, G); + W(a, -1e-3, J, p); } }, - [h, v, B] - ), Z = N(); + [p, W, L] + ), Z = A(); k(() => { - !Z.current && n && E && (Z.current = !0, C(E, !1).then((f) => W(f))); - }, [n, E, C, W]), k(() => () => { - F.stop(); - }, [F]); - const ce = async () => { - D ? (F.stop(), W(z)) : await Y(); - }, ae = L || H; - return Ae({ - pattern: z, - started: h && D, - getTime: () => F.now(), - drawTime: v, - onDraw: B + !Z.current && n && y && (Z.current = !0, o(y, !1).then((a) => $(a))); + }, [n, y, o, $]), k(() => () => { + C.stop(); + }, [C]); + const ae = async () => { + N ? (C.stop(), $(x)) : await Y(); + }, se = P || z; + return Ne({ + pattern: x, + started: L(x) && N, + getTime: () => C.now(), + drawTime: p, + onDraw: W }), { - id: R, - canvasId: a, - code: E, + id: D, + canvasId: i, + code: y, setCode: S, - error: ae, - schedulerError: L, - scheduler: F, - evalError: H, - evaluate: C, + error: se, + schedulerError: P, + scheduler: C, + evalError: z, + evaluate: o, activateCode: Y, activeCode: V, - isDirty: j, - pattern: z, - started: D, - start: d, - stop: p, - pause: X, - togglePlay: ce + isDirty: K, + pattern: x, + started: N, + start: v, + stop: j, + pause: U, + togglePlay: ae }; } -function Ce() { +function Re() { return Math.floor((1 + Math.random()) * 65536).toString(16).substring(1); } function ee({ type: e }) { - return /* @__PURE__ */ l.createElement("svg", { + return /* @__PURE__ */ d.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "sc-h-5 sc-w-5", viewBox: "0 0 20 20", fill: "currentColor" }, { - refresh: /* @__PURE__ */ l.createElement("path", { + refresh: /* @__PURE__ */ d.createElement("path", { fillRule: "evenodd", d: "M4 2a1 1 0 011 1v2.101a7.002 7.002 0 0111.601 2.566 1 1 0 11-1.885.666A5.002 5.002 0 005.999 7H9a1 1 0 010 2H4a1 1 0 01-1-1V3a1 1 0 011-1zm.008 9.057a1 1 0 011.276.61A5.002 5.002 0 0014.001 13H11a1 1 0 110-2h5a1 1 0 011 1v5a1 1 0 11-2 0v-2.101a7.002 7.002 0 01-11.601-2.566 1 1 0 01.61-1.276z", clipRule: "evenodd" }), - play: /* @__PURE__ */ l.createElement("path", { + play: /* @__PURE__ */ d.createElement("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z", clipRule: "evenodd" }), - pause: /* @__PURE__ */ l.createElement("path", { + pause: /* @__PURE__ */ d.createElement("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z", clipRule: "evenodd" }), - stop: /* @__PURE__ */ l.createElement("path", { + stop: /* @__PURE__ */ d.createElement("path", { fillRule: "evenodd", d: "M2 10a8 8 0 1116 0 8 8 0 01-16 0zm5-2.25A.75.75 0 017.75 7h4.5a.75.75 0 01.75.75v4.5a.75.75 0 01-.75.75h-4.5a.75.75 0 01-.75-.75v-4.5z", clipRule: "evenodd" }) }[e]); } -const Re = "_container_3i85k_1", xe = "_header_3i85k_5", Le = "_buttons_3i85k_9", qe = "_button_3i85k_9", ze = "_buttonDisabled_3i85k_17", He = "_error_3i85k_21", Pe = "_body_3i85k_25", _ = { - container: Re, - header: xe, - buttons: Le, +const xe = "_container_3i85k_1", Le = "_header_3i85k_5", Pe = "_buttons_3i85k_9", qe = "_button_3i85k_9", ze = "_buttonDisabled_3i85k_17", He = "_error_3i85k_21", Se = "_body_3i85k_25", F = { + container: xe, + header: Le, + buttons: Pe, button: qe, buttonDisabled: ze, error: He, - body: Pe -}, Se = () => me().currentTime; -function Ye({ tune: e, hideOutsideView: r = !1, enableKeyboard: t, drawTime: n, punchcard: s, canvasHeight: m = 200 }) { - n = n || (s ? [0, 4] : void 0); - const u = !!n, o = y( - n ? (d) => document.querySelector("#" + d)?.getContext("2d") : null, + body: Se +}, Ve = () => he().currentTime; +function Ze({ tune: e, hideOutsideView: t = !1, enableKeyboard: r, drawTime: n, punchcard: l, canvasHeight: m = 200 }) { + n = n || (l ? [0, 4] : void 0); + const f = !!n, c = E( + n ? (o) => document.querySelector("#" + o)?.getContext("2d") : null, [n] ), { - code: c, + code: s, setCode: g, evaluate: b, - activateCode: a, + activateCode: i, error: h, - isDirty: v, - activeCode: R, - pattern: L, - started: x, - scheduler: H, - togglePlay: P, - stop: E, + isDirty: p, + activeCode: D, + pattern: P, + started: R, + scheduler: z, + togglePlay: H, + stop: y, canvasId: S, id: V } = De({ initialCode: e, - defaultOutput: fe, - editPattern: (d) => s ? d.punchcard() : d, - getTime: Se, - evalOnMount: u, - drawContext: o, + defaultOutput: me, + editPattern: (o) => l ? o.punchcard() : o, + getTime: Ve, + evalOnMount: f, + drawContext: c, drawTime: n - }), [q, z] = M(), [K, D] = he({ + }), [q, x] = _(), [I, N] = ge({ threshold: 0.01 - }), O = N(), j = J(() => ((D || !r) && (O.current = !0), D || O.current), [D, r]); - _e({ + }), O = A(), K = Q(() => ((N || !t) && (O.current = !0), N || O.current), [N, t]); + Me({ view: q, - pattern: L, - active: x && !R?.includes("strudel disable-highlighting"), - getTime: () => H.now() + pattern: P, + active: R && !D?.includes("strudel disable-highlighting"), + getTime: () => z.now() }), te(() => { - if (t) { - const d = async (p) => { - (p.ctrlKey || p.altKey) && (p.code === "Enter" ? (p.preventDefault(), ye(q), await a()) : p.code === "Period" && (E(), p.preventDefault())); + if (r) { + const o = async (v) => { + (v.ctrlKey || v.altKey) && (v.code === "Enter" ? (v.preventDefault(), we(q), await i()) : v.code === "Period" && (y(), v.preventDefault())); }; - return window.addEventListener("keydown", d, !0), () => window.removeEventListener("keydown", d, !0); + return window.addEventListener("keydown", o, !0), () => window.removeEventListener("keydown", o, !0); } - }, [t, L, c, b, E, q]); - const [F, C] = M([]); - return Ve( - y((d) => { - const { data: p } = d.detail; - p?.hap?.context?.id === V && C((U) => U.concat([d.detail]).slice(-10)); + }, [r, P, s, b, y, q]); + const [L, C] = _([]); + return Oe( + E((o) => { + const { data: v } = o.detail; + v?.hap?.context?.id === V && C((U) => U.concat([o.detail]).slice(-10)); }, []) - ), /* @__PURE__ */ l.createElement("div", { - className: _.container, - ref: K - }, /* @__PURE__ */ l.createElement("div", { - className: _.header - }, /* @__PURE__ */ l.createElement("div", { - className: _.buttons - }, /* @__PURE__ */ l.createElement("button", { - className: T(_.button, x ? "sc-animate-pulse" : ""), - onClick: () => P() - }, /* @__PURE__ */ l.createElement(ee, { - type: x ? "stop" : "play" - })), /* @__PURE__ */ l.createElement("button", { - className: T(v ? _.button : _.buttonDisabled), - onClick: () => a() - }, /* @__PURE__ */ l.createElement(ee, { + ), /* @__PURE__ */ d.createElement("div", { + className: F.container, + ref: I + }, /* @__PURE__ */ d.createElement("div", { + className: F.header + }, /* @__PURE__ */ d.createElement("div", { + className: F.buttons + }, /* @__PURE__ */ d.createElement("button", { + className: T(F.button, R ? "sc-animate-pulse" : ""), + onClick: () => H() + }, /* @__PURE__ */ d.createElement(ee, { + type: R ? "stop" : "play" + })), /* @__PURE__ */ d.createElement("button", { + className: T(p ? F.button : F.buttonDisabled), + onClick: () => i() + }, /* @__PURE__ */ d.createElement(ee, { type: "refresh" - }))), h && /* @__PURE__ */ l.createElement("div", { - className: _.error - }, h.message)), /* @__PURE__ */ l.createElement("div", { - className: _.body - }, j && /* @__PURE__ */ l.createElement(Fe, { - value: c, + }))), h && /* @__PURE__ */ d.createElement("div", { + className: F.error + }, h.message)), /* @__PURE__ */ d.createElement("div", { + className: F.body + }, K && /* @__PURE__ */ d.createElement(_e, { + value: s, onChange: g, - onViewChanged: z - })), n && /* @__PURE__ */ l.createElement("canvas", { + onViewChanged: x + })), n && /* @__PURE__ */ d.createElement("canvas", { id: S, className: "w-full pointer-events-none", height: m, - ref: (d) => { - d && d.width !== d.clientWidth && (d.width = d.clientWidth); + ref: (o) => { + o && o.width !== o.clientWidth && (o.width = o.clientWidth); } - }), !!F.length && /* @__PURE__ */ l.createElement("div", { + }), !!L.length && /* @__PURE__ */ d.createElement("div", { className: "sc-bg-gray-800 sc-rounded-md sc-p-2" - }, F.map(({ message: d }, p) => /* @__PURE__ */ l.createElement("div", { - key: p - }, d)))); + }, L.map(({ message: o }, v) => /* @__PURE__ */ d.createElement("div", { + key: v + }, o)))); } -function Ve(e) { - Oe(pe.key, e); +function Oe(e) { + Be(ve.key, e); } -function Oe(e, r, t = !1) { - k(() => (document.addEventListener(e, r, t), () => { - document.removeEventListener(e, r, t); - }), [r]); +function Be(e, t, r = !1) { + k(() => (document.addEventListener(e, t, r), () => { + document.removeEventListener(e, t, r); + }), [t]); } -const Ze = (e) => te(() => (window.addEventListener("keydown", e, !0), () => window.removeEventListener("keydown", e, !0)), [e]); +const Te = (e) => te(() => (window.addEventListener("keydown", e, !0), () => window.removeEventListener("keydown", e, !0)), [e]); export { - Fe as CodeMirror, - Ye as MiniRepl, + _e as CodeMirror, + Ze as MiniRepl, T as cx, - ye as flash, - _e as useHighlighting, - Ze as useKeydown, - Ne as usePostMessage, + we as flash, + Me as useHighlighting, + Te as useKeydown, + Ce as usePostMessage, De as useStrudel }; diff --git a/packages/react/src/hooks/usePatternFrame.mjs b/packages/react/src/hooks/usePatternFrame.mjs index 3670bf6a..065c6ba7 100644 --- a/packages/react/src/hooks/usePatternFrame.mjs +++ b/packages/react/src/hooks/usePatternFrame.mjs @@ -8,13 +8,13 @@ function usePatternFrame({ pattern, started, getTime, onDraw, drawTime = [-2, 2] let visibleHaps = useRef([]); let lastFrame = useRef(null); useEffect(() => { - if (pattern) { + if (pattern && started) { const t = getTime(); const futureHaps = pattern.queryArc(Math.max(t, 0), t + lookahead + 0.1); // +0.1 = workaround for weird holes in query.. visibleHaps.current = visibleHaps.current.filter((h) => h.whole.begin < t); visibleHaps.current = visibleHaps.current.concat(futureHaps); } - }, [pattern]); + }, [pattern, started]); const { start: startFrame, stop: stopFrame } = useFrame( useCallback(() => { const phase = getTime() + lookahead; diff --git a/packages/react/src/hooks/useStrudel.mjs b/packages/react/src/hooks/useStrudel.mjs index 563f4885..527aa708 100644 --- a/packages/react/src/hooks/useStrudel.mjs +++ b/packages/react/src/hooks/useStrudel.mjs @@ -30,6 +30,7 @@ function useStrudel({ const [pattern, setPattern] = useState(); const [started, setStarted] = useState(false); const isDirty = code !== activeCode; + const shouldPaint = useCallback((pat) => !!(pat?.context?.onPaint && drawContext), [drawContext]); // TODO: make sure this hook reruns when scheduler.started changes const { scheduler, evaluate, start, stop, pause } = useMemo( @@ -93,14 +94,14 @@ function useStrudel({ const drawFirstFrame = useCallback( (pat) => { - if (drawContext && onDraw) { + if (shouldPaint(pat)) { const [_, lookahead] = drawTime; const haps = pat.queryArc(0, lookahead); // draw at -0.001 to avoid activating haps at 0 onDraw(pat, -0.001, haps, drawTime); } }, - [drawContext, drawTime, onDraw], + [drawTime, onDraw, shouldPaint], ); const inited = useRef(); @@ -130,7 +131,7 @@ function useStrudel({ usePatternFrame({ pattern, - started: drawContext && started, + started: shouldPaint(pattern) && started, getTime: () => scheduler.now(), drawTime, onDraw,