diff --git a/packages/react/dist/index.cjs.js b/packages/react/dist/index.cjs.js index 8310c64d..9cc83def 100644 --- a/packages/react/dist/index.cjs.js +++ b/packages/react/dist/index.cjs.js @@ -1,3 +1,3 @@ -"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});var t=require("react"),oe=require("@uiw/react-codemirror"),S=require("@codemirror/view"),H=require("@codemirror/state"),se=require("@codemirror/lang-javascript"),u=require("@lezer/highlight"),ne=require("@uiw/codemirror-themes"),ce=require("react-hook-inview"),U=require("@strudel.cycles/eval"),ie=require("@strudel.cycles/core/util.mjs"),k=require("@strudel.cycles/tone"),V=require("@strudel.cycles/core"),T=require("@strudel.cycles/midi");function $(e){return e&&typeof e=="object"&&"default"in e?e:{default:e}}var m=$(t),le=$(oe),ue=ne.createTheme({theme:"dark",settings:{background:"#222",foreground:"#75baff",caret:"#ffcc00",selection:"rgba(128, 203, 196, 0.5)",selectionMatch:"#036dd626",lineHighlight:"#8a91991a",gutterBackground:"transparent",gutterForeground:"#676e95"},styles:[{tag:u.tags.keyword,color:"#c792ea"},{tag:u.tags.operator,color:"#89ddff"},{tag:u.tags.special(u.tags.variableName),color:"#eeffff"},{tag:u.tags.typeName,color:"#f07178"},{tag:u.tags.atom,color:"#f78c6c"},{tag:u.tags.number,color:"#ff5370"},{tag:u.tags.definition(u.tags.variableName),color:"#82aaff"},{tag:u.tags.string,color:"#c3e88d"},{tag:u.tags.special(u.tags.string),color:"#f07178"},{tag:u.tags.comment,color:"#7d8799"},{tag:u.tags.variableName,color:"#f07178"},{tag:u.tags.tagName,color:"#ff5370"},{tag:u.tags.bracket,color:"#a2a1a4"},{tag:u.tags.meta,color:"#ffcb6b"},{tag:u.tags.attributeName,color:"#c792ea"},{tag:u.tags.propertyName,color:"#c792ea"},{tag:u.tags.className,color:"#decb6b"},{tag:u.tags.invalid,color:"#ffffff"}]});const z=H.StateEffect.define(),de=H.StateField.define({create(){return S.Decoration.none},update(e,a){try{for(let s of a.effects)if(s.is(z))if(s.value){const c=S.Decoration.mark({attributes:{style:"background-color: #FFCA2880"}});e=S.Decoration.set([c.range(0,a.newDoc.length)])}else e=S.Decoration.set([]);return e}catch(s){return console.warn("flash error",s),e}},provide:e=>S.EditorView.decorations.from(e)}),Q=e=>{e.dispatch({effects:z.of(!0)}),setTimeout(()=>{e.dispatch({effects:z.of(!1)})},200)},A=H.StateEffect.define(),fe=H.StateField.define({create(){return S.Decoration.none},update(e,a){try{for(let s of a.effects)if(s.is(A)){const c=s.value.map(d=>(d.context.locations||[]).map(({start:l,end:i})=>{const f=d.context.color||"#FFCA28";let o=a.newDoc.line(l.line).from+l.column,r=a.newDoc.line(i.line).from+i.column;const b=a.newDoc.length;return o>b||r>b?void 0:S.Decoration.mark({attributes:{style:`outline: 1.5px solid ${f};`}}).range(o,r)})).flat().filter(Boolean)||[];e=S.Decoration.set(c,!0)}return e}catch{return S.Decoration.set([])}},provide:e=>S.EditorView.decorations.from(e)}),ge=[se.javascript(),ue,fe,de];function J({value:e,onChange:a,onViewChanged:s,onSelectionChange:c,options:d,editorDidMount:l}){const i=t.useCallback(r=>{a?.(r)},[a]),f=t.useCallback(r=>{s?.(r)},[s]),o=t.useCallback(r=>{r.selectionSet&&c&&c?.(r.state.selection)},[c]);return m.default.createElement(m.default.Fragment,null,m.default.createElement(le.default,{value:e,onChange:i,onCreateEditor:f,onUpdate:o,extensions:ge}))}function G(e){const{onEvent:a,onQuery:s,onSchedule:c,ready:d=!0,onDraw:l}=e,[i,f]=t.useState(!1),o=1,r=()=>Math.floor(k.Tone.getTransport().seconds/o),b=(h=r())=>{const w=new V.TimeSpan(h,h+1),N=s?.(new V.State(w))||[];c?.(N,h);const F=w.begin.valueOf();k.Tone.getTransport().cancel(F);const _=(h+1)*o-.5,R=Math.max(k.Tone.getTransport().seconds,_)+.1;k.Tone.getTransport().schedule(()=>{b(h+1)},R),N?.filter(E=>E.part.begin.equals(E.whole?.begin)).forEach(E=>{k.Tone.getTransport().schedule(M=>{a(M,E,k.Tone.getContext().currentTime),k.Tone.Draw.schedule(()=>{l?.(M,E)},M)},E.part.begin.valueOf())})};t.useEffect(()=>{d&&b()},[a,c,s,l,d]);const C=async()=>{f(!0),await k.Tone.start(),k.Tone.getTransport().start("+0.1")},v=()=>{k.Tone.getTransport().pause(),f(!1)};return{start:C,stop:v,onEvent:a,started:i,setStarted:f,toggle:()=>i?v():C(),query:b,activeCycle:r}}function X(e){return t.useEffect(()=>(window.addEventListener("message",e),()=>window.removeEventListener("message",e)),[e]),t.useCallback(a=>window.postMessage(a,"*"),[])}let me=()=>Math.floor((1+Math.random())*65536).toString(16).substring(1);const he=e=>encodeURIComponent(btoa(e));function Y({tune:e,defaultSynth:a,autolink:s=!0,onEvent:c,onDraw:d}){const l=t.useMemo(()=>me(),[]),[i,f]=t.useState(e),[o,r]=t.useState(),[b,C]=t.useState(""),[v,y]=t.useState(),[h,w]=t.useState(!1),[N,F]=t.useState(""),[_,R]=t.useState(),E=t.useMemo(()=>i!==o||v,[i,o,v]),M=t.useCallback(g=>C(n=>n+`${n?` +"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});var t=require("react"),re=require("@uiw/react-codemirror"),D=require("@codemirror/view"),A=require("@codemirror/state"),ae=require("@codemirror/lang-javascript"),u=require("@lezer/highlight"),oe=require("@uiw/codemirror-themes"),se=require("react-hook-inview"),I=require("@strudel.cycles/eval"),ne=require("@strudel.cycles/core/util.mjs"),C=require("@strudel.cycles/tone"),P=require("@strudel.cycles/core"),S=require("@strudel.cycles/midi");function K(e){return e&&typeof e=="object"&&"default"in e?e:{default:e}}var h=K(t),ce=K(re),ie=oe.createTheme({theme:"dark",settings:{background:"#222",foreground:"#75baff",caret:"#ffcc00",selection:"rgba(128, 203, 196, 0.5)",selectionMatch:"#036dd626",lineHighlight:"#8a91991a",gutterBackground:"transparent",gutterForeground:"#676e95"},styles:[{tag:u.tags.keyword,color:"#c792ea"},{tag:u.tags.operator,color:"#89ddff"},{tag:u.tags.special(u.tags.variableName),color:"#eeffff"},{tag:u.tags.typeName,color:"#f07178"},{tag:u.tags.atom,color:"#f78c6c"},{tag:u.tags.number,color:"#ff5370"},{tag:u.tags.definition(u.tags.variableName),color:"#82aaff"},{tag:u.tags.string,color:"#c3e88d"},{tag:u.tags.special(u.tags.string),color:"#f07178"},{tag:u.tags.comment,color:"#7d8799"},{tag:u.tags.variableName,color:"#f07178"},{tag:u.tags.tagName,color:"#ff5370"},{tag:u.tags.bracket,color:"#a2a1a4"},{tag:u.tags.meta,color:"#ffcb6b"},{tag:u.tags.attributeName,color:"#c792ea"},{tag:u.tags.propertyName,color:"#c792ea"},{tag:u.tags.className,color:"#decb6b"},{tag:u.tags.invalid,color:"#ffffff"}]});const V=A.StateEffect.define(),le=A.StateField.define({create(){return D.Decoration.none},update(e,a){try{for(let s of a.effects)if(s.is(V))if(s.value){const c=D.Decoration.mark({attributes:{style:"background-color: #FFCA2880"}});e=D.Decoration.set([c.range(0,a.newDoc.length)])}else e=D.Decoration.set([]);return e}catch(s){return console.warn("flash error",s),e}},provide:e=>D.EditorView.decorations.from(e)}),U=e=>{e.dispatch({effects:V.of(!0)}),setTimeout(()=>{e.dispatch({effects:V.of(!1)})},200)},W=A.StateEffect.define(),ue=A.StateField.define({create(){return D.Decoration.none},update(e,a){try{for(let s of a.effects)if(s.is(W)){const c=s.value.map(l=>(l.context.locations||[]).map(({start:f,end:i})=>{const d=l.context.color||"#FFCA28";let r=a.newDoc.line(f.line).from+f.column,o=a.newDoc.line(i.line).from+i.column;const p=a.newDoc.length;return r>p||o>p?void 0:D.Decoration.mark({attributes:{style:`outline: 1.5px solid ${d};`}}).range(r,o)})).flat().filter(Boolean)||[];e=D.Decoration.set(c,!0)}return e}catch{return D.Decoration.set([])}},provide:e=>D.EditorView.decorations.from(e)}),de=[ae.javascript(),ie,ue,le];function $({value:e,onChange:a,onViewChanged:s,onSelectionChange:c,options:l,editorDidMount:f}){const i=t.useCallback(o=>{a?.(o)},[a]),d=t.useCallback(o=>{s?.(o)},[s]),r=t.useCallback(o=>{o.selectionSet&&c&&c?.(o.state.selection)},[c]);return h.default.createElement(h.default.Fragment,null,h.default.createElement(ce.default,{value:e,onChange:i,onCreateEditor:d,onUpdate:r,extensions:de}))}function Q(e){const{onEvent:a,onQuery:s,onSchedule:c,ready:l=!0,onDraw:f}=e,[i,d]=t.useState(!1),r=1,o=()=>Math.floor(C.Tone.getTransport().seconds/r),p=(g=o())=>{const M=new P.TimeSpan(g,g+1),q=s?.(new P.State(M))||[];c?.(q,g);const _=M.begin.valueOf();C.Tone.getTransport().cancel(_);const T=(g+1)*r-.5,x=Math.max(C.Tone.getTransport().seconds,T)+.1;C.Tone.getTransport().schedule(()=>{p(g+1)},x),q?.filter(w=>w.part.begin.equals(w.whole?.begin)).forEach(w=>{C.Tone.getTransport().schedule(E=>{a(E,w,C.Tone.getContext().currentTime),C.Tone.Draw.schedule(()=>{f?.(E,w)},E)},w.part.begin.valueOf())})};t.useEffect(()=>{l&&p()},[a,c,s,f,l]);const y=async()=>{d(!0),await C.Tone.start(),C.Tone.getTransport().start("+0.1")},b=()=>{C.Tone.getTransport().pause(),d(!1)};return{start:y,stop:b,onEvent:a,started:i,setStarted:d,toggle:()=>i?b():y(),query:p,activeCycle:o}}function J(e){return t.useEffect(()=>(window.addEventListener("message",e),()=>window.removeEventListener("message",e)),[e]),t.useCallback(a=>window.postMessage(a,"*"),[])}let fe=()=>Math.floor((1+Math.random())*65536).toString(16).substring(1);const ge=e=>encodeURIComponent(btoa(e));function G({tune:e,defaultSynth:a,autolink:s=!0,onEvent:c,onDraw:l}){const f=t.useMemo(()=>fe(),[]),[i,d]=t.useState(e),[r,o]=t.useState(),[p,y]=t.useState(""),[b,k]=t.useState(),[g,M]=t.useState(!1),[q,_]=t.useState(""),[T,x]=t.useState(),w=t.useMemo(()=>i!==r||b,[i,r,b]),E=t.useCallback(m=>y(n=>n+`${n?` -`:""}${g}`),[]),L=t.useMemo(()=>{if(o&&!o.includes("strudel disable-highlighting"))return(g,n)=>d?.(g,n,o)},[o,d]),P=t.useMemo(()=>o&&o.includes("strudel hide-header"),[o]),W=t.useMemo(()=>o&&o.includes("strudel hide-console"),[o]),p=G({onDraw:L,onEvent:t.useCallback((g,n,te)=>{try{c?.(n),n.context.logs?.length&&n.context.logs.forEach(M);const{onTrigger:q,velocity:re}=n.context;if(q)q(g,n,te,1);else if(a){const ae=ie.getPlayableNoteValue(n);a.triggerAttackRelease(ae,n.duration.valueOf(),g,re)}else throw new Error("no defaultSynth passed to useRepl.")}catch(q){console.warn(q),q.message="unplayable event: "+q?.message,M(q.message)}},[c,M,a]),onQuery:t.useCallback(g=>{try{return _?.query(g)||[]}catch(n){return console.warn(n),n.message="query error: "+n.message,y(n),[]}},[_]),onSchedule:t.useCallback((g,n)=>ee(g),[]),ready:!!_&&!!o}),j=X(({data:{from:g,type:n}})=>{n==="start"&&g!==l&&(p.setStarted(!1),r(void 0))}),B=t.useCallback(async(g=i)=>{if(o&&!E){y(void 0),p.start();return}try{w(!0);const n=await U.evaluate(g);p.start(),j({type:"start",from:l}),R(()=>n.pattern),s&&(window.location.hash="#"+encodeURIComponent(btoa(i))),F(he(i)),y(void 0),r(g),w(!1)}catch(n){n.message="evaluation error: "+n.message,console.warn(n),y(n)}},[o,E,i,p,s,l,j]),ee=(g,n)=>{g.length};return{hideHeader:P,hideConsole:W,pending:h,code:i,setCode:f,pattern:_,error:v,cycle:p,setPattern:R,dirty:E,log:b,togglePlay:()=>{p.started?p.stop():B()},setActiveCode:r,activateCode:B,activeCode:o,pushLog:M,hash:N}}function O(...e){return e.filter(Boolean).join(" ")}let x=[],I;function Z({view:e,pattern:a,active:s}){t.useEffect(()=>{if(e)if(a&&s){let d=function(){try{const l=k.Tone.getTransport().seconds,f=[Math.max(I||l,l-1/10),l+1/60];I=l+1/60,x=x.filter(r=>r.whole.end>l);const o=a.queryArc(...f).filter(r=>r.hasOnset());x=x.concat(o),e.dispatch({effects:A.of(x)})}catch{e.dispatch({effects:A.of([])})}c=requestAnimationFrame(d)},c=requestAnimationFrame(d);return()=>{cancelAnimationFrame(c)}}else x=[],e.dispatch({effects:A.of([])})},[a,s,e])}const pe="_container_3i85k_1",be="_header_3i85k_5",ve="_buttons_3i85k_9",ye="_button_3i85k_9",we="_buttonDisabled_3i85k_17",Ee="_error_3i85k_21",Me="_body_3i85k_25";var D={container:pe,header:be,buttons:ve,button:ye,buttonDisabled:we,error:Ee,body:Me};function K({type:e}){return m.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:m.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:m.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:m.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"})}[e])}function Ce({tune:e,defaultSynth:a,hideOutsideView:s=!1,theme:c,init:d,onEvent:l,enableKeyboard:i}){const{code:f,setCode:o,pattern:r,activeCode:b,activateCode:C,evaluateOnly:v,error:y,cycle:h,dirty:w,togglePlay:N,stop:F}=Y({tune:e,defaultSynth:a,autolink:!1,onEvent:l});t.useEffect(()=>{d&&v()},[e,d]);const[_,R]=t.useState(),[E,M]=ce.useInView({threshold:.01}),L=t.useRef(),P=t.useMemo(()=>((M||!s)&&(L.current=!0),M||L.current),[M,s]);return Z({view:_,pattern:r,active:h.started&&!b?.includes("strudel disable-highlighting")}),t.useLayoutEffect(()=>{if(i){const W=async p=>{(p.ctrlKey||p.altKey)&&(p.code==="Enter"?(p.preventDefault(),Q(_),await C()):p.code==="Period"&&(h.stop(),p.preventDefault()))};return window.addEventListener("keydown",W,!0),()=>window.removeEventListener("keydown",W,!0)}},[i,r,f,C,h,_]),m.default.createElement("div",{className:D.container,ref:E},m.default.createElement("div",{className:D.header},m.default.createElement("div",{className:D.buttons},m.default.createElement("button",{className:O(D.button,h.started?"sc-animate-pulse":""),onClick:()=>N()},m.default.createElement(K,{type:h.started?"pause":"play"})),m.default.createElement("button",{className:O(w?D.button:D.buttonDisabled),onClick:()=>C()},m.default.createElement(K,{type:"refresh"}))),y&&m.default.createElement("div",{className:D.error},y.message)),m.default.createElement("div",{className:D.body},P&&m.default.createElement(J,{value:f,onChange:o,onViewChanged:R})))}function ke({defaultOutput:e,interval:a,getTime:s,code:c,evalOnMount:d=!0}){const[l,i]=t.useState(),[f,o]=t.useState(),[r,b]=t.useState(c),C=c!==r,v=t.useMemo(()=>new V.Scheduler({interval:a,onTrigger:e,onError:i,getTime:s}),[e,a]),y=t.useCallback(async()=>{if(!c){console.log("no code..");return}try{const{pattern:w}=await U.evaluate(c);b(c),v?.setPattern(w),o()}catch(w){o(w),console.warn("eval error",w)}},[c,v]),h=t.useRef();return t.useEffect(()=>{!h.current&&d&&(h.current=!0,y())},[y,d]),{schedulerError:l,scheduler:v,evalError:f,evaluate:y,activeCode:r,isDirty:C}}const _e=e=>t.useLayoutEffect(()=>(window.addEventListener("keydown",e,!0),()=>window.removeEventListener("keydown",e,!0)),[e]);function Te(e){const{ready:a,connected:s,disconnected:c}=e,[d,l]=t.useState(!0),[i,f]=t.useState(T.WebMidi?.outputs||[]);return t.useEffect(()=>{T.enableWebMidi().then(()=>{T.WebMidi.addListener("connected",r=>{f([...T.WebMidi.outputs]),s?.(T.WebMidi,r)}),T.WebMidi.addListener("disconnected",r=>{f([...T.WebMidi.outputs]),c?.(T.WebMidi,r)}),a?.(T.WebMidi),l(!1)}).catch(r=>{if(r){console.error(r),console.warn("Web Midi could not be enabled..");return}})},[a,s,c,i]),{loading:d,outputs:i,outputByName:r=>T.WebMidi.getOutputByName(r)}}exports.CodeMirror=J;exports.MiniRepl=Ce;exports.cx=O;exports.flash=Q;exports.useCycle=G;exports.useHighlighting=Z;exports.useKeydown=_e;exports.usePostMessage=X;exports.useRepl=Y;exports.useStrudel=ke;exports.useWebMidi=Te; +`:""}${m}`),[]),F=t.useMemo(()=>{if(r&&!r.includes("strudel disable-highlighting"))return(m,n)=>l?.(m,n,r)},[r,l]),H=t.useMemo(()=>r&&r.includes("strudel hide-header"),[r]),L=t.useMemo(()=>r&&r.includes("strudel hide-console"),[r]),v=Q({onDraw:F,onEvent:t.useCallback((m,n,Z)=>{try{c?.(n),n.context.logs?.length&&n.context.logs.forEach(E);const{onTrigger:R,velocity:ee}=n.context;if(R)R(m,n,Z,1);else if(a){const te=ne.getPlayableNoteValue(n);a.triggerAttackRelease(te,n.duration.valueOf(),m,ee)}else throw new Error("no defaultSynth passed to useRepl.")}catch(R){console.warn(R),R.message="unplayable event: "+R?.message,E(R.message)}},[c,E,a]),onQuery:t.useCallback(m=>{try{return T?.query(m)||[]}catch(n){return console.warn(n),n.message="query error: "+n.message,k(n),[]}},[T]),onSchedule:t.useCallback((m,n)=>Y(m),[]),ready:!!T&&!!r}),O=J(({data:{from:m,type:n}})=>{n==="start"&&m!==f&&(v.setStarted(!1),o(void 0))}),j=t.useCallback(async(m=i)=>{if(r&&!w){k(void 0),v.start();return}try{M(!0);const n=await I.evaluate(m);v.start(),O({type:"start",from:f}),x(()=>n.pattern),s&&(window.location.hash="#"+encodeURIComponent(btoa(i))),_(ge(i)),k(void 0),o(m),M(!1)}catch(n){n.message="evaluation error: "+n.message,console.warn(n),k(n)}},[r,w,i,v,s,f,O]),Y=(m,n)=>{m.length};return{hideHeader:H,hideConsole:L,pending:g,code:i,setCode:d,pattern:T,error:b,cycle:v,setPattern:x,dirty:w,log:p,togglePlay:()=>{v.started?v.stop():j()},setActiveCode:o,activateCode:j,activeCode:r,pushLog:E,hash:q}}function z(...e){return e.filter(Boolean).join(" ")}function X({view:e,pattern:a,active:s,getTime:c}){const l=t.useRef([]),f=t.useRef();t.useEffect(()=>{if(e)if(a&&s){let d=function(){try{const r=c(),p=[Math.max(f.current||r,r-1/10),r+1/60];f.current=r+1/60,l.current=l.current.filter(b=>b.whole.end>r);const y=a.queryArc(...p).filter(b=>b.hasOnset());l.current=l.current.concat(y),e.dispatch({effects:W.of(l.current)})}catch{e.dispatch({effects:W.of([])})}i=requestAnimationFrame(d)},i=requestAnimationFrame(d);return()=>{cancelAnimationFrame(i)}}else l.current=[],e.dispatch({effects:W.of([])})},[a,s,e])}const me="_container_3i85k_1",he="_header_3i85k_5",pe="_buttons_3i85k_9",be="_button_3i85k_9",ve="_buttonDisabled_3i85k_17",ye="_error_3i85k_21",we="_body_3i85k_25";var N={container:me,header:he,buttons:pe,button:be,buttonDisabled:ve,error:ye,body:we};function B({type:e}){return h.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:h.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:h.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:h.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"})}[e])}function Ee({tune:e,defaultSynth:a,hideOutsideView:s=!1,theme:c,init:l,onEvent:f,enableKeyboard:i}){const{code:d,setCode:r,pattern:o,activeCode:p,activateCode:y,evaluateOnly:b,error:k,cycle:g,dirty:M,togglePlay:q,stop:_}=G({tune:e,defaultSynth:a,autolink:!1,onEvent:f});t.useEffect(()=>{l&&b()},[e,l]);const[T,x]=t.useState(),[w,E]=se.useInView({threshold:.01}),F=t.useRef(),H=t.useMemo(()=>((E||!s)&&(F.current=!0),E||F.current),[E,s]);return X({view:T,pattern:o,active:g.started&&!p?.includes("strudel disable-highlighting"),getTime:()=>C.Tone.getTransport().seconds}),t.useLayoutEffect(()=>{if(i){const L=async v=>{(v.ctrlKey||v.altKey)&&(v.code==="Enter"?(v.preventDefault(),U(T),await y()):v.code==="Period"&&(g.stop(),v.preventDefault()))};return window.addEventListener("keydown",L,!0),()=>window.removeEventListener("keydown",L,!0)}},[i,o,d,y,g,T]),h.default.createElement("div",{className:N.container,ref:w},h.default.createElement("div",{className:N.header},h.default.createElement("div",{className:N.buttons},h.default.createElement("button",{className:z(N.button,g.started?"sc-animate-pulse":""),onClick:()=>q()},h.default.createElement(B,{type:g.started?"pause":"play"})),h.default.createElement("button",{className:z(M?N.button:N.buttonDisabled),onClick:()=>y()},h.default.createElement(B,{type:"refresh"}))),k&&h.default.createElement("div",{className:N.error},k.message)),h.default.createElement("div",{className:N.body},H&&h.default.createElement($,{value:d,onChange:r,onViewChanged:x})))}function Me({defaultOutput:e,interval:a,getTime:s,code:c,evalOnMount:l=!1}){const[f,i]=t.useState(),[d,r]=t.useState(),[o,p]=t.useState(c),[y,b]=t.useState(),k=c!==o,g=t.useMemo(()=>new P.Scheduler({interval:a,onTrigger:e,onError:i,getTime:s}),[e,a]),M=t.useCallback(async()=>{if(!c){console.log("no code..");return}try{const{pattern:_}=await I.evaluate(c);p(c),g?.setPattern(_),b(_),r()}catch(_){r(_),console.warn("eval error",_)}},[c,g]),q=t.useRef();return t.useEffect(()=>{!q.current&&l&&(q.current=!0,M())},[M,l]),{schedulerError:f,scheduler:g,evalError:d,evaluate:M,activeCode:o,isDirty:k,pattern:y}}const Ce=e=>t.useLayoutEffect(()=>(window.addEventListener("keydown",e,!0),()=>window.removeEventListener("keydown",e,!0)),[e]);function ke(e){const{ready:a,connected:s,disconnected:c}=e,[l,f]=t.useState(!0),[i,d]=t.useState(S.WebMidi?.outputs||[]);return t.useEffect(()=>{S.enableWebMidi().then(()=>{S.WebMidi.addListener("connected",o=>{d([...S.WebMidi.outputs]),s?.(S.WebMidi,o)}),S.WebMidi.addListener("disconnected",o=>{d([...S.WebMidi.outputs]),c?.(S.WebMidi,o)}),a?.(S.WebMidi),f(!1)}).catch(o=>{if(o){console.error(o),console.warn("Web Midi could not be enabled..");return}})},[a,s,c,i]),{loading:l,outputs:i,outputByName:o=>S.WebMidi.getOutputByName(o)}}exports.CodeMirror=$;exports.MiniRepl=Ee;exports.cx=z;exports.flash=U;exports.useCycle=Q;exports.useHighlighting=X;exports.useKeydown=Ce;exports.usePostMessage=J;exports.useRepl=G;exports.useStrudel=Me;exports.useWebMidi=ke; diff --git a/packages/react/dist/index.es.js b/packages/react/dist/index.es.js index ec549f94..4cce6dc7 100644 --- a/packages/react/dist/index.es.js +++ b/packages/react/dist/index.es.js @@ -401,10 +401,9 @@ function cx(...classes) { return classes.filter(Boolean).join(' '); } -let highlights = []; // actively highlighted events -let lastEnd; - -function useHighlighting({ view, pattern, active }) { +function useHighlighting({ view, pattern, active, getTime }) { + const highlights = useRef([]); + const lastEnd = useRef(); useEffect(() => { if (view) { if (pattern && active) { @@ -412,16 +411,16 @@ function useHighlighting({ view, pattern, active }) { function updateHighlights() { try { - const audioTime = Tone.getTransport().seconds; + const audioTime = getTime(); // force min framerate of 10 fps => fixes crash on tab refocus, where lastEnd could be far away // see https://github.com/tidalcycles/strudel/issues/108 - const begin = Math.max(lastEnd || audioTime, audioTime - 1 / 10); + const begin = Math.max(lastEnd.current || audioTime, audioTime - 1 / 10); const span = [begin, audioTime + 1 / 60]; - lastEnd = audioTime + 1 / 60; - highlights = highlights.filter((hap) => hap.whole.end > audioTime); // keep only highlights that are still active + lastEnd.current = audioTime + 1 / 60; + highlights.current = highlights.current.filter((hap) => hap.whole.end > audioTime); // keep only highlights that are still active const haps = pattern.queryArc(...span).filter((hap) => hap.hasOnset()); - highlights = highlights.concat(haps); // add potential new onsets - view.dispatch({ effects: setHighlights.of(highlights) }); // highlight all still active + new active haps + highlights.current = highlights.current.concat(haps); // add potential new onsets + view.dispatch({ effects: setHighlights.of(highlights.current) }); // highlight all still active + new active haps } catch (err) { // console.log('error in updateHighlights', err); view.dispatch({ effects: setHighlights.of([]) }); @@ -433,7 +432,7 @@ function useHighlighting({ view, pattern, active }) { cancelAnimationFrame(frame); }; } else { - highlights = []; + highlights.current = []; view.dispatch({ effects: setHighlights.of([]) }); } } @@ -505,7 +504,12 @@ function MiniRepl({ tune, defaultSynth, hideOutsideView = false, theme, init, on } return isVisible || wasVisible.current; }, [isVisible, hideOutsideView]); - useHighlighting({ view, pattern, active: cycle.started && !activeCode?.includes("strudel disable-highlighting") }); + useHighlighting({ + view, + pattern, + active: cycle.started && !activeCode?.includes("strudel disable-highlighting"), + getTime: () => Tone.getTransport().seconds + }); useLayoutEffect(() => { if (enableKeyboard) { const handleKeyPress = async (e) => { @@ -552,11 +556,12 @@ function MiniRepl({ tune, defaultSynth, hideOutsideView = false, theme, init, on }))); } -function useStrudel({ defaultOutput, interval, getTime, code, evalOnMount = true }) { +function useStrudel({ defaultOutput, interval, getTime, code, evalOnMount = false }) { // scheduler const [schedulerError, setSchedulerError] = useState(); const [evalError, setEvalError] = useState(); const [activeCode, setActiveCode] = useState(code); + const [pattern, setPattern] = useState(); const isDirty = code !== activeCode; // TODO: how / when to remove schedulerError? const scheduler = useMemo( @@ -570,9 +575,10 @@ function useStrudel({ defaultOutput, interval, getTime, code, evalOnMount = true } try { // TODO: let user inject custom eval function? - const { pattern } = await evaluate(code); + const { pattern: _pattern } = await evaluate(code); setActiveCode(code); - scheduler?.setPattern(pattern); + scheduler?.setPattern(_pattern); + setPattern(_pattern); setEvalError(); } catch (err) { setEvalError(err); @@ -588,7 +594,7 @@ function useStrudel({ defaultOutput, interval, getTime, code, evalOnMount = true } }, [evaluate$1, evalOnMount]); - return { schedulerError, scheduler, evalError, evaluate: evaluate$1, activeCode, isDirty }; + return { schedulerError, scheduler, evalError, evaluate: evaluate$1, activeCode, isDirty, pattern }; } // set active pattern on ctrl+enter