@adcops/autocore-react 3.3.34 → 3.3.36

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.
@@ -43,6 +43,16 @@ export interface IndicatorButtonProps extends Omit<ButtonProps, "value"> {
43
43
  * cycle on onColor.
44
44
  */
45
45
  flash?: boolean;
46
+ /** Callback fired when the button is pressed (mouse down or touch start). */
47
+ onPress?: (e: React.MouseEvent | React.TouchEvent) => void;
48
+ /** Callback fired when the button is released (mouse up, touch end, or mouse leave). */
49
+ onRelease?: (e: React.MouseEvent | React.TouchEvent) => void;
50
+ /**
51
+ * Momentary tag writer. When the button is pressed, this is called with `true`.
52
+ * When the button is released or the mouse leaves, it is called with `false`.
53
+ * Pass the `write` function from `useAutoCoreTag` directly to this prop.
54
+ */
55
+ momentary?: (value: boolean) => void | Promise<void>;
46
56
  }
47
57
  export declare const IndicatorButton: React.FC<IndicatorButtonProps>;
48
58
  export default IndicatorButton;
@@ -1 +1 @@
1
- {"version":3,"file":"IndicatorButton.d.ts","sourceRoot":"","sources":["../../src/components/IndicatorButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuD,MAAM,OAAO,CAAC;AAE5E,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAK7D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,OAAO,uBAAuB,CAAC;AAE/B,MAAM,CAAC,OAAO,MAAM,0BAA0B,GAC1C,MAAM,EAAE,GACR,SAAS,EAAE,GACX,SAAS,CAAC;AAEd,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC;IACtE,2GAA2G;IAC3G,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,6BAA6B;IAC7B,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IAElC,mDAAmD;IACnD,OAAO,CAAC,EAAE,cAAc,CAAC;IAEzB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,cAAc,CAAC;IAE1B,+CAA+C;IAC/C,OAAO,CAAC,EAAE,0BAA0B,CAAC;IAErC,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,uBAAuB;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,sDAAsD;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,mDAAmD;IACnD,WAAW,CAAC,EAAE,GAAG,CAAC;IAElB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,UAAU,CAAC;IAExB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,kEAAkE;IAClE,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAKD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAwJ1D,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"IndicatorButton.d.ts","sourceRoot":"","sources":["../../src/components/IndicatorButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuD,MAAM,OAAO,CAAC;AAE5E,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAK7D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,OAAO,uBAAuB,CAAC;AAE/B,MAAM,CAAC,OAAO,MAAM,0BAA0B,GAC1C,MAAM,EAAE,GACR,SAAS,EAAE,GACX,SAAS,CAAC;AAEd,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC;IACtE,2GAA2G;IAC3G,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,6BAA6B;IAC7B,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IAElC,mDAAmD;IACnD,OAAO,CAAC,EAAE,cAAc,CAAC;IAEzB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,cAAc,CAAC;IAE1B,+CAA+C;IAC/C,OAAO,CAAC,EAAE,0BAA0B,CAAC;IAErC,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,uBAAuB;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,sDAAsD;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,mDAAmD;IACnD,WAAW,CAAC,EAAE,GAAG,CAAC;IAElB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,UAAU,CAAC;IAExB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,kEAAkE;IAClE,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAE3D,wFAAwF;IACxF,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAE7D;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtD;AAKD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAkK1D,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -1 +1 @@
1
- import{jsx as _jsx}from"react/jsx-runtime";import React,{useCallback,useContext,useEffect,useState}from"react";import clsx from"clsx";import{Button}from"primereact/button";import{EventEmitterContext}from"../core/EventEmitterContext";import{IndicatorColor}from"../core/IndicatorColor";export{IndicatorColor};import{ActionMode}from"../core/ActionMode";export{ActionMode};import"./IndicatorButton.css";const toPrimeIcon=o=>o?o.includes("pi ")?o:`pi ${o}`:void 0;export const IndicatorButton=({topic:o,value:t,onColor:e=IndicatorColor.IndicatorGreen,offColor:n="gray",options:r,icon:i,onIcon:c,offIcon:a,command:s,commandTopic:l,commandArgs:d,actionMode:u,invert:f,className:m,label:p,style:x,disabled:C,hidden:b,flash:I,...h})=>{const{subscribe:v,unsubscribe:g,dispatch:M}=useContext(EventEmitterContext),[E,y]=useState(void 0),[A,S]=useState(!1);useEffect(()=>{if(!o||!v)return;const t=v(o,o=>y(o));return()=>{try{g&&void 0!==t&&g(t)}catch{}}},[o,v,g]);const k=void 0!==t?t:E,B=(()=>{if(!r||0===r.length)return p;if(r.length>2){if("number"==typeof k){const o=Math.trunc(k);if(o>=0&&o<r.length&&null!=r[o])return String(r[o])}else if("string"==typeof k){const o=r.findIndex(o=>o===k);if(o>=0)return String(r[o])}return p}const o=k?r[1]:r[0];return null!=o&&String(o).length>0?String(o):p})(),T=toPrimeIcon((k?c:a)??i);let j=k?e:n;void 0===k&&(j=IndicatorColor.IndicatorInvalid);const P=useCallback(o=>{if(!s||!M)return;const t={topic:l,value:f?!o:o,...d??{}};M({topic:s,payload:t})},[s,M,f,d,l]),w=useCallback(()=>{A||(S(!0),u!==ActionMode.Tap&&u!==ActionMode.Pressed||P(!0))},[A,u,P]),N=useCallback(()=>{A&&(S(!1),u===ActionMode.Tap?P(!1):u===ActionMode.Released&&P(!0))},[A,u,P]),R={color:"white",backgroundColor:I?void 0:j,display:b?"none":void 0,...I?{"--flash-on":e,"--flash-off":n}:{},...x??{}};return _jsx(Button,{...h,label:B,icon:T,className:clsx(m,I&&"indicator-button-flash"),style:R,disabled:!!C,onMouseDown:w,onTouchStart:w,onMouseUp:N,onTouchEnd:N})};export default IndicatorButton;
1
+ import{jsx as _jsx}from"react/jsx-runtime";import React,{useCallback,useContext,useEffect,useState}from"react";import clsx from"clsx";import{Button}from"primereact/button";import{EventEmitterContext}from"../core/EventEmitterContext";import{IndicatorColor}from"../core/IndicatorColor";export{IndicatorColor};import{ActionMode}from"../core/ActionMode";export{ActionMode};import"./IndicatorButton.css";const toPrimeIcon=o=>o?o.includes("pi ")?o:`pi ${o}`:void 0;export const IndicatorButton=({topic:o,value:t,onColor:e=IndicatorColor.IndicatorGreen,offColor:n="gray",options:r,icon:i,onIcon:c,offIcon:s,command:a,commandTopic:l,commandArgs:d,actionMode:u,invert:f,className:m,label:p,style:x,disabled:C,hidden:b,flash:I,onPress:h,onRelease:v,momentary:g,...M})=>{const{subscribe:y,unsubscribe:E,dispatch:A}=useContext(EventEmitterContext),[S,k]=useState(void 0),[B,T]=useState(!1);useEffect(()=>{if(!o||!y)return;const t=y(o,o=>k(o));return()=>{try{E&&void 0!==t&&E(t)}catch{}}},[o,y,E]);const j=void 0!==t?t:S,P=(()=>{if(!r||0===r.length)return p;if(r.length>2){if("number"==typeof j){const o=Math.trunc(j);if(o>=0&&o<r.length&&null!=r[o])return String(r[o])}else if("string"==typeof j){const o=r.findIndex(o=>o===j);if(o>=0)return String(r[o])}return p}const o=j?r[1]:r[0];return null!=o&&String(o).length>0?String(o):p})(),R=toPrimeIcon((j?c:s)??i);let w=j?e:n;void 0===j&&(w=IndicatorColor.IndicatorInvalid);const N=useCallback(o=>{if(!a||!A)return;const t={topic:l,value:f?!o:o,...d??{}};A({topic:a,payload:t})},[a,A,f,d,l]),_=useCallback(o=>{B||C||(T(!0),g&&g(!0),h&&h(o),u!==ActionMode.Tap&&u!==ActionMode.Pressed||N(!0))},[B,C,u,N,h,g]),D=useCallback(o=>{B&&!C&&(T(!1),g&&g(!1),v&&v(o),u===ActionMode.Tap?N(!1):u===ActionMode.Released&&N(!0))},[B,C,u,N,v,g]),G={color:"white",backgroundColor:I?void 0:w,display:b?"none":void 0,...I?{"--flash-on":e,"--flash-off":n}:{},...x??{}};return _jsx(Button,{...M,label:P,icon:R,className:clsx(m,I&&"indicator-button-flash"),style:G,disabled:!!C,onMouseDown:_,onTouchStart:_,onMouseUp:D,onTouchEnd:D,onMouseLeave:D})};export default IndicatorButton;
@@ -1 +1 @@
1
- {"version":3,"file":"AutoCoreTagContext.d.ts","sourceRoot":"","sources":["../../src/core/AutoCoreTagContext.tsx"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,KAAK,EAAE,EAQV,KAAK,SAAS,EACjB,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EACR,gBAAgB,EAChB,SAAS,EACT,WAAW,EACd,MAAM,oBAAoB,CAAC;AAI5B;;;GAGG;AACH,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE3C;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,8CAQ7B,CAAC;AAsBH;;;;GAIG;AAIH;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC;IACvC,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,EAAE,SAAS,SAAS,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB,CAqdA,CAAC"}
1
+ {"version":3,"file":"AutoCoreTagContext.d.ts","sourceRoot":"","sources":["../../src/core/AutoCoreTagContext.tsx"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,KAAK,EAAE,EAQV,KAAK,SAAS,EACjB,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EACR,gBAAgB,EAChB,SAAS,EACT,WAAW,EACd,MAAM,oBAAoB,CAAC;AAI5B;;;GAGG;AACH,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE3C;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,8CAU7B,CAAC;AAsBH;;;;GAIG;AAIH;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC;IACvC,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,EAAE,SAAS,SAAS,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB,CAufA,CAAC"}
@@ -1 +1 @@
1
- import{jsx as _jsx}from"react/jsx-runtime";import React,{useRef,createContext,useCallback,useContext,useEffect,useMemo,useState}from"react";import{EventEmitterContext}from"./EventEmitterContext";import{MessageType}from"../hub/CommandMessage";export const AutoCoreTagContext=createContext({values:{},rawValues:{},isLoading:!0,write:async()=>{},tap:async()=>{},scales:{},updateScale:async()=>{}});const sleep=e=>new Promise(t=>setTimeout(t,e));export const AutoCoreTagProvider=({children:e,tags:t,scales:a,eagerRead:s=!0})=>{const n=useRef(!1),c=useMemo(()=>({}),[]),r=a??c,{invoke:o,read:u,write:l,serverSubscribe:i,isConnected:f,subscribe:m,unsubscribe:b}=useContext(EventEmitterContext),[y,g]=useState(()=>{const e={};for(const a of t)void 0!==a.initialValue&&(e[a.tagName]=a.initialValue);return e}),[d,p]=useState({}),[v,C]=useState(r),N=useRef(v),h=useRef(y);useEffect(()=>{N.current=v},[v]),useEffect(()=>{h.current=y},[y]);const[w,T]=useState(!0),x=useCallback((e,t)=>{const{valueType:a,scale:s,codec:n}=e;if("number"===a&&"number"==typeof t&&s){const e=N.current[s];return t*(e?.scale??1)}if("json"===a&&n?.fromServer)try{return n.fromServer(t)}catch{}return t},[]),E=useCallback((e,t)=>{const{valueType:a,scale:s,codec:n}=e;if("json"===a&&n?.toServer)try{t=n.toServer(t)}catch{}if("number"===a&&"number"==typeof t&&s){const e=N.current[s];return t/(e?.scale??1)}return t},[]),S=useCallback(e=>{const a=t.filter(t=>t.scale===e);a.length&&p(e=>{const t={...e};for(const e of a){const a=h.current[e.tagName];if("number"!=typeof a)continue;const s=x(e,a);t[e.tagName]!==s&&(t[e.tagName]=s)}return t})},[t,x]),k=useCallback((e,t)=>{g(a=>a[e.tagName]===t?a:{...a,[e.tagName]:t});const a=x(e,t);p(t=>t[e.tagName]===a?t:{...t,[e.tagName]:a})},[x]),M=useCallback(async(e,t,a)=>{const s=a?.concurrency??4,n=a?.minDelayMs??20,c=a?.jitterMs??40;let r=0;const l=Array.from({length:s},()=>(async()=>{for(;;){const a=r++;if(a>=t.length)return;const s=t[a];try{let t=!1;try{await o(s.fqdn,MessageType.Request,{action:"refresh"}),t=!0}catch{}if(!t){const t="GNV"===e.toUpperCase()?{group:"ux"}:{};try{const e=await u(s.fqdn,t);e?.success&&k(s,e.data)}catch(e){}}}catch(e){}finally{const e=Math.floor(Math.random()*c);await sleep(n+e)}}})());await Promise.all(l)},[o,u,k]),j=useCallback(async()=>{for(const[e,t]of Object.entries(r)){if(!t.serverTag)continue;const{domain:a,symbolName:s}=t.serverTag;try{const t=await u(`${a}.${s}`,{group:"ux"});if(t.data&&(t.success??1)&&(t.valid??1)){const a=JSON.parse(t.data);if(a&&"number"==typeof a.scale){const{scale:t,label:s}=a;C(a=>({...a,[e]:{...a[e],scale:t,label:s??a[e]?.label??"---"}})),S(e)}}}catch{}}},[u,r,S]);useEffect(()=>{let e=!0;const a=[],c=async()=>{if(e&&!n.current){n.current=!0;try{await(async()=>{try{await j();for(const n of t){await i(n.tagName,n.fqdn,n.subscriptionOptions);const t=m(n.tagName,t=>{e&&k(n,t)});a.push(t),s&&u(n.fqdn).then(t=>{e&&t?.success&&k(n,t.data)}).catch(e=>{})}}finally{e&&setTimeout(()=>e&&T(!1),100)}})()}finally{e&&setTimeout(()=>e&&T(!1),100)}}};if(f())c();else{const e=m("HUB/connected",()=>{b(e),c()});a.push(e)}return()=>{e=!1,a.forEach(b),n.current=!1}},[m,b,f,o,i,s,t,j,M,k]);const q=useMemo(()=>Object.entries(r).filter(([,e])=>e.serverTag).map(([e,t])=>({scaleName:e,domain:t.serverTag.domain,symbolName:t.serverTag.symbolName})),[r]);useEffect(()=>{let e=!0;const t=[];for(const{scaleName:a,domain:s,symbolName:n}of q){const c=m(`${s}.${n}`,t=>{if(!e)return;const s=t?.value;if(s&&"object"==typeof s&&"number"==typeof s.scale){const{scale:e,label:t}=s;C(s=>({...s,[a]:{...s[a],scale:e,label:t??s[a]?.label??"---"}})),S(a)}});t.push(c)}return()=>{e=!1,t.forEach(b)}},[m,b,q,S]);const R=useCallback(async(e,a)=>{const s=t.find(t=>t.tagName===e);if(!s)return;const n=E(s,a);await l(s.fqdn,n)},[t,l,E]),$=useCallback(async e=>{const a=t.find(t=>t.tagName===e);a&&"boolean"===a.valueType&&(await l(a.fqdn,!0),await sleep(300),await l(a.fqdn,!1))},[t,l]),V=useCallback(async(e,t,a)=>{const s=v[e];if(s){if(s.serverTag){const n=`${s.serverTag.domain}.${s.serverTag.symbolName}`;await l(n,{name:e,scale:t,label:a})}C(s=>({...s,[e]:{...s[e],scale:t,label:a}})),S(e)}},[v,l,S]);useEffect(()=>{p(e=>{const a={...e};for(const e of t){const t=h.current[e.tagName];if(void 0===t)continue;const s=x(e,t);a[e.tagName]!==s&&(a[e.tagName]=s)}return a})},[t,x,v]);const A=useMemo(()=>({values:d,rawValues:y,isLoading:w,write:R,tap:$,scales:v,updateScale:V}),[d,y,w,R,$,v,V]);return _jsx(AutoCoreTagContext.Provider,{value:A,children:e})};
1
+ import{jsx as _jsx}from"react/jsx-runtime";import React,{useRef,createContext,useCallback,useContext,useEffect,useMemo,useState}from"react";import{EventEmitterContext}from"./EventEmitterContext";import{MessageType}from"../hub/CommandMessage";export const AutoCoreTagContext=createContext({values:{},rawValues:{},isLoading:!0,write:async()=>{},tap:async()=>{},press:async()=>{},release:async()=>{},scales:{},updateScale:async()=>{}});const sleep=e=>new Promise(t=>setTimeout(t,e));export const AutoCoreTagProvider=({children:e,tags:t,scales:a,eagerRead:s=!0})=>{const n=useRef(!1),c=useMemo(()=>({}),[]),r=a??c,{invoke:o,read:l,write:u,serverSubscribe:i,isConnected:f,subscribe:m,unsubscribe:y}=useContext(EventEmitterContext),[b,d]=useState(()=>{const e={};for(const a of t)void 0!==a.initialValue&&(e[a.tagName]=a.initialValue);return e}),[g,p]=useState({}),[v,C]=useState(r),N=useRef(v),h=useRef(b);useEffect(()=>{N.current=v},[v]),useEffect(()=>{h.current=b},[b]);const[T,w]=useState(!0),x=useCallback((e,t)=>{const{valueType:a,scale:s,codec:n}=e;if("number"===a&&"number"==typeof t&&s){const e=N.current[s];return t*(e?.scale??1)}if("json"===a&&n?.fromServer)try{return n.fromServer(t)}catch{}return t},[]),E=useCallback((e,t)=>{const{valueType:a,scale:s,codec:n}=e;if("json"===a&&n?.toServer)try{t=n.toServer(t)}catch{}if("number"===a&&"number"==typeof t&&s){const e=N.current[s];return t/(e?.scale??1)}return t},[]),k=useCallback(e=>{const a=t.filter(t=>t.scale===e);a.length&&p(e=>{const t={...e};for(const e of a){const a=h.current[e.tagName];if("number"!=typeof a)continue;const s=x(e,a);t[e.tagName]!==s&&(t[e.tagName]=s)}return t})},[t,x]),S=useCallback((e,t)=>{d(a=>a[e.tagName]===t?a:{...a,[e.tagName]:t});const a=x(e,t);p(t=>t[e.tagName]===a?t:{...t,[e.tagName]:a})},[x]),M=useCallback(async(e,t,a)=>{const s=a?.concurrency??4,n=a?.minDelayMs??20,c=a?.jitterMs??40;let r=0;const u=Array.from({length:s},()=>(async()=>{for(;;){const a=r++;if(a>=t.length)return;const s=t[a];try{let t=!1;try{await o(s.fqdn,MessageType.Request,{action:"refresh"}),t=!0}catch{}if(!t){const t="GNV"===e.toUpperCase()?{group:"ux"}:{};try{const e=await l(s.fqdn,t);e?.success&&S(s,e.data)}catch(e){}}}catch(e){}finally{const e=Math.floor(Math.random()*c);await sleep(n+e)}}})());await Promise.all(u)},[o,l,S]),j=useCallback(async()=>{for(const[e,t]of Object.entries(r)){if(!t.serverTag)continue;const{domain:a,symbolName:s}=t.serverTag;try{const t=await l(`${a}.${s}`,{group:"ux"});if(t.data&&(t.success??1)&&(t.valid??1)){const a=JSON.parse(t.data);if(a&&"number"==typeof a.scale){const{scale:t,label:s}=a;C(a=>({...a,[e]:{...a[e],scale:t,label:s??a[e]?.label??"---"}})),k(e)}}}catch{}}},[l,r,k]);useEffect(()=>{let e=!0;const a=[],c=async()=>{if(e&&!n.current){n.current=!0;try{await(async()=>{try{await j();for(const n of t){await i(n.tagName,n.fqdn,n.subscriptionOptions);const t=m(n.tagName,t=>{e&&S(n,t)});a.push(t),s&&l(n.fqdn).then(t=>{e&&t?.success&&S(n,t.data)}).catch(e=>{})}}finally{e&&setTimeout(()=>e&&w(!1),100)}})()}finally{e&&setTimeout(()=>e&&w(!1),100)}}};if(f())c();else{const e=m("HUB/connected",()=>{y(e),c()});a.push(e)}return()=>{e=!1,a.forEach(y),n.current=!1}},[m,y,f,o,i,s,t,j,M,S]);const q=useMemo(()=>Object.entries(r).filter(([,e])=>e.serverTag).map(([e,t])=>({scaleName:e,domain:t.serverTag.domain,symbolName:t.serverTag.symbolName})),[r]);useEffect(()=>{let e=!0;const t=[];for(const{scaleName:a,domain:s,symbolName:n}of q){const c=m(`${s}.${n}`,t=>{if(!e)return;const s=t?.value;if(s&&"object"==typeof s&&"number"==typeof s.scale){const{scale:e,label:t}=s;C(s=>({...s,[a]:{...s[a],scale:e,label:t??s[a]?.label??"---"}})),k(a)}});t.push(c)}return()=>{e=!1,t.forEach(y)}},[m,y,q,k]);const R=useCallback(async(e,a)=>{const s=t.find(t=>t.tagName===e);if(!s)return;const n=E(s,a);await u(s.fqdn,n)},[t,u,E]),$=useCallback(async e=>{const a=t.find(t=>t.tagName===e);a&&"boolean"===a.valueType&&(u(a.fqdn,!0).catch(e=>{}),await sleep(300),u(a.fqdn,!1).catch(e=>{}))},[t,u]),V=useCallback(async e=>{const a=t.find(t=>t.tagName===e);a&&"boolean"===a.valueType&&await u(a.fqdn,!0)},[t,u]),A=useCallback(async e=>{const a=t.find(t=>t.tagName===e);a&&"boolean"===a.valueType&&await u(a.fqdn,!1)},[t,u]),O=useCallback(async(e,t,a)=>{const s=v[e];if(s){if(s.serverTag){const n=`${s.serverTag.domain}.${s.serverTag.symbolName}`;await u(n,{name:e,scale:t,label:a})}C(s=>({...s,[e]:{...s[e],scale:t,label:a}})),k(e)}},[v,u,k]);useEffect(()=>{p(e=>{const a={...e};for(const e of t){const t=h.current[e.tagName];if(void 0===t)continue;const s=x(e,t);a[e.tagName]!==s&&(a[e.tagName]=s)}return a})},[t,x,v]);const P=useMemo(()=>({values:g,rawValues:b,isLoading:T,write:R,tap:$,press:V,release:A,scales:v,updateScale:O}),[g,b,T,R,$,V,A,v,O]);return _jsx(AutoCoreTagContext.Provider,{value:P,children:e})};
@@ -39,6 +39,10 @@ export type TagBinding<T> = Readonly<{
39
39
  write: (displayValue: T) => Promise<void>;
40
40
  /** Momentary action; typically boolean true→false pulse. */
41
41
  tap: () => Promise<void>;
42
+ /** Sets boolean tag to true. */
43
+ press: () => Promise<void>;
44
+ /** Sets boolean tag to false. */
45
+ release: () => Promise<void>;
42
46
  /** True while initial read/bootstrapping is in progress. */
43
47
  isLoading: boolean;
44
48
  }>;
@@ -268,6 +272,10 @@ export interface BaseContextValue<VMap extends Record<string, any>> {
268
272
  * Typically used for boolean "request" bits.
269
273
  */
270
274
  tap: <K extends keyof VMap & string>(tagName: K) => Promise<void>;
275
+ /** Sets boolean tag to true. */
276
+ press: <K extends keyof VMap & string>(tagName: K) => Promise<void>;
277
+ /** Sets boolean tag to false. */
278
+ release: <K extends keyof VMap & string>(tagName: K) => Promise<void>;
271
279
  /** Current scale configurations by name. */
272
280
  scales: Record<string, ScaleConfig>;
273
281
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"AutoCoreTagTypes.d.ts","sourceRoot":"","sources":["../../src/core/AutoCoreTagTypes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AutoCoreTagTypes.d.ts","sourceRoot":"","sources":["../../src/core/AutoCoreTagTypes.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,8 @@ export declare function makeAutoCoreTagHooks<Spec extends readonly TagConfig[]>(
5
5
  readonly rawValue: unknown;
6
6
  readonly write: (displayValue: TagValueMap<Spec>[K]) => Promise<void>;
7
7
  readonly tap: () => Promise<void>;
8
+ readonly press: () => Promise<void>;
9
+ readonly release: () => Promise<void>;
8
10
  readonly isLoading: boolean;
9
11
  };
10
12
  readonly useAutoCoreTags: <K extends Spec[number]["tagName"]>(tagNames: readonly K[]) => {
@@ -1 +1 @@
1
- {"version":3,"file":"useAutoCoreTag.d.ts","sourceRoot":"","sources":["../../src/hooks/useAutoCoreTag.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEzF,wBAAgB,oBAAoB,CAAC,IAAI,SAAS,SAAS,SAAS,EAAE,EAClE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAC3D,IAAI,EAAE,IAAI;8BAYc,CAAC,2CAA4B,CAAC;;;;;;;+BAyB7B,CAAC,4CAA6B,SAAS,CAAC,EAAE;4BAO/C,CAAC;;kCAYyB,CAAC;;;iCAUpB,CAAC,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,mBAAM,CAAC,KAAK,CAAC,SAAQ,GAAG,EAAE;;;;;;;uCAW3C,MAAM;;EAKtD"}
1
+ {"version":3,"file":"useAutoCoreTag.d.ts","sourceRoot":"","sources":["../../src/hooks/useAutoCoreTag.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEzF,wBAAgB,oBAAoB,CAAC,IAAI,SAAS,SAAS,SAAS,EAAE,EAClE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAC3D,IAAI,EAAE,IAAI;8BAYc,CAAC,2CAA4B,CAAC;;;;;;;;;+BA6B7B,CAAC,4CAA6B,SAAS,CAAC,EAAE;4BAO/C,CAAC;;kCAYyB,CAAC;;;iCAUpB,CAAC,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,mBAAM,CAAC,KAAK,CAAC,SAAQ,GAAG,EAAE;;;;;;;uCAW3C,MAAM;;EAKtD"}
@@ -1 +1 @@
1
- import{useCallback,useContext,useMemo}from"react";export function makeAutoCoreTagHooks(e,a){return{useAutoCoreTag:t=>{const{values:s,rawValues:u,isLoading:o,write:r,tap:n}=useContext(e),l=(e=>a.find(a=>a.tagName===e))(t);if(!l)throw new Error(`useAutoCoreTag: unknown tagName '${String(t)}'`);const i=useCallback(e=>r(t,e),[r,t]),c=useCallback(()=>n?.(t),[n,t]);return{value:s[t],rawValue:u[t],write:i,tap:c,isLoading:o}},useAutoCoreTags:a=>{const{values:t,rawValues:s,isLoading:u,write:o}=useContext(e);return{values:useMemo(()=>Object.fromEntries(a.map(e=>[e,t[e]])),[t,a]),rawValues:useMemo(()=>Object.fromEntries(a.map(e=>[e,s[e]])),[s,a]),write:useCallback(async(e,a)=>{await o(e,a)},[o]),isLoading:u}},useAutoCoreSelect:(a,t=[])=>{const{values:s,isLoading:u}=useContext(e);return{selected:useMemo(()=>a(s),[s,...t]),isLoading:u}},useScales:()=>{const{scales:a,updateScale:t}=useContext(e),s=useCallback(e=>a[e],[a]);return{scales:a,updateScale:t,getScale:s}}}}
1
+ import{useCallback,useContext,useMemo}from"react";export function makeAutoCoreTagHooks(e,a){return{useAutoCoreTag:s=>{const{values:t,rawValues:u,isLoading:o,write:r,tap:l,press:n,release:c}=useContext(e),i=(e=>a.find(a=>a.tagName===e))(s);if(!i)throw new Error(`useAutoCoreTag: unknown tagName '${String(s)}'`);const C=useCallback(e=>r(s,e),[r,s]),g=useCallback(()=>l?.(s),[l,s]),m=useCallback(()=>n?.(s),[n,s]),w=useCallback(()=>c?.(s),[c,s]);return{value:t[s],rawValue:u[s],write:C,tap:g,press:m,release:w,isLoading:o}},useAutoCoreTags:a=>{const{values:s,rawValues:t,isLoading:u,write:o}=useContext(e);return{values:useMemo(()=>Object.fromEntries(a.map(e=>[e,s[e]])),[s,a]),rawValues:useMemo(()=>Object.fromEntries(a.map(e=>[e,t[e]])),[t,a]),write:useCallback(async(e,a)=>{await o(e,a)},[o]),isLoading:u}},useAutoCoreSelect:(a,s=[])=>{const{values:t,isLoading:u}=useContext(e);return{selected:useMemo(()=>a(t),[t,...s]),isLoading:u}},useScales:()=>{const{scales:a,updateScale:s}=useContext(e),t=useCallback(e=>a[e],[a]);return{scales:a,updateScale:s,getScale:t}}}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adcops/autocore-react",
3
- "version": "3.3.34",
3
+ "version": "3.3.36",
4
4
  "description": "A React component library for industrial user interfaces.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -69,6 +69,19 @@ export interface IndicatorButtonProps extends Omit<ButtonProps, "value"> {
69
69
  * cycle on onColor.
70
70
  */
71
71
  flash?: boolean;
72
+
73
+ /** Callback fired when the button is pressed (mouse down or touch start). */
74
+ onPress?: (e: React.MouseEvent | React.TouchEvent) => void;
75
+
76
+ /** Callback fired when the button is released (mouse up, touch end, or mouse leave). */
77
+ onRelease?: (e: React.MouseEvent | React.TouchEvent) => void;
78
+
79
+ /**
80
+ * Momentary tag writer. When the button is pressed, this is called with `true`.
81
+ * When the button is released or the mouse leaves, it is called with `false`.
82
+ * Pass the `write` function from `useAutoCoreTag` directly to this prop.
83
+ */
84
+ momentary?: (value: boolean) => void | Promise<void>;
72
85
  }
73
86
 
74
87
  const toPrimeIcon = (cls?: string) =>
@@ -94,6 +107,9 @@ export const IndicatorButton: React.FC<IndicatorButtonProps> = ({
94
107
  disabled,
95
108
  hidden,
96
109
  flash,
110
+ onPress,
111
+ onRelease,
112
+ momentary,
97
113
  ...restProps
98
114
  }) => {
99
115
  const { subscribe, unsubscribe, dispatch } = useContext(
@@ -179,25 +195,31 @@ export const IndicatorButton: React.FC<IndicatorButtonProps> = ({
179
195
  [command, dispatch, invert, commandArgs, commandTopic]
180
196
  );
181
197
 
182
- const handleOnPressed = useCallback(() => {
183
- if (isPressed) return;
198
+ const handleOnPressed = useCallback((e: React.MouseEvent | React.TouchEvent) => {
199
+ if (isPressed || disabled) return;
184
200
  setIsPressed(true);
185
201
 
202
+ if (momentary) momentary(true);
203
+ if (onPress) onPress(e);
204
+
186
205
  if (actionMode === ActionMode.Tap || actionMode === ActionMode.Pressed) {
187
206
  dispatchCommand(true);
188
207
  }
189
- }, [isPressed, actionMode, dispatchCommand]);
208
+ }, [isPressed, disabled, actionMode, dispatchCommand, onPress, momentary]);
190
209
 
191
- const handleOnReleased = useCallback(() => {
192
- if (!isPressed) return;
210
+ const handleOnReleased = useCallback((e: React.MouseEvent | React.TouchEvent) => {
211
+ if (!isPressed || disabled) return;
193
212
  setIsPressed(false);
194
213
 
214
+ if (momentary) momentary(false);
215
+ if (onRelease) onRelease(e);
216
+
195
217
  if (actionMode === ActionMode.Tap) {
196
218
  dispatchCommand(false);
197
219
  } else if (actionMode === ActionMode.Released) {
198
220
  dispatchCommand(true);
199
221
  }
200
- }, [isPressed, actionMode, dispatchCommand]);
222
+ }, [isPressed, disabled, actionMode, dispatchCommand, onRelease, momentary]);
201
223
 
202
224
  const mergedStyle: React.CSSProperties = {
203
225
  color: "white",
@@ -224,6 +246,7 @@ export const IndicatorButton: React.FC<IndicatorButtonProps> = ({
224
246
  onTouchStart={handleOnPressed}
225
247
  onMouseUp={handleOnReleased}
226
248
  onTouchEnd={handleOnReleased}
249
+ onMouseLeave={handleOnReleased} // Safety net for drag-offs
227
250
  />
228
251
  );
229
252
  };
@@ -104,6 +104,8 @@ export const AutoCoreTagContext = createContext<BaseContextValue<VMapRuntime>>({
104
104
  isLoading: true,
105
105
  write: async () => { },
106
106
  tap: async () => { },
107
+ press: async () => { },
108
+ release: async () => { },
107
109
  scales: {},
108
110
  updateScale: async () => { },
109
111
  });
@@ -538,6 +540,8 @@ export const AutoCoreTagProvider: React.FC<{
538
540
 
539
541
  /**
540
542
  * Momentary pulse for boolean tags (True -> Wait 300ms -> False).
543
+ * Now uses try...finally to ensure the tag is always reset to false
544
+ * even if the connection is lost or an error occurs during the pulse.
541
545
  */
542
546
  const tap = useCallback(
543
547
  async (tagName: string) => {
@@ -551,9 +555,40 @@ export const AutoCoreTagProvider: React.FC<{
551
555
  return;
552
556
  }
553
557
 
554
- await hubWrite(cfg.fqdn, true);
558
+ // Fire and forget the writes. WebSockets guarantee ordered delivery.
559
+ // We don't await them here so that the pulse is responsive and
560
+ // doesn't hang if the server is slow to acknowledge the first write.
561
+ hubWrite(cfg.fqdn, true).catch(e => console.error(`tap(): write true failed`, e));
562
+
555
563
  await sleep(300);
556
- await hubWrite(cfg.fqdn, false);
564
+
565
+ hubWrite(cfg.fqdn, false).catch(e => console.error(`tap(): write false failed`, e));
566
+ },
567
+ [tags, hubWrite]
568
+ );
569
+
570
+ /**
571
+ * Sets a boolean tag to TRUE.
572
+ */
573
+ const press = useCallback(
574
+ async (tagName: string) => {
575
+ const cfg = tags.find((t) => t.tagName === tagName);
576
+ if (cfg && cfg.valueType === "boolean") {
577
+ await hubWrite(cfg.fqdn, true);
578
+ }
579
+ },
580
+ [tags, hubWrite]
581
+ );
582
+
583
+ /**
584
+ * Sets a boolean tag to FALSE.
585
+ */
586
+ const release = useCallback(
587
+ async (tagName: string) => {
588
+ const cfg = tags.find((t) => t.tagName === tagName);
589
+ if (cfg && cfg.valueType === "boolean") {
590
+ await hubWrite(cfg.fqdn, false);
591
+ }
557
592
  },
558
593
  [tags, hubWrite]
559
594
  );
@@ -612,11 +647,12 @@ export const AutoCoreTagProvider: React.FC<{
612
647
  isLoading,
613
648
  write,
614
649
  tap,
650
+ press,
651
+ release,
615
652
  scales: scaleValues,
616
653
  updateScale,
617
- }),
618
- [values, rawValues, isLoading, write, tap, scaleValues, updateScale]
619
- );
654
+ }), [values, rawValues, isLoading, write, tap, press, release, scaleValues, updateScale]);
655
+
620
656
 
621
657
  return (
622
658
  <AutoCoreTagContext.Provider value={ctxValue}>
@@ -58,6 +58,10 @@ export type TagBinding<T> = Readonly<{
58
58
  write: (displayValue: T) => Promise<void>;
59
59
  /** Momentary action; typically boolean true→false pulse. */
60
60
  tap: () => Promise<void>;
61
+ /** Sets boolean tag to true. */
62
+ press: () => Promise<void>;
63
+ /** Sets boolean tag to false. */
64
+ release: () => Promise<void>;
61
65
  /** True while initial read/bootstrapping is in progress. */
62
66
  isLoading: boolean;
63
67
  }>;
@@ -320,6 +324,12 @@ export interface BaseContextValue<VMap extends Record<string, any>> {
320
324
  */
321
325
  tap: <K extends keyof VMap & string>(tagName: K) => Promise<void>;
322
326
 
327
+ /** Sets boolean tag to true. */
328
+ press: <K extends keyof VMap & string>(tagName: K) => Promise<void>;
329
+
330
+ /** Sets boolean tag to false. */
331
+ release: <K extends keyof VMap & string>(tagName: K) => Promise<void>;
332
+
323
333
  /** Current scale configurations by name. */
324
334
  scales: Record<string, ScaleConfig>;
325
335
 
@@ -31,7 +31,7 @@ export function makeAutoCoreTagHooks<Spec extends readonly TagConfig[]>(
31
31
  * Returns current value, raw value, direct server writer, and tap helper.
32
32
  */
33
33
  const useAutoCoreTag = <K extends TagNames>(tagName: K) => {
34
- const { values, rawValues, isLoading, write: ctxWrite, tap: ctxTap } = useContext(Context);
34
+ const { values, rawValues, isLoading, write: ctxWrite, tap: ctxTap, press: ctxPress, release: ctxRelease } = useContext(Context);
35
35
 
36
36
  const cfg = findCfg(tagName as string);
37
37
  if (!cfg) throw new Error(`useAutoCoreTag: unknown tagName '${String(tagName)}'`);
@@ -42,12 +42,16 @@ export function makeAutoCoreTagHooks<Spec extends readonly TagConfig[]>(
42
42
  );
43
43
 
44
44
  const tap = useCallback(() => ctxTap?.(tagName), [ctxTap, tagName]);
45
+ const press = useCallback(() => ctxPress?.(tagName), [ctxPress, tagName]);
46
+ const release = useCallback(() => ctxRelease?.(tagName), [ctxRelease, tagName]);
45
47
 
46
48
  return {
47
49
  value: values[tagName] as VMap[K],
48
50
  rawValue: rawValues[tagName as string],
49
51
  write,
50
52
  tap,
53
+ press,
54
+ release,
51
55
  isLoading,
52
56
  } as const;
53
57
  };