diff --git a/packages/react/dist/index.cjs.js b/packages/react/dist/index.cjs.js index 089ed987c..fd5ba902e 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"),ae=require("react-codemirror6"),H=require("@codemirror/view"),$=require("@codemirror/state"),re=require("@codemirror/lang-javascript"),n=require("@codemirror/highlight"),ne=require("react-hook-inview"),se=require("@strudel.cycles/eval"),ce=require("@strudel.cycles/core/util.mjs"),p=require("@strudel.cycles/tone"),z=require("@strudel.cycles/core"),y=require("@strudel.cycles/midi");function le(e){return e&&typeof e=="object"&&"default"in e?e:{default:e}}var g=le(t);const ie="#abb2bf",ue="#7d8799",de="#ffffff",fe="#21252b",V="rgba(0, 0, 0, 0.5)",ge="transparent",A="#353a42",me="rgba(128, 203, 196, 0.5)",F="#ffcc00",be=H.EditorView.theme({"&":{color:"#ffffff",backgroundColor:ge,fontSize:"15px","z-index":11},".cm-content":{caretColor:F,lineHeight:"22px"},".cm-line":{background:"#2C323699"},"&.cm-focused .cm-cursor":{backgroundColor:F,width:"3px"},"&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection":{backgroundColor:me},".cm-panels":{backgroundColor:fe,color:"#ffffff"},".cm-panels.cm-panels-top":{borderBottom:"2px solid black"},".cm-panels.cm-panels-bottom":{borderTop:"2px solid black"},".cm-searchMatch":{backgroundColor:"#72a1ff59",outline:"1px solid #457dff"},".cm-searchMatch.cm-searchMatch-selected":{backgroundColor:"#6199ff2f"},".cm-activeLine":{backgroundColor:V},".cm-selectionMatch":{backgroundColor:"#aafe661a"},"&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket":{backgroundColor:"#bad0f847",outline:"1px solid #515a6b"},".cm-gutters":{background:"transparent",color:"#676e95",border:"none"},".cm-activeLineGutter":{backgroundColor:V},".cm-foldPlaceholder":{backgroundColor:"transparent",border:"none",color:"#ddd"},".cm-tooltip":{border:"none",backgroundColor:A},".cm-tooltip .cm-tooltip-arrow:before":{borderTopColor:"transparent",borderBottomColor:"transparent"},".cm-tooltip .cm-tooltip-arrow:after":{borderTopColor:A,borderBottomColor:A},".cm-tooltip-autocomplete":{"& > ul > li[aria-selected]":{backgroundColor:V,color:ie}}},{dark:!0}),pe=n.HighlightStyle.define([{tag:n.tags.keyword,color:"#c792ea"},{tag:n.tags.operator,color:"#89ddff"},{tag:n.tags.special(n.tags.variableName),color:"#eeffff"},{tag:n.tags.typeName,color:"#f07178"},{tag:n.tags.atom,color:"#f78c6c"},{tag:n.tags.number,color:"#ff5370"},{tag:n.tags.definition(n.tags.variableName),color:"#82aaff"},{tag:n.tags.string,color:"#c3e88d"},{tag:n.tags.special(n.tags.string),color:"#f07178"},{tag:n.tags.comment,color:ue},{tag:n.tags.variableName,color:"#f07178"},{tag:n.tags.tagName,color:"#ff5370"},{tag:n.tags.bracket,color:"#a2a1a4"},{tag:n.tags.meta,color:"#ffcb6b"},{tag:n.tags.attributeName,color:"#c792ea"},{tag:n.tags.propertyName,color:"#c792ea"},{tag:n.tags.className,color:"#decb6b"},{tag:n.tags.invalid,color:de}]),he=[be,pe],W=$.StateEffect.define(),ve=$.StateField.define({create(){return H.Decoration.none},update(e,a){try{for(let i of a.effects)i.is(W)&&(e=H.Decoration.set(i.value.flatMap(u=>(u.context.locations||[]).map(({start:d,end:s})=>{const c=u.context.color||"#FFCA28";let m=a.newDoc.line(d.line).from+d.column,l=a.newDoc.line(s.line).from+s.column;const r=a.newDoc.length;return m>r||l>r?void 0:H.Decoration.mark({attributes:{style:`outline: 1px solid ${c}`}}).range(m,l)})).filter(Boolean),!0));return e}catch{return e}},provide:e=>H.EditorView.decorations.from(e)});function Q({value:e,onChange:a,onViewChanged:i,onCursor:u,options:d,editorDidMount:s,theme:c}){return g.default.createElement(g.default.Fragment,null,g.default.createElement(ae.CodeMirror,{onViewChange:i,style:{display:"flex",flexDirection:"column",flex:"1 0 auto"},value:e,onChange:a,extensions:[re.javascript(),c||he,ve]}))}function U(e){const{onEvent:a,onQuery:i,onSchedule:u,ready:d=!0,onDraw:s}=e,[c,m]=t.useState(!1),l=1,r=()=>Math.floor(p.Tone.getTransport().seconds/l),w=(C=r())=>{const S=new z.TimeSpan(C,C+1),D=i?.(new z.State(S))||[];u?.(D,C);const B=S.begin.valueOf();p.Tone.getTransport().cancel(B);const v=(C+1)*l-.5,N=Math.max(p.Tone.getTransport().seconds,v)+.1;p.Tone.getTransport().schedule(()=>{w(C+1)},N),D?.filter(b=>b.part.begin.equals(b.whole?.begin)).forEach(b=>{p.Tone.getTransport().schedule(k=>{a(k,b,p.Tone.getContext().currentTime),p.Tone.Draw.schedule(()=>{s?.(k,b)},k)},b.part.begin.valueOf())})};t.useEffect(()=>{d&&w()},[a,u,i,s,d]);const x=async()=>{m(!0),await p.Tone.start(),p.Tone.getTransport().start("+0.1")},h=()=>{p.Tone.getTransport().pause(),m(!1)};return{start:x,stop:h,onEvent:a,started:c,setStarted:m,toggle:()=>c?h():x(),query:w,activeCycle:r}}function G(e){return t.useEffect(()=>(window.addEventListener("message",e),()=>window.removeEventListener("message",e)),[e]),t.useCallback(a=>window.postMessage(a,"*"),[])}let ye=()=>Math.floor((1+Math.random())*65536).toString(16).substring(1);const Ce=e=>encodeURIComponent(btoa(e));function J({tune:e,defaultSynth:a,autolink:i=!0,onEvent:u,onDraw:d}){const s=t.useMemo(()=>ye(),[]),[c,m]=t.useState(e),[l,r]=t.useState(),[w,x]=t.useState(""),[h,_]=t.useState(),[C,S]=t.useState(!1),[D,B]=t.useState(""),[v,N]=t.useState(),b=t.useMemo(()=>c!==l||h,[c,l,h]),k=t.useCallback(f=>x(o=>o+`${o?` +"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});var t=require("react"),re=require("react-codemirror6"),H=require("@codemirror/view"),Q=require("@codemirror/state"),ne=require("@codemirror/lang-javascript"),n=require("@codemirror/highlight"),se=require("react-hook-inview"),ce=require("@strudel.cycles/eval"),le=require("@strudel.cycles/core/util.mjs"),p=require("@strudel.cycles/tone"),j=require("@strudel.cycles/core"),C=require("@strudel.cycles/midi");function ie(e){return e&&typeof e=="object"&&"default"in e?e:{default:e}}var u=ie(t);const ue="#abb2bf",de="#7d8799",fe="#ffffff",ge="#21252b",z="rgba(0, 0, 0, 0.5)",me="transparent",A="#353a42",be="rgba(128, 203, 196, 0.5)",I="#ffcc00",pe=H.EditorView.theme({"&":{color:"#ffffff",backgroundColor:me,fontSize:"15px","z-index":11},".cm-content":{caretColor:I,lineHeight:"22px"},".cm-line":{background:"#2C323699"},"&.cm-focused .cm-cursor":{backgroundColor:I,width:"3px"},"&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection":{backgroundColor:be},".cm-panels":{backgroundColor:ge,color:"#ffffff"},".cm-panels.cm-panels-top":{borderBottom:"2px solid black"},".cm-panels.cm-panels-bottom":{borderTop:"2px solid black"},".cm-searchMatch":{backgroundColor:"#72a1ff59",outline:"1px solid #457dff"},".cm-searchMatch.cm-searchMatch-selected":{backgroundColor:"#6199ff2f"},".cm-activeLine":{backgroundColor:z},".cm-selectionMatch":{backgroundColor:"#aafe661a"},"&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket":{backgroundColor:"#bad0f847",outline:"1px solid #515a6b"},".cm-gutters":{background:"transparent",color:"#676e95",border:"none"},".cm-activeLineGutter":{backgroundColor:z},".cm-foldPlaceholder":{backgroundColor:"transparent",border:"none",color:"#ddd"},".cm-tooltip":{border:"none",backgroundColor:A},".cm-tooltip .cm-tooltip-arrow:before":{borderTopColor:"transparent",borderBottomColor:"transparent"},".cm-tooltip .cm-tooltip-arrow:after":{borderTopColor:A,borderBottomColor:A},".cm-tooltip-autocomplete":{"& > ul > li[aria-selected]":{backgroundColor:z,color:ue}}},{dark:!0}),he=n.HighlightStyle.define([{tag:n.tags.keyword,color:"#c792ea"},{tag:n.tags.operator,color:"#89ddff"},{tag:n.tags.special(n.tags.variableName),color:"#eeffff"},{tag:n.tags.typeName,color:"#f07178"},{tag:n.tags.atom,color:"#f78c6c"},{tag:n.tags.number,color:"#ff5370"},{tag:n.tags.definition(n.tags.variableName),color:"#82aaff"},{tag:n.tags.string,color:"#c3e88d"},{tag:n.tags.special(n.tags.string),color:"#f07178"},{tag:n.tags.comment,color:de},{tag:n.tags.variableName,color:"#f07178"},{tag:n.tags.tagName,color:"#ff5370"},{tag:n.tags.bracket,color:"#a2a1a4"},{tag:n.tags.meta,color:"#ffcb6b"},{tag:n.tags.attributeName,color:"#c792ea"},{tag:n.tags.propertyName,color:"#c792ea"},{tag:n.tags.className,color:"#decb6b"},{tag:n.tags.invalid,color:fe}]),ve=[pe,he],W=Q.StateEffect.define(),ye=Q.StateField.define({create(){return H.Decoration.none},update(e,a){try{for(let i of a.effects)i.is(W)&&(e=H.Decoration.set(i.value.flatMap(d=>(d.context.locations||[]).map(({start:f,end:s})=>{const c=d.context.color||"#FFCA28";let m=a.newDoc.line(f.line).from+f.column,l=a.newDoc.line(s.line).from+s.column;const r=a.newDoc.length;return m>r||l>r?void 0:H.Decoration.mark({attributes:{style:`outline: 1px solid ${c}`}}).range(m,l)})).filter(Boolean),!0));return e}catch{return e}},provide:e=>H.EditorView.decorations.from(e)});function U({value:e,onChange:a,onViewChanged:i,onCursor:d,options:f,editorDidMount:s,theme:c}){return u.default.createElement(u.default.Fragment,null,u.default.createElement(re.CodeMirror,{onViewChange:i,style:{display:"flex",flexDirection:"column",flex:"1 0 auto"},value:e,onChange:a,extensions:[ne.javascript(),c||ve,ye]}))}function G(e){const{onEvent:a,onQuery:i,onSchedule:d,ready:f=!0,onDraw:s}=e,[c,m]=t.useState(!1),l=1,r=()=>Math.floor(p.Tone.getTransport().seconds/l),M=(h=r())=>{const N=new j.TimeSpan(h,h+1),R=i?.(new j.State(N))||[];d?.(R,h);const B=N.begin.valueOf();p.Tone.getTransport().cancel(B);const k=(h+1)*l-.5,E=Math.max(p.Tone.getTransport().seconds,k)+.1;p.Tone.getTransport().schedule(()=>{M(h+1)},E),R?.filter(b=>b.part.begin.equals(b.whole?.begin)).forEach(b=>{p.Tone.getTransport().schedule(y=>{a(y,b,p.Tone.getContext().currentTime),p.Tone.Draw.schedule(()=>{s?.(y,b)},y)},b.part.begin.valueOf())})};t.useEffect(()=>{f&&M()},[a,d,i,s,f]);const _=async()=>{m(!0),await p.Tone.start(),p.Tone.getTransport().start("+0.1")},v=(h=!1)=>{h?(p.Tone.getTransport().cancel(),p.Tone.getTransport().stop()):p.Tone.getTransport().pause(),m(!1)};return{start:_,stop:v,onEvent:a,started:c,setStarted:m,toggle:()=>c?v():_(),query:M,activeCycle:r}}function J(e){return t.useEffect(()=>(window.addEventListener("message",e),()=>window.removeEventListener("message",e)),[e]),t.useCallback(a=>window.postMessage(a,"*"),[])}let Ce=()=>Math.floor((1+Math.random())*65536).toString(16).substring(1);const we=e=>encodeURIComponent(btoa(e));function K({tune:e,defaultSynth:a,autolink:i=!0,onEvent:d,onDraw:f}){const s=t.useMemo(()=>Ce(),[]),[c,m]=t.useState(e),[l,r]=t.useState(),[M,_]=t.useState(""),[v,S]=t.useState(),[h,N]=t.useState(!1),[R,B]=t.useState(""),[k,E]=t.useState(),b=t.useMemo(()=>c!==l||v,[c,l,v]),y=t.useCallback(g=>_(o=>o+`${o?` -`:""}${f}`),[]),X=t.useMemo(()=>{if(l&&!l.includes("strudel disable-highlighting"))return(f,o)=>d?.(f,o,l)},[l,d]),M=U({onDraw:X,onEvent:t.useCallback((f,o,E)=>{try{u?.(o),o.context.logs?.length&&o.context.logs.forEach(k);const{onTrigger:q,velocity:te}=o.context;if(q)q(f,o,E,1,o.wholeOrPart().begin.valueOf(),o.duration.valueOf());else if(a){const oe=ce.getPlayableNoteValue(o);a.triggerAttackRelease(oe,o.duration.valueOf(),f,te)}else throw new Error("no defaultSynth passed to useRepl.")}catch(q){console.warn(q),q.message="unplayable event: "+q?.message,k(q.message)}},[u,k,a]),onQuery:t.useCallback(f=>{try{return v?.query(f)||[]}catch(o){return console.warn(o),o.message="query error: "+o.message,_(o),[]}},[v]),onSchedule:t.useCallback((f,o)=>Y(f,o),[]),ready:!!v&&!!l}),O=G(({data:{from:f,type:o}})=>{o==="start"&&f!==s&&(M.setStarted(!1),r(void 0))}),P=t.useCallback(async(f=c,o=!1)=>{if(l&&!b){_(void 0),!o&&M.start();return}try{S(!0);const E=await se.evaluate(f);!o&&M.start(),O({type:"start",from:s}),N(()=>E.pattern),i&&(window.location.hash="#"+encodeURIComponent(btoa(c))),B(Ce(c)),_(void 0),r(f),S(!1)}catch(E){E.message="evaluation error: "+E.message,console.warn(E),_(E)}},[l,b,c,M,i,s,O]),Y=(f,o)=>{f.length},Z=()=>{M.started?M.stop():P()},ee=()=>{P(c,!0)};return t.useEffect(()=>()=>M.stop(),[]),{pending:C,code:c,setCode:m,pattern:v,error:h,cycle:M,setPattern:N,dirty:b,log:w,togglePlay:Z,setActiveCode:r,activateCode:P,evaluateOnly:ee,activeCode:l,pushLog:k,hash:D}}function L(...e){return e.filter(Boolean).join(" ")}let R=[],j;function K({view:e,pattern:a,active:i}){t.useEffect(()=>{if(e)if(a&&i){let d=function(){try{const s=p.Tone.getTransport().seconds,m=[Math.max(j||s,s-1/10),s+1/60];j=s+1/60,R=R.filter(r=>r.whole.end>s);const l=a.queryArc(...m).filter(r=>r.hasOnset());R=R.concat(l),e.dispatch({effects:W.of(R)})}catch{e.dispatch({effects:W.of([])})}u=requestAnimationFrame(d)},u=requestAnimationFrame(d);return()=>{cancelAnimationFrame(u)}}else R=[],e.dispatch({effects:W.of([])})},[a,i,e])}const we="_container_10e1g_1",ke="_header_10e1g_5",Me="_buttons_10e1g_9",Ee="_button_10e1g_9",Te="_buttonDisabled_10e1g_17",xe="_error_10e1g_21",_e="_body_10e1g_25";var T={container:we,header:ke,buttons:Me,button:Ee,buttonDisabled:Te,error:xe,body:_e};function I({type:e}){return g.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:g.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:g.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:g.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 Se({tune:e,defaultSynth:a,hideOutsideView:i=!1,theme:u,init:d}){const{code:s,setCode:c,pattern:m,activeCode:l,activateCode:r,evaluateOnly:w,error:x,cycle:h,dirty:_,togglePlay:C}=J({tune:e,defaultSynth:a,autolink:!1});t.useEffect(()=>{d&&w()},[e,d]);const[S,D]=t.useState(),[B,v]=ne.useInView({threshold:.01}),N=t.useRef(),b=t.useMemo(()=>((v||!i)&&(N.current=!0),v||N.current),[v,i]);return K({view:S,pattern:m,active:h.started&&!l?.includes("strudel disable-highlighting")}),g.default.createElement("div",{className:T.container,ref:B},g.default.createElement("div",{className:T.header},g.default.createElement("div",{className:T.buttons},g.default.createElement("button",{className:L(T.button,h.started?"sc-animate-pulse":""),onClick:()=>C()},g.default.createElement(I,{type:h.started?"pause":"play"})),g.default.createElement("button",{className:L(_?T.button:T.buttonDisabled),onClick:()=>r()},g.default.createElement(I,{type:"refresh"}))),x&&g.default.createElement("div",{className:T.error},x.message)),g.default.createElement("div",{className:T.body},b&&g.default.createElement(Q,{theme:u,value:s,onChange:c,onViewChanged:D})))}function Ne(e){const{ready:a,connected:i,disconnected:u}=e,[d,s]=t.useState(!0),[c,m]=t.useState(y.WebMidi?.outputs||[]);return t.useEffect(()=>{y.enableWebMidi().then(()=>{y.WebMidi.addListener("connected",r=>{m([...y.WebMidi.outputs]),i?.(y.WebMidi,r)}),y.WebMidi.addListener("disconnected",r=>{m([...y.WebMidi.outputs]),u?.(y.WebMidi,r)}),a?.(y.WebMidi),s(!1)}).catch(r=>{if(r){console.error(r),console.warn("Web Midi could not be enabled..");return}})},[a,i,u,c]),{loading:d,outputs:c,outputByName:r=>y.WebMidi.getOutputByName(r)}}exports.CodeMirror=Q;exports.MiniRepl=Se;exports.cx=L;exports.useCycle=U;exports.useHighlighting=K;exports.usePostMessage=G;exports.useRepl=J;exports.useWebMidi=Ne; +`:""}${g}`),[]),Y=t.useMemo(()=>{if(l&&!l.includes("strudel disable-highlighting"))return(g,o)=>f?.(g,o,l)},[l,f]),T=G({onDraw:Y,onEvent:t.useCallback((g,o,x)=>{try{d?.(o),o.context.logs?.length&&o.context.logs.forEach(y);const{onTrigger:q,velocity:oe}=o.context;if(q)q(g,o,x,1,o.wholeOrPart().begin.valueOf(),o.duration.valueOf());else if(a){const ae=le.getPlayableNoteValue(o);a.triggerAttackRelease(ae,o.duration.valueOf(),g,oe)}else throw new Error("no defaultSynth passed to useRepl.")}catch(q){console.warn(q),q.message="unplayable event: "+q?.message,y(q.message)}},[d,y,a]),onQuery:t.useCallback(g=>{try{return k?.query(g)||[]}catch(o){return console.warn(o),o.message="query error: "+o.message,S(o),[]}},[k]),onSchedule:t.useCallback((g,o)=>Z(g,o),[]),ready:!!k&&!!l}),O=J(({data:{from:g,type:o}})=>{o==="start"&&g!==s&&(T.setStarted(!1),r(void 0))}),V=t.useCallback(async(g=c,o=!1)=>{if(l&&!b){S(void 0),!o&&T.start();return}try{N(!0);const x=await ce.evaluate(g);!o&&T.start(),O({type:"start",from:s}),E(()=>x.pattern),i&&(window.location.hash="#"+encodeURIComponent(btoa(c))),B(we(c)),S(void 0),r(g),N(!1)}catch(x){x.message="evaluation error: "+x.message,console.warn(x),S(x)}},[l,b,c,T,i,s,O]),Z=(g,o)=>{g.length},ee=()=>{T.started?T.stop():V()},F=()=>{T.stop(!0),r(void 0)},te=()=>{V(c,!0)};return t.useEffect(()=>()=>F(),[]),{pending:h,code:c,setCode:m,pattern:k,error:v,cycle:T,setPattern:E,dirty:b,log:M,togglePlay:ee,stop:F,setActiveCode:r,activateCode:V,evaluateOnly:te,activeCode:l,pushLog:y,hash:R}}function P(...e){return e.filter(Boolean).join(" ")}let D=[],$;function X({view:e,pattern:a,active:i}){t.useEffect(()=>{if(e)if(a&&i){let f=function(){try{const s=p.Tone.getTransport().seconds,m=[Math.max($||s,s-1/10),s+1/60];$=s+1/60,D=D.filter(r=>r.whole.end>s);const l=a.queryArc(...m).filter(r=>r.hasOnset());D=D.concat(l),e.dispatch({effects:W.of(D)})}catch{e.dispatch({effects:W.of([])})}d=requestAnimationFrame(f)},d=requestAnimationFrame(f);return()=>{cancelAnimationFrame(d)}}else D=[],e.dispatch({effects:W.of([])})},[a,i,e])}const Me="_container_10e1g_1",ke="_header_10e1g_5",Ee="_buttons_10e1g_9",Te="_button_10e1g_9",xe="_buttonDisabled_10e1g_17",_e="_error_10e1g_21",Se="_body_10e1g_25";var w={container:Me,header:ke,buttons:Ee,button:Te,buttonDisabled:xe,error:_e,body:Se};function L({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:"M10 18a8 8 0 100-16 8 8 0 000 16zM8 7a1 1 0 00-1 1v4a1 1 0 001 1h4a1 1 0 001-1V8a1 1 0 00-1-1H8z",clipRule:"evenodd"})}[e])}function Ne({tune:e,defaultSynth:a,hideOutsideView:i=!1,theme:d,init:f}){const{code:s,setCode:c,pattern:m,activeCode:l,activateCode:r,evaluateOnly:M,error:_,cycle:v,dirty:S,togglePlay:h,stop:N}=K({tune:e,defaultSynth:a,autolink:!1});t.useEffect(()=>{f&&M()},[e,f]);const[R,B]=t.useState(),[k,E]=se.useInView({threshold:.01}),b=t.useRef(),y=t.useMemo(()=>((E||!i)&&(b.current=!0),E||b.current),[E,i]);return X({view:R,pattern:m,active:v.started&&!l?.includes("strudel disable-highlighting")}),u.default.createElement("div",{className:w.container,ref:k},u.default.createElement("div",{className:w.header},u.default.createElement("div",{className:w.buttons},u.default.createElement("button",{className:P(w.button,v.started?"sc-animate-pulse":""),onClick:()=>h()},u.default.createElement(L,{type:v.started?"pause":"play"})),u.default.createElement("button",{className:P(S?w.button:w.buttonDisabled),onClick:()=>r()},u.default.createElement(L,{type:"refresh"})),u.default.createElement("button",{className:P(w.button),onClick:()=>N(!0)},u.default.createElement(L,{type:"stop"}))),_&&u.default.createElement("div",{className:w.error},_.message)),u.default.createElement("div",{className:w.body},y&&u.default.createElement(U,{theme:d,value:s,onChange:c,onViewChanged:B})))}function qe(e){const{ready:a,connected:i,disconnected:d}=e,[f,s]=t.useState(!0),[c,m]=t.useState(C.WebMidi?.outputs||[]);return t.useEffect(()=>{C.enableWebMidi().then(()=>{C.WebMidi.addListener("connected",r=>{m([...C.WebMidi.outputs]),i?.(C.WebMidi,r)}),C.WebMidi.addListener("disconnected",r=>{m([...C.WebMidi.outputs]),d?.(C.WebMidi,r)}),a?.(C.WebMidi),s(!1)}).catch(r=>{if(r){console.error(r),console.warn("Web Midi could not be enabled..");return}})},[a,i,d,c]),{loading:f,outputs:c,outputByName:r=>C.WebMidi.getOutputByName(r)}}exports.CodeMirror=U;exports.MiniRepl=Ne;exports.cx=P;exports.useCycle=G;exports.useHighlighting=X;exports.usePostMessage=J;exports.useRepl=K;exports.useWebMidi=qe; diff --git a/packages/react/dist/index.es.js b/packages/react/dist/index.es.js index 7d527bb89..7ee7b6e86 100644 --- a/packages/react/dist/index.es.js +++ b/packages/react/dist/index.es.js @@ -256,8 +256,13 @@ function useCycle(props) { await Tone.start(); Tone.getTransport().start('+0.1'); }; - const stop = () => { - Tone.getTransport().pause(); + const stop = (setZero = false) => { + if (setZero) { + Tone.getTransport().cancel(); + Tone.getTransport().stop(); + } else { + Tone.getTransport().pause(); + } setStarted(false); }; const toggle = () => (started ? stop() : start()); @@ -423,12 +428,17 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw: onDrawP } }; + const stop = () => { + cycle.stop(true); + setActiveCode(undefined); + }; + const evaluateOnly = () => { activateCode(code, true); }; useEffect(() => { - return () => cycle.stop(); + return () => stop(); }, []); return { @@ -442,6 +452,7 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw: onDrawP dirty, log, togglePlay, + stop, setActiveCode, activateCode, evaluateOnly, @@ -543,12 +554,17 @@ function Icon({ type }) { 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__ */ React.createElement("path", { + fillRule: "evenodd", + d: "M10 18a8 8 0 100-16 8 8 0 000 16zM8 7a1 1 0 00-1 1v4a1 1 0 001 1h4a1 1 0 001-1V8a1 1 0 00-1-1H8z", + clipRule: "evenodd" }) }[type]); } function MiniRepl({ tune, defaultSynth, hideOutsideView = false, theme, init }) { - const { code, setCode, pattern, activeCode, activateCode, evaluateOnly, error, cycle, dirty, togglePlay } = useRepl({ + const { code, setCode, pattern, activeCode, activateCode, evaluateOnly, error, cycle, dirty, togglePlay, stop } = useRepl({ tune, defaultSynth, autolink: false @@ -585,6 +601,11 @@ function MiniRepl({ tune, defaultSynth, hideOutsideView = false, theme, init }) onClick: () => activateCode() }, /* @__PURE__ */ React.createElement(Icon, { type: "refresh" + })), /* @__PURE__ */ React.createElement("button", { + className: cx(styles.button), + onClick: () => stop(true) + }, /* @__PURE__ */ React.createElement(Icon, { + type: "stop" }))), error && /* @__PURE__ */ React.createElement("div", { className: styles.error }, error.message)), /* @__PURE__ */ React.createElement("div", { diff --git a/packages/react/src/components/Icon.tsx b/packages/react/src/components/Icon.tsx index 0ae722a3a..d64d08883 100644 --- a/packages/react/src/components/Icon.tsx +++ b/packages/react/src/components/Icon.tsx @@ -26,6 +26,13 @@ export function Icon({ type }) { clipRule="evenodd" /> ), + stop: ( + + ), }[type] } diff --git a/packages/react/src/components/MiniRepl.jsx b/packages/react/src/components/MiniRepl.jsx index d36c30b5e..bcebc95ff 100644 --- a/packages/react/src/components/MiniRepl.jsx +++ b/packages/react/src/components/MiniRepl.jsx @@ -10,11 +10,12 @@ import styles from './MiniRepl.module.css'; import { Icon } from './Icon'; export function MiniRepl({ tune, defaultSynth, hideOutsideView = false, theme, init }) { - const { code, setCode, pattern, activeCode, activateCode, evaluateOnly, error, cycle, dirty, togglePlay } = useRepl({ - tune, - defaultSynth, - autolink: false, - }); + const { code, setCode, pattern, activeCode, activateCode, evaluateOnly, error, cycle, dirty, togglePlay, stop } = + useRepl({ + tune, + defaultSynth, + autolink: false, + }); useEffect(() => { init && evaluateOnly(); }, [tune, init]); @@ -40,6 +41,9 @@ export function MiniRepl({ tune, defaultSynth, hideOutsideView = false, theme, i + {error &&
{error.message}
} diff --git a/packages/react/src/hooks/useCycle.mjs b/packages/react/src/hooks/useCycle.mjs index 5a68c9dac..dc93ddc31 100644 --- a/packages/react/src/hooks/useCycle.mjs +++ b/packages/react/src/hooks/useCycle.mjs @@ -66,8 +66,13 @@ function useCycle(props) { await Tone.start(); Tone.getTransport().start('+0.1'); }; - const stop = () => { - Tone.getTransport().pause(); + const stop = (setZero = false) => { + if (setZero) { + Tone.getTransport().cancel(); + Tone.getTransport().stop(); + } else { + Tone.getTransport().pause(); + } setStarted(false); }; const toggle = () => (started ? stop() : start()); diff --git a/packages/react/src/hooks/useRepl.mjs b/packages/react/src/hooks/useRepl.mjs index a7c9cbe37..93f7b1b6c 100644 --- a/packages/react/src/hooks/useRepl.mjs +++ b/packages/react/src/hooks/useRepl.mjs @@ -142,12 +142,17 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw: onDrawP } }; + const stop = () => { + cycle.stop(true); + setActiveCode(undefined); + }; + const evaluateOnly = () => { activateCode(code, true); }; useEffect(() => { - return () => cycle.stop(); + return () => stop(); }, []); return { @@ -161,6 +166,7 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw: onDrawP dirty, log, togglePlay, + stop, setActiveCode, activateCode, evaluateOnly, diff --git a/packages/tone/pianoroll.mjs b/packages/tone/pianoroll.mjs index f195f6327..9233b0407 100644 --- a/packages/tone/pianoroll.mjs +++ b/packages/tone/pianoroll.mjs @@ -51,9 +51,6 @@ Pattern.prototype.pianoroll = function ({ let foldValues = []; flipTime && timeRange.reverse(); flipValues && valueRange.reverse(); - - // duration to px (on timeAxis) - const playheadPosition = scale(-from / timeExtent, ...timeRange); this.draw( (ctx, events, t) => { ctx.fillStyle = background; @@ -66,15 +63,6 @@ Pattern.prototype.pianoroll = function ({ ctx.fillStyle = event.context?.color || inactive; ctx.strokeStyle = event.context?.color || active; ctx.globalAlpha = event.context.velocity ?? 1; - ctx.beginPath(); - if (vertical) { - ctx.moveTo(0, playheadPosition); - ctx.lineTo(valueAxis, playheadPosition); - } else { - ctx.moveTo(playheadPosition, 0); - ctx.lineTo(playheadPosition, valueAxis); - } - ctx.stroke(); const timePx = scale((event.whole.begin - (flipTime ? to : from)) / timeExtent, ...timeRange); let durationPx = scale(event.duration / timeExtent, 0, timeAxis); @@ -104,6 +92,17 @@ Pattern.prototype.pianoroll = function ({ } isActive ? ctx.strokeRect(...coords) : ctx.fillRect(...coords); }); + const playheadPosition = scale(-from / timeExtent, ...timeRange); + // draw playhead + ctx.beginPath(); + if (vertical) { + ctx.moveTo(0, playheadPosition); + ctx.lineTo(valueAxis, playheadPosition); + } else { + ctx.moveTo(playheadPosition, 0); + ctx.lineTo(playheadPosition, valueAxis); + } + ctx.stroke(); }, { from: from - overscan,