@ramesesinc/platform-core 0.1.9 → 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.
Files changed (58) hide show
  1. package/dist/components/action/LookupPage.d.ts +2 -1
  2. package/dist/components/action/LookupPage.js +4 -3
  3. package/dist/components/action/Play.d.ts +6 -0
  4. package/dist/components/action/Play.js +40 -0
  5. package/dist/components/action/ProgressBar.d.ts +8 -0
  6. package/dist/components/action/ProgressBar.js +146 -0
  7. package/dist/components/action/ViewPage.d.ts +2 -1
  8. package/dist/components/action/ViewPage.js +19 -9
  9. package/dist/components/common/UIMenu.js +4 -3
  10. package/dist/components/index.d.ts +4 -1
  11. package/dist/components/index.js +4 -1
  12. package/dist/components/input/Combo.d.ts +21 -0
  13. package/dist/components/input/Combo.js +137 -0
  14. package/dist/components/input/DateField.js +7 -14
  15. package/dist/components/input/Text.d.ts +5 -0
  16. package/dist/components/input/Text.js +42 -7
  17. package/dist/components/list/EditableMenu.d.ts +2 -0
  18. package/dist/components/list/EditableMenu.js +128 -0
  19. package/dist/components/list/TabMenu.js +2 -2
  20. package/dist/components/list/TreeMenu.js +17 -12
  21. package/dist/components/table/DataList.d.ts +1 -1
  22. package/dist/components/table/DataList.js +49 -24
  23. package/dist/components/table/DataTable.d.ts +2 -0
  24. package/dist/components/table/DataTable.js +31 -22
  25. package/dist/components/view/FilterView.js +1 -1
  26. package/dist/components/view/HtmlForm.js +12 -9
  27. package/dist/components/view/PageView.js +36 -9
  28. package/dist/components/view/RootView.js +16 -16
  29. package/dist/core/AuthContext.js +1 -1
  30. package/dist/core/Page.js +2 -4
  31. package/dist/core/PageCache.d.ts +0 -2
  32. package/dist/core/PageCache.js +3 -8
  33. package/dist/core/PageContext.js +12 -0
  34. package/dist/core/PageViewContext.d.ts +8 -2
  35. package/dist/core/PageViewContext.js +129 -75
  36. package/dist/core/Panel.js +31 -9
  37. package/dist/index.css +79 -0
  38. package/dist/layouts/CardLayout.d.ts +2 -2
  39. package/dist/layouts/CardLayout.js +3 -4
  40. package/dist/layouts/HPanel.d.ts +2 -2
  41. package/dist/layouts/HPanel.js +1 -2
  42. package/dist/layouts/VPanel.d.ts +2 -2
  43. package/dist/layouts/VPanel.js +1 -2
  44. package/dist/layouts/index.d.ts +2 -3
  45. package/dist/layouts/index.js +2 -3
  46. package/dist/lib/utils/ExprUtil.js +18 -29
  47. package/dist/lib/utils/ResourceLoader.js +19 -7
  48. package/dist/lib/utils/SectionProvider.js +1 -1
  49. package/dist/lib/utils/initResourceLoader.d.ts +2 -0
  50. package/dist/lib/utils/initResourceLoader.js +64 -95
  51. package/dist/lib/utils/nunjucks.d.ts +2 -0
  52. package/dist/lib/utils/nunjucks.js +8 -0
  53. package/dist/templates/CrudFormTemplate.js +2 -3
  54. package/dist/templates/DataListTemplate.js +1 -1
  55. package/dist/templates/WizardTemplate.js +3 -1
  56. package/package.json +1 -1
  57. package/dist/components/input/Select.d.ts +0 -14
  58. 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, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
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 })) : (_jsxs("button", { onClick: handleClick, className: `px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors ${className}`, children: [icon && _jsx("span", { className: "dl-action-icon", children: icon }), title || "View Page"] })) }));
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,6 @@
1
+ type PlayProps = {
2
+ name?: string;
3
+ opt?: Record<string, any>;
4
+ };
5
+ declare const Play: (props: PlayProps) => import("react/jsx-runtime").JSX.Element;
6
+ export default Play;
@@ -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,8 @@
1
+ type ProgressBarProps = {
2
+ value?: number;
3
+ depends?: string;
4
+ caption?: string;
5
+ opt?: Record<string, any>;
6
+ };
7
+ declare const ProgressBar: (props: ProgressBarProps) => import("react/jsx-runtime").JSX.Element;
8
+ export default ProgressBar;
@@ -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, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
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 = (e) => {
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() === '') && dataContext.getType() === 'row') {
51
- preferredMode = "window";
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 })) : (_jsxs("button", { onClick: handleClick, className: `px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors ${className}`, children: [icon && _jsx("span", { className: "dl-action-icon", children: icon }), title || "View Page"] })) }));
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
- setMenus(Array.isArray(res) ? res : []);
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((_b = err === null || err === void 0 ? void 0 : err.message) !== null && _b !== void 0 ? _b : "Failed to load menus");
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";
@@ -27,7 +28,9 @@ export type { ShowPopupViewRef, CreatePopupViewRef, UsePopupViewResult } from ".
27
28
  export { default as AlertMessage } from "./action/AlertMessage";
28
29
  export { default as DeleteData } from "./action/DeleteData";
29
30
  export { default as Edit } from "./action/Edit";
31
+ export { default as Play } from "./action/Play";
30
32
  export { default as ProcessRunner } from "./action/ProcessRunner";
33
+ export { default as ProgressBar } from "./action/ProgressBar";
31
34
  export { default as Refresh } from "./action/Refresh";
32
35
  export { default as SaveData } from "./action/SaveData";
33
36
  export { default as SelectData } from "./action/SelectData";
@@ -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";
@@ -31,7 +32,9 @@ export { default as PopupView } from "./view/PopupView";
31
32
  export { default as AlertMessage } from "./action/AlertMessage";
32
33
  export { default as DeleteData } from "./action/DeleteData";
33
34
  export { default as Edit } from "./action/Edit";
35
+ export { default as Play } from "./action/Play";
34
36
  export { default as ProcessRunner } from "./action/ProcessRunner";
37
+ export { default as ProgressBar } from "./action/ProgressBar";
35
38
  export { default as Refresh } from "./action/Refresh";
36
39
  export { default as SaveData } from "./action/SaveData";
37
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 (date.getDate() === selectedDay &&
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 (date.getDate() === today.getDate() &&
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: [_jsxs("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 }), _jsx("button", { type: "button", onClick: toggleCalendar, className: "border rounded px-3 py-1 bg-white hover:bg-gray-50", children: "\uD83D\uDCC5" })] }), 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) => {
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
  }
@@ -1,7 +1,12 @@
1
1
  import { UIInputProps } from "../common/UIInput";
2
+ export type TextCase = "upper" | "lower" | "capitalize" | "none";
3
+ export declare const applyTextCase: (value: string, mode: TextCase) => string;
2
4
  type TextFieldProps = UIInputProps & {
3
5
  required?: boolean;
4
6
  immediate?: boolean;
7
+ align?: "left" | "center" | "right";
8
+ noSpace?: boolean;
9
+ placeholder?: string;
5
10
  };
6
11
  declare const TextField: (props: TextFieldProps) => import("react/jsx-runtime").JSX.Element;
7
12
  export default TextField;