@ramesesinc/platform-core 0.1.6 → 0.1.9
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/components/action/LookupPage.js +9 -31
- package/dist/components/action/ViewPage.d.ts +2 -0
- package/dist/components/action/ViewPage.js +25 -31
- package/dist/components/common/UIComponent.js +4 -3
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.js +1 -0
- package/dist/components/table/DataList.js +2 -2
- package/dist/components/view/PopupView.d.ts +13 -0
- package/dist/components/view/PopupView.js +25 -20
- package/dist/core/DataContext.d.ts +7 -4
- package/dist/core/DataContext.js +16 -4
- package/dist/core/Page.js +25 -26
- package/dist/core/PageCache.js +7 -7
- package/dist/core/PageContext.js +17 -7
- package/dist/core/PageViewContext.d.ts +13 -1
- package/dist/core/PageViewContext.js +75 -2
- package/dist/core/PopupContext.d.ts +49 -0
- package/dist/core/PopupContext.js +380 -0
- package/dist/core/RowContext.js +1 -1
- package/dist/core/WindowContext.d.ts +15 -0
- package/dist/core/WindowContext.js +28 -0
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.js +1 -0
- package/dist/index.css +25 -7
- package/dist/lib/utils/BeanUtils.js +7 -7
- package/dist/templates/DataListTemplate.js +7 -2
- package/dist/templates/ExplorerTemplate.js +1 -1
- package/package.json +5 -5
- package/dist/components/action/AlertMessage.tsx +0 -38
- package/dist/components/action/Button.tsx +0 -230
- package/dist/components/action/CancelEdit.tsx +0 -40
- package/dist/components/action/DeleteData.tsx +0 -73
- package/dist/components/action/Edit.tsx +0 -40
- package/dist/components/action/LookupPage.tsx +0 -113
- package/dist/components/action/ProcessRunner.tsx +0 -337
- package/dist/components/action/Refresh.tsx +0 -35
- package/dist/components/action/SaveData.tsx +0 -74
- package/dist/components/action/SelectData.tsx +0 -47
- package/dist/components/action/Undo.tsx +0 -50
- package/dist/components/action/UpdateData.tsx +0 -49
- package/dist/components/action/UpdateState.tsx +0 -40
- package/dist/components/action/ViewBackPage.tsx +0 -46
- package/dist/components/action/ViewPage.tsx +0 -141
- package/dist/components/common/UIComponent.tsx +0 -86
- package/dist/components/common/UIInput.tsx +0 -49
- package/dist/components/common/UIMenu.tsx +0 -91
- package/dist/components/index.ts +0 -51
- package/dist/components/input/CodeEditor.tsx +0 -188
- package/dist/components/input/DateField.tsx +0 -274
- package/dist/components/input/DayPicker.tsx +0 -5
- package/dist/components/input/HtmlCode.tsx +0 -203
- package/dist/components/input/JsonCode.tsx +0 -205
- package/dist/components/input/MonthPicker.tsx +0 -5
- package/dist/components/input/ScriptCode.tsx +0 -195
- package/dist/components/input/Select.tsx +0 -78
- package/dist/components/input/SqlCode.tsx +0 -162
- package/dist/components/input/StringDecision.tsx +0 -64
- package/dist/components/input/Text.tsx +0 -57
- package/dist/components/input/YearPicker.tsx +0 -81
- package/dist/components/list/IconMenu.tsx +0 -115
- package/dist/components/list/TabMenu.tsx +0 -127
- package/dist/components/list/TreeMenu.tsx +0 -279
- package/dist/components/list/TxnTaskList.tsx +0 -198
- package/dist/components/output/Label.tsx +0 -50
- package/dist/components/table/DataList.tsx +0 -820
- package/dist/components/table/DataTable.tsx +0 -572
- package/dist/components/table/ListHandler.ts +0 -276
- package/dist/components/table/TableContext.tsx +0 -122
- package/dist/components/view/ComponentView.tsx +0 -102
- package/dist/components/view/FilterView.tsx +0 -21
- package/dist/components/view/HtmlForm.tsx +0 -176
- package/dist/components/view/HtmlView.tsx +0 -98
- package/dist/components/view/IFrameView.tsx +0 -48
- package/dist/components/view/Modal.tsx +0 -72
- package/dist/components/view/PageView.tsx +0 -131
- package/dist/components/view/PopupView.tsx +0 -160
- package/dist/components/view/RootView.tsx +0 -109
- package/dist/components/view/WizardView.tsx +0 -48
- package/dist/lib/layouts/BorderLayout.tsx +0 -31
- package/dist/lib/layouts/CardLayout.tsx +0 -73
- package/dist/lib/layouts/CenterLayout.tsx +0 -20
- package/dist/lib/layouts/GridLayout.tsx +0 -20
- package/dist/lib/layouts/HPanel.tsx +0 -31
- package/dist/lib/layouts/HorizontalLayout.tsx +0 -29
- package/dist/lib/layouts/MainLayout.tsx +0 -16
- package/dist/lib/layouts/PageLayout.tsx +0 -29
- package/dist/lib/layouts/VPanel.tsx +0 -27
- package/dist/lib/layouts/XLayout.tsx +0 -29
- package/dist/lib/layouts/YLayout.tsx +0 -29
- package/dist/lib/layouts/index.ts +0 -13
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { localAPI } from "@ramesesinc/lib/local-api";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
3
|
-
import { useApp } from "../../core/AppContext";
|
|
4
|
-
import { usePageContext } from "../../core/PageContext";
|
|
5
|
-
import useDependHandler from "../../core/UIDependHandler";
|
|
6
|
-
import { render } from "../../lib/utils/ExprUtil";
|
|
7
|
-
import UIComponent from "../common/UIComponent";
|
|
8
|
-
|
|
9
|
-
type HtmlLabelProps = {
|
|
10
|
-
label?: string;
|
|
11
|
-
depends?: string;
|
|
12
|
-
expr?: string;
|
|
13
|
-
templateid?: string;
|
|
14
|
-
data?: Record<string, any>;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const Html = (props: HtmlLabelProps) => {
|
|
18
|
-
const { depends, expr, templateid } = props ?? {};
|
|
19
|
-
|
|
20
|
-
const [htmlTemplate, setHtmlTemplate] = useState(""); // raw template
|
|
21
|
-
const [renderedHtml, setRenderedHtml] = useState(""); // rendered output
|
|
22
|
-
const pageContext = usePageContext();
|
|
23
|
-
const binding = pageContext?.binding;
|
|
24
|
-
const { tenant, module } = useApp();
|
|
25
|
-
|
|
26
|
-
// ← single render function used everywhere
|
|
27
|
-
const renderTemplate = (template: string) => {
|
|
28
|
-
if (!template) return "";
|
|
29
|
-
try {
|
|
30
|
-
const data = pageContext?.getAllData() ?? {};
|
|
31
|
-
return render(template, data);
|
|
32
|
-
} catch (error) {
|
|
33
|
-
console.error("Template render error:", error);
|
|
34
|
-
return template;
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
// ← single expression render
|
|
39
|
-
const renderExpression = (expression: string) => {
|
|
40
|
-
if (!expression) return "";
|
|
41
|
-
try {
|
|
42
|
-
const data = pageContext?.getData() ?? {};
|
|
43
|
-
return render(expression, { data });
|
|
44
|
-
} catch (error) {
|
|
45
|
-
console.error("Expression render error:", error);
|
|
46
|
-
return expression;
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
// ← load template only once when templateid changes
|
|
51
|
-
useEffect(() => {
|
|
52
|
-
if (templateid == null || templateid.trim() === "") return;
|
|
53
|
-
|
|
54
|
-
const loadHtmlContent = async () => {
|
|
55
|
-
try {
|
|
56
|
-
const htmlContent = await localAPI.useMgmt(tenant!, module!).get("html_templates", templateid);
|
|
57
|
-
if (htmlContent != null) {
|
|
58
|
-
setHtmlTemplate(htmlContent.htmlCode); // ← just store raw template
|
|
59
|
-
} else {
|
|
60
|
-
setHtmlTemplate("");
|
|
61
|
-
}
|
|
62
|
-
} catch (error) {
|
|
63
|
-
console.error("Error loading HTML template:", error);
|
|
64
|
-
setHtmlTemplate("");
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
loadHtmlContent();
|
|
69
|
-
}, [templateid]);
|
|
70
|
-
|
|
71
|
-
// ← re-render whenever template OR binding data changes
|
|
72
|
-
useEffect(() => {
|
|
73
|
-
if (htmlTemplate) {
|
|
74
|
-
setRenderedHtml(renderTemplate(htmlTemplate));
|
|
75
|
-
} else if (expr) {
|
|
76
|
-
setRenderedHtml(renderExpression(expr));
|
|
77
|
-
}
|
|
78
|
-
}, [htmlTemplate, binding?.raw]); // ← binding.raw triggers when data changes
|
|
79
|
-
|
|
80
|
-
// ← onRefresh called when depends changes
|
|
81
|
-
const onRefresh = () => {
|
|
82
|
-
if (htmlTemplate) {
|
|
83
|
-
setRenderedHtml(renderTemplate(htmlTemplate));
|
|
84
|
-
} else if (expr) {
|
|
85
|
-
setRenderedHtml(renderExpression(expr));
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
useDependHandler({ name: depends, onRefresh });
|
|
90
|
-
|
|
91
|
-
return (
|
|
92
|
-
<UIComponent {...(props ?? {})}>
|
|
93
|
-
<div className="h-[calc(100vh-80px)] overflow-y-auto overflow-x-auto" dangerouslySetInnerHTML={{ __html: renderedHtml }} />
|
|
94
|
-
</UIComponent>
|
|
95
|
-
);
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
export default Html;
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useEffect, useRef, useState } from "react";
|
|
4
|
-
import { usePageContext } from "../../core/PageContext";
|
|
5
|
-
|
|
6
|
-
const Iframe = (props: Record<string, any>) => {
|
|
7
|
-
// console.log(props);
|
|
8
|
-
const { url = "", name, depends = "page", width = "100%", height = "100%" } = props ?? {};
|
|
9
|
-
const pageContext = usePageContext();
|
|
10
|
-
const lastValueRef = useRef<any>();
|
|
11
|
-
const [iframeUrl, setIframeUrl] = useState(url);
|
|
12
|
-
|
|
13
|
-
const dependHandler = (value: any) => {
|
|
14
|
-
if (lastValueRef.current === value) return; // skip if unchanged
|
|
15
|
-
lastValueRef.current = value;
|
|
16
|
-
|
|
17
|
-
// value is expected to be a URL (string)
|
|
18
|
-
if (typeof value === "string") {
|
|
19
|
-
setIframeUrl(value);
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
if (!depends) return;
|
|
25
|
-
const unsubscribe = pageContext?.dependsTo(depends, dependHandler);
|
|
26
|
-
return unsubscribe;
|
|
27
|
-
}, [depends]);
|
|
28
|
-
|
|
29
|
-
if (!iframeUrl) return null;
|
|
30
|
-
|
|
31
|
-
return (
|
|
32
|
-
<div className="h-[calc(100vh-60px)]">
|
|
33
|
-
<iframe
|
|
34
|
-
src={iframeUrl}
|
|
35
|
-
name={name}
|
|
36
|
-
title={name || "iframe"}
|
|
37
|
-
style={{
|
|
38
|
-
width,
|
|
39
|
-
height,
|
|
40
|
-
border: "none",
|
|
41
|
-
}}
|
|
42
|
-
loading="lazy"
|
|
43
|
-
/>
|
|
44
|
-
</div>
|
|
45
|
-
);
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export default Iframe;
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import clsx from "clsx";
|
|
4
|
-
import { MouseEvent, ReactNode, useEffect } from "react";
|
|
5
|
-
|
|
6
|
-
export type ModalRenderFn = (close: () => void) => ReactNode;
|
|
7
|
-
|
|
8
|
-
export type ModalProps = {
|
|
9
|
-
open: boolean;
|
|
10
|
-
onClose: () => void;
|
|
11
|
-
children: ReactNode | ModalRenderFn;
|
|
12
|
-
title?: string;
|
|
13
|
-
className?: string;
|
|
14
|
-
width?: string; // e.g. "500px" or "50%"
|
|
15
|
-
height?: string; // e.g. "400px" or "80%"
|
|
16
|
-
hideCloseButton?: boolean;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const Modal = ({ open, onClose, title, children, className, width = "600px", height, hideCloseButton = false }: ModalProps) => {
|
|
20
|
-
useEffect(() => {
|
|
21
|
-
const handleKey = (e: KeyboardEvent) => {
|
|
22
|
-
if (e.key === "Escape") {
|
|
23
|
-
onClose();
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
if (open) {
|
|
28
|
-
document.addEventListener("keydown", handleKey);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return () => {
|
|
32
|
-
document.removeEventListener("keydown", handleKey);
|
|
33
|
-
};
|
|
34
|
-
}, [open, onClose]);
|
|
35
|
-
|
|
36
|
-
if (!open) return null;
|
|
37
|
-
|
|
38
|
-
const handleOverlayClick = (e: MouseEvent<HTMLDivElement>) => {
|
|
39
|
-
// if (e.target === e.currentTarget) {
|
|
40
|
-
// onClose();
|
|
41
|
-
// }
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
return (
|
|
45
|
-
<div className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/40" onClick={handleOverlayClick}>
|
|
46
|
-
<div
|
|
47
|
-
className={clsx("relative bg-white rounded-lg shadow-lg p-2 w-full max-w-[90vw] transition-all duration-300 ease-in-out", className)}
|
|
48
|
-
style={{ width, height }}
|
|
49
|
-
role="dialog"
|
|
50
|
-
aria-modal="true"
|
|
51
|
-
aria-labelledby={title ? "modal-title" : undefined}
|
|
52
|
-
>
|
|
53
|
-
{title && (
|
|
54
|
-
<h2 id="modal-title" className="text-lg font-semibold mb-4 border-b pb-2 text-gray-800">
|
|
55
|
-
{title}
|
|
56
|
-
</h2>
|
|
57
|
-
)}
|
|
58
|
-
|
|
59
|
-
{/* Modal Content */}
|
|
60
|
-
<div className="overflow-auto">{typeof children === "function" ? children(onClose) : children}</div>
|
|
61
|
-
|
|
62
|
-
{!hideCloseButton && (
|
|
63
|
-
<button onClick={onClose} aria-label="Close modal" className="absolute top-2 right-2 text-gray-500 hover:text-gray-800 transition-colors">
|
|
64
|
-
✕
|
|
65
|
-
</button>
|
|
66
|
-
)}
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export default Modal;
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import React, { forwardRef, memo, useEffect, useImperativeHandle, useRef, useState } from "react";
|
|
4
|
-
import Page from "../../core/Page";
|
|
5
|
-
import { usePageContext } from "../../core/PageContext";
|
|
6
|
-
import { PageViewContextValue, PageViewHandle, PageViewProvider, usePageViewContext } from "../../core/PageViewContext";
|
|
7
|
-
import useDependHandler from "../../core/UIDependHandler";
|
|
8
|
-
import { useUrlParams } from "../../hooks/useUrlParams";
|
|
9
|
-
import UIComponent, { UIComponentProps } from "../common/UIComponent";
|
|
10
|
-
|
|
11
|
-
type StableShellProps = {
|
|
12
|
-
uiProps: Record<string, any>;
|
|
13
|
-
handle: PageViewHandle;
|
|
14
|
-
slotRef: React.RefObject<PageSlotHandle>;
|
|
15
|
-
paths: string[]; // ← new
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const StableShell = memo((props: StableShellProps) => {
|
|
19
|
-
const { uiProps, slotRef, handle, paths } = props ?? {};
|
|
20
|
-
return (
|
|
21
|
-
<UIComponent {...uiProps}>
|
|
22
|
-
<PageViewProvider handle={handle} paths={paths ?? []}>
|
|
23
|
-
<PageSlot ref={slotRef} />
|
|
24
|
-
</PageViewProvider>
|
|
25
|
-
</UIComponent>
|
|
26
|
-
);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
interface PageViewProps extends UIComponentProps {
|
|
30
|
-
depends?: string;
|
|
31
|
-
url?: string;
|
|
32
|
-
fallback?: React.ReactNode;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const PageView = memo((props: PageViewProps) => {
|
|
36
|
-
const { name = "selectedPage", depends, url } = props ?? {};
|
|
37
|
-
const [forceUpdate, setForceUpdate] = useState({});
|
|
38
|
-
const providerRef = useRef<PageViewContextValue>({} as PageViewContextValue);
|
|
39
|
-
const { setAnchorPath } = useUrlParams();
|
|
40
|
-
const slotRef = useRef<PageSlotHandle>(null);
|
|
41
|
-
const pageContext = usePageContext();
|
|
42
|
-
const [ownPaths, setOwnPaths] = useState<string[]>([]);
|
|
43
|
-
const isEmpty = (value: string | null | undefined) => value == null || value.trim() === "";
|
|
44
|
-
|
|
45
|
-
const pageView = usePageViewContext();
|
|
46
|
-
|
|
47
|
-
let preferredName = isEmpty(name) ? depends : name;
|
|
48
|
-
let preferredDepends = isEmpty(depends) ? preferredName : depends;
|
|
49
|
-
|
|
50
|
-
const newProps = { ...props, name: preferredName, depends: preferredDepends };
|
|
51
|
-
|
|
52
|
-
const propsRef = useRef(newProps);
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
propsRef.current = newProps;
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
const getUrl = () => {
|
|
58
|
-
if (url != null && url.trim() !== "") return url;
|
|
59
|
-
if (newProps.name) return pageContext.get(newProps.name);
|
|
60
|
-
return null;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const getUrlRef = useRef(getUrl);
|
|
64
|
-
useEffect(() => {
|
|
65
|
-
getUrlRef.current = getUrl;
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// Stable handle — never recreated
|
|
69
|
-
const pageViewHandleRef = useRef({
|
|
70
|
-
displayName: "PageView#pageViewHandle",
|
|
71
|
-
init: (ref: PageViewContextValue) => {
|
|
72
|
-
providerRef.current = ref;
|
|
73
|
-
setForceUpdate({});
|
|
74
|
-
},
|
|
75
|
-
renderPage: (page: string | null) => {
|
|
76
|
-
if (page == null || page.trim() === "") {
|
|
77
|
-
slotRef.current?.update(null, "null");
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
setOwnPaths([page]); // ← track own paths
|
|
81
|
-
const key = "page-" + Math.random().toString(36).slice(2);
|
|
82
|
-
const comp = <Page {...propsRef.current} url={page} key={key} />;
|
|
83
|
-
slotRef.current?.update(comp, page);
|
|
84
|
-
},
|
|
85
|
-
isStandalone: () => {
|
|
86
|
-
return pageView == null ? true : pageView.isStandalone();
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
const onRefresh = (val?: any) => {
|
|
91
|
-
setForceUpdate({ val }); // ← carry the value
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
useDependHandler({ name: newProps.depends, onRefresh });
|
|
95
|
-
|
|
96
|
-
useEffect(() => {
|
|
97
|
-
const prov = providerRef.current;
|
|
98
|
-
if (prov == null || typeof prov.setPage !== "function") return;
|
|
99
|
-
|
|
100
|
-
const url = getUrlRef.current();
|
|
101
|
-
// console.log("pageView forceUpdate", url, providerRef.current);
|
|
102
|
-
providerRef.current.setPage(url);
|
|
103
|
-
}, [forceUpdate]);
|
|
104
|
-
|
|
105
|
-
return <StableShell uiProps={newProps} handle={pageViewHandleRef.current} slotRef={slotRef} paths={ownPaths} />;
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
type PageSlotHandle = {
|
|
109
|
-
update: (content: React.ReactNode, opt?: any) => void;
|
|
110
|
-
};
|
|
111
|
-
const PageSlot = memo(
|
|
112
|
-
forwardRef<PageSlotHandle>((_, ref) => {
|
|
113
|
-
const [content, setContent] = useState<React.ReactNode>(null);
|
|
114
|
-
const [opt, setOpt] = useState<any>(null);
|
|
115
|
-
|
|
116
|
-
useImperativeHandle(
|
|
117
|
-
ref,
|
|
118
|
-
() => ({
|
|
119
|
-
update: (content: React.ReactNode, opt?: any) => {
|
|
120
|
-
setContent(content);
|
|
121
|
-
setOpt(opt);
|
|
122
|
-
},
|
|
123
|
-
}),
|
|
124
|
-
[],
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
return <>{content == null ? null : content}</>;
|
|
128
|
-
}),
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
export default PageView;
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import { getError } from "@ramesesinc/client";
|
|
2
|
-
import clsx from "clsx";
|
|
3
|
-
import React, { forwardRef, memo, useEffect, useImperativeHandle, useRef, useState } from "react";
|
|
4
|
-
import { twMerge } from "tailwind-merge";
|
|
5
|
-
import { EventHandler } from "../../core";
|
|
6
|
-
import Page from "../../core/Page";
|
|
7
|
-
import { PageViewContextValue, PageViewHandle, PageViewProvider } from "../../core/PageViewContext";
|
|
8
|
-
|
|
9
|
-
type PopupViewProps = {
|
|
10
|
-
url: string;
|
|
11
|
-
popupClassName?: string;
|
|
12
|
-
onClose?: () => void;
|
|
13
|
-
eventHandler?: EventHandler | null;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const PopupView = (props: PopupViewProps) => {
|
|
17
|
-
const { url, popupClassName, onClose = () => {}, eventHandler } = props ?? {};
|
|
18
|
-
|
|
19
|
-
const [paths, setPaths] = useState<string[]>([]);
|
|
20
|
-
|
|
21
|
-
const providerRef = useRef<PageViewContextValue>({} as PageViewContextValue);
|
|
22
|
-
const slotRef = useRef<PopupSlotHandle>(null);
|
|
23
|
-
|
|
24
|
-
const [newRootPath, setNewRootPath] = useState<string | null>(null);
|
|
25
|
-
const [reInitPage, setReInitPage] = useState(true);
|
|
26
|
-
|
|
27
|
-
const mainPath = useRef("");
|
|
28
|
-
|
|
29
|
-
const defaultPopupClass = `bg-white rounded-lg shadow-xl w-[90%] h-[90%] flex flex-col`;
|
|
30
|
-
const finalPopupClass = twMerge(clsx(defaultPopupClass, popupClassName));
|
|
31
|
-
|
|
32
|
-
const loadPage = (path: string | null) => {
|
|
33
|
-
// console.log("popupview load page", path);
|
|
34
|
-
let comp = null;
|
|
35
|
-
try {
|
|
36
|
-
const key = "page-" + Math.random().toString(36).slice(2);
|
|
37
|
-
comp = <Page url={path} key={key} />;
|
|
38
|
-
} catch (error: any) {
|
|
39
|
-
const e = getError(error);
|
|
40
|
-
comp = <div>{e.message}</div>;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// update the child slot
|
|
44
|
-
slotRef.current?.update(comp, finalPopupClass, onClose);
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
useEffect(() => {
|
|
48
|
-
// console.log("popupview change url", url);
|
|
49
|
-
const paths = (url == null || url.trim() === "" ? "" : url).split("#");
|
|
50
|
-
const [firstPath] = paths;
|
|
51
|
-
mainPath.current = firstPath;
|
|
52
|
-
setPaths(paths);
|
|
53
|
-
}, [url]);
|
|
54
|
-
|
|
55
|
-
useEffect(() => {
|
|
56
|
-
// this routine is for the initial loading
|
|
57
|
-
// console.log("popupview change paths", paths);
|
|
58
|
-
loadPage(mainPath.current);
|
|
59
|
-
setReInitPage(false);
|
|
60
|
-
}, [paths]);
|
|
61
|
-
|
|
62
|
-
useEffect(() => {
|
|
63
|
-
if (reInitPage) {
|
|
64
|
-
// let the initial loading take effect
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
loadPage(newRootPath);
|
|
69
|
-
}, [newRootPath]);
|
|
70
|
-
|
|
71
|
-
const pageViewHandle = {
|
|
72
|
-
displayName: "PopupView#pageViewHandle",
|
|
73
|
-
init: (ref: PageViewContextValue) => {
|
|
74
|
-
providerRef.current = ref;
|
|
75
|
-
},
|
|
76
|
-
renderPage: (page: string) => {
|
|
77
|
-
setNewRootPath(page);
|
|
78
|
-
},
|
|
79
|
-
isStandalone: () => true,
|
|
80
|
-
} as PageViewHandle;
|
|
81
|
-
|
|
82
|
-
return (
|
|
83
|
-
<PageViewProvider prefix="popup" paths={paths} handle={pageViewHandle} eventHandler={eventHandler}>
|
|
84
|
-
<ChildrenSlot ref={slotRef} />
|
|
85
|
-
</PageViewProvider>
|
|
86
|
-
);
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
export default PopupView;
|
|
90
|
-
|
|
91
|
-
type PopupSlotHandle = {
|
|
92
|
-
update: (content: React.ReactNode, popupClassName: string, onClose: () => void) => void;
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const ChildrenSlot = memo(
|
|
96
|
-
forwardRef<PopupSlotHandle>((_, ref) => {
|
|
97
|
-
const [content, setContent] = useState<React.ReactNode>(null);
|
|
98
|
-
|
|
99
|
-
const optionsRef = useRef<Record<string, any>>({});
|
|
100
|
-
|
|
101
|
-
useImperativeHandle(
|
|
102
|
-
ref,
|
|
103
|
-
() => ({
|
|
104
|
-
update: (content: React.ReactNode, popupClassName: string, onClose: () => void) => {
|
|
105
|
-
const options = { popupClassName, onClose };
|
|
106
|
-
setContent(wrapContent(content, options));
|
|
107
|
-
optionsRef.current = options;
|
|
108
|
-
},
|
|
109
|
-
}),
|
|
110
|
-
[],
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
const handleClose = () => {
|
|
114
|
-
setContent(null);
|
|
115
|
-
|
|
116
|
-
const { onClose } = optionsRef.current;
|
|
117
|
-
if (onClose != null && typeof onClose === "function") {
|
|
118
|
-
onClose();
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const wrapContent = (comp: React.ReactNode, options: Record<string, any>): React.ReactNode => {
|
|
123
|
-
if (comp == null) {
|
|
124
|
-
return null;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const { popupClassName } = options;
|
|
128
|
-
return (
|
|
129
|
-
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
|
130
|
-
<div className={popupClassName}>
|
|
131
|
-
{/* Header */}
|
|
132
|
-
<div className="flex items-center justify-between px-4 py-3 border-b">
|
|
133
|
-
<h2 className="text-lg font-semibold">Page Viewer</h2>
|
|
134
|
-
<button onClick={handleClose} className="w-8 h-8 flex items-center justify-center rounded-md hover:bg-gray-100 transition-colors">
|
|
135
|
-
<svg
|
|
136
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
137
|
-
width="20"
|
|
138
|
-
height="20"
|
|
139
|
-
viewBox="0 0 24 24"
|
|
140
|
-
fill="none"
|
|
141
|
-
stroke="currentColor"
|
|
142
|
-
strokeWidth="2"
|
|
143
|
-
strokeLinecap="round"
|
|
144
|
-
strokeLinejoin="round"
|
|
145
|
-
>
|
|
146
|
-
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
147
|
-
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
148
|
-
</svg>
|
|
149
|
-
</button>
|
|
150
|
-
</div>
|
|
151
|
-
{/* Content */}
|
|
152
|
-
<div className="flex-1 overflow-hidden">{comp}</div>
|
|
153
|
-
</div>
|
|
154
|
-
</div>
|
|
155
|
-
);
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
return <>{content == null ? null : content}</>;
|
|
159
|
-
}),
|
|
160
|
-
);
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { getError } from "@ramesesinc/client";
|
|
2
|
-
import { forwardRef, memo, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
|
|
3
|
-
import { EventHandler } from "../../core";
|
|
4
|
-
import Page from "../../core/Page";
|
|
5
|
-
import { PageViewContextValue, PageViewHandle, PageViewProvider } from "../../core/PageViewContext";
|
|
6
|
-
|
|
7
|
-
type RootViewProps = {
|
|
8
|
-
url: string;
|
|
9
|
-
eventHandler?: EventHandler | null;
|
|
10
|
-
standalone?: boolean;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const RootView = (props: RootViewProps) => {
|
|
14
|
-
const { url, eventHandler, standalone = true } = props ?? {};
|
|
15
|
-
|
|
16
|
-
const [paths, setPaths] = useState<string[]>([]);
|
|
17
|
-
|
|
18
|
-
const mainPath = useRef("");
|
|
19
|
-
|
|
20
|
-
const [newRootPath, setNewRootPath] = useState<string | null>(null);
|
|
21
|
-
const [reInitPage, setReInitPage] = useState(true);
|
|
22
|
-
|
|
23
|
-
const providerRef = useRef<PageViewContextValue>({} as PageViewContextValue);
|
|
24
|
-
|
|
25
|
-
const loadPage = (path: string | null) => {
|
|
26
|
-
let comp = null;
|
|
27
|
-
try {
|
|
28
|
-
// console.log("RootView loadPage", path); // main#tasklist
|
|
29
|
-
const pageUUID = "page-" + Math.random().toString(36).slice(2);
|
|
30
|
-
comp = <Page url={path} key={pageUUID} />;
|
|
31
|
-
} catch (error: any) {
|
|
32
|
-
const e = getError(error);
|
|
33
|
-
// console.log("rootview loadpage error", e);
|
|
34
|
-
comp = <div>{e.message}</div>;
|
|
35
|
-
}
|
|
36
|
-
// update provider paths but maintain the rootPath
|
|
37
|
-
// providerRef.current?.updatePaths(newPaths);
|
|
38
|
-
// update the child slot
|
|
39
|
-
slotRef.current?.update(comp);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
useLayoutEffect(() => {
|
|
43
|
-
const paths = (url == null || url.trim() === "" ? "" : url).split("#");
|
|
44
|
-
// console.log("RootView useLayoutEffect ", url, paths);
|
|
45
|
-
const [firstPath] = paths;
|
|
46
|
-
mainPath.current = firstPath;
|
|
47
|
-
setPaths(paths);
|
|
48
|
-
}, [url]);
|
|
49
|
-
|
|
50
|
-
useEffect(() => {
|
|
51
|
-
// this routine is for the initial loading
|
|
52
|
-
// pass the original url
|
|
53
|
-
loadPage(url);
|
|
54
|
-
setReInitPage(false);
|
|
55
|
-
}, [paths]);
|
|
56
|
-
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
if (reInitPage) {
|
|
59
|
-
// let the initial loading take effect
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
loadPage(newRootPath);
|
|
64
|
-
}, [newRootPath]);
|
|
65
|
-
|
|
66
|
-
const pageViewHandle = {
|
|
67
|
-
displayName: "RootView#pageViewHandle",
|
|
68
|
-
init: (ref: PageViewContextValue) => {
|
|
69
|
-
providerRef.current = ref;
|
|
70
|
-
},
|
|
71
|
-
renderPage: (page: string) => {
|
|
72
|
-
// console.log("RootView renderPage", page);
|
|
73
|
-
setNewRootPath(page);
|
|
74
|
-
},
|
|
75
|
-
isStandalone: () => standalone,
|
|
76
|
-
} as PageViewHandle;
|
|
77
|
-
|
|
78
|
-
const slotRef = useRef<ChildrenSlotHandle>(null);
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
<PageViewProvider prefix="root" paths={paths} handle={pageViewHandle} eventHandler={eventHandler}>
|
|
82
|
-
<ChildrenSlot ref={slotRef} />
|
|
83
|
-
</PageViewProvider>
|
|
84
|
-
);
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
export default RootView;
|
|
88
|
-
|
|
89
|
-
type ChildrenSlotHandle = {
|
|
90
|
-
update: (content: React.ReactNode) => void;
|
|
91
|
-
};
|
|
92
|
-
const ChildrenSlot = memo(
|
|
93
|
-
forwardRef<ChildrenSlotHandle>((_, ref) => {
|
|
94
|
-
const [content, setContent] = useState<React.ReactNode>(null);
|
|
95
|
-
|
|
96
|
-
useImperativeHandle(
|
|
97
|
-
ref,
|
|
98
|
-
() => ({
|
|
99
|
-
update: (content: React.ReactNode) => {
|
|
100
|
-
// console.log("childrenslot update", content);
|
|
101
|
-
setContent(content);
|
|
102
|
-
},
|
|
103
|
-
}),
|
|
104
|
-
[],
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
return <>{content == null ? null : content}</>;
|
|
108
|
-
}),
|
|
109
|
-
);
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef } from "react";
|
|
2
|
-
import { usePageContext } from "../../core/PageContext";
|
|
3
|
-
import { StepActionHandler, StepHandler } from "../../core/StepHandler";
|
|
4
|
-
import ComponentView from "./ComponentView";
|
|
5
|
-
|
|
6
|
-
type WizardViewProps = {
|
|
7
|
-
name: string;
|
|
8
|
-
items: Record<string, any>[];
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const WizardView = (props: WizardViewProps) => {
|
|
12
|
-
const { name = "wizard", items = [] } = props ?? {};
|
|
13
|
-
const pageContext = usePageContext();
|
|
14
|
-
const handlerRef = useRef<StepActionHandler | null>(null);
|
|
15
|
-
|
|
16
|
-
if (handlerRef.current == null) {
|
|
17
|
-
const callback = (item: Record<string, any>) => {
|
|
18
|
-
const onInit = item.events?.onInit;
|
|
19
|
-
if (onInit != null && typeof onInit === "function") {
|
|
20
|
-
onInit();
|
|
21
|
-
}
|
|
22
|
-
pageContext?.set(name, item);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const handler = StepHandler(items, callback);
|
|
26
|
-
|
|
27
|
-
for (const it of items) {
|
|
28
|
-
const item = it as Record<string, any>;
|
|
29
|
-
if (item.attr == null) item.attr = {};
|
|
30
|
-
item.attr.stepHandler = handler;
|
|
31
|
-
item.attr.events = {};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
handlerRef.current = handler;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
pageContext?.set(name, items[0]);
|
|
39
|
-
}, []);
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<div>
|
|
43
|
-
<ComponentView name={name} depends={name} />
|
|
44
|
-
</div>
|
|
45
|
-
);
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export default WizardView;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { ReactNode } from "react";
|
|
2
|
-
import HorizontalLayout from "./HorizontalLayout";
|
|
3
|
-
import PageLayout from "./PageLayout";
|
|
4
|
-
|
|
5
|
-
type BorderLayoutProps = {
|
|
6
|
-
layoutid?: string;
|
|
7
|
-
className?: string;
|
|
8
|
-
vgap?: number;
|
|
9
|
-
hgap?: number;
|
|
10
|
-
|
|
11
|
-
north?: ReactNode;
|
|
12
|
-
south?: ReactNode;
|
|
13
|
-
east?: ReactNode;
|
|
14
|
-
west?: ReactNode;
|
|
15
|
-
|
|
16
|
-
children?: ReactNode;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const BorderLayout = ({ layoutid, className, vgap = 0, hgap = 0, north, south, east, west, children }: BorderLayoutProps) => {
|
|
20
|
-
const preferredLayoutId = layoutid ?? "" ? layoutid : "borderlayout";
|
|
21
|
-
|
|
22
|
-
return (
|
|
23
|
-
<PageLayout layoutid={`${preferredLayoutId}`} className={className} gap={vgap} header={north} footer={south}>
|
|
24
|
-
<HorizontalLayout layoutid={`${preferredLayoutId}-center`} gap={hgap} left={west} right={east}>
|
|
25
|
-
{children}
|
|
26
|
-
</HorizontalLayout>
|
|
27
|
-
</PageLayout>
|
|
28
|
-
);
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export default BorderLayout;
|