@djvlc/runtime-host-react 1.1.4 → 1.1.6
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.
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=require("react"),r=require("@djvlc/runtime-core"),n=require("react/jsx-runtime"),t={initTime:0,loadTime:0,renderTime:0,totalTime:0,initTimestamp:null,readyTimestamp:null};function o(n){const[o,a]=e.useState(null),[i,l]=e.useState(!0),[s,c]=e.useState("idle"),[u,d]=e.useState(null),[p,m]=e.useState(null),[h,f]=e.useState(null),[w,y]=e.useState(t),v=e.useRef(null),g=e.useRef({startTime:0,initStartTime:0,loadStartTime:0,renderStartTime:0}),x=e.useMemo(()=>"ready"===s,[s]),T=e.useMemo(()=>"error"===s||null!==p,[s,p]),b=e.useCallback(async()=>{const e=n.containerRef?.current;if(!e)throw new Error("Container element not found");g.current.startTime=performance.now(),g.current.initStartTime=g.current.startTime,n.enableMetrics&&y(e=>({...e,initTimestamp:Date.now()}));const t=r.createRuntime({...n,container:e,onError:e=>{m(e),n.onError?.(e)},onEvent:e=>{n.onEvent?.(e)}});v.current=t,a(t),t.onStateChange(e=>{c(e.phase),l("ready"!==e.phase&&"error"!==e.phase),e.page&&d(e.page),e.error&&m(e.error)}),await t.init(),f(t.getHostApi()),n.enableMetrics&&y(e=>({...e,initTime:performance.now()-g.current.initStartTime}))},[n]),E=e.useCallback(async()=>{if(!v.current)throw new Error("Runtime not initialized");g.current.loadStartTime=performance.now();const e=await v.current.load();return d(e),f(v.current.getHostApi()),n.enableMetrics&&y(e=>({...e,loadTime:performance.now()-g.current.loadStartTime})),e},[n.enableMetrics]),A=e.useCallback(async()=>{if(!v.current)throw new Error("Runtime not initialized");if(g.current.renderStartTime=performance.now(),await v.current.render(),l(!1),n.enableMetrics){const e=performance.now();y(r=>({...r,renderTime:e-g.current.renderStartTime,totalTime:e-g.current.startTime,readyTimestamp:Date.now()}))}},[n.enableMetrics]),I=e.useCallback(()=>{v.current?.destroy(),v.current=null,a(null),f(null),d(null),m(null),c("idle"),l(!0),y(t)},[]),N=e.useCallback(async()=>{if(!v.current)throw new Error("Runtime not initialized");m(null),l(!0),await E(),await A()},[E,A]),j=e.useCallback((e,r)=>{v.current?.setVariable(e,r)},[]),R=e.useCallback(e=>{v.current&&Object.entries(e).forEach(([e,r])=>{v.current?.setVariable(e,r)})},[]),C=e.useCallback(e=>v.current?.getState().variables[e],[]),P=e.useCallback(async e=>{await(v.current?.refreshData(e))},[]),S=e.useCallback(async(e,r)=>{const n=h;if(!n)throw new Error("HostAPI not available");const t=await n.executeAction(e,r||{});if(t.success)return t.data;throw new Error(t.errorMessage||"Action failed")},[h]);return{runtime:o,loading:i,phase:s,page:u,error:p,hostApi:h,isReady:x,hasError:T,metrics:w,init:b,load:E,render:A,destroy:I,reload:N,setVariable:j,setVariables:R,getVariable:C,refreshData:P,executeAction:S}}var a={phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1},i=e.createContext({runtime:null,state:a,hostApi:null});function l({runtime:e,state:r,hostApi:t,children:o}){const a={runtime:e,state:r,hostApi:t};return n.jsx(i.Provider,{value:a,children:o})}function s(){return e.useContext(i)}var c={phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1};function u(r,n){const t=s(),[o,a]=e.useState(!1),[i,l]=e.useState(),[c,u]=e.useState(null),[d,p]=e.useState(0),m=e.useRef(!0);e.useEffect(()=>(m.current=!0,()=>{m.current=!1}),[]);const h=e.useCallback(()=>{l(void 0),u(null),p(0)},[]),f=e.useCallback(async(e,o)=>{const a=t.hostApi;if(!a)throw new Error("HostAPI not available");try{const n=await a.executeAction(r,e);if(n.success)return n.data;throw new Error(n.errorMessage||"Action failed")}catch(r){if(o>0)return await new Promise(e=>setTimeout(e,n?.retryDelay||1e3)),f(e,o-1);throw r}},[t.hostApi,r,n?.retryDelay]);return{execute:e.useCallback(async e=>{if(m.current){a(!0),u(null),p(e=>e+1);try{const r=await f(e,n?.retryCount||0);return m.current&&(l(r),n?.onSuccess?.(r)),r}catch(e){const r=e;throw m.current&&(u(r),n?.onError?.(r)),e}finally{m.current&&a(!1)}}},[f,n]),loading:o,result:i,error:c,reset:h,executionCount:d}}exports.DJVProvider=function({runtime:r,hostApi:t,children:o,className:a,debug:i=!1,onStateChange:s,onPhaseChange:u,onError:d}){const[p,m]=e.useState(r?.getState()||c),h=e.useRef(p.phase);return e.useEffect(()=>{if(!r)return void m(c);m(r.getState());const e=r.onStateChange(e=>{m(e),s?.(e),e.phase!==h.current&&(u?.(e.phase),h.current=e.phase),e.error&&d?.(e.error)});return()=>{e()}},[r,s,u,d,i]),e.useEffect(()=>{},[t]),n.jsx(l,{runtime:r,state:p,hostApi:t,children:n.jsx("div",{className:["djvlc-provider",a].filter(Boolean).join(" "),"data-phase":p.phase,children:o})})},exports.DJVRenderer=function({pageUid:r,apiBaseUrl:t,cdnBaseUrl:a,channel:i="prod",userId:s,deviceId:c,authToken:u,previewToken:d,debug:p=!1,enableSRI:m=!0,onLoad:h,onError:f,onReady:w,onPhaseChange:y,loadingComponent:v,errorComponent:g,emptyComponent:x,children:T,className:b,style:E,retryCount:A=3,retryDelay:I=1e3,timeout:N=3e4}){const j=e.useRef(null),R=e.useRef(!0),C=e.useRef(0),[P,S]=e.useState({phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1}),U={pageUid:r,apiBaseUrl:t,cdnBaseUrl:a,channel:i,userId:s,deviceId:c,authToken:u,previewToken:d,debug:p,enableSRI:m,containerRef:j,onError:e=>{f?.(e)}},{runtime:k,loading:q,phase:B,page:D,error:M,hostApi:V,init:z,load:L,render:H,destroy:O}=o(U);e.useEffect(()=>{y?.(B)},[B,y]);const J=e.useCallback(async()=>{if(!j.current||!R.current)return;const e=new Promise((e,r)=>{setTimeout(()=>r(new Error("加载超时")),N)});try{await Promise.race([(async()=>{await z();const e=await L();R.current&&h?.(e),await H(),R.current&&(w?.(),C.current=0,k&&k.onStateChange(e=>{R.current&&S(e)}))})(),e])}catch(e){if(!R.current)return;C.current<A&&(C.current++,setTimeout(()=>{R.current&&J()},I))}},[z,L,H,k,h,w,N,A,I,p]),F=e.useCallback(()=>{C.current=0,J()},[J]);return e.useEffect(()=>(R.current=!0,J(),()=>{R.current=!1,O()}),[r]),n.jsx(l,{runtime:k,state:P,hostApi:V,children:n.jsxs("div",{ref:j,className:`djvlc-renderer ${b||""}`,style:E,"data-phase":B,"data-page-uid":r,children:[q?v||n.jsxs("div",{className:"djvlc-loading",children:[n.jsx("div",{className:"djvlc-loading-spinner"}),n.jsx("span",{children:"加载中..."}),C.current>0&&n.jsxs("span",{className:"djvlc-loading-retry",children:["重试 ",C.current,"/",A]})]}):null,M?"function"==typeof g?g(M,F):g||n.jsxs("div",{className:"djvlc-error",children:[n.jsx("div",{className:"djvlc-error-icon",children:"⚠️"}),n.jsxs("span",{className:"djvlc-error-message",children:["加载失败:",M.message]}),n.jsx("button",{className:"djvlc-error-retry-btn",onClick:F,type:"button",children:"重试"})]}):null,q||M||D||"ready"!==B||D?null:x||n.jsx("div",{className:"djvlc-empty",children:n.jsx("span",{children:"暂无内容"})}),T]})})},exports.RuntimeContext=i,exports.RuntimeProvider=l,exports.useAction=u,exports.useAsync=function(r,n=[],t){const[o,a]=e.useState(),[i,l]=e.useState(!1),[s,c]=e.useState(null),u=e.useRef(!0);e.useEffect(()=>(u.current=!0,()=>{u.current=!1}),[]);const d=e.useCallback(async()=>{if(u.current){l(!0),c(null);try{const e=await r();return u.current&&(a(e),t?.onSuccess?.(e)),e}catch(e){const r=e;return void(u.current&&(c(r),t?.onError?.(r)))}finally{u.current&&l(!1)}}},[r,...n]);return e.useEffect(()=>{!1!==t?.immediate&&d()},[]),{data:o,loading:i,error:s,execute:d}},exports.useComponentState=function(r){const n=s().state.components.get(r);return e.useMemo(()=>({isLoaded:"loaded"===n?.status,isLoading:"loading"===n?.status,hasError:"failed"===n?.status,loadTime:n?.loadTime,info:n}),[n])},exports.useDJVRuntime=function(){const r=s(),n=e.useMemo(()=>{const e=r.state.phase;return"ready"!==e&&"error"!==e},[r.state.phase]),t="ready"===r.state.phase,o="error"===r.state.phase||null!==r.state.error,a=e.useCallback(async()=>{if(!r.runtime)throw new Error("Runtime not available");await r.runtime.load(),await r.runtime.render()},[r.runtime]);return{runtime:r.runtime,state:r.state,loading:n,phase:r.state.phase,error:r.state.error,page:r.state.page,isReady:t,hasError:o,reload:a}},exports.useData=function(r,n,t){const o=s(),[a,i]=e.useState(),[l,c]=e.useState(!1),[u,d]=e.useState(null),[p,m]=e.useState(!1),h=e.useRef(!0),f=e.useRef(n);e.useEffect(()=>(h.current=!0,()=>{h.current=!1}),[]);const w=e.useCallback(async e=>{const n=o.hostApi;if(n&&h.current){c(!0),d(null);try{const o=await n.requestData(r,e||f.current);if(!h.current)return;i(o),m(!0),t?.onSuccess?.(o)}catch(e){if(h.current){const r=e;d(r),t?.onError?.(r)}}finally{h.current&&c(!1)}}},[o.hostApi,r,t]);return e.useEffect(()=>{const e=f.current;f.current=n,!1!==t?.refreshOnParamsChange&&o.hostApi&&p&&JSON.stringify(e)!==JSON.stringify(n)&&w()},[n,o.hostApi,t?.refreshOnParamsChange,p,w]),e.useEffect(()=>{!1!==t?.immediate&&o.hostApi&&w()},[o.hostApi]),e.useEffect(()=>{if(!t?.refreshInterval||t.refreshInterval<=0)return;const e=setInterval(()=>{w()},t.refreshInterval);return()=>clearInterval(e)},[t?.refreshInterval,w]),{data:a,loading:l,error:u,refetch:w,isFetched:p}},exports.useDebouncedAction=function(r,n=300){const{execute:t,loading:o,result:a,error:i}=u(r),l=e.useRef(null),s=e.useRef(!0);return e.useEffect(()=>(s.current=!0,()=>{s.current=!1,l.current&&clearTimeout(l.current)}),[]),{execute:e.useCallback(e=>{l.current&&clearTimeout(l.current),l.current=setTimeout(()=>{s.current&&t(e).catch(()=>{})},n)},[t,n]),loading:o,result:a,error:i,cancel:e.useCallback(()=>{l.current&&(clearTimeout(l.current),l.current=null)},[])}},exports.useHostApi=function(){const e=s();if(!e.hostApi)throw new Error("HostAPI not available. Make sure runtime is initialized.");return e.hostApi},exports.useLifecycle=function(r){const n=s(),[t,o]=e.useState(!1),[a,i]=e.useState(!1),l=e.useRef(n.state.phase),c=e.useRef(!0);return e.useEffect(()=>(c.current=!0,()=>{c.current=!1}),[]),e.useEffect(()=>{const e=n.state.phase;e!==l.current&&(r?.onPhaseChange?.(e),l.current=e),t||"idle"===e||(o(!0),Promise.resolve(r?.onMounted?.()).catch(e=>{r?.onError?.(e)})),a||"ready"!==e||(i(!0),Promise.resolve(r?.onReady?.()).catch(e=>{r?.onError?.(e)})),"error"===e&&n.state.error&&r?.onError?.(n.state.error)},[n.state.phase,n.state.error,t,a,r]),{phase:n.state.phase,hasMounted:t,hasReady:a}},exports.usePageInfo=function(){const r=s().state.page;return e.useMemo(()=>({pageUid:r?.pageUid,pageVersionId:r?.pageVersionId,schemaVersion:r?.pageJson?.schemaVersion,title:r?.title,config:r?.config,isLoaded:null!==r}),[r])},exports.usePrevious=function(r){const n=e.useRef();return e.useEffect(()=>{n.current=r},[r]),n.current},exports.useQuery=function(r,n){const t=s(),[o,a]=e.useState(!1),[i,l]=e.useState(null),[c,u]=e.useState(null),d=e.useRef(!0),p=t.state.queries[r],m=e.useCallback(async()=>{if(d.current){a(!0),l(null);try{await(t.runtime?.refreshData(r)),d.current&&u(Date.now())}catch(e){d.current&&l(e)}finally{d.current&&a(!1)}}},[t.runtime,r]);return e.useEffect(()=>(d.current=!0,n?.refreshOnMount&&t.runtime&&m(),()=>{d.current=!1}),[]),e.useEffect(()=>{if(!n?.refreshInterval||n.refreshInterval<=0)return;const e=setInterval(()=>{m()},n.refreshInterval);return()=>clearInterval(e)},[n?.refreshInterval,m]),e.useEffect(()=>{if(!n?.refreshOnFocus)return;const e=()=>{m()};return window.addEventListener("focus",e),()=>window.removeEventListener("focus",e)},[n?.refreshOnFocus,m]),{data:p,loading:o,error:i,refetch:m,lastUpdated:c}},exports.useReactRuntime=o,exports.useRuntimeContext=s,exports.useRuntimeEvent=function(r,n){const t=s();e.useEffect(()=>{const e=t.runtime?.on(r,e=>{n(e.data)});return()=>{e?.()}},[t.runtime,r,n])},exports.useRuntimeState=function(e){return s().state.variables[e]},exports.useRuntimeStateWritable=function(r,n){const t=s();return[t.state.variables[r]??n,e.useCallback(e=>{t.runtime?.setVariable(r,e)},[t.runtime,r])]},exports.useWhen=function(r,n,t){const[o,a]=e.useState(!1),{once:i=!0}=t||{};return e.useEffect(()=>{!r||i&&o||(a(!0),n())},[r,n,i,o]),{executed:o}};
|
|
1
|
+
var e=require("react"),r=require("@djvlc/runtime-core"),n=require("react/jsx-runtime"),t={initTime:0,loadTime:0,renderTime:0,totalTime:0,initTimestamp:null,readyTimestamp:null};function o(n){const[o,a]=e.useState(null),[i,l]=e.useState(!0),[s,c]=e.useState("idle"),[u,d]=e.useState(null),[p,m]=e.useState(null),[h,f]=e.useState(null),[w,y]=e.useState(t),v=e.useRef(null),g=e.useRef({startTime:0,initStartTime:0,loadStartTime:0,renderStartTime:0}),x=e.useMemo(()=>"ready"===s,[s]),T=e.useMemo(()=>"error"===s||null!==p,[s,p]),b=e.useCallback(async()=>{const e=n.containerRef?.current;if(!e)throw new Error("Container element not found");g.current.startTime=performance.now(),g.current.initStartTime=g.current.startTime,n.enableMetrics&&y(e=>({...e,initTimestamp:Date.now()}));const t=r.createRuntime({...n,container:e,onError:e=>{m(e),n.onError?.(e)},onEvent:e=>{n.onEvent?.(e)}});v.current=t,a(t),t.onStateChange(e=>{c(e.phase),l("ready"!==e.phase&&"error"!==e.phase),e.page&&d(e.page),e.error&&m(e.error)}),await t.init(),f(t.getHostApi()),n.enableMetrics&&y(e=>({...e,initTime:performance.now()-g.current.initStartTime}))},[n]),E=e.useCallback(async()=>{if(!v.current)throw new Error("Runtime not initialized");g.current.loadStartTime=performance.now();const e=await v.current.load();return d(e),f(v.current.getHostApi()),n.enableMetrics&&y(e=>({...e,loadTime:performance.now()-g.current.loadStartTime})),e},[n.enableMetrics]),I=e.useCallback(async()=>{if(!v.current)throw new Error("Runtime not initialized");if(g.current.renderStartTime=performance.now(),await v.current.render(),l(!1),n.enableMetrics){const e=performance.now();y(r=>({...r,renderTime:e-g.current.renderStartTime,totalTime:e-g.current.startTime,readyTimestamp:Date.now()}))}},[n.enableMetrics]),A=e.useCallback(()=>{v.current?.destroy(),v.current=null,a(null),f(null),d(null),m(null),c("idle"),l(!0),y(t)},[]),N=e.useCallback(async()=>{if(!v.current)throw new Error("Runtime not initialized");m(null),l(!0),await E(),await I()},[E,I]),j=e.useCallback((e,r)=>{v.current?.setVariable(e,r)},[]),R=e.useCallback(e=>{v.current&&Object.entries(e).forEach(([e,r])=>{v.current?.setVariable(e,r)})},[]),C=e.useCallback(e=>v.current?.getState().variables[e],[]),P=e.useCallback(async e=>{await(v.current?.refreshData(e))},[]),S=e.useCallback(async(e,r)=>{const n=h;if(!n)throw new Error("HostAPI not available");const t=await n.executeAction(e,r||{});if(t.success)return t.data;throw new Error(t.errorMessage||"Action failed")},[h]);return{runtime:o,loading:i,phase:s,page:u,error:p,hostApi:h,isReady:x,hasError:T,metrics:w,init:b,load:E,render:I,destroy:A,reload:N,setVariable:j,setVariables:R,getVariable:C,refreshData:P,executeAction:S}}var a={phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1},i=e.createContext({runtime:null,state:a,hostApi:null});function l({runtime:e,state:r,hostApi:t,children:o}){const a={runtime:e,state:r,hostApi:t};return n.jsx(i.Provider,{value:a,children:o})}function s(){return e.useContext(i)}var c={phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1};function u(r,n){const t=s(),[o,a]=e.useState(!1),[i,l]=e.useState(),[c,u]=e.useState(null),[d,p]=e.useState(0),m=e.useRef(!0);e.useEffect(()=>(m.current=!0,()=>{m.current=!1}),[]);const h=e.useCallback(()=>{l(void 0),u(null),p(0)},[]),f=e.useCallback(async(e,o)=>{const a=t.hostApi;if(!a)throw new Error("HostAPI not available");try{const n=await a.executeAction(r,e);if(n.success)return n.data;throw new Error(n.errorMessage||"Action failed")}catch(r){if(o>0)return await new Promise(e=>setTimeout(e,n?.retryDelay||1e3)),f(e,o-1);throw r}},[t.hostApi,r,n?.retryDelay]);return{execute:e.useCallback(async e=>{if(m.current){a(!0),u(null),p(e=>e+1);try{const r=await f(e,n?.retryCount||0);return m.current&&(l(r),n?.onSuccess?.(r)),r}catch(e){const r=e;throw m.current&&(u(r),n?.onError?.(r)),e}finally{m.current&&a(!1)}}},[f,n]),loading:o,result:i,error:c,reset:h,executionCount:d}}exports.DJVProvider=function({runtime:r,hostApi:t,children:o,className:a,debug:i=!1,onStateChange:s,onPhaseChange:u,onError:d}){const[p,m]=e.useState(r?.getState()||c),h=e.useRef(p.phase);return e.useEffect(()=>{if(!r)return void m(c);m(r.getState());const e=r.onStateChange(e=>{m(e),s?.(e),e.phase!==h.current&&(u?.(e.phase),h.current=e.phase),e.error&&d?.(e.error)});return()=>{e()}},[r,s,u,d,i]),e.useEffect(()=>{},[t]),n.jsx(l,{runtime:r,state:p,hostApi:t,children:n.jsx("div",{className:["djvlc-provider",a].filter(Boolean).join(" "),"data-phase":p.phase,children:o})})},exports.DJVRenderer=function({pageId:r,apiBaseUrl:t,cdnBaseUrl:a,channel:i="prod",userId:s,deviceId:c,authToken:u,previewToken:d,debug:p=!1,enableSRI:m=!0,onLoad:h,onError:f,onReady:w,onPhaseChange:y,loadingComponent:v,errorComponent:g,emptyComponent:x,children:T,className:b,style:E,retryCount:I=3,retryDelay:A=1e3,timeout:N=3e4}){const j=e.useRef(null),R=e.useRef(!0),C=e.useRef(0),[P,S]=e.useState({phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1}),k={pageId:r,apiBaseUrl:t,cdnBaseUrl:a,channel:i,userId:s,deviceId:c,authToken:u,previewToken:d,debug:p,enableSRI:m,containerRef:j,onError:e=>{f?.(e)}},{runtime:q,loading:B,phase:D,page:M,error:U,hostApi:V,init:z,load:L,render:H,destroy:O}=o(k);e.useEffect(()=>{y?.(D)},[D,y]);const J=e.useCallback(async()=>{if(!j.current||!R.current)return;const e=new Promise((e,r)=>{setTimeout(()=>r(new Error("加载超时")),N)});try{await Promise.race([(async()=>{await z();const e=await L();R.current&&h?.(e),await H(),R.current&&(w?.(),C.current=0,q&&q.onStateChange(e=>{R.current&&S(e)}))})(),e])}catch(e){if(!R.current)return;C.current<I&&(C.current++,setTimeout(()=>{R.current&&J()},A))}},[z,L,H,q,h,w,N,I,A,p]),F=e.useCallback(()=>{C.current=0,J()},[J]);return e.useEffect(()=>(R.current=!0,J(),()=>{R.current=!1,O()}),[r]),n.jsx(l,{runtime:q,state:P,hostApi:V,children:n.jsxs("div",{ref:j,className:`djvlc-renderer ${b||""}`,style:E,"data-phase":D,"data-page-id":r,children:[B?v||n.jsxs("div",{className:"djvlc-loading",children:[n.jsx("div",{className:"djvlc-loading-spinner"}),n.jsx("span",{children:"加载中..."}),C.current>0&&n.jsxs("span",{className:"djvlc-loading-retry",children:["重试 ",C.current,"/",I]})]}):null,U?"function"==typeof g?g(U,F):g||n.jsxs("div",{className:"djvlc-error",children:[n.jsx("div",{className:"djvlc-error-icon",children:"⚠️"}),n.jsxs("span",{className:"djvlc-error-message",children:["加载失败:",U.message]}),n.jsx("button",{className:"djvlc-error-retry-btn",onClick:F,type:"button",children:"重试"})]}):null,B||U||M||"ready"!==D||M?null:x||n.jsx("div",{className:"djvlc-empty",children:n.jsx("span",{children:"暂无内容"})}),T]})})},exports.RuntimeContext=i,exports.RuntimeProvider=l,exports.useAction=u,exports.useAsync=function(r,n=[],t){const[o,a]=e.useState(),[i,l]=e.useState(!1),[s,c]=e.useState(null),u=e.useRef(!0);e.useEffect(()=>(u.current=!0,()=>{u.current=!1}),[]);const d=e.useCallback(async()=>{if(u.current){l(!0),c(null);try{const e=await r();return u.current&&(a(e),t?.onSuccess?.(e)),e}catch(e){const r=e;return void(u.current&&(c(r),t?.onError?.(r)))}finally{u.current&&l(!1)}}},[r,...n]);return e.useEffect(()=>{!1!==t?.immediate&&d()},[]),{data:o,loading:i,error:s,execute:d}},exports.useComponentState=function(r){const n=s().state.components.get(r);return e.useMemo(()=>({isLoaded:"loaded"===n?.status,isLoading:"loading"===n?.status,hasError:"failed"===n?.status,loadTime:n?.loadTime,info:n}),[n])},exports.useDJVRuntime=function(){const r=s(),n=e.useMemo(()=>{const e=r.state.phase;return"ready"!==e&&"error"!==e},[r.state.phase]),t="ready"===r.state.phase,o="error"===r.state.phase||null!==r.state.error,a=e.useCallback(async()=>{if(!r.runtime)throw new Error("Runtime not available");await r.runtime.load(),await r.runtime.render()},[r.runtime]);return{runtime:r.runtime,state:r.state,loading:n,phase:r.state.phase,error:r.state.error,page:r.state.page,isReady:t,hasError:o,reload:a}},exports.useData=function(r,n,t){const o=s(),[a,i]=e.useState(),[l,c]=e.useState(!1),[u,d]=e.useState(null),[p,m]=e.useState(!1),h=e.useRef(!0),f=e.useRef(n);e.useEffect(()=>(h.current=!0,()=>{h.current=!1}),[]);const w=e.useCallback(async e=>{const n=o.hostApi;if(n&&h.current){c(!0),d(null);try{const o=await n.requestData(r,e||f.current);if(!h.current)return;i(o),m(!0),t?.onSuccess?.(o)}catch(e){if(h.current){const r=e;d(r),t?.onError?.(r)}}finally{h.current&&c(!1)}}},[o.hostApi,r,t]);return e.useEffect(()=>{const e=f.current;f.current=n,!1!==t?.refreshOnParamsChange&&o.hostApi&&p&&JSON.stringify(e)!==JSON.stringify(n)&&w()},[n,o.hostApi,t?.refreshOnParamsChange,p,w]),e.useEffect(()=>{!1!==t?.immediate&&o.hostApi&&w()},[o.hostApi]),e.useEffect(()=>{if(!t?.refreshInterval||t.refreshInterval<=0)return;const e=setInterval(()=>{w()},t.refreshInterval);return()=>clearInterval(e)},[t?.refreshInterval,w]),{data:a,loading:l,error:u,refetch:w,isFetched:p}},exports.useDebouncedAction=function(r,n=300){const{execute:t,loading:o,result:a,error:i}=u(r),l=e.useRef(null),s=e.useRef(!0);return e.useEffect(()=>(s.current=!0,()=>{s.current=!1,l.current&&clearTimeout(l.current)}),[]),{execute:e.useCallback(e=>{l.current&&clearTimeout(l.current),l.current=setTimeout(()=>{s.current&&t(e).catch(()=>{})},n)},[t,n]),loading:o,result:a,error:i,cancel:e.useCallback(()=>{l.current&&(clearTimeout(l.current),l.current=null)},[])}},exports.useHostApi=function(){const e=s();if(!e.hostApi)throw new Error("HostAPI not available. Make sure runtime is initialized.");return e.hostApi},exports.useLifecycle=function(r){const n=s(),[t,o]=e.useState(!1),[a,i]=e.useState(!1),l=e.useRef(n.state.phase),c=e.useRef(!0);return e.useEffect(()=>(c.current=!0,()=>{c.current=!1}),[]),e.useEffect(()=>{const e=n.state.phase;e!==l.current&&(r?.onPhaseChange?.(e),l.current=e),t||"idle"===e||(o(!0),Promise.resolve(r?.onMounted?.()).catch(e=>{r?.onError?.(e)})),a||"ready"!==e||(i(!0),Promise.resolve(r?.onReady?.()).catch(e=>{r?.onError?.(e)})),"error"===e&&n.state.error&&r?.onError?.(n.state.error)},[n.state.phase,n.state.error,t,a,r]),{phase:n.state.phase,hasMounted:t,hasReady:a}},exports.usePageInfo=function(){const r=s().state.page;return e.useMemo(()=>({pageId:r?.pageId,pageVersionId:r?.pageVersionId,schemaVersion:r?.pageJson?.schemaVersion,title:r?.title,config:r?.config,isLoaded:null!==r}),[r])},exports.usePrevious=function(r){const n=e.useRef();return e.useEffect(()=>{n.current=r},[r]),n.current},exports.useQuery=function(r,n){const t=s(),[o,a]=e.useState(!1),[i,l]=e.useState(null),[c,u]=e.useState(null),d=e.useRef(!0),p=t.state.queries[r],m=e.useCallback(async()=>{if(d.current){a(!0),l(null);try{await(t.runtime?.refreshData(r)),d.current&&u(Date.now())}catch(e){d.current&&l(e)}finally{d.current&&a(!1)}}},[t.runtime,r]);return e.useEffect(()=>(d.current=!0,n?.refreshOnMount&&t.runtime&&m(),()=>{d.current=!1}),[]),e.useEffect(()=>{if(!n?.refreshInterval||n.refreshInterval<=0)return;const e=setInterval(()=>{m()},n.refreshInterval);return()=>clearInterval(e)},[n?.refreshInterval,m]),e.useEffect(()=>{if(!n?.refreshOnFocus)return;const e=()=>{m()};return window.addEventListener("focus",e),()=>window.removeEventListener("focus",e)},[n?.refreshOnFocus,m]),{data:p,loading:o,error:i,refetch:m,lastUpdated:c}},exports.useReactRuntime=o,exports.useRuntimeContext=s,exports.useRuntimeEvent=function(r,n){const t=s();e.useEffect(()=>{const e=t.runtime?.on(r,e=>{n(e.data)});return()=>{e?.()}},[t.runtime,r,n])},exports.useRuntimeState=function(e){return s().state.variables[e]},exports.useRuntimeStateWritable=function(r,n){const t=s();return[t.state.variables[r]??n,e.useCallback(e=>{t.runtime?.setVariable(r,e)},[t.runtime,r])]},exports.useWhen=function(r,n,t){const[o,a]=e.useState(!1),{once:i=!0}=t||{};return e.useEffect(()=>{!r||i&&o||(a(!0),n())},[r,n,i,o]),{executed:o}};
|
package/dist/index.d.cts
CHANGED
|
@@ -127,7 +127,7 @@ declare function useRuntimeContext(): RuntimeContextValue;
|
|
|
127
127
|
*/
|
|
128
128
|
interface DJVRendererProps {
|
|
129
129
|
/** 页面 UID */
|
|
130
|
-
|
|
130
|
+
pageId: string;
|
|
131
131
|
/** API 基础 URL */
|
|
132
132
|
apiBaseUrl: string;
|
|
133
133
|
/** CDN 基础 URL */
|
|
@@ -176,7 +176,7 @@ interface DJVRendererProps {
|
|
|
176
176
|
/**
|
|
177
177
|
* DJV 渲染器组件
|
|
178
178
|
*/
|
|
179
|
-
declare function DJVRenderer({
|
|
179
|
+
declare function DJVRenderer({ pageId, apiBaseUrl, cdnBaseUrl, channel, userId, deviceId, authToken, previewToken, debug, enableSRI, onLoad, onError, onReady, onPhaseChange, loadingComponent, errorComponent, emptyComponent, children, className, style, retryCount, retryDelay, timeout, }: DJVRendererProps): JSX.Element;
|
|
180
180
|
|
|
181
181
|
/**
|
|
182
182
|
* DJV Provider 组件
|
|
@@ -310,7 +310,7 @@ declare function useRuntimeEvent<T = unknown>(eventType: string, handler: (data:
|
|
|
310
310
|
*/
|
|
311
311
|
declare function usePageInfo(): {
|
|
312
312
|
/** 页面 UID */
|
|
313
|
-
|
|
313
|
+
pageId: string | undefined;
|
|
314
314
|
/** 页面版本 ID */
|
|
315
315
|
pageVersionId: string | undefined;
|
|
316
316
|
/** Schema 版本 */
|
package/dist/index.d.ts
CHANGED
|
@@ -127,7 +127,7 @@ declare function useRuntimeContext(): RuntimeContextValue;
|
|
|
127
127
|
*/
|
|
128
128
|
interface DJVRendererProps {
|
|
129
129
|
/** 页面 UID */
|
|
130
|
-
|
|
130
|
+
pageId: string;
|
|
131
131
|
/** API 基础 URL */
|
|
132
132
|
apiBaseUrl: string;
|
|
133
133
|
/** CDN 基础 URL */
|
|
@@ -176,7 +176,7 @@ interface DJVRendererProps {
|
|
|
176
176
|
/**
|
|
177
177
|
* DJV 渲染器组件
|
|
178
178
|
*/
|
|
179
|
-
declare function DJVRenderer({
|
|
179
|
+
declare function DJVRenderer({ pageId, apiBaseUrl, cdnBaseUrl, channel, userId, deviceId, authToken, previewToken, debug, enableSRI, onLoad, onError, onReady, onPhaseChange, loadingComponent, errorComponent, emptyComponent, children, className, style, retryCount, retryDelay, timeout, }: DJVRendererProps): JSX.Element;
|
|
180
180
|
|
|
181
181
|
/**
|
|
182
182
|
* DJV Provider 组件
|
|
@@ -310,7 +310,7 @@ declare function useRuntimeEvent<T = unknown>(eventType: string, handler: (data:
|
|
|
310
310
|
*/
|
|
311
311
|
declare function usePageInfo(): {
|
|
312
312
|
/** 页面 UID */
|
|
313
|
-
|
|
313
|
+
pageId: string | undefined;
|
|
314
314
|
/** 页面版本 ID */
|
|
315
315
|
pageVersionId: string | undefined;
|
|
316
316
|
/** Schema 版本 */
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createContext as e,useState as r,useRef as n,useMemo as t,useCallback as a,useContext as o,useEffect as i}from"react";import{createRuntime as l}from"@djvlc/runtime-core";import{jsx as s,jsxs as c}from"react/jsx-runtime";var u={initTime:0,loadTime:0,renderTime:0,totalTime:0,initTimestamp:null,readyTimestamp:null};function d(e){const[o,i]=r(null),[s,c]=r(!0),[d,m]=r("idle"),[f,h]=r(null),[p,w]=r(null),[y,v]=r(null),[g,T]=r(u),b=n(null),E=n({startTime:0,initStartTime:0,loadStartTime:0,renderStartTime:0}),A=t(()=>"ready"===d,[d]),I=t(()=>"error"===d||null!==p,[d,p]),N=a(async()=>{const r=e.containerRef?.current;if(!r)throw new Error("Container element not found");E.current.startTime=performance.now(),E.current.initStartTime=E.current.startTime,e.enableMetrics&&T(e=>({...e,initTimestamp:Date.now()}));const n=l({...e,container:r,onError:r=>{w(r),e.onError?.(r)},onEvent:r=>{e.onEvent?.(r)}});b.current=n,i(n),n.onStateChange(e=>{m(e.phase),c("ready"!==e.phase&&"error"!==e.phase),e.page&&h(e.page),e.error&&w(e.error)}),await n.init(),v(n.getHostApi()),e.enableMetrics&&T(e=>({...e,initTime:performance.now()-E.current.initStartTime}))},[e]),j=a(async()=>{if(!b.current)throw new Error("Runtime not initialized");E.current.loadStartTime=performance.now();const r=await b.current.load();return h(r),v(b.current.getHostApi()),e.enableMetrics&&T(e=>({...e,loadTime:performance.now()-E.current.loadStartTime})),r},[e.enableMetrics]),R=a(async()=>{if(!b.current)throw new Error("Runtime not initialized");if(E.current.renderStartTime=performance.now(),await b.current.render(),c(!1),e.enableMetrics){const e=performance.now();T(r=>({...r,renderTime:e-E.current.renderStartTime,totalTime:e-E.current.startTime,readyTimestamp:Date.now()}))}},[e.enableMetrics]),C=a(()=>{b.current?.destroy(),b.current=null,i(null),v(null),h(null),w(null),m("idle"),c(!0),T(u)},[]),P=a(async()=>{if(!b.current)throw new Error("Runtime not initialized");w(null),c(!0),await j(),await R()},[j,R]),x=a((e,r)=>{b.current?.setVariable(e,r)},[]),S=a(e=>{b.current&&Object.entries(e).forEach(([e,r])=>{b.current?.setVariable(e,r)})},[]),U=a(e=>b.current?.getState().variables[e],[]),k=a(async e=>{await(b.current?.refreshData(e))},[]),B=a(async(e,r)=>{const n=y;if(!n)throw new Error("HostAPI not available");const t=await n.executeAction(e,r||{});if(t.success)return t.data;throw new Error(t.errorMessage||"Action failed")},[y]);return{runtime:o,loading:s,phase:d,page:f,error:p,hostApi:y,isReady:A,hasError:I,metrics:g,init:N,load:j,render:R,destroy:C,reload:P,setVariable:x,setVariables:S,getVariable:U,refreshData:k,executeAction:B}}var m=e({runtime:null,state:{phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1},hostApi:null});function f({runtime:e,state:r,hostApi:n,children:t}){const a={runtime:e,state:r,hostApi:n};return s(m.Provider,{value:a,children:t})}function h(){return o(m)}function p({pageUid:e,apiBaseUrl:t,cdnBaseUrl:o,channel:l="prod",userId:u,deviceId:m,authToken:h,previewToken:p,debug:w=!1,enableSRI:y=!0,onLoad:v,onError:g,onReady:T,onPhaseChange:b,loadingComponent:E,errorComponent:A,emptyComponent:I,children:N,className:j,style:R,retryCount:C=3,retryDelay:P=1e3,timeout:x=3e4}){const S=n(null),U=n(!0),k=n(0),[B,D]=r({phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1}),M={pageUid:e,apiBaseUrl:t,cdnBaseUrl:o,channel:l,userId:u,deviceId:m,authToken:h,previewToken:p,debug:w,enableSRI:y,containerRef:S,onError:e=>{g?.(e)}},{runtime:V,loading:z,phase:L,page:q,error:H,hostApi:O,init:J,load:F,render:$,destroy:G}=d(M);i(()=>{b?.(L)},[L,b]);const K=a(async()=>{if(!S.current||!U.current)return;const e=new Promise((e,r)=>{setTimeout(()=>r(new Error("加载超时")),x)});try{await Promise.race([(async()=>{await J();const e=await F();U.current&&v?.(e),await $(),U.current&&(T?.(),k.current=0,V&&V.onStateChange(e=>{U.current&&D(e)}))})(),e])}catch(e){if(!U.current)return;k.current<C&&(k.current++,setTimeout(()=>{U.current&&K()},P))}},[J,F,$,V,v,T,x,C,P,w]),Q=a(()=>{k.current=0,K()},[K]);return i(()=>(U.current=!0,K(),()=>{U.current=!1,G()}),[e]),s(f,{runtime:V,state:B,hostApi:O,children:c("div",{ref:S,className:`djvlc-renderer ${j||""}`,style:R,"data-phase":L,"data-page-uid":e,children:[z?E||c("div",{className:"djvlc-loading",children:[s("div",{className:"djvlc-loading-spinner"}),s("span",{children:"加载中..."}),k.current>0&&c("span",{className:"djvlc-loading-retry",children:["重试 ",k.current,"/",C]})]}):null,H?"function"==typeof A?A(H,Q):A||c("div",{className:"djvlc-error",children:[s("div",{className:"djvlc-error-icon",children:"⚠️"}),c("span",{className:"djvlc-error-message",children:["加载失败:",H.message]}),s("button",{className:"djvlc-error-retry-btn",onClick:Q,type:"button",children:"重试"})]}):null,z||H||q||"ready"!==L||q?null:I||s("div",{className:"djvlc-empty",children:s("span",{children:"暂无内容"})}),N]})})}var w={phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1};function y({runtime:e,hostApi:t,children:a,className:o,debug:l=!1,onStateChange:c,onPhaseChange:u,onError:d}){const[m,h]=r(e?.getState()||w),p=n(m.phase);return i(()=>{if(!e)return void h(w);h(e.getState());const r=e.onStateChange(e=>{h(e),c?.(e),e.phase!==p.current&&(u?.(e.phase),p.current=e.phase),e.error&&d?.(e.error)});return()=>{r()}},[e,c,u,d,l]),i(()=>{},[t]),s(f,{runtime:e,state:m,hostApi:t,children:s("div",{className:["djvlc-provider",o].filter(Boolean).join(" "),"data-phase":m.phase,children:a})})}function v(){const e=h(),r=t(()=>{const r=e.state.phase;return"ready"!==r&&"error"!==r},[e.state.phase]),n="ready"===e.state.phase,o="error"===e.state.phase||null!==e.state.error,i=a(async()=>{if(!e.runtime)throw new Error("Runtime not available");await e.runtime.load(),await e.runtime.render()},[e.runtime]);return{runtime:e.runtime,state:e.state,loading:r,phase:e.state.phase,error:e.state.error,page:e.state.page,isReady:n,hasError:o,reload:i}}function g(){const e=h();if(!e.hostApi)throw new Error("HostAPI not available. Make sure runtime is initialized.");return e.hostApi}function T(e){return h().state.variables[e]}function b(e,r){const n=h();return[n.state.variables[e]??r,a(r=>{n.runtime?.setVariable(e,r)},[n.runtime,e])]}function E(e,t){const o=h(),[l,s]=r(!1),[c,u]=r(null),[d,m]=r(null),f=n(!0),p=o.state.queries[e],w=a(async()=>{if(f.current){s(!0),u(null);try{await(o.runtime?.refreshData(e)),f.current&&m(Date.now())}catch(e){f.current&&u(e)}finally{f.current&&s(!1)}}},[o.runtime,e]);return i(()=>(f.current=!0,t?.refreshOnMount&&o.runtime&&w(),()=>{f.current=!1}),[]),i(()=>{if(!t?.refreshInterval||t.refreshInterval<=0)return;const e=setInterval(()=>{w()},t.refreshInterval);return()=>clearInterval(e)},[t?.refreshInterval,w]),i(()=>{if(!t?.refreshOnFocus)return;const e=()=>{w()};return window.addEventListener("focus",e),()=>window.removeEventListener("focus",e)},[t?.refreshOnFocus,w]),{data:p,loading:l,error:c,refetch:w,lastUpdated:d}}function A(e,t){const o=h(),[l,s]=r(!1),[c,u]=r(),[d,m]=r(null),[f,p]=r(0),w=n(!0);i(()=>(w.current=!0,()=>{w.current=!1}),[]);const y=a(()=>{u(void 0),m(null),p(0)},[]),v=a(async(r,n)=>{const a=o.hostApi;if(!a)throw new Error("HostAPI not available");try{const n=await a.executeAction(e,r);if(n.success)return n.data;throw new Error(n.errorMessage||"Action failed")}catch(e){if(n>0)return await new Promise(e=>setTimeout(e,t?.retryDelay||1e3)),v(r,n-1);throw e}},[o.hostApi,e,t?.retryDelay]);return{execute:a(async e=>{if(w.current){s(!0),m(null),p(e=>e+1);try{const r=await v(e,t?.retryCount||0);return w.current&&(u(r),t?.onSuccess?.(r)),r}catch(e){const r=e;throw w.current&&(m(r),t?.onError?.(r)),e}finally{w.current&&s(!1)}}},[v,t]),loading:l,result:c,error:d,reset:y,executionCount:f}}function I(e,t,o){const l=h(),[s,c]=r(),[u,d]=r(!1),[m,f]=r(null),[p,w]=r(!1),y=n(!0),v=n(t);i(()=>(y.current=!0,()=>{y.current=!1}),[]);const g=a(async r=>{const n=l.hostApi;if(n&&y.current){d(!0),f(null);try{const t=await n.requestData(e,r||v.current);if(!y.current)return;c(t),w(!0),o?.onSuccess?.(t)}catch(e){if(y.current){const r=e;f(r),o?.onError?.(r)}}finally{y.current&&d(!1)}}},[l.hostApi,e,o]);return i(()=>{const e=v.current;v.current=t,!1!==o?.refreshOnParamsChange&&l.hostApi&&p&&JSON.stringify(e)!==JSON.stringify(t)&&g()},[t,l.hostApi,o?.refreshOnParamsChange,p,g]),i(()=>{!1!==o?.immediate&&l.hostApi&&g()},[l.hostApi]),i(()=>{if(!o?.refreshInterval||o.refreshInterval<=0)return;const e=setInterval(()=>{g()},o.refreshInterval);return()=>clearInterval(e)},[o?.refreshInterval,g]),{data:s,loading:u,error:m,refetch:g,isFetched:p}}function N(e,r){const n=h();i(()=>{const t=n.runtime?.on(e,e=>{r(e.data)});return()=>{t?.()}},[n.runtime,e,r])}function j(){const e=h().state.page;return t(()=>({pageUid:e?.pageUid,pageVersionId:e?.pageVersionId,schemaVersion:e?.pageJson?.schemaVersion,title:e?.title,config:e?.config,isLoaded:null!==e}),[e])}function R(e){const r=h().state.components.get(e);return t(()=>({isLoaded:"loaded"===r?.status,isLoading:"loading"===r?.status,hasError:"failed"===r?.status,loadTime:r?.loadTime,info:r}),[r])}function C(e){const t=h(),[a,o]=r(!1),[l,s]=r(!1),c=n(t.state.phase),u=n(!0);return i(()=>(u.current=!0,()=>{u.current=!1}),[]),i(()=>{const r=t.state.phase;r!==c.current&&(e?.onPhaseChange?.(r),c.current=r),a||"idle"===r||(o(!0),Promise.resolve(e?.onMounted?.()).catch(r=>{e?.onError?.(r)})),l||"ready"!==r||(s(!0),Promise.resolve(e?.onReady?.()).catch(r=>{e?.onError?.(r)})),"error"===r&&t.state.error&&e?.onError?.(t.state.error)},[t.state.phase,t.state.error,a,l,e]),{phase:t.state.phase,hasMounted:a,hasReady:l}}function P(e,n,t){const[a,o]=r(!1),{once:l=!0}=t||{};return i(()=>{!e||l&&a||(o(!0),n())},[e,n,l,a]),{executed:a}}function x(e,r=300){const{execute:t,loading:o,result:l,error:s}=A(e),c=n(null),u=n(!0);return i(()=>(u.current=!0,()=>{u.current=!1,c.current&&clearTimeout(c.current)}),[]),{execute:a(e=>{c.current&&clearTimeout(c.current),c.current=setTimeout(()=>{u.current&&t(e).catch(()=>{})},r)},[t,r]),loading:o,result:l,error:s,cancel:a(()=>{c.current&&(clearTimeout(c.current),c.current=null)},[])}}function S(e,t=[],o){const[l,s]=r(),[c,u]=r(!1),[d,m]=r(null),f=n(!0);i(()=>(f.current=!0,()=>{f.current=!1}),[]);const h=a(async()=>{if(f.current){u(!0),m(null);try{const r=await e();return f.current&&(s(r),o?.onSuccess?.(r)),r}catch(e){const r=e;return void(f.current&&(m(r),o?.onError?.(r)))}finally{f.current&&u(!1)}}},[e,...t]);return i(()=>{!1!==o?.immediate&&h()},[]),{data:l,loading:c,error:d,execute:h}}function U(e){const r=n();return i(()=>{r.current=e},[e]),r.current}export{y as DJVProvider,p as DJVRenderer,m as RuntimeContext,f as RuntimeProvider,A as useAction,S as useAsync,R as useComponentState,v as useDJVRuntime,I as useData,x as useDebouncedAction,g as useHostApi,C as useLifecycle,j as usePageInfo,U as usePrevious,E as useQuery,d as useReactRuntime,h as useRuntimeContext,N as useRuntimeEvent,T as useRuntimeState,b as useRuntimeStateWritable,P as useWhen};
|
|
1
|
+
import{createContext as e,useState as r,useRef as n,useMemo as t,useCallback as a,useContext as o,useEffect as i}from"react";import{createRuntime as l}from"@djvlc/runtime-core";import{jsx as s,jsxs as c}from"react/jsx-runtime";var u={initTime:0,loadTime:0,renderTime:0,totalTime:0,initTimestamp:null,readyTimestamp:null};function d(e){const[o,i]=r(null),[s,c]=r(!0),[d,m]=r("idle"),[f,h]=r(null),[p,w]=r(null),[y,v]=r(null),[g,T]=r(u),b=n(null),E=n({startTime:0,initStartTime:0,loadStartTime:0,renderStartTime:0}),I=t(()=>"ready"===d,[d]),A=t(()=>"error"===d||null!==p,[d,p]),N=a(async()=>{const r=e.containerRef?.current;if(!r)throw new Error("Container element not found");E.current.startTime=performance.now(),E.current.initStartTime=E.current.startTime,e.enableMetrics&&T(e=>({...e,initTimestamp:Date.now()}));const n=l({...e,container:r,onError:r=>{w(r),e.onError?.(r)},onEvent:r=>{e.onEvent?.(r)}});b.current=n,i(n),n.onStateChange(e=>{m(e.phase),c("ready"!==e.phase&&"error"!==e.phase),e.page&&h(e.page),e.error&&w(e.error)}),await n.init(),v(n.getHostApi()),e.enableMetrics&&T(e=>({...e,initTime:performance.now()-E.current.initStartTime}))},[e]),j=a(async()=>{if(!b.current)throw new Error("Runtime not initialized");E.current.loadStartTime=performance.now();const r=await b.current.load();return h(r),v(b.current.getHostApi()),e.enableMetrics&&T(e=>({...e,loadTime:performance.now()-E.current.loadStartTime})),r},[e.enableMetrics]),R=a(async()=>{if(!b.current)throw new Error("Runtime not initialized");if(E.current.renderStartTime=performance.now(),await b.current.render(),c(!1),e.enableMetrics){const e=performance.now();T(r=>({...r,renderTime:e-E.current.renderStartTime,totalTime:e-E.current.startTime,readyTimestamp:Date.now()}))}},[e.enableMetrics]),C=a(()=>{b.current?.destroy(),b.current=null,i(null),v(null),h(null),w(null),m("idle"),c(!0),T(u)},[]),P=a(async()=>{if(!b.current)throw new Error("Runtime not initialized");w(null),c(!0),await j(),await R()},[j,R]),x=a((e,r)=>{b.current?.setVariable(e,r)},[]),S=a(e=>{b.current&&Object.entries(e).forEach(([e,r])=>{b.current?.setVariable(e,r)})},[]),k=a(e=>b.current?.getState().variables[e],[]),B=a(async e=>{await(b.current?.refreshData(e))},[]),D=a(async(e,r)=>{const n=y;if(!n)throw new Error("HostAPI not available");const t=await n.executeAction(e,r||{});if(t.success)return t.data;throw new Error(t.errorMessage||"Action failed")},[y]);return{runtime:o,loading:s,phase:d,page:f,error:p,hostApi:y,isReady:I,hasError:A,metrics:g,init:N,load:j,render:R,destroy:C,reload:P,setVariable:x,setVariables:S,getVariable:k,refreshData:B,executeAction:D}}var m=e({runtime:null,state:{phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1},hostApi:null});function f({runtime:e,state:r,hostApi:n,children:t}){const a={runtime:e,state:r,hostApi:n};return s(m.Provider,{value:a,children:t})}function h(){return o(m)}function p({pageId:e,apiBaseUrl:t,cdnBaseUrl:o,channel:l="prod",userId:u,deviceId:m,authToken:h,previewToken:p,debug:w=!1,enableSRI:y=!0,onLoad:v,onError:g,onReady:T,onPhaseChange:b,loadingComponent:E,errorComponent:I,emptyComponent:A,children:N,className:j,style:R,retryCount:C=3,retryDelay:P=1e3,timeout:x=3e4}){const S=n(null),k=n(!0),B=n(0),[D,M]=r({phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1}),U={pageId:e,apiBaseUrl:t,cdnBaseUrl:o,channel:l,userId:u,deviceId:m,authToken:h,previewToken:p,debug:w,enableSRI:y,containerRef:S,onError:e=>{g?.(e)}},{runtime:V,loading:z,phase:L,page:q,error:H,hostApi:O,init:J,load:F,render:$,destroy:G}=d(U);i(()=>{b?.(L)},[L,b]);const K=a(async()=>{if(!S.current||!k.current)return;const e=new Promise((e,r)=>{setTimeout(()=>r(new Error("加载超时")),x)});try{await Promise.race([(async()=>{await J();const e=await F();k.current&&v?.(e),await $(),k.current&&(T?.(),B.current=0,V&&V.onStateChange(e=>{k.current&&M(e)}))})(),e])}catch(e){if(!k.current)return;B.current<C&&(B.current++,setTimeout(()=>{k.current&&K()},P))}},[J,F,$,V,v,T,x,C,P,w]),Q=a(()=>{B.current=0,K()},[K]);return i(()=>(k.current=!0,K(),()=>{k.current=!1,G()}),[e]),s(f,{runtime:V,state:D,hostApi:O,children:c("div",{ref:S,className:`djvlc-renderer ${j||""}`,style:R,"data-phase":L,"data-page-id":e,children:[z?E||c("div",{className:"djvlc-loading",children:[s("div",{className:"djvlc-loading-spinner"}),s("span",{children:"加载中..."}),B.current>0&&c("span",{className:"djvlc-loading-retry",children:["重试 ",B.current,"/",C]})]}):null,H?"function"==typeof I?I(H,Q):I||c("div",{className:"djvlc-error",children:[s("div",{className:"djvlc-error-icon",children:"⚠️"}),c("span",{className:"djvlc-error-message",children:["加载失败:",H.message]}),s("button",{className:"djvlc-error-retry-btn",onClick:Q,type:"button",children:"重试"})]}):null,z||H||q||"ready"!==L||q?null:A||s("div",{className:"djvlc-empty",children:s("span",{children:"暂无内容"})}),N]})})}var w={phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1};function y({runtime:e,hostApi:t,children:a,className:o,debug:l=!1,onStateChange:c,onPhaseChange:u,onError:d}){const[m,h]=r(e?.getState()||w),p=n(m.phase);return i(()=>{if(!e)return void h(w);h(e.getState());const r=e.onStateChange(e=>{h(e),c?.(e),e.phase!==p.current&&(u?.(e.phase),p.current=e.phase),e.error&&d?.(e.error)});return()=>{r()}},[e,c,u,d,l]),i(()=>{},[t]),s(f,{runtime:e,state:m,hostApi:t,children:s("div",{className:["djvlc-provider",o].filter(Boolean).join(" "),"data-phase":m.phase,children:a})})}function v(){const e=h(),r=t(()=>{const r=e.state.phase;return"ready"!==r&&"error"!==r},[e.state.phase]),n="ready"===e.state.phase,o="error"===e.state.phase||null!==e.state.error,i=a(async()=>{if(!e.runtime)throw new Error("Runtime not available");await e.runtime.load(),await e.runtime.render()},[e.runtime]);return{runtime:e.runtime,state:e.state,loading:r,phase:e.state.phase,error:e.state.error,page:e.state.page,isReady:n,hasError:o,reload:i}}function g(){const e=h();if(!e.hostApi)throw new Error("HostAPI not available. Make sure runtime is initialized.");return e.hostApi}function T(e){return h().state.variables[e]}function b(e,r){const n=h();return[n.state.variables[e]??r,a(r=>{n.runtime?.setVariable(e,r)},[n.runtime,e])]}function E(e,t){const o=h(),[l,s]=r(!1),[c,u]=r(null),[d,m]=r(null),f=n(!0),p=o.state.queries[e],w=a(async()=>{if(f.current){s(!0),u(null);try{await(o.runtime?.refreshData(e)),f.current&&m(Date.now())}catch(e){f.current&&u(e)}finally{f.current&&s(!1)}}},[o.runtime,e]);return i(()=>(f.current=!0,t?.refreshOnMount&&o.runtime&&w(),()=>{f.current=!1}),[]),i(()=>{if(!t?.refreshInterval||t.refreshInterval<=0)return;const e=setInterval(()=>{w()},t.refreshInterval);return()=>clearInterval(e)},[t?.refreshInterval,w]),i(()=>{if(!t?.refreshOnFocus)return;const e=()=>{w()};return window.addEventListener("focus",e),()=>window.removeEventListener("focus",e)},[t?.refreshOnFocus,w]),{data:p,loading:l,error:c,refetch:w,lastUpdated:d}}function I(e,t){const o=h(),[l,s]=r(!1),[c,u]=r(),[d,m]=r(null),[f,p]=r(0),w=n(!0);i(()=>(w.current=!0,()=>{w.current=!1}),[]);const y=a(()=>{u(void 0),m(null),p(0)},[]),v=a(async(r,n)=>{const a=o.hostApi;if(!a)throw new Error("HostAPI not available");try{const n=await a.executeAction(e,r);if(n.success)return n.data;throw new Error(n.errorMessage||"Action failed")}catch(e){if(n>0)return await new Promise(e=>setTimeout(e,t?.retryDelay||1e3)),v(r,n-1);throw e}},[o.hostApi,e,t?.retryDelay]);return{execute:a(async e=>{if(w.current){s(!0),m(null),p(e=>e+1);try{const r=await v(e,t?.retryCount||0);return w.current&&(u(r),t?.onSuccess?.(r)),r}catch(e){const r=e;throw w.current&&(m(r),t?.onError?.(r)),e}finally{w.current&&s(!1)}}},[v,t]),loading:l,result:c,error:d,reset:y,executionCount:f}}function A(e,t,o){const l=h(),[s,c]=r(),[u,d]=r(!1),[m,f]=r(null),[p,w]=r(!1),y=n(!0),v=n(t);i(()=>(y.current=!0,()=>{y.current=!1}),[]);const g=a(async r=>{const n=l.hostApi;if(n&&y.current){d(!0),f(null);try{const t=await n.requestData(e,r||v.current);if(!y.current)return;c(t),w(!0),o?.onSuccess?.(t)}catch(e){if(y.current){const r=e;f(r),o?.onError?.(r)}}finally{y.current&&d(!1)}}},[l.hostApi,e,o]);return i(()=>{const e=v.current;v.current=t,!1!==o?.refreshOnParamsChange&&l.hostApi&&p&&JSON.stringify(e)!==JSON.stringify(t)&&g()},[t,l.hostApi,o?.refreshOnParamsChange,p,g]),i(()=>{!1!==o?.immediate&&l.hostApi&&g()},[l.hostApi]),i(()=>{if(!o?.refreshInterval||o.refreshInterval<=0)return;const e=setInterval(()=>{g()},o.refreshInterval);return()=>clearInterval(e)},[o?.refreshInterval,g]),{data:s,loading:u,error:m,refetch:g,isFetched:p}}function N(e,r){const n=h();i(()=>{const t=n.runtime?.on(e,e=>{r(e.data)});return()=>{t?.()}},[n.runtime,e,r])}function j(){const e=h().state.page;return t(()=>({pageId:e?.pageId,pageVersionId:e?.pageVersionId,schemaVersion:e?.pageJson?.schemaVersion,title:e?.title,config:e?.config,isLoaded:null!==e}),[e])}function R(e){const r=h().state.components.get(e);return t(()=>({isLoaded:"loaded"===r?.status,isLoading:"loading"===r?.status,hasError:"failed"===r?.status,loadTime:r?.loadTime,info:r}),[r])}function C(e){const t=h(),[a,o]=r(!1),[l,s]=r(!1),c=n(t.state.phase),u=n(!0);return i(()=>(u.current=!0,()=>{u.current=!1}),[]),i(()=>{const r=t.state.phase;r!==c.current&&(e?.onPhaseChange?.(r),c.current=r),a||"idle"===r||(o(!0),Promise.resolve(e?.onMounted?.()).catch(r=>{e?.onError?.(r)})),l||"ready"!==r||(s(!0),Promise.resolve(e?.onReady?.()).catch(r=>{e?.onError?.(r)})),"error"===r&&t.state.error&&e?.onError?.(t.state.error)},[t.state.phase,t.state.error,a,l,e]),{phase:t.state.phase,hasMounted:a,hasReady:l}}function P(e,n,t){const[a,o]=r(!1),{once:l=!0}=t||{};return i(()=>{!e||l&&a||(o(!0),n())},[e,n,l,a]),{executed:a}}function x(e,r=300){const{execute:t,loading:o,result:l,error:s}=I(e),c=n(null),u=n(!0);return i(()=>(u.current=!0,()=>{u.current=!1,c.current&&clearTimeout(c.current)}),[]),{execute:a(e=>{c.current&&clearTimeout(c.current),c.current=setTimeout(()=>{u.current&&t(e).catch(()=>{})},r)},[t,r]),loading:o,result:l,error:s,cancel:a(()=>{c.current&&(clearTimeout(c.current),c.current=null)},[])}}function S(e,t=[],o){const[l,s]=r(),[c,u]=r(!1),[d,m]=r(null),f=n(!0);i(()=>(f.current=!0,()=>{f.current=!1}),[]);const h=a(async()=>{if(f.current){u(!0),m(null);try{const r=await e();return f.current&&(s(r),o?.onSuccess?.(r)),r}catch(e){const r=e;return void(f.current&&(m(r),o?.onError?.(r)))}finally{f.current&&u(!1)}}},[e,...t]);return i(()=>{!1!==o?.immediate&&h()},[]),{data:l,loading:c,error:d,execute:h}}function k(e){const r=n();return i(()=>{r.current=e},[e]),r.current}export{y as DJVProvider,p as DJVRenderer,m as RuntimeContext,f as RuntimeProvider,I as useAction,S as useAsync,R as useComponentState,v as useDJVRuntime,A as useData,x as useDebouncedAction,g as useHostApi,C as useLifecycle,j as usePageInfo,k as usePrevious,E as useQuery,d as useReactRuntime,h as useRuntimeContext,N as useRuntimeEvent,T as useRuntimeState,b as useRuntimeStateWritable,P as useWhen};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djvlc/runtime-host-react",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
4
4
|
"description": "DJV 低代码平台 React 宿主适配器",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"clean": "rimraf dist"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@djvlc/runtime-core": "1.0
|
|
29
|
+
"@djvlc/runtime-core": "1.1.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/node": "^20.10.0",
|