diff --git a/packages/react/dist/index.cjs.js b/packages/react/dist/index.cjs.js index e5a62aa0..19f8cb09 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"),J=require("@uiw/react-codemirror"),p=require("@codemirror/view"),F=require("@codemirror/state"),$=require("@codemirror/lang-javascript"),o=require("@lezer/highlight"),G=require("@uiw/codemirror-themes"),Q=require("react-hook-inview"),z=require("@strudel.cycles/webaudio"),W=require("@strudel.cycles/core"),X=require("@strudel.cycles/transpiler"),V=e=>e&&typeof e=="object"&&"default"in e?e:{default:e},n=V(t),Y=V(J),Z=G.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:o.tags.keyword,color:"#c792ea"},{tag:o.tags.operator,color:"#89ddff"},{tag:o.tags.special(o.tags.variableName),color:"#eeffff"},{tag:o.tags.typeName,color:"#c3e88d"},{tag:o.tags.atom,color:"#f78c6c"},{tag:o.tags.number,color:"#c3e88d"},{tag:o.tags.definition(o.tags.variableName),color:"#82aaff"},{tag:o.tags.string,color:"#c3e88d"},{tag:o.tags.special(o.tags.string),color:"#c3e88d"},{tag:o.tags.comment,color:"#7d8799"},{tag:o.tags.variableName,color:"#c792ea"},{tag:o.tags.tagName,color:"#c3e88d"},{tag:o.tags.bracket,color:"#525154"},{tag:o.tags.meta,color:"#ffcb6b"},{tag:o.tags.attributeName,color:"#c792ea"},{tag:o.tags.propertyName,color:"#c792ea"},{tag:o.tags.className,color:"#decb6b"},{tag:o.tags.invalid,color:"#ffffff"}]});const x=F.StateEffect.define(),ee=F.StateField.define({create(){return p.Decoration.none},update(e,r){try{for(let a of r.effects)if(a.is(x))if(a.value){const c=p.Decoration.mark({attributes:{style:"background-color: #FFCA2880"}});e=p.Decoration.set([c.range(0,r.newDoc.length)])}else e=p.Decoration.set([]);return e}catch(a){return console.warn("flash error",a),e}},provide:e=>p.EditorView.decorations.from(e)}),j=e=>{e.dispatch({effects:x.of(!0)}),setTimeout(()=>{e.dispatch({effects:x.of(!1)})},200)},q=F.StateEffect.define(),te=F.StateField.define({create(){return p.Decoration.none},update(e,r){try{for(let a of r.effects)if(a.is(q)){const c=a.value.map(i=>(i.context.locations||[]).map(({start:g,end:d})=>{const f=i.context.color||"#FFCA28";let s=r.newDoc.line(g.line).from+g.column,l=r.newDoc.line(d.line).from+d.column;const m=r.newDoc.length;return s>m||l>m?void 0:p.Decoration.mark({attributes:{style:`outline: 1.5px solid ${f};`}}).range(s,l)})).flat().filter(Boolean)||[];e=p.Decoration.set(c,!0)}return e}catch{return p.Decoration.set([])}},provide:e=>p.EditorView.decorations.from(e)}),re=[$.javascript(),Z,te,ee];function B({value:e,onChange:r,onViewChanged:a,onSelectionChange:c,options:i,editorDidMount:g}){const d=t.useCallback(l=>{r?.(l)},[r]),f=t.useCallback(l=>{a?.(l)},[a]),s=t.useCallback(l=>{l.selectionSet&&c&&c?.(l.state.selection)},[c]);return n.default.createElement(n.default.Fragment,null,n.default.createElement(Y.default,{value:e,onChange:d,onCreateEditor:f,onUpdate:s,extensions:re}))}function P(...e){return e.filter(Boolean).join(" ")}function I({view:e,pattern:r,active:a,getTime:c}){const i=t.useRef([]),g=t.useRef();t.useEffect(()=>{if(e)if(r&&a){let f=function(){try{const s=c(),m=[Math.max(g.current||s,s-1/10,0),s+1/60];g.current=m[1],i.current=i.current.filter(u=>u.whole.end>s);const v=r.queryArc(...m).filter(u=>u.hasOnset());i.current=i.current.concat(v),e.dispatch({effects:q.of(i.current)})}catch{e.dispatch({effects:q.of([])})}d=requestAnimationFrame(f)},d=requestAnimationFrame(f);return()=>{cancelAnimationFrame(d)}}else i.current=[],e.dispatch({effects:q.of([])})},[r,a,e])}const oe="_container_3i85k_1",ae="_header_3i85k_5",ne="_buttons_3i85k_9",se="_button_3i85k_9",ce="_buttonDisabled_3i85k_17",ie="_error_3i85k_21",le="_body_3i85k_25",w={container:oe,header:ae,buttons:ne,button:se,buttonDisabled:ce,error:ie,body:le};function T({type:e}){return n.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:n.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:n.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:n.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 K({defaultOutput:e,interval:r,getTime:a,evalOnMount:c=!1,initialCode:i="",autolink:g=!1,afterEval:d,onEvalError:f}){const[s,l]=t.useState(),[m,v]=t.useState(),[u,C]=t.useState(i),[D,M]=t.useState(u),[k,A]=t.useState(),[S,_]=t.useState(!1),N=u!==D,{scheduler:E,evaluate:y,start:b,stop:O,pause:U}=t.useMemo(()=>W.repl({interval:r,defaultOutput:e,onSchedulerError:l,onEvalError:h=>{v(h),f?.(h)},getTime:a,transpiler:X.transpiler,beforeEval:({code:h})=>{C(h)},afterEval:({pattern:h,code:L})=>{M(L),A(h),v(),l(),g&&(window.location.hash="#"+encodeURIComponent(btoa(L))),d?.()},onToggle:h=>_(h)}),[e,r,a]),R=t.useCallback(async(h=!0)=>y(u,h),[y,u]),H=t.useRef();return t.useEffect(()=>{!H.current&&c&&u&&(H.current=!0,R())},[R,c,u]),t.useEffect(()=>()=>{E.stop()},[E]),{code:u,setCode:C,error:s||m,schedulerError:s,scheduler:E,evalError:m,evaluate:y,activateCode:R,activeCode:D,isDirty:N,pattern:k,started:S,start:b,stop:O,pause:U,togglePlay:async()=>{S?E.pause():await R()}}}const ue=()=>z.getAudioContext().currentTime;function de({tune:e,hideOutsideView:r=!1,init:a,enableKeyboard:c}){const{code:i,setCode:g,evaluate:d,activateCode:f,error:s,isDirty:l,activeCode:m,pattern:v,started:u,scheduler:C,togglePlay:D,stop:M}=K({initialCode:e,defaultOutput:z.webaudioOutput,getTime:ue}),[k,A]=t.useState(),[S,_]=Q.useInView({threshold:.01}),N=t.useRef(),E=t.useMemo(()=>((_||!r)&&(N.current=!0),_||N.current),[_,r]);return I({view:k,pattern:v,active:u&&!m?.includes("strudel disable-highlighting"),getTime:()=>C.getPhase()}),t.useLayoutEffect(()=>{if(c){const y=async b=>{(b.ctrlKey||b.altKey)&&(b.code==="Enter"?(b.preventDefault(),j(k),await f()):b.code==="Period"&&(M(),b.preventDefault()))};return window.addEventListener("keydown",y,!0),()=>window.removeEventListener("keydown",y,!0)}},[c,v,i,d,M,k]),n.default.createElement("div",{className:w.container,ref:S},n.default.createElement("div",{className:w.header},n.default.createElement("div",{className:w.buttons},n.default.createElement("button",{className:P(w.button,u?"sc-animate-pulse":""),onClick:()=>D()},n.default.createElement(T,{type:u?"pause":"play"})),n.default.createElement("button",{className:P(l?w.button:w.buttonDisabled),onClick:()=>f()},n.default.createElement(T,{type:"refresh"}))),s&&n.default.createElement("div",{className:w.error},s.message)),n.default.createElement("div",{className:w.body},E&&n.default.createElement(B,{value:i,onChange:g,onViewChanged:A})))}function fe(e){return t.useEffect(()=>(window.addEventListener("message",e),()=>window.removeEventListener("message",e)),[e]),t.useCallback(r=>window.postMessage(r,"*"),[])}const ge=e=>t.useLayoutEffect(()=>(window.addEventListener("keydown",e,!0),()=>window.removeEventListener("keydown",e,!0)),[e]);exports.CodeMirror=B;exports.MiniRepl=de;exports.cx=P;exports.flash=j;exports.useHighlighting=I;exports.useKeydown=ge;exports.usePostMessage=fe;exports.useStrudel=K; +"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const t=require("react"),$=require("@uiw/react-codemirror"),v=require("@codemirror/view"),R=require("@codemirror/state"),G=require("@codemirror/lang-javascript"),o=require("@lezer/highlight"),Q=require("@uiw/codemirror-themes"),W=require("react-hook-inview"),z=require("@strudel.cycles/webaudio"),X=require("@strudel.cycles/core"),Y=require("@strudel.cycles/transpiler"),V=e=>e&&typeof e=="object"&&"default"in e?e:{default:e},n=V(t),Z=V($),ee=Q.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:o.tags.keyword,color:"#c792ea"},{tag:o.tags.operator,color:"#89ddff"},{tag:o.tags.special(o.tags.variableName),color:"#eeffff"},{tag:o.tags.typeName,color:"#c3e88d"},{tag:o.tags.atom,color:"#f78c6c"},{tag:o.tags.number,color:"#c3e88d"},{tag:o.tags.definition(o.tags.variableName),color:"#82aaff"},{tag:o.tags.string,color:"#c3e88d"},{tag:o.tags.special(o.tags.string),color:"#c3e88d"},{tag:o.tags.comment,color:"#7d8799"},{tag:o.tags.variableName,color:"#c792ea"},{tag:o.tags.tagName,color:"#c3e88d"},{tag:o.tags.bracket,color:"#525154"},{tag:o.tags.meta,color:"#ffcb6b"},{tag:o.tags.attributeName,color:"#c792ea"},{tag:o.tags.propertyName,color:"#c792ea"},{tag:o.tags.className,color:"#decb6b"},{tag:o.tags.invalid,color:"#ffffff"}]});const x=R.StateEffect.define(),te=R.StateField.define({create(){return v.Decoration.none},update(e,r){try{for(let a of r.effects)if(a.is(x))if(a.value){const s=v.Decoration.mark({attributes:{style:"background-color: #FFCA2880"}});e=v.Decoration.set([s.range(0,r.newDoc.length)])}else e=v.Decoration.set([]);return e}catch(a){return console.warn("flash error",a),e}},provide:e=>v.EditorView.decorations.from(e)}),j=e=>{e.dispatch({effects:x.of(!0)}),setTimeout(()=>{e.dispatch({effects:x.of(!1)})},200)},N=R.StateEffect.define(),re=R.StateField.define({create(){return v.Decoration.none},update(e,r){try{for(let a of r.effects)if(a.is(N)){const s=a.value.map(c=>(c.context.locations||[]).map(({start:f,end:u})=>{const d=c.context.color||"#FFCA28";let i=r.newDoc.line(f.line).from+f.column,l=r.newDoc.line(u.line).from+u.column;const g=r.newDoc.length;return i>g||l>g?void 0:v.Decoration.mark({attributes:{style:`outline: 1.5px solid ${d};`}}).range(i,l)})).flat().filter(Boolean)||[];e=v.Decoration.set(s,!0)}return e}catch{return v.Decoration.set([])}},provide:e=>v.EditorView.decorations.from(e)}),oe=[G.javascript(),ee,re,te];function B({value:e,onChange:r,onViewChanged:a,onSelectionChange:s,options:c,editorDidMount:f}){const u=t.useCallback(l=>{r?.(l)},[r]),d=t.useCallback(l=>{a?.(l)},[a]),i=t.useCallback(l=>{l.selectionSet&&s&&s?.(l.state.selection)},[s]);return n.default.createElement(n.default.Fragment,null,n.default.createElement(Z.default,{value:e,onChange:u,onCreateEditor:d,onUpdate:i,extensions:oe}))}function P(...e){return e.filter(Boolean).join(" ")}function I({view:e,pattern:r,active:a,getTime:s}){const c=t.useRef([]),f=t.useRef();t.useEffect(()=>{if(e)if(r&&a){let d=function(){try{const i=s(),g=[Math.max(f.current||i,i-1/10,0),i+1/60];f.current=g[1],c.current=c.current.filter(m=>m.whole.end>i);const w=r.queryArc(...g).filter(m=>m.hasOnset());c.current=c.current.concat(w),e.dispatch({effects:N.of(c.current)})}catch{e.dispatch({effects:N.of([])})}u=requestAnimationFrame(d)},u=requestAnimationFrame(d);return()=>{cancelAnimationFrame(u)}}else c.current=[],e.dispatch({effects:N.of([])})},[r,a,e])}const ae="_container_3i85k_1",ne="_header_3i85k_5",se="_buttons_3i85k_9",ce="_button_3i85k_9",ie="_buttonDisabled_3i85k_17",le="_error_3i85k_21",ue="_body_3i85k_25",E={container:ae,header:ne,buttons:se,button:ce,buttonDisabled:ie,error:le,body:ue};function T({type:e}){return n.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:n.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:n.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:n.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 K({defaultOutput:e,interval:r,getTime:a,evalOnMount:s=!1,initialCode:c="",autolink:f=!1,beforeEval:u,afterEval:d,onEvalError:i}){const[l,g]=t.useState(),[w,m]=t.useState(),[b,D]=t.useState(c),[_,C]=t.useState(b),[q,F]=t.useState(),[k,M]=t.useState(!1),A=b!==_,{scheduler:y,evaluate:h,start:O,stop:U,pause:J}=t.useMemo(()=>X.repl({interval:r,defaultOutput:e,onSchedulerError:g,onEvalError:p=>{m(p),i?.(p)},getTime:a,transpiler:Y.transpiler,beforeEval:({code:p})=>{D(p),u?.()},afterEval:({pattern:p,code:L})=>{C(L),F(p),m(),g(),f&&(window.location.hash="#"+encodeURIComponent(btoa(L))),d?.()},onToggle:p=>M(p)}),[e,r,a]),S=t.useCallback(async(p=!0)=>h(b,p),[h,b]),H=t.useRef();return t.useEffect(()=>{!H.current&&s&&b&&(H.current=!0,S())},[S,s,b]),t.useEffect(()=>()=>{y.stop()},[y]),{code:b,setCode:D,error:l||w,schedulerError:l,scheduler:y,evalError:w,evaluate:h,activateCode:S,activeCode:_,isDirty:A,pattern:q,started:k,start:O,stop:U,pause:J,togglePlay:async()=>{k?y.pause():await S()}}}const de=()=>z.getAudioContext().currentTime;function fe({tune:e,hideOutsideView:r=!1,init:a,enableKeyboard:s}){const{code:c,setCode:f,evaluate:u,activateCode:d,error:i,isDirty:l,activeCode:g,pattern:w,started:m,scheduler:b,togglePlay:D,stop:_}=K({initialCode:e,defaultOutput:z.webaudioOutput,getTime:de}),[C,q]=t.useState(),[F,k]=W.useInView({threshold:.01}),M=t.useRef(),A=t.useMemo(()=>((k||!r)&&(M.current=!0),k||M.current),[k,r]);return I({view:C,pattern:w,active:m&&!g?.includes("strudel disable-highlighting"),getTime:()=>b.getPhase()}),t.useLayoutEffect(()=>{if(s){const y=async h=>{(h.ctrlKey||h.altKey)&&(h.code==="Enter"?(h.preventDefault(),j(C),await d()):h.code==="Period"&&(_(),h.preventDefault()))};return window.addEventListener("keydown",y,!0),()=>window.removeEventListener("keydown",y,!0)}},[s,w,c,u,_,C]),n.default.createElement("div",{className:E.container,ref:F},n.default.createElement("div",{className:E.header},n.default.createElement("div",{className:E.buttons},n.default.createElement("button",{className:P(E.button,m?"sc-animate-pulse":""),onClick:()=>D()},n.default.createElement(T,{type:m?"pause":"play"})),n.default.createElement("button",{className:P(l?E.button:E.buttonDisabled),onClick:()=>d()},n.default.createElement(T,{type:"refresh"}))),i&&n.default.createElement("div",{className:E.error},i.message)),n.default.createElement("div",{className:E.body},A&&n.default.createElement(B,{value:c,onChange:f,onViewChanged:q})))}function ge(e){return t.useEffect(()=>(window.addEventListener("message",e),()=>window.removeEventListener("message",e)),[e]),t.useCallback(r=>window.postMessage(r,"*"),[])}const me=e=>t.useLayoutEffect(()=>(window.addEventListener("keydown",e,!0),()=>window.removeEventListener("keydown",e,!0)),[e]);exports.CodeMirror=B;exports.MiniRepl=fe;exports.cx=P;exports.flash=j;exports.useHighlighting=I;exports.useKeydown=me;exports.usePostMessage=ge;exports.useStrudel=K; diff --git a/packages/react/dist/index.es.js b/packages/react/dist/index.es.js index c43e176b..4ee17068 100644 --- a/packages/react/dist/index.es.js +++ b/packages/react/dist/index.es.js @@ -1,15 +1,15 @@ -import n, { useCallback as C, useRef as P, useEffect as z, useState as E, useMemo as q, useLayoutEffect as I } from "react"; -import G from "@uiw/react-codemirror"; -import { Decoration as b, EditorView as K } from "@codemirror/view"; +import n, { useCallback as N, useRef as x, useEffect as R, useState as y, useMemo as q, useLayoutEffect as I } from "react"; +import J from "@uiw/react-codemirror"; +import { Decoration as E, EditorView as K } from "@codemirror/view"; import { StateEffect as O, StateField as j } from "@codemirror/state"; -import { javascript as J } from "@codemirror/lang-javascript"; +import { javascript as Q } from "@codemirror/lang-javascript"; import { tags as r } from "@lezer/highlight"; -import { createTheme as Q } from "@uiw/codemirror-themes"; -import { useInView as W } from "react-hook-inview"; -import { webaudioOutput as X, getAudioContext as Y } from "@strudel.cycles/webaudio"; -import { repl as Z } from "@strudel.cycles/core"; -import { transpiler as ee } from "@strudel.cycles/transpiler"; -const te = Q({ +import { createTheme as W } from "@uiw/codemirror-themes"; +import { useInView as X } from "react-hook-inview"; +import { webaudioOutput as Y, getAudioContext as Z } from "@strudel.cycles/webaudio"; +import { repl as ee } from "@strudel.cycles/core"; +import { transpiler as te } from "@strudel.cycles/transpiler"; +const re = W({ theme: "dark", settings: { background: "#222", @@ -42,113 +42,113 @@ const te = Q({ { tag: r.invalid, color: "#ffffff" } ] }); -const L = O.define(), re = j.define({ +const L = O.define(), oe = j.define({ create() { - return b.none; + return E.none; }, update(e, t) { try { for (let o of t.effects) if (o.is(L)) if (o.value) { - const s = b.mark({ attributes: { style: "background-color: #FFCA2880" } }); - e = b.set([s.range(0, t.newDoc.length)]); + const a = E.mark({ attributes: { style: "background-color: #FFCA2880" } }); + e = E.set([a.range(0, t.newDoc.length)]); } else - e = b.set([]); + e = E.set([]); return e; } catch (o) { return console.warn("flash error", o), e; } }, provide: (e) => K.decorations.from(e) -}), oe = (e) => { +}), ne = (e) => { e.dispatch({ effects: L.of(!0) }), setTimeout(() => { e.dispatch({ effects: L.of(!1) }); }, 200); -}, R = O.define(), ne = j.define({ +}, A = O.define(), ae = j.define({ create() { - return b.none; + return E.none; }, update(e, t) { try { for (let o of t.effects) - if (o.is(R)) { - const s = o.value.map( - (c) => (c.context.locations || []).map(({ start: f, end: d }) => { - const u = c.context.color || "#FFCA28"; - let a = t.newDoc.line(f.line).from + f.column, i = t.newDoc.line(d.line).from + d.column; - const m = t.newDoc.length; - return a > m || i > m ? void 0 : b.mark({ attributes: { style: `outline: 1.5px solid ${u};` } }).range(a, i); + if (o.is(A)) { + const a = o.value.map( + (s) => (s.context.locations || []).map(({ start: u, end: l }) => { + const d = s.context.color || "#FFCA28"; + let c = t.newDoc.line(u.line).from + u.column, i = t.newDoc.line(l.line).from + l.column; + const f = t.newDoc.length; + return c > f || i > f ? void 0 : E.mark({ attributes: { style: `outline: 1.5px solid ${d};` } }).range(c, i); }) ).flat().filter(Boolean) || []; - e = b.set(s, !0); + e = E.set(a, !0); } return e; } catch { - return b.set([]); + return E.set([]); } }, provide: (e) => K.decorations.from(e) -}), ae = [J(), te, ne, re]; -function se({ value: e, onChange: t, onViewChanged: o, onSelectionChange: s, options: c, editorDidMount: f }) { - const d = C( +}), se = [Q(), re, ae, oe]; +function ce({ value: e, onChange: t, onViewChanged: o, onSelectionChange: a, options: s, editorDidMount: u }) { + const l = N( (i) => { t?.(i); }, [t] - ), u = C( + ), d = N( (i) => { o?.(i); }, [o] - ), a = C( + ), c = N( (i) => { - i.selectionSet && s && s?.(i.state.selection); + i.selectionSet && a && a?.(i.state.selection); }, - [s] + [a] ); - return /* @__PURE__ */ n.createElement(n.Fragment, null, /* @__PURE__ */ n.createElement(G, { + return /* @__PURE__ */ n.createElement(n.Fragment, null, /* @__PURE__ */ n.createElement(J, { value: e, - onChange: d, - onCreateEditor: u, - onUpdate: a, - extensions: ae + onChange: l, + onCreateEditor: d, + onUpdate: c, + extensions: se })); } function S(...e) { return e.filter(Boolean).join(" "); } -function ce({ view: e, pattern: t, active: o, getTime: s }) { - const c = P([]), f = P(); - z(() => { +function ie({ view: e, pattern: t, active: o, getTime: a }) { + const s = x([]), u = x(); + R(() => { if (e) if (t && o) { - let u = function() { + let d = function() { try { - const a = s(), m = [Math.max(f.current || a, a - 1 / 10, 0), a + 1 / 60]; - f.current = m[1], c.current = c.current.filter((l) => l.whole.end > a); - const p = t.queryArc(...m).filter((l) => l.hasOnset()); - c.current = c.current.concat(p), e.dispatch({ effects: R.of(c.current) }); + const c = a(), f = [Math.max(u.current || c, c - 1 / 10, 0), c + 1 / 60]; + u.current = f[1], s.current = s.current.filter((m) => m.whole.end > c); + const v = t.queryArc(...f).filter((m) => m.hasOnset()); + s.current = s.current.concat(v), e.dispatch({ effects: A.of(s.current) }); } catch { - e.dispatch({ effects: R.of([]) }); + e.dispatch({ effects: A.of([]) }); } - d = requestAnimationFrame(u); - }, d = requestAnimationFrame(u); + l = requestAnimationFrame(d); + }, l = requestAnimationFrame(d); return () => { - cancelAnimationFrame(d); + cancelAnimationFrame(l); }; } else - c.current = [], e.dispatch({ effects: R.of([]) }); + s.current = [], e.dispatch({ effects: A.of([]) }); }, [t, o, e]); } -const ie = "_container_3i85k_1", le = "_header_3i85k_5", de = "_buttons_3i85k_9", ue = "_button_3i85k_9", fe = "_buttonDisabled_3i85k_17", me = "_error_3i85k_21", ge = "_body_3i85k_25", v = { - container: ie, - header: le, - buttons: de, - button: ue, - buttonDisabled: fe, - error: me, - body: ge +const le = "_container_3i85k_1", de = "_header_3i85k_5", ue = "_buttons_3i85k_9", fe = "_button_3i85k_9", me = "_buttonDisabled_3i85k_17", ge = "_error_3i85k_21", pe = "_body_3i85k_25", b = { + container: le, + header: de, + buttons: ue, + button: fe, + buttonDisabled: me, + error: ge, + body: pe }; function B({ type: e }) { return /* @__PURE__ */ n.createElement("svg", { @@ -174,133 +174,134 @@ function B({ type: e }) { }) }[e]); } -function pe({ +function he({ defaultOutput: e, interval: t, getTime: o, - evalOnMount: s = !1, - initialCode: c = "", - autolink: f = !1, + evalOnMount: a = !1, + initialCode: s = "", + autolink: u = !1, + beforeEval: l, afterEval: d, - onEvalError: u + onEvalError: c }) { - const [a, i] = E(), [m, p] = E(), [l, N] = E(c), [D, F] = E(l), [k, H] = E(), [M, _] = E(!1), A = l !== D, { scheduler: w, evaluate: y, start: h, stop: U, pause: $ } = q( - () => Z({ + const [i, f] = y(), [v, m] = y(), [h, D] = y(s), [_, C] = y(h), [P, z] = y(), [k, F] = y(!1), H = h !== _, { scheduler: w, evaluate: g, start: U, stop: $, pause: G } = q( + () => ee({ interval: t, defaultOutput: e, - onSchedulerError: i, - onEvalError: (g) => { - p(g), u?.(g); + onSchedulerError: f, + onEvalError: (p) => { + m(p), c?.(p); }, getTime: o, - transpiler: ee, - beforeEval: ({ code: g }) => { - N(g); + transpiler: te, + beforeEval: ({ code: p }) => { + D(p), l?.(); }, - afterEval: ({ pattern: g, code: V }) => { - F(V), H(g), p(), i(), f && (window.location.hash = "#" + encodeURIComponent(btoa(V))), d?.(); + afterEval: ({ pattern: p, code: V }) => { + C(V), z(p), m(), f(), u && (window.location.hash = "#" + encodeURIComponent(btoa(V))), d?.(); }, - onToggle: (g) => _(g) + onToggle: (p) => F(p) }), [e, t, o] - ), x = C(async (g = !0) => y(l, g), [y, l]), T = P(); - return z(() => { - !T.current && s && l && (T.current = !0, x()); - }, [x, s, l]), z(() => () => { + ), M = N(async (p = !0) => g(h, p), [g, h]), T = x(); + return R(() => { + !T.current && a && h && (T.current = !0, M()); + }, [M, a, h]), R(() => () => { w.stop(); }, [w]), { - code: l, - setCode: N, - error: a || m, - schedulerError: a, + code: h, + setCode: D, + error: i || v, + schedulerError: i, scheduler: w, - evalError: m, - evaluate: y, - activateCode: x, - activeCode: D, - isDirty: A, - pattern: k, - started: M, - start: h, - stop: U, - pause: $, + evalError: v, + evaluate: g, + activateCode: M, + activeCode: _, + isDirty: H, + pattern: P, + started: k, + start: U, + stop: $, + pause: G, togglePlay: async () => { - M ? w.pause() : await x(); + k ? w.pause() : await M(); } }; } -const he = () => Y().currentTime; -function xe({ tune: e, hideOutsideView: t = !1, init: o, enableKeyboard: s }) { +const ve = () => Z().currentTime; +function Re({ tune: e, hideOutsideView: t = !1, init: o, enableKeyboard: a }) { const { - code: c, - setCode: f, - evaluate: d, - activateCode: u, - error: a, + code: s, + setCode: u, + evaluate: l, + activateCode: d, + error: c, isDirty: i, - activeCode: m, - pattern: p, - started: l, - scheduler: N, + activeCode: f, + pattern: v, + started: m, + scheduler: h, togglePlay: D, - stop: F - } = pe({ + stop: _ + } = he({ initialCode: e, - defaultOutput: X, - getTime: he - }), [k, H] = E(), [M, _] = W({ + defaultOutput: Y, + getTime: ve + }), [C, P] = y(), [z, k] = X({ threshold: 0.01 - }), A = P(), w = q(() => ((_ || !t) && (A.current = !0), _ || A.current), [_, t]); - return ce({ - view: k, - pattern: p, - active: l && !m?.includes("strudel disable-highlighting"), - getTime: () => N.getPhase() + }), F = x(), H = q(() => ((k || !t) && (F.current = !0), k || F.current), [k, t]); + return ie({ + view: C, + pattern: v, + active: m && !f?.includes("strudel disable-highlighting"), + getTime: () => h.getPhase() }), I(() => { - if (s) { - const y = async (h) => { - (h.ctrlKey || h.altKey) && (h.code === "Enter" ? (h.preventDefault(), oe(k), await u()) : h.code === "Period" && (F(), h.preventDefault())); + if (a) { + const w = async (g) => { + (g.ctrlKey || g.altKey) && (g.code === "Enter" ? (g.preventDefault(), ne(C), await d()) : g.code === "Period" && (_(), g.preventDefault())); }; - return window.addEventListener("keydown", y, !0), () => window.removeEventListener("keydown", y, !0); + return window.addEventListener("keydown", w, !0), () => window.removeEventListener("keydown", w, !0); } - }, [s, p, c, d, F, k]), /* @__PURE__ */ n.createElement("div", { - className: v.container, - ref: M + }, [a, v, s, l, _, C]), /* @__PURE__ */ n.createElement("div", { + className: b.container, + ref: z }, /* @__PURE__ */ n.createElement("div", { - className: v.header + className: b.header }, /* @__PURE__ */ n.createElement("div", { - className: v.buttons + className: b.buttons }, /* @__PURE__ */ n.createElement("button", { - className: S(v.button, l ? "sc-animate-pulse" : ""), + className: S(b.button, m ? "sc-animate-pulse" : ""), onClick: () => D() }, /* @__PURE__ */ n.createElement(B, { - type: l ? "pause" : "play" + type: m ? "pause" : "play" })), /* @__PURE__ */ n.createElement("button", { - className: S(i ? v.button : v.buttonDisabled), - onClick: () => u() + className: S(i ? b.button : b.buttonDisabled), + onClick: () => d() }, /* @__PURE__ */ n.createElement(B, { type: "refresh" - }))), a && /* @__PURE__ */ n.createElement("div", { - className: v.error - }, a.message)), /* @__PURE__ */ n.createElement("div", { - className: v.body - }, w && /* @__PURE__ */ n.createElement(se, { - value: c, - onChange: f, - onViewChanged: H + }))), c && /* @__PURE__ */ n.createElement("div", { + className: b.error + }, c.message)), /* @__PURE__ */ n.createElement("div", { + className: b.body + }, H && /* @__PURE__ */ n.createElement(ce, { + value: s, + onChange: u, + onViewChanged: P }))); } -function Re(e) { - return z(() => (window.addEventListener("message", e), () => window.removeEventListener("message", e)), [e]), C((t) => window.postMessage(t, "*"), []); +function Pe(e) { + return R(() => (window.addEventListener("message", e), () => window.removeEventListener("message", e)), [e]), N((t) => window.postMessage(t, "*"), []); } -const Pe = (e) => I(() => (window.addEventListener("keydown", e, !0), () => window.removeEventListener("keydown", e, !0)), [e]); +const ze = (e) => I(() => (window.addEventListener("keydown", e, !0), () => window.removeEventListener("keydown", e, !0)), [e]); export { - se as CodeMirror, - xe as MiniRepl, + ce as CodeMirror, + Re as MiniRepl, S as cx, - oe as flash, - ce as useHighlighting, - Pe as useKeydown, - Re as usePostMessage, - pe as useStrudel + ne as flash, + ie as useHighlighting, + ze as useKeydown, + Pe as usePostMessage, + he as useStrudel }; diff --git a/packages/react/src/hooks/useStrudel.mjs b/packages/react/src/hooks/useStrudel.mjs index 37d47ebc..097ca1aa 100644 --- a/packages/react/src/hooks/useStrudel.mjs +++ b/packages/react/src/hooks/useStrudel.mjs @@ -9,6 +9,7 @@ function useStrudel({ evalOnMount = false, initialCode = '', autolink = false, + beforeEval, afterEval, onEvalError, }) { @@ -36,6 +37,7 @@ function useStrudel({ transpiler, beforeEval: ({ code }) => { setCode(code); + beforeEval?.(); }, afterEval: ({ pattern: _pattern, code }) => { setActiveCode(code); diff --git a/repl/README.md b/repl/README.md index 0df11d94..c72b799a 100644 --- a/repl/README.md +++ b/repl/README.md @@ -47,4 +47,4 @@ currently broken / buggy: - [ ] find a way to display errors when console is closed / another tab selected - [x] scheduler.getPhase is quantized to clock interval - => draw was choppy + that also caused useHighlighting bugs -- [ ] pianoroll keeps rolling when pressing stop \ No newline at end of file +- [ ] pianoroll keeps rolling when pressing stop diff --git a/repl/src/App.jsx b/repl/src/App.jsx index 19d846bf..5adec2d4 100644 --- a/repl/src/App.jsx +++ b/repl/src/App.jsx @@ -114,6 +114,10 @@ function App() { defaultOutput: webaudioOutput, getTime, autolink: true, + beforeEval: () => { + cleanupUi(); + cleanupDraw(); + }, }); // init code @@ -175,7 +179,6 @@ function App() { } else { logger('[repl] stopped. tip: you can also stop by pressing ctrl+dot', 'highlight'); stop(); - // cleanupDraw(); } }; const handleUpdate = () => { @@ -186,9 +189,6 @@ function App() { const handleShuffle = async () => { const { code, name } = getRandomTune(); logger(`[repl] ✨ loading random tune "${name}"`); - - cleanupDraw(); - cleanupUi(); resetLoadedSamples(); await prebake(); // declare default samples await evaluate(code, false);