@django-bridge/react 0.5.0 → 0.6.0-rc.1
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.d.ts +31 -9
- package/dist/index.js +1 -1
- package/package.json +2 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,31 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import Telepath from 'telepath-unpack';
|
|
1
|
+
import React, { ReactNode, ReactElement, FunctionComponent, Context } from 'react';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
interface PackedValuesById {
|
|
4
|
+
[id: string]: any;
|
|
5
|
+
}
|
|
6
|
+
interface ValuesById {
|
|
7
|
+
[id: string]: any;
|
|
8
|
+
}
|
|
9
|
+
interface ConstructorRegistry {
|
|
10
|
+
[name: string]: new (...args: any[]) => any;
|
|
11
|
+
}
|
|
12
|
+
declare class Telepath {
|
|
13
|
+
constructors: ConstructorRegistry;
|
|
14
|
+
constructor();
|
|
15
|
+
register(name: string, constructor: new (...args: any[]) => any): void;
|
|
16
|
+
unpack(objData: any): any;
|
|
17
|
+
scanForIds(objData: any, packedValuesById: PackedValuesById): void;
|
|
18
|
+
unpackWithRefs(objData: any, packedValuesById: PackedValuesById, valuesById: ValuesById): any;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
declare class Config$1<V> {
|
|
22
|
+
views: Map<string, V>;
|
|
6
23
|
telepathRegistry: Telepath;
|
|
7
24
|
constructor();
|
|
8
|
-
addView: <P>(name: string, component:
|
|
25
|
+
addView: <P>(name: string, component: V) => Config$1<V>;
|
|
9
26
|
addAdapter: <Cls>(name: string, ctor: {
|
|
10
27
|
new (...args: any[]): Cls;
|
|
11
|
-
}) => Config$1
|
|
28
|
+
}) => Config$1<V>;
|
|
12
29
|
unpack: (data: Record<string, unknown>) => Record<string, unknown>;
|
|
13
30
|
}
|
|
14
31
|
|
|
@@ -54,6 +71,7 @@ interface NetworkErrorResponse {
|
|
|
54
71
|
}
|
|
55
72
|
type DjangoBridgeResponse = ReloadResponse | RedirectResponse | RenderResponse | CloseOverlayResponse | ServerErrorResponse | NetworkErrorResponse;
|
|
56
73
|
|
|
74
|
+
type ShouldReloadCallback = (newPath: string, newProps: Record<string, unknown>) => boolean;
|
|
57
75
|
interface Frame<Props = Record<string, unknown>> {
|
|
58
76
|
id: number;
|
|
59
77
|
path: string;
|
|
@@ -61,7 +79,7 @@ interface Frame<Props = Record<string, unknown>> {
|
|
|
61
79
|
view: string;
|
|
62
80
|
props: Props;
|
|
63
81
|
context: Record<string, unknown>;
|
|
64
|
-
shouldReloadCallback?:
|
|
82
|
+
shouldReloadCallback?: ShouldReloadCallback;
|
|
65
83
|
}
|
|
66
84
|
|
|
67
85
|
interface NavigateOptions {
|
|
@@ -91,6 +109,7 @@ interface Navigation {
|
|
|
91
109
|
openOverlay: (path: string, render: (content: ReactNode) => ReactNode, options?: OpenOverlayOptions) => void;
|
|
92
110
|
refreshProps: () => Promise<void>;
|
|
93
111
|
isNavigating: boolean;
|
|
112
|
+
setShouldReloadCallback: (callback: ShouldReloadCallback) => void;
|
|
94
113
|
}
|
|
95
114
|
declare const NavigationContext: React.Context<Navigation>;
|
|
96
115
|
declare const FormWidgetChangeNotificationContext: React.Context<() => void>;
|
|
@@ -110,7 +129,7 @@ declare const Link: React.ForwardRefExoticComponent<React.AnchorHTMLAttributes<H
|
|
|
110
129
|
skipDirtyFormCheck?: boolean;
|
|
111
130
|
} & React.RefAttributes<HTMLAnchorElement>>;
|
|
112
131
|
|
|
113
|
-
declare class Config extends Config$1 {
|
|
132
|
+
declare class Config extends Config$1<FunctionComponent> {
|
|
114
133
|
contextProviders: Map<string, Context<unknown>>;
|
|
115
134
|
constructor();
|
|
116
135
|
addContextProvider: <C>(name: string, context: Context<C>) => Config;
|
|
@@ -140,6 +159,9 @@ interface DirtyForm {
|
|
|
140
159
|
declare const DirtyFormContext: React.Context<DirtyForm>;
|
|
141
160
|
declare function DirtyFormMarker(): React.ReactElement;
|
|
142
161
|
|
|
162
|
+
declare function useAutoRefresh(enabled: boolean, interval: number): void;
|
|
163
|
+
declare function useShouldReloadCallback(callback: ShouldReloadCallback, deps: React.DependencyList): void;
|
|
164
|
+
|
|
143
165
|
interface NavigationController {
|
|
144
166
|
parent: NavigationController | null;
|
|
145
167
|
currentFrame: Frame;
|
|
@@ -159,4 +181,4 @@ interface AppProps {
|
|
|
159
181
|
}
|
|
160
182
|
declare function App({ config, initialResponse }: AppProps): ReactElement;
|
|
161
183
|
|
|
162
|
-
export { App, type AppProps, BuildLinkElement, Config, type DirtyForm, DirtyFormContext, DirtyFormMarker, Form, FormSubmissionStatus, FormWidgetChangeNotificationContext, type Frame, Link, type Message, MessagesContext, type Metadata, type Navigation, NavigationContext, type NavigationController, OverlayContext, RenderFrame, type DjangoBridgeResponse as Response, buildLinkElement };
|
|
184
|
+
export { App, type AppProps, BuildLinkElement, Config, type DirtyForm, DirtyFormContext, DirtyFormMarker, Form, FormSubmissionStatus, FormWidgetChangeNotificationContext, type Frame, Link, type Message, MessagesContext, type Metadata, type Navigation, NavigationContext, type NavigationController, OverlayContext, RenderFrame, type DjangoBridgeResponse as Response, buildLinkElement, useAutoRefresh, useShouldReloadCallback };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var we=Object.create;var V=Object.defineProperty;var Pe=Object.getOwnPropertyDescriptor;var be=Object.getOwnPropertyNames;var Fe=Object.getPrototypeOf,Me=Object.prototype.hasOwnProperty;var De=(e,o)=>{for(var t in o)V(e,t,{get:o[t],enumerable:!0})},fe=(e,o,t,n)=>{if(o&&typeof o=="object"||typeof o=="function")for(let r of be(o))!Me.call(e,r)&&r!==t&&V(e,r,{get:()=>o[r],enumerable:!(n=Pe(o,r))||n.enumerable});return e};var D=(e,o,t)=>(t=e!=null?we(Fe(e)):{},fe(o||!e||!e.__esModule?V(t,"default",{value:e,enumerable:!0}):t,e)),ke=e=>fe(V({},"__esModule",{value:!0}),e);var Be={};De(Be,{App:()=>Oe,BuildLinkElement:()=>se,Config:()=>X,DirtyFormContext:()=>F,DirtyFormMarker:()=>J,Form:()=>le,FormSubmissionStatus:()=>Q,FormWidgetChangeNotificationContext:()=>K,Link:()=>Ce,MessagesContext:()=>L,NavigationContext:()=>k,OverlayContext:()=>z,RenderFrame:()=>Z,buildLinkElement:()=>ie});module.exports=ke(Be);var M=D(require("react"));var ve=D(require("telepath-unpack")),q=class{views;telepathRegistry;constructor(){this.views=new Map,this.telepathRegistry=new ve.default,this.addAdapter("Date",Date)}addView=(o,t)=>(this.views.set(o,t),this);addAdapter=(o,t)=>(this.telepathRegistry.register(o,t),this);unpack=o=>this.telepathRegistry.unpack(o)};async function O(e,o){let t,n={"X-Requested-With":"DjangoBridge"};o&&(n["X-DjangoBridge-Overlay"]="true");try{t=await fetch(e,{headers:n})}catch{return{action:"network-error"}}return t.status===500?{action:"server-error"}:t.headers.get("X-DjangoBridge-Action")?t.json():{action:"reload"}}async function te(e,o,t){let n,r={"X-Requested-With":"DjangoBridge"};t&&(r["X-DjangoBridge-Overlay"]="true");try{n=await fetch(e,{method:"post",headers:r,body:o})}catch{return{action:"network-error"}}return n.status===500?{action:"server-error"}:n.headers.get("X-DjangoBridge-Action")?n.json():{action:"reload"}}var u=require("react");var Y=1;function $(e,o,t,n,r={}){Y+=1;let[i,p]=(0,u.useState)({id:Y,path:n,metadata:{title:"Loading"},view:"loading",props:{},context:{}}),[v,c]=(0,u.useState)(!1),g=(0,u.useCallback)((s,R,P,b,N,S,U=!0,ye=!0)=>{let de=i.id,me=P!==i.view||ye;if(me&&(Y+=1,de=Y),!e&&(document.title=R.title,U)){let pe=0,xe=window.scrollY,ge=window.history?.state;ge?.prevPath===s&&(pe=ge.prevScrollPosition??0),window.history.pushState({prevPath:window.location.pathname,prevScrollPosition:xe},"",s),window.scrollTo(0,pe)}let ue={id:de,path:s,metadata:R,view:P,props:b,context:N};p(ue),r.onNavigation&&r.onNavigation(ue,me,S)},[r,i.id,i.view,e]),[d,C]=(0,u.useState)(null),h=(0,u.useCallback)((s,R,P=!0,b=!1)=>{if(s.action==="reload")if(!e)window.location.href=R;else return e.handleResponse(s,R);else{if(s.action==="redirect")return C(s.path),Promise.resolve();if(s.action==="render"){if(e&&!s.overlay)return e.handleResponse(s,R);let N=o(s.props),S=o(s.context),U=!b;U&&s.view===i.view&&i.shouldReloadCallback&&(U=i.shouldReloadCallback(R,N)),g(R,s.metadata,s.view,N,S,s.messages,P,U)}else if(s.action==="close-overlay")r.onOverlayClose&&r.onOverlayClose(s.messages);else{if(s.action==="server-error")return r.onServerError&&r.onServerError("server"),Promise.reject();if(s.action==="network-error")return r.onServerError&&r.onServerError("network"),Promise.reject()}}return Promise.resolve()},[r,i,e,g,o]),f=(0,u.useRef)(1),l=(0,u.useRef)(1),y=(0,u.useRef)(!1),a=(0,u.useCallback)(async(s,R,P,b=!1)=>{f.current+=1;let N=f.current;y.current=!0;let S=await s();N<l.current||(l.current=N,S!==null&&(await h(S,R,P,b),y.current=!1))},[h]),m=(0,u.useCallback)((s,R=!0)=>{let P=s;if(!s.startsWith("/")){let b=new URL(s);if(b.origin!==window.location.origin)return window.location.href=s,Promise.resolve();P=b.pathname+b.search}return c(!0),a(()=>O(P,!!e),P,R).finally(()=>{c(!1)})},[a,e]),w=(0,u.useCallback)((s,R)=>{s===i.id&&(i.path=R,e||history.replaceState({},"",i.path))},[i,e]),oe=(0,u.useCallback)((s,R)=>a(()=>te(s,R,!!e),s,!0),[a,e]),Re=(0,u.useCallback)(()=>y.current?Promise.resolve():a(()=>O(i.path,!!e),i.path,!1,!0),[i.path,a,e]);return(0,u.useEffect)(()=>{h(t,n,!1)},[]),(0,u.useEffect)(()=>{d&&(C(null),m(d))},[m,d]),{parent:e,currentFrame:i,isLoading:i.view==="loading",handleResponse:h,navigate:m,replacePath:w,submitForm:oe,refreshProps:Re,isNavigating:v,setIsNavigating:c}}var x=D(require("react")),A=require("react/jsx-runtime"),re=x.default.createContext(()=>{}),F=x.default.createContext({isDirty:!1,requestUnload:()=>Promise.resolve(),unloadRequested:!1,unloadBlocked:!1,confirmUnload:()=>{},cancelUnload:()=>{},unloadConfirmed:!1});function ne({handleBrowserUnload:e=!1,children:o}){let[t,n]=x.default.useState(!1),[r,i]=x.default.useState({cb:()=>{}}),[p,v]=x.default.useState(!1),[c,g]=x.default.useState(!1),d=x.default.useRef(null),C=()=>d.current&&!!d.current.querySelector("div.dirty-form-marker")||!1;x.default.useEffect(()=>{if(e&&c){let y="This page has unsaved changes.",a=m=>C()?(m.returnValue=y,y):"";return window.addEventListener("beforeunload",a),()=>{window.removeEventListener("beforeunload",a)}}return()=>{}},[e,c]);let h=x.default.useContext(re),f=x.default.useCallback(()=>{g(C()),h()},[h]),l=x.default.useMemo(()=>({isDirty:c,requestUnload:()=>c&&C()?(n(!0),new Promise(y=>{i({cb:y})})):Promise.resolve(),unloadRequested:t,unloadBlocked:c&&t,confirmUnload:()=>{t&&(v(!0),r.cb(),n(!1),i({cb:()=>{}}))},cancelUnload:()=>{t&&(n(!1),i({cb:()=>{}}))},unloadConfirmed:p}),[c,r,p,t]);return(0,A.jsx)("div",{ref:d,children:(0,A.jsx)(re.Provider,{value:f,children:(0,A.jsx)(F.Provider,{value:l,children:o})})})}function J(){let e=x.default.useContext(re);return x.default.useEffect(e),(0,A.jsx)("div",{className:"dirty-form-marker",style:{display:"none"}})}var ae=D(require("react"));var B=D(require("react")),z=B.default.createContext({overlay:!1,closeRequested:!1,requestClose:()=>{console.error("OverlayContext.requestClose() called from outside an overlay")},onCloseCompleted:()=>{console.error("OverlayContext.onCloseCompleted() called from outside an overlay")}}),k=B.default.createContext({frameId:0,path:"/",props:{},context:{},navigate:()=>(console.error("navigate() called from outside a Django Bridge Browser"),Promise.resolve()),replacePath:()=>{console.error("replacePath() called from outside a Django Bridge Browser")},submitForm:()=>(console.error("submitForm() called from outside a Django Bridge Browser"),Promise.resolve()),openOverlay:()=>{throw console.error("openOverlay() called from outside a Django Bridge Browser"),new Error("Modal cannot be opened here")},refreshProps:()=>(console.error("refreshProps() called from outside a Django Bridge Browser"),Promise.resolve()),isNavigating:!1}),K=B.default.createContext(()=>{}),Q=B.default.createContext(!1),L=B.default.createContext({messages:[],pushMessage:()=>{}});var j=require("react/jsx-runtime");function Ne({config:e,frame:o}){let t=e.views.get(o.view);if(!t)return(0,j.jsxs)("p",{children:["Unknown view '",o.view,"'"]});let n=(0,j.jsx)(t,{...o.props});return e.contextProviders.forEach((r,i)=>{n=(0,j.jsx)(r.Provider,{value:o.context[i],children:n})}),(0,j.jsx)("div",{children:n},o.id)}var Z=Ne;var _=require("react/jsx-runtime");function Ee({config:e,navigationController:o,openOverlay:t}){let{currentFrame:n,navigate:r,replacePath:i,submitForm:p,refreshProps:v,isNavigating:c}=o,{isDirty:g,requestUnload:d,cancelUnload:C}=ae.default.useContext(F),h=ae.default.useMemo(()=>({frameId:n.id,path:n.path,props:n.props,context:n.context,navigate:(f,l={})=>!g||l.skipDirtyFormCheck===!0?(l.skipDirtyFormCheck===!0&&C(),r(f,l.pushState)):d().then(()=>r(f,l.pushState)),replacePath:i,submitForm:p,openOverlay:t,refreshProps:v,isNavigating:c}),[n,i,p,t,g,d,C,r,v,c]);return(0,_.jsx)(k.Provider,{value:h,children:(0,_.jsx)("div",{children:(0,_.jsx)(Z,{config:e,frame:n})},n.id)})}var ee=Ee;var W=D(require("react"));var he=require("react/jsx-runtime");function ie({children:e,href:o,skipDirtyFormCheck:t=!1,...n},{navigate:r},i){return(0,he.jsx)("a",{onClick:v=>{o&&(v.preventDefault(),r(o,{skipDirtyFormCheck:t}))},href:o||"#",ref:i,...n,children:e})}var se=W.default.createContext(ie),Se=W.default.forwardRef((e,o)=>{let t=W.default.useContext(k);return W.default.useContext(se)(e,t,o)}),Ce=Se;var X=class extends q{contextProviders;constructor(){super(),this.contextProviders=new Map}addContextProvider=(o,t)=>(this.contextProviders.set(o,t),this)};var T=D(require("react"));var I=require("react/jsx-runtime");function le({children:e,onSubmit:o,isDirty:t=!1,disableDirtyCheck:n=!1,...r}){let{submitForm:i,navigate:p}=T.default.useContext(k),[v,c]=T.default.useState(!1),[g,d]=T.default.useState(t),{cancelUnload:C}=T.default.useContext(F),h=l=>{if(g&&C(),!(o&&(o(l),l.defaultPrevented))&&l.target instanceof HTMLFormElement){if(v){l.preventDefault();return}let y=new FormData(l.target);if(l.nativeEvent instanceof SubmitEvent&&l.nativeEvent.submitter){let{submitter:a}=l.nativeEvent;(a instanceof HTMLButtonElement||a instanceof HTMLInputElement)&&a.name&&a.value&&y.set(a.name,a.value)}if(l.target.method==="post")l.preventDefault(),c(!0),i(l.target.action,y).catch(()=>c(!1));else if(l.target.method==="get"){l.preventDefault();let a=Array.from(y.entries()).map(w=>`${encodeURIComponent(w[0])}=${encodeURIComponent(w[1])}`).join("&"),m=l.target.action+(l.target.action.indexOf("?")===-1?"?":"&")+a;c(!0),p(m).catch(()=>c(!1))}}},f=T.default.useCallback(()=>{d(!0)},[]);return(0,I.jsxs)("form",{onSubmit:h,...r,children:[g&&!n&&(0,I.jsx)(J,{}),(0,I.jsx)(Q.Provider,{value:v,children:(0,I.jsx)(K.Provider,{value:f,children:e})})]})}var G=D(require("react"));var H=require("react/jsx-runtime");function ce({config:e,initialResponse:o,initialPath:t,parentNavigationContoller:n,render:r,requestClose:i,closeRequested:p,onCloseCompleted:v,onServerError:c}){let{pushMessage:g}=G.default.useContext(L),d=$(n,e.unpack,o,t,{onNavigation:(l,y,a)=>{a.forEach(g)},onOverlayClose:l=>{l.forEach(g),i()},onServerError:c}),C=G.default.useContext(F),h=G.default.useCallback(({skipDirtyFormCheck:l=!1}={})=>{!l&&C.isDirty?C.requestUnload().then(()=>i()):i()},[C,i]),f=G.default.useMemo(()=>({overlay:!0,closeRequested:p,requestClose:h,onCloseCompleted:v}),[p,v,h]);return d.isLoading?(0,H.jsx)(H.Fragment,{}):(0,H.jsx)(z.Provider,{value:f,children:r((0,H.jsx)(ee,{config:e,navigationController:d,openOverlay:()=>{}}))})}var E=require("react/jsx-runtime");function Oe({config:e,initialResponse:o}){let[t,n]=M.default.useReducer((a,m)=>{switch(m.action){case"push":return a.concat([m.message]);case"clear":return[];default:return a}},[]),r=M.default.useCallback(a=>{n({action:"push",message:a})},[n]),i=M.default.useCallback(a=>{a==="server"?r({level:"error",text:"A server error occurred. Please try again later."}):a==="network"&&r({level:"error",text:"A network error occurred. Please check your internet connection or try again later."})},[r]),[p,v]=M.default.useState(null),[c,g]=M.default.useState(!1),d=M.default.useRef(null),C=(a,m,w)=>{m&&(g(!0),d.current=null),m&&n({action:"clear"}),w.forEach(r)},h=window.location.pathname+window.location.search+window.location.hash,f=$(null,e.unpack,o,h,{onNavigation:C,onServerError:i});M.default.useEffect(()=>{let a=document.querySelector(".django-bridge-load");a instanceof HTMLElement&&(a.classList.add("django-bridge-load--hidden"),setTimeout(()=>{a.remove()},200));let m=()=>{f.navigate(document.location.pathname,!1)};return window.addEventListener("popstate",m),()=>{window.removeEventListener("popstate",m)}},[]);let l=async(a,m,{onClose:w}={})=>{f.setIsNavigating(!0);let oe=await O(a,!0);w&&(d.current=w),g(!1),v({render:m,initialResponse:oe,initialPath:a}),f.setIsNavigating(!1)},y=M.default.useMemo(()=>({messages:t,pushMessage:r}),[t,r]);return(0,E.jsx)(ne,{handleBrowserUnload:!0,children:(0,E.jsxs)(L.Provider,{value:y,children:[p&&(0,E.jsx)(ne,{children:(0,E.jsx)(ce,{config:e,initialResponse:p.initialResponse,initialPath:p.initialPath,parentNavigationContoller:f,render:a=>p.render(a),requestClose:()=>g(!0),closeRequested:c,onCloseCompleted:()=>{v(null),g(!1),d.current&&(d.current(),d.current=null)},onServerError:i})}),!f.isLoading&&(0,E.jsx)(ee,{config:e,navigationController:f,openOverlay:(a,m,w)=>void l(a,m,w)})]})})}0&&(module.exports={App,BuildLinkElement,Config,DirtyFormContext,DirtyFormMarker,Form,FormSubmissionStatus,FormWidgetChangeNotificationContext,Link,MessagesContext,NavigationContext,OverlayContext,RenderFrame,buildLinkElement});
|
|
1
|
+
"use strict";var Fe=Object.create;var Y=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var Me=Object.getOwnPropertyNames;var Ee=Object.getPrototypeOf,Ne=Object.prototype.hasOwnProperty;var Se=(n,e)=>{for(var t in e)Y(n,t,{get:e[t],enumerable:!0})},ye=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Me(e))!Ne.call(n,o)&&o!==t&&Y(n,o,{get:()=>e[o],enumerable:!(r=be(e,o))||r.enumerable});return n};var N=(n,e,t)=>(t=n!=null?Fe(Ee(n)):{},ye(e||!n||!n.__esModule?Y(t,"default",{value:n,enumerable:!0}):t,n)),Oe=n=>ye(Y({},"__esModule",{value:!0}),n);var _e={};Se(_e,{App:()=>Te,BuildLinkElement:()=>ue,Config:()=>X,DirtyFormContext:()=>b,DirtyFormMarker:()=>z,Form:()=>fe,FormSubmissionStatus:()=>ee,FormWidgetChangeNotificationContext:()=>Z,Link:()=>Ce,MessagesContext:()=>T,NavigationContext:()=>P,OverlayContext:()=>Q,RenderFrame:()=>te,buildLinkElement:()=>de,useAutoRefresh:()=>xe,useShouldReloadCallback:()=>we});module.exports=Oe(_e);var E=N(require("react"));var I=class{constructors;constructor(){this.constructors={}}register(e,t){this.constructors[e]=t}unpack(e){let t={};this.scanForIds(e,t);let r={};return this.unpackWithRefs(e,t,r)}scanForIds(e,t){if(e===null||typeof e!="object")return;if(Array.isArray(e)){e.forEach(o=>this.scanForIds(o,t));return}let r=!1;if("_id"in e&&(r=!0,t[e._id]=e),("_type"in e||"_val"in e||"_ref"in e)&&(r=!0),"_list"in e&&(r=!0,e._list.forEach(o=>this.scanForIds(o,t))),"_args"in e&&(r=!0,e._args.forEach(o=>this.scanForIds(o,t))),"_dict"in e){r=!0;for(let[o,i]of Object.entries(e._dict))this.scanForIds(i,t)}if(!r)for(let[o,i]of Object.entries(e))this.scanForIds(i,t)}unpackWithRefs(e,t,r){if(e===null||typeof e!="object")return e;if(Array.isArray(e))return e.map(i=>this.unpackWithRefs(i,t,r));let o;if("_ref"in e)e._ref in r?o=r[e._ref]:o=this.unpackWithRefs(t[e._ref],t,r);else if("_val"in e)o=e._val;else if("_list"in e)o=e._list.map(i=>this.unpackWithRefs(i,t,r));else if("_dict"in e){o={};for(let[i,c]of Object.entries(e._dict))o[i]=this.unpackWithRefs(c,t,r)}else if("_type"in e){let i=e._type,c=this.constructors[i];if(typeof c!="function")throw new Error(`telepath encountered unknown object type ${i}`);let f=e._args.map(d=>this.unpackWithRefs(d,t,r));o=new c(...f)}else{if("_id"in e)throw new Error("telepath encountered object with _id but no type specified");o={};for(let[i,c]of Object.entries(e))o[i]=this.unpackWithRefs(c,t,r);return o}return"_id"in e&&(r[e._id]=o),o}};var W=class{views;telepathRegistry;constructor(){this.views=new Map,this.telepathRegistry=new I,this.addAdapter("Date",Date)}addView=(e,t)=>(this.views.set(e,t),this);addAdapter=(e,t)=>(this.telepathRegistry.register(e,t),this);unpack=e=>this.telepathRegistry.unpack(e)};async function L(n,e){let t,r={"X-Requested-With":"DjangoBridge"};e&&(r["X-DjangoBridge-Overlay"]="true");try{t=await fetch(n,{headers:r})}catch{return{action:"network-error"}}return t.status===500?{action:"server-error"}:t.headers.get("X-DjangoBridge-Action")?t.json():{action:"reload"}}async function se(n,e,t){let r,o={"X-Requested-With":"DjangoBridge"};t&&(o["X-DjangoBridge-Overlay"]="true");try{r=await fetch(n,{method:"post",headers:o,body:e})}catch{return{action:"network-error"}}return r.status===500?{action:"server-error"}:r.headers.get("X-DjangoBridge-Action")?r.json():{action:"reload"}}var g=require("react");var J=1;function K(n,e,t,r,o={}){J+=1;let[i,c]=(0,g.useState)({id:J,path:r,metadata:{title:"Loading"},view:"loading",props:{},context:{}}),[f,d]=(0,g.useState)(!1),v=(0,g.useCallback)((a,y,k,F,D,S,ie=!0,q=!0)=>{let $=i.id,pe=k!==i.view||q;if(pe&&(J+=1,$=J),!n&&(document.title=y.title,ie)){let ve=0,ke=window.scrollY,he=window.history?.state;he?.prevPath===a&&(ve=he.prevScrollPosition??0),window.history.pushState({prevPath:window.location.pathname,prevScrollPosition:ke},"",a),window.scrollTo(0,ve)}let ge={id:$,path:a,metadata:y,view:k,props:F,context:D};c(ge),o.onNavigation&&o.onNavigation(ge,pe,S)},[o,i.id,i.view,n]),[u,h]=(0,g.useState)(null),C=(0,g.useCallback)((a,y,k=!0,F=!1,D=!1)=>{if(a.action==="reload")if(!n)window.location.href=y;else return n.handleResponse(a,y);else{if(a.action==="redirect")return h(a.path),Promise.resolve();if(a.action==="render"){if(n&&!a.overlay){D&&console.warn(`openOverlay('${y}') returned a response that couldn't be rendered in an overlay.`);let $=n.handleResponse(a,y);return o.onEscalate&&o.onEscalate(),$}let S=e(a.props),ie=e(a.context),q=!F;q&&a.view===i.view&&i.shouldReloadCallback&&(q=i.shouldReloadCallback(y,S)),v(y,a.metadata,a.view,S,ie,a.messages,k,q)}else if(a.action==="close-overlay")o.onOverlayClose&&o.onOverlayClose(a.messages);else{if(a.action==="server-error")return o.onServerError&&o.onServerError("server"),Promise.reject();if(a.action==="network-error")return o.onServerError&&o.onServerError("network"),Promise.reject()}}return Promise.resolve()},[o,i,n,v,e]),m=(0,g.useRef)(1),l=(0,g.useRef)(1),R=(0,g.useRef)(!1),s=(0,g.useCallback)(async(a,y,k,F=!1)=>{m.current+=1;let D=m.current;R.current=!0;let S=await a();D<l.current||(l.current=D,S!==null&&(await C(S,y,k,F),R.current=!1))},[C]),p=(0,g.useCallback)((a,y=!0)=>{let k=a;if(!a.startsWith("/")){let F=new URL(a);if(F.origin!==window.location.origin)return window.location.href=a,Promise.resolve();k=F.pathname+F.search}return d(!0),s(()=>L(k,!!n),k,y).finally(()=>{d(!1)})},[s,n]),w=(0,g.useCallback)((a,y)=>{a===i.id&&(i.path=y,n||history.replaceState({},"",i.path))},[i,n]),ne=(0,g.useCallback)((a,y)=>s(()=>se(a,y,!!n),a,!0),[s,n]),Pe=(0,g.useCallback)(()=>R.current?Promise.resolve():s(()=>L(i.path,!!n),i.path,!1,!0),[i.path,s,n]);return(0,g.useEffect)(()=>{C(t,r,!1,!1,!0)},[]),(0,g.useEffect)(()=>{u&&(h(null),p(u))},[p,u]),{parent:n,currentFrame:i,isLoading:i.view==="loading",handleResponse:C,navigate:p,replacePath:w,submitForm:ne,refreshProps:Pe,isNavigating:f,setIsNavigating:d}}var x=N(require("react")),j=require("react/jsx-runtime"),ae=x.default.createContext(()=>{}),b=x.default.createContext({isDirty:!1,requestUnload:()=>Promise.resolve(),unloadRequested:!1,unloadBlocked:!1,confirmUnload:()=>{},cancelUnload:()=>{},unloadConfirmed:!1});function le({handleBrowserUnload:n=!1,children:e}){let[t,r]=x.default.useState(!1),[o,i]=x.default.useState({cb:()=>{}}),[c,f]=x.default.useState(!1),[d,v]=x.default.useState(!1),u=x.default.useRef(null),h=()=>u.current&&!!u.current.querySelector("div.dirty-form-marker")||!1;x.default.useEffect(()=>{if(n&&d){let R="This page has unsaved changes.",s=p=>h()?(p.returnValue=R,R):"";return window.addEventListener("beforeunload",s),()=>{window.removeEventListener("beforeunload",s)}}return()=>{}},[n,d]);let C=x.default.useContext(ae),m=x.default.useCallback(()=>{v(h()),C()},[C]),l=x.default.useMemo(()=>({isDirty:d,requestUnload:()=>d&&h()?(r(!0),new Promise(R=>{i({cb:R})})):Promise.resolve(),unloadRequested:t,unloadBlocked:d&&t,confirmUnload:()=>{t&&(f(!0),o.cb(),r(!1),i({cb:()=>{}}))},cancelUnload:()=>{t&&(r(!1),i({cb:()=>{}}))},unloadConfirmed:c}),[d,o,c,t]);return(0,j.jsx)("div",{ref:u,children:(0,j.jsx)(ae.Provider,{value:m,children:(0,j.jsx)(b.Provider,{value:l,children:e})})})}function z(){let n=x.default.useContext(ae);return x.default.useEffect(n),(0,j.jsx)("div",{className:"dirty-form-marker",style:{display:"none"}})}var ce=N(require("react"));var B=N(require("react")),Q=B.default.createContext({overlay:!1,closeRequested:!1,requestClose:()=>{console.error("OverlayContext.requestClose() called from outside an overlay")},onCloseCompleted:()=>{console.error("OverlayContext.onCloseCompleted() called from outside an overlay")}}),P=B.default.createContext({frameId:0,path:"/",props:{},context:{},navigate:()=>(console.error("navigate() called from outside a Django Bridge Browser"),Promise.resolve()),replacePath:()=>{console.error("replacePath() called from outside a Django Bridge Browser")},submitForm:()=>(console.error("submitForm() called from outside a Django Bridge Browser"),Promise.resolve()),openOverlay:()=>{throw console.error("openOverlay() called from outside a Django Bridge Browser"),new Error("Modal cannot be opened here")},refreshProps:()=>(console.error("refreshProps() called from outside a Django Bridge Browser"),Promise.resolve()),isNavigating:!1,setShouldReloadCallback:()=>{}}),Z=B.default.createContext(()=>{}),ee=B.default.createContext(!1),T=B.default.createContext({messages:[],pushMessage:()=>{}});var _=require("react/jsx-runtime");function De({config:n,frame:e}){let t=n.views.get(e.view);if(!t)return(0,_.jsxs)("p",{children:["Unknown view '",e.view,"'"]});let r=(0,_.jsx)(t,{...e.props});return n.contextProviders.forEach((o,i)=>{r=(0,_.jsx)(o.Provider,{value:e.context[i],children:r})}),(0,_.jsx)("div",{children:r},e.id)}var te=De;var oe=require("react/jsx-runtime");function Le({config:n,navigationController:e,openOverlay:t}){let{currentFrame:r,navigate:o,replacePath:i,submitForm:c,refreshProps:f,isNavigating:d}=e,{isDirty:v,requestUnload:u,cancelUnload:h}=ce.default.useContext(b),C=ce.default.useMemo(()=>({frameId:r.id,path:r.path,props:r.props,context:r.context,navigate:(m,l={})=>!v||l.skipDirtyFormCheck===!0?(l.skipDirtyFormCheck===!0&&h(),o(m,l.pushState)):u().then(()=>o(m,l.pushState)),replacePath:i,submitForm:c,openOverlay:t,refreshProps:f,isNavigating:d,setShouldReloadCallback:m=>{r.shouldReloadCallback=m}}),[r,i,c,t,v,u,h,o,f,d]);return(0,oe.jsx)(P.Provider,{value:C,children:(0,oe.jsx)("div",{children:(0,oe.jsx)(te,{config:n,frame:r})},r.id)})}var re=Le;var V=N(require("react"));var Re=require("react/jsx-runtime");function de({children:n,href:e,skipDirtyFormCheck:t=!1,...r},{navigate:o},i){return(0,Re.jsx)("a",{onClick:f=>{e&&(f.preventDefault(),o(e,{skipDirtyFormCheck:t}))},href:e||"#",ref:i,...r,children:n})}var ue=V.default.createContext(de),Be=V.default.forwardRef((n,e)=>{let t=V.default.useContext(P);return V.default.useContext(ue)(n,t,e)}),Ce=Be;var X=class extends W{contextProviders;constructor(){super(),this.contextProviders=new Map}addContextProvider=(e,t)=>(this.contextProviders.set(e,t),this)};var A=N(require("react"));var U=require("react/jsx-runtime");function fe({children:n,onSubmit:e,isDirty:t=!1,disableDirtyCheck:r=!1,...o}){let{submitForm:i,navigate:c}=A.default.useContext(P),[f,d]=A.default.useState(!1),[v,u]=A.default.useState(t),{cancelUnload:h}=A.default.useContext(b),C=l=>{if(v&&h(),!(e&&(e(l),l.defaultPrevented))&&l.target instanceof HTMLFormElement){if(f){l.preventDefault();return}let R=new FormData(l.target);if(l.nativeEvent instanceof SubmitEvent&&l.nativeEvent.submitter){let{submitter:s}=l.nativeEvent;(s instanceof HTMLButtonElement||s instanceof HTMLInputElement)&&s.name&&s.value&&R.set(s.name,s.value)}if(l.target.method==="post")l.preventDefault(),d(!0),i(l.target.action,R).catch(()=>d(!1));else if(l.target.method==="get"){l.preventDefault();let s=Array.from(R.entries()).map(w=>`${encodeURIComponent(w[0])}=${encodeURIComponent(w[1])}`).join("&"),p=l.target.action+(l.target.action.indexOf("?")===-1?"?":"&")+s;d(!0),c(p).catch(()=>d(!1))}}},m=A.default.useCallback(()=>{u(!0)},[]);return(0,U.jsxs)("form",{onSubmit:C,...o,children:[v&&!r&&(0,U.jsx)(z,{}),(0,U.jsx)(ee.Provider,{value:f,children:(0,U.jsx)(Z.Provider,{value:m,children:n})})]})}var G=N(require("react"));var H=require("react/jsx-runtime");function me({config:n,initialResponse:e,initialPath:t,parentNavigationController:r,render:o,requestClose:i,closeRequested:c,onCloseCompleted:f,onServerError:d}){let{pushMessage:v}=G.default.useContext(T),u=K(r,n.unpack,e,t,{onNavigation:(l,R,s)=>{s.forEach(v)},onEscalate:()=>{f()},onOverlayClose:l=>{l.forEach(v),i()},onServerError:d}),h=G.default.useContext(b),C=G.default.useCallback(({skipDirtyFormCheck:l=!1}={})=>{!l&&h.isDirty?h.requestUnload().then(()=>i()):i()},[h,i]),m=G.default.useMemo(()=>({overlay:!0,closeRequested:c,requestClose:C,onCloseCompleted:f}),[c,f,C]);return u.isLoading?(0,H.jsx)(H.Fragment,{}):(0,H.jsx)(Q.Provider,{value:m,children:o((0,H.jsx)(re,{config:n,navigationController:u,openOverlay:()=>{}}))})}var M=N(require("react"));function xe(n,e){let{refreshProps:t}=M.default.useContext(P);M.default.useEffect(()=>{if(!n)return()=>{};let r=null,o=()=>{r=setTimeout(()=>{t(),o()},e)};return o(),()=>{r&&clearTimeout(r)}},[n,e,t])}function we(n,e){let t=(0,M.useCallback)(n,e),{setShouldReloadCallback:r}=(0,M.useContext)(P);(0,M.useEffect)(()=>r(t),[t,r])}var O=require("react/jsx-runtime");function Te({config:n,initialResponse:e}){let[t,r]=E.default.useReducer((s,p)=>{switch(p.action){case"push":return s.concat([p.message]);case"clear":return[];default:return s}},[]),o=E.default.useCallback(s=>{r({action:"push",message:s})},[r]),i=E.default.useCallback(s=>{s==="server"?o({level:"error",text:"A server error occurred. Please try again later."}):s==="network"&&o({level:"error",text:"A network error occurred. Please check your internet connection or try again later."})},[o]),[c,f]=E.default.useState(null),[d,v]=E.default.useState(!1),u=E.default.useRef(null),h=(s,p,w)=>{p&&(v(!0),u.current=null),p&&r({action:"clear"}),w.forEach(o)},C=window.location.pathname+window.location.search+window.location.hash,m=K(null,n.unpack,e,C,{onNavigation:h,onServerError:i});E.default.useEffect(()=>{let s=document.querySelector(".django-bridge-load");s instanceof HTMLElement&&(s.classList.add("django-bridge-load--hidden"),setTimeout(()=>{s.remove()},200));let p=()=>{m.navigate(document.location.pathname,!1)};return window.addEventListener("popstate",p),()=>{window.removeEventListener("popstate",p)}},[]);let l=async(s,p,{onClose:w}={})=>{if(c){console.error("Unable to open overlay as an overlay is already open.");return}m.setIsNavigating(!0);let ne=await L(s,!0);w&&(u.current=w),v(!1),f({render:p,initialResponse:ne,initialPath:s}),m.setIsNavigating(!1)},R=E.default.useMemo(()=>({messages:t,pushMessage:o}),[t,o]);return(0,O.jsx)(le,{handleBrowserUnload:!0,children:(0,O.jsxs)(T.Provider,{value:R,children:[c&&(0,O.jsx)(le,{children:(0,O.jsx)(me,{config:n,initialResponse:c.initialResponse,initialPath:c.initialPath,parentNavigationController:m,render:s=>c.render(s),requestClose:()=>v(!0),closeRequested:d,onCloseCompleted:()=>{f(null),v(!1),u.current&&(u.current(),u.current=null)},onServerError:i})}),!m.isLoading&&(0,O.jsx)(re,{config:n,navigationController:m,openOverlay:(s,p,w)=>{l(s,p,w)}})]})})}0&&(module.exports={App,BuildLinkElement,Config,DirtyFormContext,DirtyFormMarker,Form,FormSubmissionStatus,FormWidgetChangeNotificationContext,Link,MessagesContext,NavigationContext,OverlayContext,RenderFrame,buildLinkElement,useAutoRefresh,useShouldReloadCallback});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@django-bridge/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0-rc.1",
|
|
4
4
|
"description": "The simple way to build Django applications with modern React frontends",
|
|
5
5
|
"repository": "https://github.com/django-bridge/django-bridge",
|
|
6
6
|
"license": "BSD-3-Clause",
|
|
@@ -26,8 +26,7 @@
|
|
|
26
26
|
]
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"react": "^18.2.0"
|
|
30
|
-
"telepath-unpack": "^0.0.4"
|
|
29
|
+
"react": "^18.2.0"
|
|
31
30
|
},
|
|
32
31
|
"devDependencies": {
|
|
33
32
|
"@types/node": "^12.0.0",
|