cabbage-react 1.0.15 → 1.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,23 +1,78 @@
1
1
  export class Cabbage {
2
2
  /**
3
- * Main entry point for sending any data from UI widgets to the Cabbage backend.
3
+ * Main entry point for sending widget value changes to the Cabbage backend.
4
+ *
4
5
  * This function automatically routes messages to the appropriate backend function
5
6
  * based on the automatable flag:
6
7
  *
7
- * - automatable=true: Routes to sendParameterUpdate for real-time parameter control /
8
- * this also sends the value as channel data to Csound
8
+ * - `automatable=true`: Routes to `sendParameterUpdate()` for DAW-automatable parameters.
9
+ * The value is sent to the DAW for automation recording and also forwarded to Csound.
10
+ *
11
+ * - `automatable=false`: Routes to `sendChannelData()` for non-automatable data.
12
+ * The value is sent directly to Csound without DAW parameter involvement.
13
+ *
14
+ * **When to use**: Call this from widget event handlers (e.g., pointer events, input changes)
15
+ * when the user interacts with a widget.
16
+ *
17
+ * **When NOT to use**: Do not call this when handling incoming `parameterChange` messages
18
+ * from the backend. Those messages are for display updates only.
19
+ *
20
+ * @param {Object} message - The message object containing widget data
21
+ * @param {string} message.channel - The channel name
22
+ * @param {number} message.paramIdx - Parameter index (required if automatable)
23
+ * @param {number|string} message.value - The value to send
24
+ * @param {Object|null} vscode - VS Code API object (null for plugin mode)
25
+ * @param {boolean} automatable - Whether this widget is DAW-automatable
26
+ */
27
+ static sendChannelUpdate(message: {
28
+ channel: string;
29
+ paramIdx: number;
30
+ value: number | string;
31
+ }, vscode?: Object | null, automatable?: boolean): void;
32
+ /**
33
+ * Internal: Send a parameter update to the DAW for automation recording.
34
+ * Use `sendChannelUpdate()` instead - it will route here automatically for automatable widgets.
35
+ *
36
+ * This function sends the parameter value to the DAW's automation system.
37
+ * The DAW will then send the value back via a `parameterChange` message,
38
+ * which updates both the UI and Csound.
9
39
  *
10
- * - automatable=false: Routes to sendChannelData for string/numeric data transmission
40
+ * **Important**: This creates a round-trip through the DAW:
41
+ * 1. UI calls `sendParameterUpdate()` with value
42
+ * 2. DAW receives and records/processes the value
43
+ * 3. DAW sends `parameterChange` back to the plugin
44
+ * 4. Plugin updates Csound and sends `parameterChange` to UI
45
+ * 5. UI updates its display (but does NOT call sendParameterUpdate again!)
11
46
  *
12
- * All widget interactions should use this function instead of calling the lower-level
13
- * sendParameterUpdate or sendChannelData functions directly.
47
+ * @param {Object} message - The parameter message
48
+ * @param {number} message.paramIdx - The parameter index (must be >= 0)
49
+ * @param {string} message.channel - The channel name
50
+ * @param {number} message.value - The parameter value (full range, not normalized)
51
+ * @param {string} [message.channelType="number"] - The channel type
52
+ * @param {Object|null} vscode - VS Code API object (null for plugin mode)
14
53
  */
15
- static sendChannelUpdate(message: any, vscode?: null, automatable?: boolean): void;
16
- static sendParameterUpdate(message: any, vscode?: null): void;
54
+ static sendParameterUpdate(message: {
55
+ paramIdx: number;
56
+ channel: string;
57
+ value: number;
58
+ channelType?: string | undefined;
59
+ }, vscode?: Object | null): void;
17
60
  static sendCustomCommand(command: any, vscode?: null, additionalData?: {}): void;
18
61
  static sendWidgetUpdate(widget: any, vscode?: null): void;
19
62
  static sendMidiMessageFromUI(statusByte: any, dataByte1: any, dataByte2: any, vscode?: null): void;
20
- static sendChannelData(channel: any, data: any, vscode?: null): void;
63
+ /**
64
+ * Internal: Send channel data directly to Csound without DAW automation involvement.
65
+ * Use `sendChannelUpdate()` instead - it will route here automatically for non-automatable widgets.
66
+ *
67
+ * Used for non-automatable widgets like buttons, file selectors, or
68
+ * any widget that sends string data. The value is sent directly to Csound's
69
+ * channel system and is not recorded by DAW automation.
70
+ *
71
+ * @param {string} channel - The Csound channel name
72
+ * @param {number|string} data - The data to send (number or string)
73
+ * @param {Object|null} vscode - VS Code API object (null for plugin mode)
74
+ */
75
+ static sendChannelData(channel: string, data: number | string, vscode?: Object | null): void;
21
76
  static MidiMessageFromHost(statusByte: any, dataByte1: any, dataByte2: any): void;
22
77
  static triggerFileOpenDialog(vscode: any, channel: any, options?: {}): void;
23
78
  static openUrl(vscode: any, url: any, file: any): void;
@@ -1 +1 @@
1
- {"version":3,"file":"cabbage.d.ts","sourceRoot":"","sources":["../../src/cabbage/cabbage.js"],"names":[],"mappings":"AAMA;IACC;;;;;;;;;;;;OAYG;IACH,mFAYC;IAED,8DAsCC;IAED,iFAiCC;IAED,0DAiBC;IAED,mGA6BC;IAED,qEAoCC;IAED,kFASC;IAED,4EA2BC;IAED,uDAsBC;IAED;;;;;;;;;;;OAWG;IACH,4BAPW,MAAM,UACN,MAAM,WACN,MAAM,QA4BhB;CACD"}
1
+ {"version":3,"file":"cabbage.d.ts","sourceRoot":"","sources":["../../src/cabbage/cabbage.js"],"names":[],"mappings":"AAqFA;IACC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,kCANG;QAAwB,OAAO,EAAvB,MAAM;QACU,QAAQ,EAAxB,MAAM;QACiB,KAAK,EAA5B,MAAM,GAAC,MAAM;KACrB,WAAQ,MAAM,GAAC,IAAI,gBACX,OAAO,QAcjB;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,oCANG;QAAwB,QAAQ,EAAxB,MAAM;QACU,OAAO,EAAvB,MAAM;QACU,KAAK,EAArB,MAAM;QACW,WAAW;KACpC,WAAQ,MAAM,GAAC,IAAI,QAwCrB;IAED,iFAiCC;IAED,0DAiBC;IAED,mGA6BC;IAED;;;;;;;;;;;OAWG;IACH,gCAJW,MAAM,QACN,MAAM,GAAC,MAAM,WACb,MAAM,GAAC,IAAI,QAsCrB;IAED,kFASC;IAED,4EA2BC;IAED,uDAsBC;IAED;;;;;;;;;;;OAWG;IACH,4BAPW,MAAM,UACN,MAAM,WACN,MAAM,QA4BhB;CACD"}
@@ -3,7 +3,7 @@
3
3
  * This hook listens for updates to a parameter value from Cabbage and
4
4
  * sends updates to Cabbage when the parameter value changes locally (e.g., through a UI slider).
5
5
  */
6
- export declare const useCabbageState: <T>(channelId: string) => {
6
+ export declare const useCabbageState: <T>(channelId: string, isDragging?: boolean) => {
7
7
  value: T | undefined;
8
8
  setValue: (value: T) => void;
9
9
  parameterIndex: number | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"useCabbageState.d.ts","sourceRoot":"","sources":["../../src/hooks/useCabbageState.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,aAAa,MAAM;;sBAQjB,CAAC;;CA0GnC,CAAC"}
1
+ {"version":3,"file":"useCabbageState.d.ts","sourceRoot":"","sources":["../../src/hooks/useCabbageState.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,aAAa,MAAM,eAAe,OAAO;;sBAMvC,CAAC;;CA+GnC,CAAC"}
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("react"),C=c.createContext({devMode:!1});console.log("Cabbage: loading cabbage.js");class f{static sendChannelUpdate(e,a=null,n=!1){if(n===!0||n===1)f.sendParameterUpdate(e,a);else{const s=e.value!==void 0?e.value:e.stringData||e.floatData;f.sendChannelData(e.channel,s,a)}}static sendParameterUpdate(e,a=null){if(e.paramIdx===void 0||e.paramIdx===null){console.error("Cabbage.sendParameterUpdate: message missing paramIdx!",e);return}if(e.paramIdx<0){console.warn("Cabbage.sendParameterUpdate: paramIdx is -1, skipping (non-automatable widget)",e);return}const n={command:"parameterChange",paramIdx:e.paramIdx,channel:e.channel,value:e.value,channelType:e.channelType||"number"};a!==null?a.postMessage(n):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(n):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",n)}static sendCustomCommand(e,a=null,n={}){const s={command:e,text:JSON.stringify(n)};if(a!==null)a.postMessage(s);else if(typeof window.sendMessageFromUI=="function"){console.log("Cabbage: Calling window.sendMessageFromUI with:",s);try{const o=window.sendMessageFromUI(s);console.log("Cabbage: sendMessageFromUI returned:",o)}catch(o){console.error("Cabbage: sendMessageFromUI threw error:",o),console.error("Cabbage: Error stack:",o.stack)}}else console.error("Cabbage: window.sendMessageFromUI is not available yet. Message:",s),console.error("Cabbage: typeof window.sendMessageFromUI:",typeof window.sendMessageFromUI),console.error("Cabbage: window.sendMessageFromUI value:",window.sendMessageFromUI)}static sendWidgetUpdate(e,a=null){const n={command:"widgetStateUpdate",obj:JSON.stringify(CabbageUtils.sanitizeForEditor(e))};a!==null?a.postMessage(n):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(n):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",n)}static sendMidiMessageFromUI(e,a,n,s=null){var o={statusByte:e,dataByte1:a,dataByte2:n};const l={command:"midiMessage",obj:JSON.stringify(o)};s!==null?s.postMessage(l):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(l):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",l)}static sendChannelData(e,a,n=null){var s={channel:e};if(typeof a=="string")s.stringData=a;else if(typeof a=="number")s.floatData=a;else{console.warn("Cabbage: sendChannelData received unsupported data type:",typeof a);return}const o={command:"channelData",obj:JSON.stringify(s)};console.log("Cabbage: sending channel data from UI",s),n!==null?n.postMessage(o):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(o):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",o)}static MidiMessageFromHost(e,a,n){console.log("Cabbage: Got MIDI Message"+e+":"+a+":"+n)}static triggerFileOpenDialog(e,a,n={}){var s={channel:a,directory:n.directory||"",filters:n.filters||"*",openAtLastKnownLocation:n.openAtLastKnownLocation!==void 0?n.openAtLastKnownLocation:!0};const o={command:"fileOpen",obj:JSON.stringify(s)};e!==null?e.postMessage(o):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(o):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",o)}static openUrl(e,a,n){var s={url:a,file:n};const o={command:"openUrl",obj:JSON.stringify(s)};e!==null?e.postMessage(o):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(o):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",o)}static requestResize(e,a,n=null){const s={command:"requestResize",width:e,height:a};if(n!==null){console.warn("Cabbage: requestResize is not supported in VS Code extension mode");return}else typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(s):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",s)}}const I=i=>{const[e,a]=c.useState();return c.useEffect(()=>{const n=s=>{const{id:o,widgetJson:l,command:b}=s.data;if(o===i&&l&&b==="widgetUpdate"){const t=JSON.parse(l);console.log(`[Cabbage-React] Received properties for channelId ${o}`,t),a(t)}};return window.addEventListener("message",n),()=>{window.removeEventListener("message",n)}},[]),{properties:e}},U=i=>{const{devMode:e}=c.useContext(C),{properties:a}=I(i),[n,s]=c.useState(),[o,l]=c.useState(),b=t=>{if(e)s(t);else{if(o===void 0){console.warn(`[Cabbage-React] parameterIndex not ready for "${i}"`);return}const d={channel:i,paramIdx:o,value:t};f.sendParameterUpdate(d,null)}};return c.useEffect(()=>{var r;const t=a==null?void 0:a.channels.find(g=>g.id===i);if(!t)return;const d=t==null?void 0:t.parameterIndex;o===void 0&&d!==void 0&&(console.log(`[Cabbage-React] Received parameterIndex for channelId "${t.id}"`,d),l(d));const m=a==null?void 0:a.value;m!=null&&(console.log(`[Cabbage-React] Received initial value for channelId "${i}"`,m),s(m));const u=(r=t.range)==null?void 0:r.defaultValue;n===void 0&&u!==void 0&&(console.log(`[Cabbage-React] Received default value for channelId "${t.id}"`,u),s(u))},[a]),c.useEffect(()=>{const t=d=>{var u;const{command:m}=d.data;if(m==="parameterChange"){const{value:r,paramIdx:g}=d.data.data;if(g!==o||r===null)return;console.log(`[Cabbage-React] Received parameterChange for parameterIndex ${g}`,r),s(r)}else if(m==="batchWidgetUpdate"){const r=d.data.widgets,g=r==null?void 0:r.find(p=>p.id===i);if(!g)return;const w=JSON.parse(g.widgetJson).channels.find(p=>p.id===i),M=(u=w==null?void 0:w.range)==null?void 0:u.value;console.log(`[Cabbage-React] Received batch widget update for channelId ${g.id}`,M),s(M)}};return window.addEventListener("message",t),()=>{window.removeEventListener("message",t)}},[o]),{value:n,setValue:b,parameterIndex:o}};exports.Cabbage=f;exports.CabbageContext=C;exports.useCabbageProperties=I;exports.useCabbageState=U;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("react");console.log("Cabbage: loading cabbage.js");class f{static sendChannelUpdate(e,a=null,n=!1){if(n===!0||n===1)f.sendParameterUpdate(e,a);else{const s=e.value!==void 0?e.value:e.stringData||e.floatData;f.sendChannelData(e.channel,s,a)}}static sendParameterUpdate(e,a=null){if(e.paramIdx===void 0||e.paramIdx===null){console.error("Cabbage.sendParameterUpdate: message missing paramIdx!",e);return}if(e.paramIdx<0){console.warn("Cabbage.sendParameterUpdate: paramIdx is -1, skipping (non-automatable widget)",e);return}const n={command:"parameterChange",paramIdx:e.paramIdx,channel:e.channel,value:e.value,channelType:e.channelType||"number"};a!==null?a.postMessage(n):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(n):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",n)}static sendCustomCommand(e,a=null,n={}){const s={command:e,text:JSON.stringify(n)};if(a!==null)a.postMessage(s);else if(typeof window.sendMessageFromUI=="function"){console.log("Cabbage: Calling window.sendMessageFromUI with:",s);try{const o=window.sendMessageFromUI(s);console.log("Cabbage: sendMessageFromUI returned:",o)}catch(o){console.error("Cabbage: sendMessageFromUI threw error:",o),console.error("Cabbage: Error stack:",o.stack)}}else console.error("Cabbage: window.sendMessageFromUI is not available yet. Message:",s),console.error("Cabbage: typeof window.sendMessageFromUI:",typeof window.sendMessageFromUI),console.error("Cabbage: window.sendMessageFromUI value:",window.sendMessageFromUI)}static sendWidgetUpdate(e,a=null){const n={command:"widgetStateUpdate",obj:JSON.stringify(CabbageUtils.sanitizeForEditor(e))};a!==null?a.postMessage(n):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(n):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",n)}static sendMidiMessageFromUI(e,a,n,s=null){var o={statusByte:e,dataByte1:a,dataByte2:n};const l={command:"midiMessage",obj:JSON.stringify(o)};s!==null?s.postMessage(l):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(l):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",l)}static sendChannelData(e,a,n=null){var s={channel:e};if(typeof a=="string")s.stringData=a;else if(typeof a=="number")s.floatData=a;else{console.warn("Cabbage: sendChannelData received unsupported data type:",typeof a);return}const o={command:"channelData",obj:JSON.stringify(s)};console.log("Cabbage: sending channel data from UI",s),n!==null?n.postMessage(o):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(o):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",o)}static MidiMessageFromHost(e,a,n){console.log("Cabbage: Got MIDI Message"+e+":"+a+":"+n)}static triggerFileOpenDialog(e,a,n={}){var s={channel:a,directory:n.directory||"",filters:n.filters||"*",openAtLastKnownLocation:n.openAtLastKnownLocation!==void 0?n.openAtLastKnownLocation:!0};const o={command:"fileOpen",obj:JSON.stringify(s)};e!==null?e.postMessage(o):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(o):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",o)}static openUrl(e,a,n){var s={url:a,file:n};const o={command:"openUrl",obj:JSON.stringify(s)};e!==null?e.postMessage(o):typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(o):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",o)}static requestResize(e,a,n=null){const s={command:"requestResize",width:e,height:a};if(n!==null){console.warn("Cabbage: requestResize is not supported in VS Code extension mode");return}else typeof window.sendMessageFromUI=="function"?window.sendMessageFromUI(s):console.error("Cabbage: window.sendMessageFromUI is not available. Message:",s)}}const I=i=>{const[e,a]=u.useState();return u.useEffect(()=>{const n=s=>{const{id:o,widgetJson:l,command:b}=s.data;if(o===i&&l&&b==="widgetUpdate"){const t=JSON.parse(l);console.log(`[Cabbage-React] Received properties for channelId ${o}`,t),a(t)}};return window.addEventListener("message",n),()=>{window.removeEventListener("message",n)}},[]),{properties:e}},C=(i,e)=>{const{properties:a}=I(i),[n,s]=u.useState(),[o,l]=u.useState(),b=t=>{if(o===void 0){console.warn(`[Cabbage-React] parameterIndex not ready for "${i}"`);return}s(t);const d={paramIdx:o,channel:i,value:t,channelType:"number"};f.sendParameterUpdate(d,null)};return u.useEffect(()=>{var r;const t=a==null?void 0:a.channels.find(g=>g.id===i);if(!t)return;const d=t==null?void 0:t.parameterIndex;o===void 0&&d!==void 0&&(console.log(`[Cabbage-React] Received parameterIndex for channelId "${t.id}"`,d),l(d));const c=a==null?void 0:a.value;c!=null&&(console.log(`[Cabbage-React] Received initial value for channelId "${i}"`,c),s(c));const m=(r=t.range)==null?void 0:r.defaultValue;n===void 0&&m!==void 0&&(console.log(`[Cabbage-React] Received default value for channelId "${t.id}"`,m),s(m))},[a]),u.useEffect(()=>{const t=d=>{var m;const{command:c}=d.data;if(c==="parameterChange"){if(e)return;const{value:r,paramIdx:g}=d.data.data;if(g!==o||r===null)return;console.log(`[Cabbage-React] Received parameterChange for parameterIndex ${g}`,r),s(r)}else if(c==="batchWidgetUpdate"){const r=d.data.widgets,g=r==null?void 0:r.find(p=>p.id===i);if(!g)return;const w=JSON.parse(g.widgetJson).channels.find(p=>p.id===i),M=(m=w==null?void 0:w.range)==null?void 0:m.value;console.log(`[Cabbage-React] Received batch widget update for channelId ${g.id}`,M),s(M)}};return window.addEventListener("message",t),()=>{window.removeEventListener("message",t)}},[o]),{value:n,setValue:b,parameterIndex:o}};exports.Cabbage=f;exports.useCabbageProperties=I;exports.useCabbageState=C;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export { CabbageContext } from './context/CabbageContext';
2
1
  export { useCabbageState } from './hooks/useCabbageState';
3
2
  export { useCabbageProperties } from './hooks/useCabbageProperties';
4
3
  export { Cabbage } from './cabbage/cabbage';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.mjs CHANGED
@@ -1,21 +1,30 @@
1
- import { createContext as C, useState as p, useEffect as M, useContext as U } from "react";
2
- const F = C({
3
- devMode: !1
4
- });
1
+ import { useState as p, useEffect as M } from "react";
5
2
  console.log("Cabbage: loading cabbage.js");
6
3
  class f {
7
4
  /**
8
- * Main entry point for sending any data from UI widgets to the Cabbage backend.
5
+ * Main entry point for sending widget value changes to the Cabbage backend.
6
+ *
9
7
  * This function automatically routes messages to the appropriate backend function
10
8
  * based on the automatable flag:
11
9
  *
12
- * - automatable=true: Routes to sendParameterUpdate for real-time parameter control /
13
- * this also sends the value as channel data to Csound
10
+ * - `automatable=true`: Routes to `sendParameterUpdate()` for DAW-automatable parameters.
11
+ * The value is sent to the DAW for automation recording and also forwarded to Csound.
12
+ *
13
+ * - `automatable=false`: Routes to `sendChannelData()` for non-automatable data.
14
+ * The value is sent directly to Csound without DAW parameter involvement.
15
+ *
16
+ * **When to use**: Call this from widget event handlers (e.g., pointer events, input changes)
17
+ * when the user interacts with a widget.
14
18
  *
15
- * - automatable=false: Routes to sendChannelData for string/numeric data transmission
19
+ * **When NOT to use**: Do not call this when handling incoming `parameterChange` messages
20
+ * from the backend. Those messages are for display updates only.
16
21
  *
17
- * All widget interactions should use this function instead of calling the lower-level
18
- * sendParameterUpdate or sendChannelData functions directly.
22
+ * @param {Object} message - The message object containing widget data
23
+ * @param {string} message.channel - The channel name
24
+ * @param {number} message.paramIdx - Parameter index (required if automatable)
25
+ * @param {number|string} message.value - The value to send
26
+ * @param {Object|null} vscode - VS Code API object (null for plugin mode)
27
+ * @param {boolean} automatable - Whether this widget is DAW-automatable
19
28
  */
20
29
  static sendChannelUpdate(e, a = null, n = !1) {
21
30
  if (n === !0 || n === 1)
@@ -25,6 +34,28 @@ class f {
25
34
  f.sendChannelData(e.channel, s, a);
26
35
  }
27
36
  }
37
+ /**
38
+ * Internal: Send a parameter update to the DAW for automation recording.
39
+ * Use `sendChannelUpdate()` instead - it will route here automatically for automatable widgets.
40
+ *
41
+ * This function sends the parameter value to the DAW's automation system.
42
+ * The DAW will then send the value back via a `parameterChange` message,
43
+ * which updates both the UI and Csound.
44
+ *
45
+ * **Important**: This creates a round-trip through the DAW:
46
+ * 1. UI calls `sendParameterUpdate()` with value
47
+ * 2. DAW receives and records/processes the value
48
+ * 3. DAW sends `parameterChange` back to the plugin
49
+ * 4. Plugin updates Csound and sends `parameterChange` to UI
50
+ * 5. UI updates its display (but does NOT call sendParameterUpdate again!)
51
+ *
52
+ * @param {Object} message - The parameter message
53
+ * @param {number} message.paramIdx - The parameter index (must be >= 0)
54
+ * @param {string} message.channel - The channel name
55
+ * @param {number} message.value - The parameter value (full range, not normalized)
56
+ * @param {string} [message.channelType="number"] - The channel type
57
+ * @param {Object|null} vscode - VS Code API object (null for plugin mode)
58
+ */
28
59
  static sendParameterUpdate(e, a = null) {
29
60
  if (e.paramIdx === void 0 || e.paramIdx === null) {
30
61
  console.error(
@@ -104,6 +135,18 @@ class f {
104
135
  l
105
136
  );
106
137
  }
138
+ /**
139
+ * Internal: Send channel data directly to Csound without DAW automation involvement.
140
+ * Use `sendChannelUpdate()` instead - it will route here automatically for non-automatable widgets.
141
+ *
142
+ * Used for non-automatable widgets like buttons, file selectors, or
143
+ * any widget that sends string data. The value is sent directly to Csound's
144
+ * channel system and is not recorded by DAW automation.
145
+ *
146
+ * @param {string} channel - The Csound channel name
147
+ * @param {number|string} data - The data to send (number or string)
148
+ * @param {Object|null} vscode - VS Code API object (null for plugin mode)
149
+ */
107
150
  static sendChannelData(e, a, n = null) {
108
151
  var s = {
109
152
  channel: e
@@ -193,7 +236,7 @@ class f {
193
236
  );
194
237
  }
195
238
  }
196
- const v = (i) => {
239
+ const U = (i) => {
197
240
  const [e, a] = p();
198
241
  return M(() => {
199
242
  const n = (s) => {
@@ -212,20 +255,22 @@ const v = (i) => {
212
255
  }, []), {
213
256
  properties: e
214
257
  };
215
- }, x = (i) => {
216
- const { devMode: e } = U(F), { properties: a } = v(i), [n, s] = p(), [o, l] = p(), u = (t) => {
217
- if (e)
218
- s(t);
219
- else {
220
- if (o === void 0) {
221
- console.warn(
222
- `[Cabbage-React] parameterIndex not ready for "${i}"`
223
- );
224
- return;
225
- }
226
- const d = { channel: i, paramIdx: o, value: t };
227
- f.sendParameterUpdate(d, null);
258
+ }, h = (i, e) => {
259
+ const { properties: a } = U(i), [n, s] = p(), [o, l] = p(), u = (t) => {
260
+ if (o === void 0) {
261
+ console.warn(
262
+ `[Cabbage-React] parameterIndex not ready for "${i}"`
263
+ );
264
+ return;
228
265
  }
266
+ s(t);
267
+ const d = {
268
+ paramIdx: o,
269
+ channel: i,
270
+ value: t,
271
+ channelType: "number"
272
+ };
273
+ f.sendParameterUpdate(d, null);
229
274
  };
230
275
  return M(() => {
231
276
  var r;
@@ -253,6 +298,7 @@ const v = (i) => {
253
298
  var m;
254
299
  const { command: c } = d.data;
255
300
  if (c === "parameterChange") {
301
+ if (e) return;
256
302
  const { value: r, paramIdx: g } = d.data.data;
257
303
  if (g !== o || r === null) return;
258
304
  console.log(
@@ -282,7 +328,6 @@ const v = (i) => {
282
328
  };
283
329
  export {
284
330
  f as Cabbage,
285
- F as CabbageContext,
286
- v as useCabbageProperties,
287
- x as useCabbageState
331
+ U as useCabbageProperties,
332
+ h as useCabbageState
288
333
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cabbage-react",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "type": "module",
5
5
  "keywords": [
6
6
  "cabbage",
@@ -1,6 +0,0 @@
1
- interface CabbageContext {
2
- devMode: boolean;
3
- }
4
- export declare const CabbageContext: import('react').Context<CabbageContext>;
5
- export {};
6
- //# sourceMappingURL=CabbageContext.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CabbageContext.d.ts","sourceRoot":"","sources":["../../src/context/CabbageContext.ts"],"names":[],"mappings":"AAEA,UAAU,cAAc;IACvB,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,eAAO,MAAM,cAAc,yCAEzB,CAAC"}