@ramesesinc/platform-core 0.1.8 → 0.1.10
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.d.ts +2 -1
- package/dist/components/action/LookupPage.js +4 -3
- package/dist/components/action/Play.d.ts +6 -0
- package/dist/components/action/Play.js +40 -0
- package/dist/components/action/ProgressBar.d.ts +8 -0
- package/dist/components/action/ProgressBar.js +146 -0
- package/dist/components/action/ViewPage.d.ts +2 -1
- package/dist/components/action/ViewPage.js +19 -9
- package/dist/components/common/UIMenu.js +4 -3
- package/dist/components/index.d.ts +7 -1
- package/dist/components/index.js +5 -1
- package/dist/components/input/Combo.d.ts +21 -0
- package/dist/components/input/Combo.js +137 -0
- package/dist/components/input/DateField.js +7 -14
- package/dist/components/input/Text.d.ts +5 -0
- package/dist/components/input/Text.js +42 -7
- package/dist/components/list/EditableMenu.d.ts +2 -0
- package/dist/components/list/EditableMenu.js +128 -0
- package/dist/components/list/TabMenu.js +2 -2
- package/dist/components/list/TreeMenu.js +17 -12
- package/dist/components/table/DataList.d.ts +1 -1
- package/dist/components/table/DataList.js +49 -24
- package/dist/components/table/DataTable.d.ts +2 -0
- package/dist/components/table/DataTable.js +31 -22
- package/dist/components/view/FilterView.js +1 -1
- package/dist/components/view/HtmlForm.js +12 -9
- package/dist/components/view/PageView.js +36 -9
- package/dist/components/view/RootView.js +16 -16
- package/dist/core/AuthContext.js +1 -1
- package/dist/core/Page.js +2 -4
- package/dist/core/PageCache.d.ts +0 -2
- package/dist/core/PageCache.js +3 -8
- package/dist/core/PageContext.js +12 -0
- package/dist/core/PageViewContext.d.ts +8 -2
- package/dist/core/PageViewContext.js +129 -75
- package/dist/core/Panel.js +31 -9
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +1 -0
- package/dist/index.css +79 -0
- package/dist/layouts/CardLayout.d.ts +2 -2
- package/dist/layouts/CardLayout.js +3 -4
- package/dist/layouts/HPanel.d.ts +2 -2
- package/dist/layouts/HPanel.js +1 -2
- package/dist/layouts/VPanel.d.ts +2 -2
- package/dist/layouts/VPanel.js +1 -2
- package/dist/layouts/index.d.ts +2 -3
- package/dist/layouts/index.js +2 -3
- package/dist/lib/utils/ExprUtil.js +18 -29
- package/dist/lib/utils/ResourceLoader.js +19 -7
- package/dist/lib/utils/SectionProvider.js +1 -1
- package/dist/lib/utils/initResourceLoader.d.ts +2 -0
- package/dist/lib/utils/initResourceLoader.js +64 -95
- package/dist/lib/utils/nunjucks.d.ts +2 -0
- package/dist/lib/utils/nunjucks.js +8 -0
- package/dist/templates/CrudFormTemplate.js +2 -3
- package/dist/templates/DataListTemplate.js +1 -1
- package/dist/templates/WizardTemplate.js +3 -1
- package/package.json +1 -1
- package/dist/components/input/Select.d.ts +0 -14
- package/dist/components/input/Select.js +0 -40
|
@@ -7,10 +7,11 @@ interface LookupPageProps extends AbstractComponent {
|
|
|
7
7
|
children?: React.ReactNode;
|
|
8
8
|
className?: string;
|
|
9
9
|
title?: string;
|
|
10
|
-
icon?: string;
|
|
10
|
+
icon?: string | React.ReactNode;
|
|
11
11
|
opt?: Record<string, any>;
|
|
12
12
|
iconOnly?: boolean;
|
|
13
13
|
popupClassName?: string;
|
|
14
|
+
variant?: "primary" | "secondary" | "danger" | "text" | "contained" | "outlined";
|
|
14
15
|
}
|
|
15
16
|
declare const LookupPage: (props: LookupPageProps) => import("react/jsx-runtime").JSX.Element;
|
|
16
17
|
export default LookupPage;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx,
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { Button } from "@ramesesinc/client";
|
|
3
4
|
import { useRef } from "react";
|
|
4
5
|
import { usePageContext } from "../../core/PageContext";
|
|
5
6
|
import { getValue, substituteExpr } from "../../lib/utils/BeanUtils";
|
|
@@ -7,7 +8,7 @@ import { usePopupView } from "../view/PopupView";
|
|
|
7
8
|
/* ------------------------------------------------------------------ */
|
|
8
9
|
/* Component */
|
|
9
10
|
const LookupPage = (props) => {
|
|
10
|
-
const { url, name = "", result = null, children, className = "", title, icon, opt = {}, popupClassName = "", iconOnly = false } = props !== null && props !== void 0 ? props : {};
|
|
11
|
+
const { url, name = "", result = null, children, className = "", title, icon, opt = {}, popupClassName = "", iconOnly = false, variant = "contained", } = props !== null && props !== void 0 ? props : {};
|
|
11
12
|
const { data = {} } = opt;
|
|
12
13
|
const pageContext = usePageContext();
|
|
13
14
|
const popupView = usePopupView();
|
|
@@ -35,6 +36,6 @@ const LookupPage = (props) => {
|
|
|
35
36
|
popupRef.current = showPopupRef;
|
|
36
37
|
};
|
|
37
38
|
/* ---------------------- Render ---------------------- */
|
|
38
|
-
return (_jsx(_Fragment, { children: iconOnly ? (_jsx("span", { onClick: handleClick, className: `cursor-pointer ${className}`, children: icon })) : (
|
|
39
|
+
return (_jsx(_Fragment, { children: iconOnly ? (_jsx("span", { onClick: handleClick, className: `cursor-pointer ${className}`, children: icon })) : (_jsx(Button, { onClick: handleClick, className: `${className}`, icon: icon, variant: variant, children: title || "Lookup Page" })) }));
|
|
39
40
|
};
|
|
40
41
|
export default LookupPage;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Pause, Play as PlayIcon, Square } from "lucide-react";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { useDataContext } from "../../core/DataContext";
|
|
5
|
+
const Play = (props) => {
|
|
6
|
+
const { name = "play", opt } = props !== null && props !== void 0 ? props : {};
|
|
7
|
+
const dataContext = useDataContext();
|
|
8
|
+
const [state, setState] = useState("idle");
|
|
9
|
+
const handlePlayPause = () => {
|
|
10
|
+
if (state === "idle") {
|
|
11
|
+
setState("playing");
|
|
12
|
+
dataContext === null || dataContext === void 0 ? void 0 : dataContext.set(name, 100); // ← start
|
|
13
|
+
}
|
|
14
|
+
else if (state === "playing") {
|
|
15
|
+
setState("paused");
|
|
16
|
+
dataContext === null || dataContext === void 0 ? void 0 : dataContext.set(name, -1); // ← pause
|
|
17
|
+
}
|
|
18
|
+
else if (state === "paused") {
|
|
19
|
+
setState("playing");
|
|
20
|
+
dataContext === null || dataContext === void 0 ? void 0 : dataContext.set(name, 100); // ← resume
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const handleStop = () => {
|
|
24
|
+
setState("idle");
|
|
25
|
+
dataContext === null || dataContext === void 0 ? void 0 : dataContext.set(name, 0); // ← stop
|
|
26
|
+
};
|
|
27
|
+
// ← listen to progress finishing
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (!name)
|
|
30
|
+
return;
|
|
31
|
+
const unsubscribe = dataContext === null || dataContext === void 0 ? void 0 : dataContext.dependsTo(name, (val) => {
|
|
32
|
+
if (val === 0) {
|
|
33
|
+
setState("idle");
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return () => unsubscribe === null || unsubscribe === void 0 ? void 0 : unsubscribe();
|
|
37
|
+
}, [name]);
|
|
38
|
+
return (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("span", { onClick: handlePlayPause, className: "cursor-pointer hover:opacity-70 transition-opacity", children: state === "playing" ? (_jsx(Pause, { size: 18, className: "text-yellow-500", fill: "currentColor" })) : state === "paused" ? (_jsx(PlayIcon, { size: 18, className: "text-blue-500", fill: "currentColor" })) : (_jsx(PlayIcon, { size: 18, className: "text-green-500", fill: "currentColor" })) }), state === "paused" && (_jsx("span", { onClick: handleStop, className: "cursor-pointer hover:opacity-70 transition-opacity", children: _jsx(Square, { size: 18, className: "text-red-500", fill: "currentColor" }) }))] }));
|
|
39
|
+
};
|
|
40
|
+
export default Play;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { useDataContext } from "../../core/DataContext";
|
|
4
|
+
const ProgressBar = (props) => {
|
|
5
|
+
const { value: propValue, depends, caption, opt } = props !== null && props !== void 0 ? props : {};
|
|
6
|
+
const [animValue, setAnimValue] = useState(0);
|
|
7
|
+
const [active, setActive] = useState(false);
|
|
8
|
+
const dataContext = useDataContext();
|
|
9
|
+
const intervalRef = useRef(null);
|
|
10
|
+
const doneRef = useRef(false);
|
|
11
|
+
const startProgress = () => {
|
|
12
|
+
if (intervalRef.current)
|
|
13
|
+
clearInterval(intervalRef.current);
|
|
14
|
+
setActive(true);
|
|
15
|
+
intervalRef.current = setInterval(() => {
|
|
16
|
+
setAnimValue((prev) => {
|
|
17
|
+
if (prev >= 100) {
|
|
18
|
+
clearInterval(intervalRef.current);
|
|
19
|
+
doneRef.current = true;
|
|
20
|
+
return 100;
|
|
21
|
+
}
|
|
22
|
+
return prev + 2;
|
|
23
|
+
});
|
|
24
|
+
}, 50);
|
|
25
|
+
};
|
|
26
|
+
const pauseProgress = () => {
|
|
27
|
+
if (intervalRef.current)
|
|
28
|
+
clearInterval(intervalRef.current);
|
|
29
|
+
setActive(false);
|
|
30
|
+
};
|
|
31
|
+
const stopProgress = () => {
|
|
32
|
+
if (intervalRef.current)
|
|
33
|
+
clearInterval(intervalRef.current);
|
|
34
|
+
doneRef.current = false;
|
|
35
|
+
setActive(false);
|
|
36
|
+
setAnimValue(0);
|
|
37
|
+
};
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (animValue >= 100) {
|
|
40
|
+
setActive(false);
|
|
41
|
+
const timeout = setTimeout(() => {
|
|
42
|
+
dataContext === null || dataContext === void 0 ? void 0 : dataContext.set(depends !== null && depends !== void 0 ? depends : "", 0);
|
|
43
|
+
}, 1500);
|
|
44
|
+
return () => clearTimeout(timeout);
|
|
45
|
+
}
|
|
46
|
+
}, [animValue]);
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (!depends)
|
|
49
|
+
return;
|
|
50
|
+
const unsubscribe = dataContext === null || dataContext === void 0 ? void 0 : dataContext.dependsTo(depends, (val) => {
|
|
51
|
+
if (val === 100) {
|
|
52
|
+
startProgress();
|
|
53
|
+
}
|
|
54
|
+
else if (val === -1) {
|
|
55
|
+
pauseProgress();
|
|
56
|
+
}
|
|
57
|
+
else if (val === 0 && !doneRef.current) {
|
|
58
|
+
stopProgress();
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
return () => unsubscribe === null || unsubscribe === void 0 ? void 0 : unsubscribe();
|
|
62
|
+
}, [depends]);
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
return () => {
|
|
65
|
+
if (intervalRef.current)
|
|
66
|
+
clearInterval(intervalRef.current);
|
|
67
|
+
};
|
|
68
|
+
}, []);
|
|
69
|
+
const getColor = () => {
|
|
70
|
+
if (animValue < 25)
|
|
71
|
+
return { bar: "#ef4444", glow: "#ff000080" };
|
|
72
|
+
if (animValue < 50)
|
|
73
|
+
return { bar: "#f97316", glow: "#ff6a0080" };
|
|
74
|
+
if (animValue < 75)
|
|
75
|
+
return { bar: "#eab308", glow: "#ffcc0080" };
|
|
76
|
+
return { bar: "#22c55e", glow: "#00ff6680" };
|
|
77
|
+
};
|
|
78
|
+
const { bar, glow } = getColor();
|
|
79
|
+
return (_jsxs("div", { className: "flex flex-col gap-1 w-full", children: [_jsxs("div", { className: "relative w-full rounded-sm overflow-hidden", style: {
|
|
80
|
+
height: "16px",
|
|
81
|
+
background: "#1a1a2e",
|
|
82
|
+
border: "1px solid #333",
|
|
83
|
+
boxShadow: "inset 0 2px 4px rgba(0,0,0,0.5)",
|
|
84
|
+
}, children: [_jsxs("div", { style: {
|
|
85
|
+
width: `${animValue}%`,
|
|
86
|
+
height: "100%",
|
|
87
|
+
background: `linear-gradient(90deg, ${bar}cc, ${bar})`,
|
|
88
|
+
boxShadow: `0 0 8px ${glow}, 0 0 2px ${bar}`,
|
|
89
|
+
transition: "width 0.3s ease",
|
|
90
|
+
position: "relative",
|
|
91
|
+
}, children: [_jsx("div", { style: {
|
|
92
|
+
position: "absolute",
|
|
93
|
+
top: 0,
|
|
94
|
+
left: 0,
|
|
95
|
+
right: 0,
|
|
96
|
+
height: "50%",
|
|
97
|
+
background: "linear-gradient(180deg, rgba(255,255,255,0.2), transparent)",
|
|
98
|
+
} }), _jsx("div", { style: {
|
|
99
|
+
position: "absolute",
|
|
100
|
+
top: 0,
|
|
101
|
+
bottom: 0,
|
|
102
|
+
width: "20px",
|
|
103
|
+
right: 0,
|
|
104
|
+
background: "linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent)",
|
|
105
|
+
animation: active ? "sweep 1s ease-in-out infinite" : "none",
|
|
106
|
+
} })] }), [25, 50, 75].map((seg) => (_jsx("div", { style: {
|
|
107
|
+
position: "absolute",
|
|
108
|
+
top: 0,
|
|
109
|
+
bottom: 0,
|
|
110
|
+
left: `${seg}%`,
|
|
111
|
+
width: "1px",
|
|
112
|
+
background: "rgba(0,0,0,0.4)",
|
|
113
|
+
zIndex: 1,
|
|
114
|
+
} }, seg)))] }), caption && (_jsxs("div", { className: "flex items-center justify-center gap-1", children: [_jsxs("span", { style: {
|
|
115
|
+
fontFamily: "monospace",
|
|
116
|
+
fontSize: "11px",
|
|
117
|
+
fontWeight: "bold",
|
|
118
|
+
color: bar,
|
|
119
|
+
textShadow: `0 0 6px ${glow}`,
|
|
120
|
+
letterSpacing: "0.05em",
|
|
121
|
+
animation: active ? "blink 1s step-end infinite" : "none",
|
|
122
|
+
}, children: [caption.toUpperCase(), active && "..."] }), _jsxs("span", { style: {
|
|
123
|
+
fontFamily: "monospace",
|
|
124
|
+
fontSize: "11px",
|
|
125
|
+
fontWeight: "bold",
|
|
126
|
+
color: bar,
|
|
127
|
+
textShadow: `0 0 6px ${glow}`,
|
|
128
|
+
}, children: [animValue, "%"] })] })), !caption && (_jsx("div", { className: "flex justify-end", children: _jsxs("span", { style: {
|
|
129
|
+
fontFamily: "monospace",
|
|
130
|
+
fontSize: "11px",
|
|
131
|
+
fontWeight: "bold",
|
|
132
|
+
color: bar,
|
|
133
|
+
textShadow: `0 0 6px ${glow}`,
|
|
134
|
+
}, children: [animValue, "%"] }) })), _jsx("style", { children: `
|
|
135
|
+
@keyframes sweep {
|
|
136
|
+
0% { opacity: 0; transform: translateX(-20px); }
|
|
137
|
+
50% { opacity: 1; }
|
|
138
|
+
100% { opacity: 0; transform: translateX(20px); }
|
|
139
|
+
}
|
|
140
|
+
@keyframes blink {
|
|
141
|
+
0%, 100% { opacity: 1; }
|
|
142
|
+
50% { opacity: 0.3; }
|
|
143
|
+
}
|
|
144
|
+
` })] }));
|
|
145
|
+
};
|
|
146
|
+
export default ProgressBar;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { AbstractComponent } from "../../types/component";
|
|
3
2
|
import { PopupOptions } from "../../core/PopupContext";
|
|
3
|
+
import { AbstractComponent } from "../../types/component";
|
|
4
4
|
interface ViewPageProps extends AbstractComponent {
|
|
5
5
|
url: string;
|
|
6
6
|
mode?: "popup" | "window";
|
|
@@ -10,6 +10,7 @@ interface ViewPageProps extends AbstractComponent {
|
|
|
10
10
|
opt?: Record<string, any>;
|
|
11
11
|
iconOnly?: boolean;
|
|
12
12
|
popupClassName?: string;
|
|
13
|
+
variant?: "primary" | "secondary" | "danger" | "text" | "contained" | "outlined";
|
|
13
14
|
popupOptions?: PopupOptions;
|
|
14
15
|
}
|
|
15
16
|
declare const ViewPage: (props: ViewPageProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx,
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { Button } from "@ramesesinc/client";
|
|
3
4
|
import { useRef } from "react";
|
|
4
5
|
import { useDataContext } from "../../core/DataContext";
|
|
5
6
|
import { usePageContext } from "../../core/PageContext";
|
|
@@ -10,7 +11,7 @@ import { usePopupView } from "../view/PopupView";
|
|
|
10
11
|
/* ------------------------------------------------------------------ */
|
|
11
12
|
/* Component */
|
|
12
13
|
const ViewPage = (props) => {
|
|
13
|
-
const { url, mode, className = "", title, icon, iconOnly = false, opt = {}, popupClassName = "", popupOptions = {} } = props !== null && props !== void 0 ? props : {};
|
|
14
|
+
const { url, mode, className = "", title, icon, iconOnly = false, opt = {}, popupClassName = "", popupOptions = {}, variant } = props !== null && props !== void 0 ? props : {};
|
|
14
15
|
const { data = {} } = opt;
|
|
15
16
|
const dataContext = useDataContext();
|
|
16
17
|
const pageView = usePageViewContext();
|
|
@@ -22,8 +23,8 @@ const ViewPage = (props) => {
|
|
|
22
23
|
var _a;
|
|
23
24
|
(_a = popupShowRef.current) === null || _a === void 0 ? void 0 : _a.close();
|
|
24
25
|
};
|
|
25
|
-
const handleClick = (
|
|
26
|
-
e.preventDefault();
|
|
26
|
+
const handleClick = () => {
|
|
27
|
+
// e.preventDefault();
|
|
27
28
|
if (!url)
|
|
28
29
|
return;
|
|
29
30
|
const getUrlParams = () => {
|
|
@@ -47,9 +48,9 @@ const ViewPage = (props) => {
|
|
|
47
48
|
const urlData = getUrlData();
|
|
48
49
|
const surl = substituteExpr(url, Object.assign(Object.assign({}, urlParams), urlData));
|
|
49
50
|
let preferredMode = mode;
|
|
50
|
-
if ((preferredMode == null || preferredMode.trim() ===
|
|
51
|
-
|
|
52
|
-
}
|
|
51
|
+
// if ((preferredMode == null || preferredMode.trim() === "") && dataContext.getType() === "row") {
|
|
52
|
+
// preferredMode = "window";
|
|
53
|
+
// }
|
|
53
54
|
if (preferredMode === "popup") {
|
|
54
55
|
const handler = {
|
|
55
56
|
onSave: (itm) => {
|
|
@@ -61,7 +62,7 @@ const ViewPage = (props) => {
|
|
|
61
62
|
},
|
|
62
63
|
};
|
|
63
64
|
const showPopupOptions = Object.assign({}, popupOptions);
|
|
64
|
-
if (popupClassName != null && popupClassName.trim() !==
|
|
65
|
+
if (popupClassName != null && popupClassName.trim() !== "") {
|
|
65
66
|
showPopupOptions.className = popupClassName;
|
|
66
67
|
}
|
|
67
68
|
const showPopupRef = popupView.create({ url: surl, onClose: onClose, eventHandler: handler }).show(showPopupOptions);
|
|
@@ -73,10 +74,19 @@ const ViewPage = (props) => {
|
|
|
73
74
|
}
|
|
74
75
|
else {
|
|
75
76
|
popupShowRef.current = null;
|
|
77
|
+
// store page context params in chain before navigating
|
|
78
|
+
const chainInfo = pageView.getPageChainInfo();
|
|
79
|
+
const allData = pageContext.getAllData();
|
|
80
|
+
chainInfo.params = Object.assign(Object.assign({}, chainInfo.params), allData);
|
|
76
81
|
pageView.pushPage(surl);
|
|
77
82
|
}
|
|
78
83
|
};
|
|
79
84
|
/* ---------------------- Render ---------------------- */
|
|
80
|
-
return (_jsx(_Fragment, { children: iconOnly ? (_jsx("span", { onClick: handleClick, className: `cursor-pointer ${className}`, children: icon })) : (
|
|
85
|
+
return (_jsx(_Fragment, { children: iconOnly ? (_jsx("span", { onClick: handleClick, className: `cursor-pointer ${className}`, children: icon })) : (
|
|
86
|
+
// <button onClick={handleClick} className={`px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors ${className}`}>
|
|
87
|
+
// {icon && <span className="dl-action-icon">{icon}</span>}
|
|
88
|
+
// {title || "View Page"}
|
|
89
|
+
// </button>
|
|
90
|
+
_jsx(Button, { onClick: handleClick, className: `${className}`, icon: icon, variant: variant, children: title || "View Page" })) }));
|
|
81
91
|
};
|
|
82
92
|
export default ViewPage;
|
|
@@ -20,14 +20,15 @@ const useUIMenu = (props) => {
|
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
22
|
const fetchMenus = async () => {
|
|
23
|
-
var _a, _b;
|
|
23
|
+
var _a, _b, _c;
|
|
24
24
|
setLoading(true);
|
|
25
25
|
setError(null);
|
|
26
26
|
try {
|
|
27
27
|
// 2️⃣ Custom API
|
|
28
28
|
if (data === null || data === void 0 ? void 0 : data.api) {
|
|
29
29
|
const res = await (pageContext === null || pageContext === void 0 ? void 0 : pageContext.execService(data.api, (_a = data.params) !== null && _a !== void 0 ? _a : {}));
|
|
30
|
-
|
|
30
|
+
const newData = (_b = res.data) !== null && _b !== void 0 ? _b : res;
|
|
31
|
+
setMenus(Array.isArray(newData) ? newData : newData ? [newData] : []);
|
|
31
32
|
return;
|
|
32
33
|
}
|
|
33
34
|
// 3️⃣ Menugroup — fetch categories + items, map to MenuGroup[]
|
|
@@ -48,7 +49,7 @@ const useUIMenu = (props) => {
|
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
catch (err) {
|
|
51
|
-
setError((
|
|
52
|
+
setError((_c = err === null || err === void 0 ? void 0 : err.message) !== null && _c !== void 0 ? _c : "Failed to load menus");
|
|
52
53
|
}
|
|
53
54
|
finally {
|
|
54
55
|
setLoading(false);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { default as Button } from "./action/Button";
|
|
2
2
|
export { default as DateField } from "./input/DateField";
|
|
3
3
|
export { default as DayPicker } from "./input/DayPicker";
|
|
4
|
+
export { default as Combo } from "./input/Combo";
|
|
4
5
|
export { default as MonthPicker } from "./input/MonthPicker";
|
|
5
|
-
export { default as Select } from "./input/Select";
|
|
6
6
|
export { default as Text } from "./input/Text";
|
|
7
7
|
export { default as YearPicker } from "./input/YearPicker";
|
|
8
8
|
export { default as HtmlCode } from "./input/HtmlCode";
|
|
@@ -10,6 +10,7 @@ export { default as JsonCode } from "./input/JsonCode";
|
|
|
10
10
|
export { default as ScriptCode } from "./input/ScriptCode";
|
|
11
11
|
export { default as SqlCode } from "./input/SqlCode";
|
|
12
12
|
export { default as StringDecision } from "./input/StringDecision";
|
|
13
|
+
export { default as EditableMenu } from "./list/EditableMenu";
|
|
13
14
|
export { default as TabMenu } from "./list/TabMenu";
|
|
14
15
|
export { default as TreeMenu } from "./list/TreeMenu";
|
|
15
16
|
export { default as Label } from "./output/Label";
|
|
@@ -21,10 +22,15 @@ export { default as HtmlView } from "./view/HtmlView";
|
|
|
21
22
|
export { default as IFrameView } from "./view/IFrameView";
|
|
22
23
|
export { default as RootView } from "./view/RootView";
|
|
23
24
|
export { default as WizardView } from "./view/WizardView";
|
|
25
|
+
export { default as PopupView } from "./view/PopupView";
|
|
26
|
+
export type { usePopupView } from "./view/PopupView";
|
|
27
|
+
export type { ShowPopupViewRef, CreatePopupViewRef, UsePopupViewResult } from "./view/PopupView";
|
|
24
28
|
export { default as AlertMessage } from "./action/AlertMessage";
|
|
25
29
|
export { default as DeleteData } from "./action/DeleteData";
|
|
26
30
|
export { default as Edit } from "./action/Edit";
|
|
31
|
+
export { default as Play } from "./action/Play";
|
|
27
32
|
export { default as ProcessRunner } from "./action/ProcessRunner";
|
|
33
|
+
export { default as ProgressBar } from "./action/ProgressBar";
|
|
28
34
|
export { default as Refresh } from "./action/Refresh";
|
|
29
35
|
export { default as SaveData } from "./action/SaveData";
|
|
30
36
|
export { default as SelectData } from "./action/SelectData";
|
package/dist/components/index.js
CHANGED
|
@@ -2,8 +2,8 @@ export { default as Button } from "./action/Button";
|
|
|
2
2
|
//inputs
|
|
3
3
|
export { default as DateField } from "./input/DateField";
|
|
4
4
|
export { default as DayPicker } from "./input/DayPicker";
|
|
5
|
+
export { default as Combo } from "./input/Combo";
|
|
5
6
|
export { default as MonthPicker } from "./input/MonthPicker";
|
|
6
|
-
export { default as Select } from "./input/Select";
|
|
7
7
|
export { default as Text } from "./input/Text";
|
|
8
8
|
export { default as YearPicker } from "./input/YearPicker";
|
|
9
9
|
//codes
|
|
@@ -14,6 +14,7 @@ export { default as SqlCode } from "./input/SqlCode";
|
|
|
14
14
|
//conditions
|
|
15
15
|
export { default as StringDecision } from "./input/StringDecision";
|
|
16
16
|
//export { default as YearPicker } from "./input/YearPicker";
|
|
17
|
+
export { default as EditableMenu } from "./list/EditableMenu";
|
|
17
18
|
export { default as TabMenu } from "./list/TabMenu";
|
|
18
19
|
export { default as TreeMenu } from "./list/TreeMenu";
|
|
19
20
|
export { default as Label } from "./output/Label";
|
|
@@ -26,11 +27,14 @@ export { default as HtmlView } from "./view/HtmlView";
|
|
|
26
27
|
export { default as IFrameView } from "./view/IFrameView";
|
|
27
28
|
export { default as RootView } from "./view/RootView";
|
|
28
29
|
export { default as WizardView } from "./view/WizardView";
|
|
30
|
+
export { default as PopupView } from "./view/PopupView";
|
|
29
31
|
//actions
|
|
30
32
|
export { default as AlertMessage } from "./action/AlertMessage";
|
|
31
33
|
export { default as DeleteData } from "./action/DeleteData";
|
|
32
34
|
export { default as Edit } from "./action/Edit";
|
|
35
|
+
export { default as Play } from "./action/Play";
|
|
33
36
|
export { default as ProcessRunner } from "./action/ProcessRunner";
|
|
37
|
+
export { default as ProgressBar } from "./action/ProgressBar";
|
|
34
38
|
export { default as Refresh } from "./action/Refresh";
|
|
35
39
|
export { default as SaveData } from "./action/SaveData";
|
|
36
40
|
export { default as SelectData } from "./action/SelectData";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { UIInputProps } from "../common/UIInput";
|
|
2
|
+
type SelectOption = {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
};
|
|
6
|
+
type ComboProps = UIInputProps & {
|
|
7
|
+
name?: string;
|
|
8
|
+
depends?: string;
|
|
9
|
+
required?: boolean;
|
|
10
|
+
immediate?: boolean;
|
|
11
|
+
items?: SelectOption[];
|
|
12
|
+
data?: Record<string, any>;
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
onChange?: (value: string) => void;
|
|
15
|
+
variant?: "primary" | "secondary" | "danger" | "text" | "contained" | "outlined";
|
|
16
|
+
radius?: "none" | "md" | "lg" | "xl" | "2xl" | "3xl" | "full";
|
|
17
|
+
size?: "sm" | "md" | "lg";
|
|
18
|
+
className?: string;
|
|
19
|
+
};
|
|
20
|
+
declare const Combo: (props: ComboProps) => import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export default Combo;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { usePageContext } from "@/core/PageContext";
|
|
3
|
+
import { ChevronDown } from "lucide-react";
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
5
|
+
import UIComponent from "../common/UIComponent";
|
|
6
|
+
import useUIInput from "../common/UIInput";
|
|
7
|
+
const RADIUS_STYLES = {
|
|
8
|
+
none: "rounded-none",
|
|
9
|
+
md: "rounded-md",
|
|
10
|
+
lg: "rounded-lg",
|
|
11
|
+
xl: "rounded-xl",
|
|
12
|
+
"2xl": "rounded-2xl",
|
|
13
|
+
"3xl": "rounded-3xl",
|
|
14
|
+
full: "rounded-full",
|
|
15
|
+
};
|
|
16
|
+
const variantStyles = {
|
|
17
|
+
primary: "border bg-blue-500 text-blue-50",
|
|
18
|
+
secondary: "border bg-white text-gray-700",
|
|
19
|
+
danger: "border bg-red-600 text-white",
|
|
20
|
+
text: "border bg-transparent text-blue-600",
|
|
21
|
+
contained: "border bg-blue-500 text-blue-50",
|
|
22
|
+
outlined: "border border-1 bg-transparent text-black",
|
|
23
|
+
};
|
|
24
|
+
const Combo = (props) => {
|
|
25
|
+
var _a, _b, _c, _d, _e, _f;
|
|
26
|
+
const { name, immediate = true, items = [], data = {}, placeholder, variant = "outlined", radius = "md", className = "" } = props !== null && props !== void 0 ? props : {};
|
|
27
|
+
const { params } = data !== null && data !== void 0 ? data : {};
|
|
28
|
+
const { projection } = params !== null && params !== void 0 ? params : {};
|
|
29
|
+
const selectRef = useRef(null);
|
|
30
|
+
const pageContext = usePageContext();
|
|
31
|
+
const [listItems, setListItems] = useState(items);
|
|
32
|
+
const [rawItems, setRawItems] = useState([]);
|
|
33
|
+
const [selectValue, setSelectValue] = useState("");
|
|
34
|
+
// derive label/value keys from projection
|
|
35
|
+
const projectedKeys = Object.keys(projection !== null && projection !== void 0 ? projection : {});
|
|
36
|
+
const labelKey = (_b = (_a = data.labelKey) !== null && _a !== void 0 ? _a : projectedKeys[0]) !== null && _b !== void 0 ? _b : "label";
|
|
37
|
+
const valueKey = (_d = (_c = data.valueKey) !== null && _c !== void 0 ? _c : projectedKeys[0]) !== null && _d !== void 0 ? _d : "value";
|
|
38
|
+
const isSpecificField = (_e = props.name) === null || _e === void 0 ? void 0 : _e.includes(".");
|
|
39
|
+
const buildValue = (rawItem) => {
|
|
40
|
+
if (isSpecificField) {
|
|
41
|
+
return rawItem[valueKey];
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
return Object.keys(projection !== null && projection !== void 0 ? projection : {}).reduce((acc, key) => {
|
|
45
|
+
acc[key] = rawItem[key];
|
|
46
|
+
return acc;
|
|
47
|
+
}, {});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const onRefresh = () => {
|
|
51
|
+
var _a;
|
|
52
|
+
const val = getValue();
|
|
53
|
+
if (val != null && typeof val === "object") {
|
|
54
|
+
setSelectValue(String((_a = val[valueKey]) !== null && _a !== void 0 ? _a : ""));
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
setSelectValue(val !== null && val !== void 0 ? val : "");
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const { getValue, setValue } = useUIInput(Object.assign(Object.assign({}, props), { onRefresh }));
|
|
61
|
+
const fetchItems = async () => {
|
|
62
|
+
var _a, _b, _c, _d;
|
|
63
|
+
if (data === null || data === void 0 ? void 0 : data.api) {
|
|
64
|
+
const res = await (pageContext === null || pageContext === void 0 ? void 0 : pageContext.execService(data.api, (_a = data.params) !== null && _a !== void 0 ? _a : {}));
|
|
65
|
+
const raw = (_c = (_b = res === null || res === void 0 ? void 0 : res.data) !== null && _b !== void 0 ? _b : res) !== null && _c !== void 0 ? _c : [];
|
|
66
|
+
setRawItems(raw);
|
|
67
|
+
const mapped = raw
|
|
68
|
+
.map((item) => {
|
|
69
|
+
var _a, _b, _c;
|
|
70
|
+
return ({
|
|
71
|
+
label: String((_a = item[labelKey]) !== null && _a !== void 0 ? _a : ""),
|
|
72
|
+
value: String((_c = (_b = item[valueKey]) !== null && _b !== void 0 ? _b : item["_id"]) !== null && _c !== void 0 ? _c : ""),
|
|
73
|
+
});
|
|
74
|
+
})
|
|
75
|
+
.sort((a, b) => a.label.localeCompare(b.label));
|
|
76
|
+
setListItems(mapped);
|
|
77
|
+
// auto-select first item
|
|
78
|
+
if (mapped.length > 0) {
|
|
79
|
+
const currentVal = getValue();
|
|
80
|
+
if (currentVal != null && currentVal !== "" && currentVal !== undefined) {
|
|
81
|
+
// value already set, just sync display
|
|
82
|
+
if (typeof currentVal === "object") {
|
|
83
|
+
setSelectValue(String((_d = currentVal[valueKey]) !== null && _d !== void 0 ? _d : ""));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
setSelectValue(String(currentVal));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
// no value set, auto-select first
|
|
91
|
+
const firstMapped = mapped[0];
|
|
92
|
+
const firstItem = raw.find((item) => { var _a, _b; return String((_b = (_a = item[valueKey]) !== null && _a !== void 0 ? _a : item["_id"]) !== null && _b !== void 0 ? _b : "") === firstMapped.value; });
|
|
93
|
+
if (firstItem) {
|
|
94
|
+
setSelectValue(firstMapped.value);
|
|
95
|
+
setValue(buildValue(firstItem));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
setListItems([...items].sort((a, b) => a.label.localeCompare(b.label)));
|
|
102
|
+
};
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
fetchItems();
|
|
105
|
+
}, []);
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
if (!(data === null || data === void 0 ? void 0 : data.api)) {
|
|
108
|
+
setListItems([...items].sort((a, b) => a.label.localeCompare(b.label)));
|
|
109
|
+
}
|
|
110
|
+
}, [items]);
|
|
111
|
+
const handleBlur = () => {
|
|
112
|
+
if (!immediate) {
|
|
113
|
+
setValue(selectValue);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
const onChange = (e) => {
|
|
117
|
+
var _a, _b;
|
|
118
|
+
const text = (_a = e.target.value) !== null && _a !== void 0 ? _a : "";
|
|
119
|
+
setSelectValue(text);
|
|
120
|
+
if (immediate) {
|
|
121
|
+
const rawItem = rawItems.find((item) => { var _a, _b; return String((_b = (_a = item[valueKey]) !== null && _a !== void 0 ? _a : item["_id"]) !== null && _b !== void 0 ? _b : "") === text; });
|
|
122
|
+
if (rawItem) {
|
|
123
|
+
setValue(buildValue(rawItem));
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
setValue(text);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
(_b = props.onChange) === null || _b === void 0 ? void 0 : _b.call(props, text);
|
|
130
|
+
};
|
|
131
|
+
const baseStyles = "w-full appearance-none cursor-pointer pl-4 pr-10 py-[4px] text-md font-medium transition-all duration-150 ease-in-out bg-transparent";
|
|
132
|
+
const focusStyles = "focus:outline-none focus:ring-0 focus:shadow-none";
|
|
133
|
+
const roundingStyle = (_f = RADIUS_STYLES[radius]) !== null && _f !== void 0 ? _f : RADIUS_STYLES["md"];
|
|
134
|
+
const finalClassName = [baseStyles, focusStyles, roundingStyle].filter(Boolean).join(" ");
|
|
135
|
+
return (_jsx(UIComponent, Object.assign({}, (props !== null && props !== void 0 ? props : {}), { children: _jsxs("div", { className: `relative inline-flex items-center overflow-hidden ${roundingStyle} ${variantStyles[variant]} ${className}`, children: [_jsxs("select", { ref: selectRef, onChange: onChange, value: selectValue, onBlur: handleBlur, className: finalClassName, children: [_jsx("option", { value: "", children: placeholder !== null && placeholder !== void 0 ? placeholder : "Select..." }), listItems.map((item) => (_jsx("option", { value: item.value, children: item.label }, item.value)))] }), _jsx("span", { className: "absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none flex items-center", children: _jsx(ChevronDown, { size: 16 }) })] }) })));
|
|
136
|
+
};
|
|
137
|
+
export default Combo;
|
|
@@ -29,7 +29,7 @@ const DateField = (props) => {
|
|
|
29
29
|
const getCurrentDate = () => {
|
|
30
30
|
if (inputValue && inputValue.match(/^\d{4}-\d{2}-\d{2}$/)) {
|
|
31
31
|
// Parse ISO date string as local date to avoid timezone issues
|
|
32
|
-
const parts = inputValue.split(
|
|
32
|
+
const parts = inputValue.split("-");
|
|
33
33
|
const year = parseInt(parts[0], 10);
|
|
34
34
|
const month = parseInt(parts[1], 10) - 1; // Month is 0-indexed
|
|
35
35
|
const day = parseInt(parts[2], 10);
|
|
@@ -46,7 +46,7 @@ const DateField = (props) => {
|
|
|
46
46
|
setInputValue(text);
|
|
47
47
|
// Update calendar date when user types a valid date
|
|
48
48
|
if (text && text.match(/^\d{4}-\d{2}-\d{2}$/)) {
|
|
49
|
-
const parts = text.split(
|
|
49
|
+
const parts = text.split("-");
|
|
50
50
|
const year = parseInt(parts[0], 10);
|
|
51
51
|
const month = parseInt(parts[1], 10) - 1;
|
|
52
52
|
const day = parseInt(parts[2], 10);
|
|
@@ -103,27 +103,20 @@ const DateField = (props) => {
|
|
|
103
103
|
if (!inputValue || !inputValue.match(/^\d{4}-\d{2}-\d{2}$/))
|
|
104
104
|
return false;
|
|
105
105
|
// Parse ISO date string as local date
|
|
106
|
-
const parts = inputValue.split(
|
|
106
|
+
const parts = inputValue.split("-");
|
|
107
107
|
const selectedYear = parseInt(parts[0], 10);
|
|
108
108
|
const selectedMonth = parseInt(parts[1], 10) - 1;
|
|
109
109
|
const selectedDay = parseInt(parts[2], 10);
|
|
110
|
-
return
|
|
111
|
-
date.getMonth() === selectedMonth &&
|
|
112
|
-
date.getFullYear() === selectedYear);
|
|
110
|
+
return date.getDate() === selectedDay && date.getMonth() === selectedMonth && date.getFullYear() === selectedYear;
|
|
113
111
|
};
|
|
114
112
|
const isToday = (date) => {
|
|
115
113
|
const today = new globalThis.Date();
|
|
116
|
-
return
|
|
117
|
-
date.getMonth() === today.getMonth() &&
|
|
118
|
-
date.getFullYear() === today.getFullYear());
|
|
114
|
+
return date.getDate() === today.getDate() && date.getMonth() === today.getMonth() && date.getFullYear() === today.getFullYear();
|
|
119
115
|
};
|
|
120
|
-
const monthNames = [
|
|
121
|
-
"January", "February", "March", "April", "May", "June",
|
|
122
|
-
"July", "August", "September", "October", "November", "December"
|
|
123
|
-
];
|
|
116
|
+
const monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
124
117
|
const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
125
118
|
const calendarDays = generateCalendarDays();
|
|
126
|
-
return (_jsx(UIComponent, Object.assign({}, (props !== null && props !== void 0 ? props : {}), { children: _jsxs("div", { className: "relative", children: [
|
|
119
|
+
return (_jsx(UIComponent, Object.assign({}, (props !== null && props !== void 0 ? props : {}), { children: _jsxs("div", { className: "relative", children: [_jsx("div", { className: "flex gap-1", children: _jsx("input", { type: "date", ref: inputRef, onChange: onChange, value: inputValue, onFocus: handleFocus, onBlur: handleBlur, className: className, min: min, max: max }) }), showCalendar && (_jsxs("div", { ref: calendarRef, className: "absolute z-10 mt-1 bg-white border rounded shadow-lg p-4", style: { minWidth: "280px" }, children: [_jsxs("div", { className: "flex justify-between items-center mb-4", children: [_jsx("button", { type: "button", onClick: previousMonth, className: "px-2 py-1 hover:bg-gray-100 rounded", children: "\u25C0" }), _jsxs("div", { className: "font-semibold", children: [monthNames[calendarDate.getMonth()], " ", calendarDate.getFullYear()] }), _jsx("button", { type: "button", onClick: nextMonth, className: "px-2 py-1 hover:bg-gray-100 rounded", children: "\u25B6" })] }), _jsx("div", { className: "grid grid-cols-7 gap-1 mb-2", children: dayNames.map((day) => (_jsx("div", { className: "text-center text-xs font-medium text-gray-600 py-1", children: day }, day))) }), _jsx("div", { className: "grid grid-cols-7 gap-1", children: calendarDays.map((date, index) => {
|
|
127
120
|
if (!date) {
|
|
128
121
|
return _jsx("div", { className: "aspect-square" }, index);
|
|
129
122
|
}
|