xmlui 0.7.19 → 0.7.21
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/{apiInterceptorWorker-C3bvewX6.mjs → apiInterceptorWorker-LRHkKnha.mjs} +1 -1
- package/dist/{grammar.tmLanguage-69iP6c5d.mjs → grammar.tmLanguage-DNepe_jP.mjs} +1 -1
- package/dist/index-5NLXyjX0.mjs +31055 -0
- package/dist/index.css +1 -1
- package/dist/scripts/bin/build-lib.js +1 -1
- package/dist/scripts/bin/index.js +2 -2
- package/dist/scripts/bin/start.js +23 -6
- package/dist/scripts/bin/viteConfig.js +1 -0
- package/dist/scripts/package.json +2 -1
- package/dist/scripts/src/abstractions/ExtensionDefs.js +2 -0
- package/dist/scripts/src/components/Carousel/CarouselItemNative.js +7 -4
- package/dist/scripts/src/components/Carousel/CarouselNative.js +6 -6
- package/dist/scripts/src/components/ComponentProvider.js +171 -148
- package/dist/scripts/src/components/FormItem/FormItemNative.js +1 -1
- package/dist/scripts/src/components/HtmlTags/HtmlTags.js +33 -0
- package/dist/scripts/src/components/RawHtml/RawHtml.js +39 -0
- package/dist/scripts/src/components/RawHtml/RawHtmlNative.js +13 -0
- package/dist/scripts/src/components/Theme/ThemeNative.js +1 -1
- package/dist/scripts/src/components-core/LoaderComponent.js +1 -1
- package/dist/scripts/src/components-core/RestApiProxy.js +1 -1
- package/dist/scripts/src/components-core/StandaloneApp.js +19 -19
- package/dist/scripts/src/components-core/{StandaloneComponentManager.js → StandaloneExtensionManager.js} +6 -13
- package/dist/scripts/src/components-core/action/APICall.js +1 -1
- package/dist/scripts/src/components-core/loader/PageableLoader.js +4 -4
- package/dist/scripts/src/components-core/{AppRoot.js → rendering/AppContent.js} +60 -145
- package/dist/scripts/src/components-core/rendering/AppRoot.js +55 -0
- package/dist/scripts/src/components-core/rendering/AppWrapper.js +44 -0
- package/dist/scripts/src/components-core/{ComponentBed.js → rendering/ComponentAdapter.js} +8 -8
- package/dist/scripts/src/components-core/rendering/ComponentWrapper.js +147 -0
- package/dist/scripts/src/components-core/rendering/Container.js +576 -0
- package/dist/scripts/src/components-core/rendering/ContainerWrapper.js +82 -0
- package/dist/scripts/src/components-core/{ErrorBoundary.js → rendering/ErrorBoundary.js} +9 -3
- package/dist/scripts/src/components-core/rendering/StateContainer.js +331 -0
- package/dist/scripts/src/components-core/{container → rendering}/buildProxy.js +11 -7
- package/dist/scripts/src/components-core/{container → rendering}/collectFnVarDeps.js +2 -2
- package/dist/scripts/src/components-core/{container → rendering}/reducer.js +3 -0
- package/dist/scripts/src/components-core/rendering/renderChild.js +81 -0
- package/dist/scripts/src/index.js +3 -6
- package/dist/scripts/src/parsers/xmlui-parser/transform.js +193 -164
- package/dist/scripts/src/syntax/grammar.tmLanguage.json +1 -1
- package/dist/style.css +1 -1
- package/dist/xmlui-metadata.mjs +4216 -4232
- package/dist/xmlui-metadata.umd.js +16 -16
- package/dist/xmlui-standalone.umd.js +262 -290
- package/dist/xmlui.d.ts +36 -61
- package/dist/xmlui.mjs +1 -1
- package/package.json +2 -1
- package/dist/index-BwlAHBcX.mjs +0 -76810
- package/dist/scripts/src/components/BarChart/BarChart.js +0 -49
- package/dist/scripts/src/components/BarChart/BarChartNative.js +0 -176
- package/dist/scripts/src/components/Map/Map.js +0 -75
- package/dist/scripts/src/components/Map/world_countries.json +0 -45307
- package/dist/scripts/src/components/PieChart/PieChart.js +0 -45
- package/dist/scripts/src/components/PieChart/PieChartNative.js +0 -165
- package/dist/scripts/src/components/chart-color-schemes.js +0 -43
- package/dist/scripts/src/components-core/container/Container.js +0 -1186
- package/dist/scripts/src/components-core/container/ContainerComponentDef.js +0 -15
- /package/dist/scripts/src/components-core/{InvalidComponent.js → rendering/InvalidComponent.js} +0 -0
- /package/dist/scripts/src/components-core/{UnknownComponent.js → rendering/UnknownComponent.js} +0 -0
- /package/dist/scripts/src/components-core/{container → rendering}/valueExtractor.js +0 -0
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
|
+
};
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.Container = void 0;
|
|
49
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
50
|
+
const containers_1 = require("@components-core/abstractions/containers");
|
|
51
|
+
const AppContext_1 = require("@components-core/AppContext");
|
|
52
|
+
const buildProxy_1 = require("@components-core/rendering/buildProxy");
|
|
53
|
+
const DebugViewProvider_1 = require("@components-core/DebugViewProvider");
|
|
54
|
+
const process_statement_async_1 = require("@components-core/script-runner/process-statement-async");
|
|
55
|
+
const process_statement_sync_1 = require("@components-core/script-runner/process-statement-sync");
|
|
56
|
+
const extractParam_1 = require("@components-core/utils/extractParam");
|
|
57
|
+
const hooks_1 = require("@components-core/utils/hooks");
|
|
58
|
+
const misc_1 = require("@components-core/utils/misc");
|
|
59
|
+
const statementUtils_1 = require("@components-core/utils/statementUtils");
|
|
60
|
+
const StateViewerNative_1 = require("@components/StateViewer/StateViewerNative");
|
|
61
|
+
const lodash_es_1 = require("lodash-es");
|
|
62
|
+
const react_compose_refs_1 = require("@radix-ui/react-compose-refs");
|
|
63
|
+
const memoize_one_1 = __importDefault(require("memoize-one"));
|
|
64
|
+
const react_1 = __importStar(require("react"));
|
|
65
|
+
const react_router_dom_1 = require("react-router-dom");
|
|
66
|
+
const renderChild_1 = require("./renderChild");
|
|
67
|
+
const ThemeContext_1 = require("@components-core/theming/ThemeContext");
|
|
68
|
+
const LoaderComponent_1 = require("@components-core/LoaderComponent");
|
|
69
|
+
const constants_1 = require("@components-core/constants");
|
|
70
|
+
// React component to display a view container and implement its behavior
|
|
71
|
+
exports.Container = (0, react_1.memo)((0, react_1.forwardRef)(function Container({ node, componentState, dispatch: containerDispatch, parentDispatch, resolvedKey, version, setVersion, statePartChanged, registerComponentApi: containerRegisterComponentApi, parentRegisterComponentApi, layoutContextRef, parentRenderContext, memoedVarsRef, isImplicit, uidInfoRef: parentUidInfoRef, }, ref) {
|
|
72
|
+
var _a;
|
|
73
|
+
const { apiBoundContainer } = node;
|
|
74
|
+
const dispatch = isImplicit ? parentDispatch : containerDispatch;
|
|
75
|
+
const registerComponentApi = isImplicit
|
|
76
|
+
? parentRegisterComponentApi
|
|
77
|
+
: containerRegisterComponentApi;
|
|
78
|
+
const appContext = (0, AppContext_1.useAppContext)();
|
|
79
|
+
const { getThemeVar } = (0, ThemeContext_1.useTheme)();
|
|
80
|
+
const navigate = (0, react_router_dom_1.useNavigate)();
|
|
81
|
+
const location = (0, react_router_dom_1.useLocation)();
|
|
82
|
+
const fnsRef = (0, react_1.useRef)({});
|
|
83
|
+
const stateRef = (0, react_1.useRef)(componentState);
|
|
84
|
+
//generally bad practise to write ref in render (https://react.dev/learn/referencing-values-with-refs#best-practices-for-refs), but:
|
|
85
|
+
// this stateRef is only used in runCodeSync/async functions, which are memoized, so it's safe to use it here (as I know: illesg)
|
|
86
|
+
// In case we sync up the stateRef with the componentState in the useEffect/useInsertionEffect/useLayoutEffect, the stateRef would lag behind the componentState
|
|
87
|
+
stateRef.current = componentState;
|
|
88
|
+
const parsedStatementsRef = (0, react_1.useRef)({});
|
|
89
|
+
const [_, startTransition] = (0, react_1.useTransition)();
|
|
90
|
+
const mountedRef = (0, react_1.useRef)(true);
|
|
91
|
+
// --- This ref holds a map of promises for each statement execution that cause any state change.
|
|
92
|
+
const statementPromises = (0, react_1.useRef)(new Map());
|
|
93
|
+
// --- Ensure that re-rendering because of version change resolves all pending statement promises.
|
|
94
|
+
(0, hooks_1.useIsomorphicLayoutEffect)(() => {
|
|
95
|
+
for (const resolve of statementPromises.current.values()) {
|
|
96
|
+
resolve();
|
|
97
|
+
}
|
|
98
|
+
}, [version]);
|
|
99
|
+
// --- Ensure that component disposal resolves all pending statement promises.
|
|
100
|
+
(0, react_1.useEffect)(() => {
|
|
101
|
+
mountedRef.current = true;
|
|
102
|
+
const leftPromises = statementPromises.current;
|
|
103
|
+
return () => {
|
|
104
|
+
mountedRef.current = false;
|
|
105
|
+
for (const resolve of leftPromises.values()) {
|
|
106
|
+
resolve();
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}, []);
|
|
110
|
+
const runCodeAsync = (0, misc_1.useEvent)((source, componentUid, options, ...eventArgs) => __awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
var _a, _b, _c;
|
|
112
|
+
// --- Check if the event handler can sign its lifecycle state
|
|
113
|
+
const canSignEventLifecycle = () => componentUid.description !== undefined && (options === null || options === void 0 ? void 0 : options.eventName) !== undefined;
|
|
114
|
+
let changes = [];
|
|
115
|
+
const getComponentStateClone = () => {
|
|
116
|
+
changes.length = 0;
|
|
117
|
+
const poj = (0, lodash_es_1.cloneDeep)(Object.assign({}, stateRef.current));
|
|
118
|
+
poj["$this"] = stateRef.current[componentUid];
|
|
119
|
+
return (0, buildProxy_1.buildProxy)(poj, (changeInfo) => {
|
|
120
|
+
var _a;
|
|
121
|
+
const idRoot = (_a = changeInfo.pathArray) === null || _a === void 0 ? void 0 : _a[0];
|
|
122
|
+
if (idRoot === null || idRoot === void 0 ? void 0 : idRoot.startsWith("$")) {
|
|
123
|
+
throw new Error("Cannot update a read-only variable");
|
|
124
|
+
}
|
|
125
|
+
changes.push(changeInfo);
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
const evalAppContext = Object.assign(Object.assign({}, appContext), { getThemeVar });
|
|
129
|
+
const evalContext = {
|
|
130
|
+
appContext: evalAppContext,
|
|
131
|
+
eventArgs,
|
|
132
|
+
localContext: getComponentStateClone(),
|
|
133
|
+
implicitContextGetter: () => {
|
|
134
|
+
return {
|
|
135
|
+
uid: componentUid,
|
|
136
|
+
state: stateRef.current,
|
|
137
|
+
dispatch,
|
|
138
|
+
appContext: evalAppContext,
|
|
139
|
+
navigate,
|
|
140
|
+
location,
|
|
141
|
+
lookupAction: (action, uid, actionOptions = {}) => {
|
|
142
|
+
return lookupAction(action, uid, Object.assign(Object.assign({}, actionOptions), { ephemeral: true }));
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
},
|
|
146
|
+
options: {
|
|
147
|
+
defaultToOptionalMemberAccess: typeof ((_a = appContext.appGlobals) === null || _a === void 0 ? void 0 : _a.defaultToOptionalMemberAccess) === "boolean"
|
|
148
|
+
? appContext.appGlobals.defaultToOptionalMemberAccess
|
|
149
|
+
: true,
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
try {
|
|
153
|
+
// --- Prepare the event handler to an arrow expression statement
|
|
154
|
+
let statements;
|
|
155
|
+
if (typeof source === "string") {
|
|
156
|
+
if (!parsedStatementsRef.current[source]) {
|
|
157
|
+
parsedStatementsRef.current[source] = (0, statementUtils_1.prepareHandlerStatements)((0, statementUtils_1.parseHandlerCode)(source), evalContext);
|
|
158
|
+
}
|
|
159
|
+
statements = parsedStatementsRef.current[source];
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
statements = [
|
|
163
|
+
{
|
|
164
|
+
type: "ArrowS",
|
|
165
|
+
expression: (0, lodash_es_1.cloneDeep)(source), //TODO illesg (talk it through why we need to deep clone, it it's omitted, it gets slower every time we run it)
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
}
|
|
169
|
+
if (!(statements === null || statements === void 0 ? void 0 : statements.length)) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (canSignEventLifecycle()) {
|
|
173
|
+
// --- Sign the event handler has been started
|
|
174
|
+
dispatch({
|
|
175
|
+
type: containers_1.ContainerActionKind.EVENT_HANDLER_STARTED,
|
|
176
|
+
payload: {
|
|
177
|
+
uid: componentUid.description,
|
|
178
|
+
eventName: options.eventName,
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
let mainThreadBlockingRuns = 0;
|
|
183
|
+
yield (0, process_statement_async_1.processStatementQueueAsync)(statements, evalContext, undefined, (evalContext) => __awaiter(this, void 0, void 0, function* () {
|
|
184
|
+
if (changes.length) {
|
|
185
|
+
mainThreadBlockingRuns = 0;
|
|
186
|
+
changes.forEach((change) => {
|
|
187
|
+
statePartChanged(change.pathArray, (0, lodash_es_1.cloneDeep)(change.newValue), change.target, change.action);
|
|
188
|
+
});
|
|
189
|
+
let resolve = null;
|
|
190
|
+
const stateUpdatedPromise = new Promise((res) => {
|
|
191
|
+
resolve = () => {
|
|
192
|
+
res(null);
|
|
193
|
+
};
|
|
194
|
+
});
|
|
195
|
+
const key = (0, misc_1.generatedId)();
|
|
196
|
+
statementPromises.current.set(key, resolve);
|
|
197
|
+
// We use this to tell react that this update is not high-priority.
|
|
198
|
+
// If we don't put it to a transition, the whole app would be blocked if we run a long,
|
|
199
|
+
// update intensive queue (e.g. an infinite loop which
|
|
200
|
+
// increments a counter, see playground example learning/01_Experiments/01_Event_Framework/app ).
|
|
201
|
+
// Before this solution, we used a setTimeout(..., 0); hack, but some browsers (chrome especially)
|
|
202
|
+
// do some funky stuff with the background tabs (e.g. all the setTimeouts are
|
|
203
|
+
// maximized to run in 1 time / minute, doesn't matter if it's timeout is 0)
|
|
204
|
+
// As of 2023. June 20, this solution works with backgrounded tabs, too.
|
|
205
|
+
startTransition(() => {
|
|
206
|
+
setVersion((prev) => prev + 1);
|
|
207
|
+
});
|
|
208
|
+
//TODO this could be a problem - if this container gets unmounted, we still have to wait for the update,
|
|
209
|
+
// but in that case this update probably happened in the parent (e.g. a button's event handler removes the whole container
|
|
210
|
+
// where the button lives, but it still has some statements to run).
|
|
211
|
+
// with this solution the statement execution doesn't stop, and we fallback waiting with a setTimeout(0)
|
|
212
|
+
if (mountedRef.current) {
|
|
213
|
+
yield stateUpdatedPromise;
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
yield (0, misc_1.delay)(0);
|
|
217
|
+
}
|
|
218
|
+
statementPromises.current.delete(key);
|
|
219
|
+
changes = [];
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
//in this else branch normally we block the main thread (we don't wait for any state promise to be resolved),
|
|
223
|
+
// so in a long-running (typically infinite loop) situation, where there aren't any changes in the state
|
|
224
|
+
// we block the main thread indefinitely... this 'mainThreadBlockingRuns' var solution makes sure that
|
|
225
|
+
// we pause in every 100 runs, and let the main thread breath a bit, so it's not frozen for the whole time
|
|
226
|
+
// (we clear that counter above, too, where we use a startTransition call to de-prioritize this work)
|
|
227
|
+
mainThreadBlockingRuns++;
|
|
228
|
+
if (mainThreadBlockingRuns > 100) {
|
|
229
|
+
mainThreadBlockingRuns = 0;
|
|
230
|
+
yield (0, misc_1.delay)(0);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
evalContext.localContext = getComponentStateClone();
|
|
234
|
+
}));
|
|
235
|
+
if (canSignEventLifecycle()) {
|
|
236
|
+
// --- Sign the event handler has successfully completed
|
|
237
|
+
dispatch({
|
|
238
|
+
type: containers_1.ContainerActionKind.EVENT_HANDLER_COMPLETED,
|
|
239
|
+
payload: {
|
|
240
|
+
uid: componentUid.description,
|
|
241
|
+
eventName: options.eventName,
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
if ((_c = (_b = evalContext.mainThread) === null || _b === void 0 ? void 0 : _b.blocks) === null || _c === void 0 ? void 0 : _c.length) {
|
|
246
|
+
return evalContext.mainThread.blocks[evalContext.mainThread.blocks.length - 1]
|
|
247
|
+
.returnValue;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
catch (e) {
|
|
251
|
+
//if we pass down an event handler to a component, we should sign the error once, not in every step of the component chain
|
|
252
|
+
// (we use it in the compoundComponent, resolving it's event handlers)
|
|
253
|
+
if ((options === null || options === void 0 ? void 0 : options.signError) !== false) {
|
|
254
|
+
appContext.signError(e);
|
|
255
|
+
}
|
|
256
|
+
if (canSignEventLifecycle()) {
|
|
257
|
+
dispatch({
|
|
258
|
+
type: containers_1.ContainerActionKind.EVENT_HANDLER_ERROR,
|
|
259
|
+
payload: {
|
|
260
|
+
uid: componentUid.description,
|
|
261
|
+
eventName: options.eventName,
|
|
262
|
+
error: e,
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
throw e;
|
|
267
|
+
}
|
|
268
|
+
}));
|
|
269
|
+
const runCodeSync = (0, react_1.useCallback)((arrowExpression, ...eventArgs) => {
|
|
270
|
+
var _a, _b;
|
|
271
|
+
const evalContext = {
|
|
272
|
+
localContext: (0, lodash_es_1.cloneDeep)(stateRef.current),
|
|
273
|
+
appContext,
|
|
274
|
+
eventArgs,
|
|
275
|
+
};
|
|
276
|
+
try {
|
|
277
|
+
const arrowStmt = {
|
|
278
|
+
type: "ArrowS",
|
|
279
|
+
expression: arrowExpression,
|
|
280
|
+
};
|
|
281
|
+
(0, process_statement_sync_1.processStatementQueue)([arrowStmt], evalContext);
|
|
282
|
+
if ((_b = (_a = evalContext.mainThread) === null || _a === void 0 ? void 0 : _a.blocks) === null || _b === void 0 ? void 0 : _b.length) {
|
|
283
|
+
return evalContext.mainThread.blocks[evalContext.mainThread.blocks.length - 1]
|
|
284
|
+
.returnValue;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
catch (e) {
|
|
288
|
+
console.error(e);
|
|
289
|
+
throw e;
|
|
290
|
+
}
|
|
291
|
+
}, [appContext]);
|
|
292
|
+
const getOrCreateEventHandlerFn = (0, misc_1.useEvent)((src, uid, options) => {
|
|
293
|
+
var _a;
|
|
294
|
+
const stringSrc = typeof src === "string" ? src : src.statement.source;
|
|
295
|
+
const fnCacheKey = `${options === null || options === void 0 ? void 0 : options.eventName};${stringSrc}`;
|
|
296
|
+
const handler = (...eventArgs) => {
|
|
297
|
+
return runCodeAsync(src, uid, options, ...(0, lodash_es_1.cloneDeep)(eventArgs));
|
|
298
|
+
};
|
|
299
|
+
if (options === null || options === void 0 ? void 0 : options.ephemeral) {
|
|
300
|
+
return handler;
|
|
301
|
+
}
|
|
302
|
+
if (!((_a = fnsRef.current[uid]) === null || _a === void 0 ? void 0 : _a[fnCacheKey])) {
|
|
303
|
+
fnsRef.current[uid] = fnsRef.current[uid] || {};
|
|
304
|
+
fnsRef.current[uid][fnCacheKey] = handler;
|
|
305
|
+
}
|
|
306
|
+
return fnsRef.current[uid][fnCacheKey];
|
|
307
|
+
});
|
|
308
|
+
const getOrCreateSyncCallbackFn = (0, react_1.useCallback)((arrowExpression, uid) => {
|
|
309
|
+
var _a;
|
|
310
|
+
const fnCacheKey = `sync-callback-${arrowExpression.source}`;
|
|
311
|
+
if (!((_a = fnsRef.current[uid]) === null || _a === void 0 ? void 0 : _a[fnCacheKey])) {
|
|
312
|
+
fnsRef.current[uid] = fnsRef.current[uid] || {};
|
|
313
|
+
fnsRef.current[uid][fnCacheKey] = (0, memoize_one_1.default)((arrowExpression) => {
|
|
314
|
+
// console.log('busting sync callback cache', arrowExpression);
|
|
315
|
+
return (...eventArgs) => {
|
|
316
|
+
// console.log("calling sync callback", arrowExpression);
|
|
317
|
+
return runCodeSync(arrowExpression, ...eventArgs);
|
|
318
|
+
};
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
return fnsRef.current[uid][fnCacheKey](arrowExpression);
|
|
322
|
+
}, [runCodeSync]);
|
|
323
|
+
const lookupSyncCallback = (0, react_1.useCallback)((action, uid) => {
|
|
324
|
+
if (!action) {
|
|
325
|
+
return undefined;
|
|
326
|
+
}
|
|
327
|
+
if (typeof action === "function") {
|
|
328
|
+
return action;
|
|
329
|
+
}
|
|
330
|
+
// const resolvedAction = extractParam(componentState, action, appContext, true);
|
|
331
|
+
if (!action) {
|
|
332
|
+
return undefined;
|
|
333
|
+
}
|
|
334
|
+
if (typeof action === "function") {
|
|
335
|
+
return action;
|
|
336
|
+
}
|
|
337
|
+
if (!action._ARROW_EXPR_) {
|
|
338
|
+
throw new Error("Only arrow expression allowed in sync callback");
|
|
339
|
+
}
|
|
340
|
+
return getOrCreateSyncCallbackFn(action, uid);
|
|
341
|
+
}, [getOrCreateSyncCallbackFn]);
|
|
342
|
+
const lookupAction = (0, react_1.useCallback)((action, uid, options) => {
|
|
343
|
+
let safeAction = action;
|
|
344
|
+
if (!action && uid.description && (options === null || options === void 0 ? void 0 : options.eventName)) {
|
|
345
|
+
const handlerFnName = `${uid.description}_on${(0, misc_1.capitalizeFirstLetter)(options === null || options === void 0 ? void 0 : options.eventName)}`;
|
|
346
|
+
if (componentState[handlerFnName] && componentState[handlerFnName]._ARROW_EXPR_) {
|
|
347
|
+
safeAction = componentState[handlerFnName];
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (!safeAction) {
|
|
351
|
+
return undefined;
|
|
352
|
+
}
|
|
353
|
+
if (typeof safeAction === "function") {
|
|
354
|
+
return safeAction;
|
|
355
|
+
}
|
|
356
|
+
return getOrCreateEventHandlerFn(safeAction, uid, options);
|
|
357
|
+
}, [componentState, getOrCreateEventHandlerFn]);
|
|
358
|
+
const isApiRegisteredInnerRef = (0, react_1.useRef)(false);
|
|
359
|
+
(0, react_1.useEffect)(() => {
|
|
360
|
+
if (!node.api) {
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (!node.containerUid) {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
if (isApiRegisteredInnerRef.current) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
isApiRegisteredInnerRef.current = true;
|
|
370
|
+
const api = {};
|
|
371
|
+
const self = Symbol("$self");
|
|
372
|
+
Object.entries(node.api).forEach(([key, value]) => {
|
|
373
|
+
api[key] = lookupAction(value, self);
|
|
374
|
+
});
|
|
375
|
+
if (!isImplicit) {
|
|
376
|
+
registerComponentApi(self, api); //we register the api as $self for the compound components,
|
|
377
|
+
}
|
|
378
|
+
parentRegisterComponentApi(node.containerUid, api); // and register it for the parent component instance
|
|
379
|
+
}, [
|
|
380
|
+
lookupAction,
|
|
381
|
+
node.api,
|
|
382
|
+
node.containerUid,
|
|
383
|
+
node.uid,
|
|
384
|
+
isImplicit,
|
|
385
|
+
parentRegisterComponentApi,
|
|
386
|
+
registerComponentApi,
|
|
387
|
+
]);
|
|
388
|
+
const cleanup = (0, misc_1.useEvent)((uid) => {
|
|
389
|
+
// console.log("CLEANUP CALLED FOR", node);
|
|
390
|
+
//TODO cleanup registered component api for that uid
|
|
391
|
+
//TODO cleanup state for that uid
|
|
392
|
+
delete fnsRef.current[uid];
|
|
393
|
+
});
|
|
394
|
+
// --- The container wraps the `renderChild` function to provide that to the child components
|
|
395
|
+
const stableRenderChild = (0, react_1.useCallback)((childNode, lc, pRenderContext, uidInfoRef) => {
|
|
396
|
+
// TODO: Check if this is a valid use case
|
|
397
|
+
if (typeof childNode === "string") {
|
|
398
|
+
throw Error("should be resolved for now");
|
|
399
|
+
}
|
|
400
|
+
// --- Make children an array if it's not
|
|
401
|
+
const children = (0, lodash_es_1.isArray)(childNode) ? childNode : [childNode];
|
|
402
|
+
if (!children || !children.length) {
|
|
403
|
+
// --- No child, nothing to render
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
// --- If there are multiple children, we need to add a `key` to each of them
|
|
407
|
+
const wrapWithFragment = children.length > 1;
|
|
408
|
+
// --- Render each child
|
|
409
|
+
const renderedChildren = children.map((child, childIndex) => {
|
|
410
|
+
if (!child) {
|
|
411
|
+
// --- No child, nothing to render: Should not happen
|
|
412
|
+
return undefined;
|
|
413
|
+
}
|
|
414
|
+
// --- Invoke the jolly-joker `renderChild` function to render the child. Note that
|
|
415
|
+
// --- in ithe context, we pass the `stableRenderChild` function, so the child can
|
|
416
|
+
// --- render its children recursively.
|
|
417
|
+
const renderedChild = (0, renderChild_1.renderChild)({
|
|
418
|
+
node: child,
|
|
419
|
+
state: componentState,
|
|
420
|
+
dispatch,
|
|
421
|
+
appContext,
|
|
422
|
+
lookupAction,
|
|
423
|
+
lookupSyncCallback,
|
|
424
|
+
registerComponentApi,
|
|
425
|
+
renderChild: stableRenderChild,
|
|
426
|
+
statePartChanged: statePartChanged,
|
|
427
|
+
layoutContext: lc,
|
|
428
|
+
parentRenderContext: pRenderContext,
|
|
429
|
+
memoedVarsRef,
|
|
430
|
+
cleanup,
|
|
431
|
+
uidInfoRef,
|
|
432
|
+
});
|
|
433
|
+
if (renderedChild === undefined) {
|
|
434
|
+
// --- No displayable child, nothing to render
|
|
435
|
+
return undefined;
|
|
436
|
+
}
|
|
437
|
+
// --- Let's process the rendered child
|
|
438
|
+
let rendered = renderedChild;
|
|
439
|
+
const key = `${childIndex}_${child.uid}`;
|
|
440
|
+
if (wrapWithFragment) {
|
|
441
|
+
// --- Add the `key` attribute to the child
|
|
442
|
+
if (react_1.default.isValidElement(renderedChild)) {
|
|
443
|
+
// --- React can display this element
|
|
444
|
+
rendered = react_1.default.cloneElement(renderedChild, { key });
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
// --- A simple text node (or alike). We need to wrap it in a `Fragment`
|
|
448
|
+
rendered = (0, jsx_runtime_1.jsx)(react_1.Fragment, { children: renderedChild }, key);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
// --- Done.
|
|
452
|
+
return rendered;
|
|
453
|
+
});
|
|
454
|
+
// --- At this point we have a React node for each child
|
|
455
|
+
if (renderedChildren.length === 1) {
|
|
456
|
+
// --- If we have a single (and valid React element) child, we compose its
|
|
457
|
+
// --- `ref` with the parent's `ref`. This allows the parent to access the child's
|
|
458
|
+
// --- DOM node. Otherwise, we use the child as is.
|
|
459
|
+
return ref && renderedChildren[0] && (0, react_1.isValidElement)(renderedChildren[0])
|
|
460
|
+
? react_1.default.cloneElement(renderedChildren[0], {
|
|
461
|
+
ref: (0, react_compose_refs_1.composeRefs)(ref, renderedChildren[0].ref),
|
|
462
|
+
})
|
|
463
|
+
: renderedChildren[0];
|
|
464
|
+
}
|
|
465
|
+
// --- Done.
|
|
466
|
+
return renderedChildren;
|
|
467
|
+
}, [
|
|
468
|
+
componentState,
|
|
469
|
+
dispatch,
|
|
470
|
+
appContext,
|
|
471
|
+
lookupAction,
|
|
472
|
+
lookupSyncCallback,
|
|
473
|
+
registerComponentApi,
|
|
474
|
+
statePartChanged,
|
|
475
|
+
memoedVarsRef,
|
|
476
|
+
cleanup,
|
|
477
|
+
ref,
|
|
478
|
+
]);
|
|
479
|
+
// --- Log the component state if you need it for debugging
|
|
480
|
+
if ((_a = node.props) === null || _a === void 0 ? void 0 : _a.debug) {
|
|
481
|
+
console.log(`Container: ${resolvedKey}`, {
|
|
482
|
+
componentState,
|
|
483
|
+
node,
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
// --- Use this object to store information about already rendered UIDs.
|
|
487
|
+
// --- We do not allow any action, loader, or transform to use the same UID; however (as of now) children
|
|
488
|
+
// --- may use the same UID.
|
|
489
|
+
const uidInfo = {};
|
|
490
|
+
const thisUidInfoRef = (0, react_1.useRef)({});
|
|
491
|
+
const uidInfoRef = node.uses === undefined ? parentUidInfoRef : thisUidInfoRef;
|
|
492
|
+
const debugContext = (0, DebugViewProvider_1.useDebugView)();
|
|
493
|
+
const stateViewProps = debugContext === null || debugContext === void 0 ? void 0 : debugContext.stateViewOptions;
|
|
494
|
+
const showContainer = stateViewProps && debugContext.displayStateView;
|
|
495
|
+
return ((0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [showContainer && ((0, jsx_runtime_1.jsxs)(StateViewerNative_1.StateViewer, { state: componentState, showBoundary: stateViewProps === null || stateViewProps === void 0 ? void 0 : stateViewProps.showBoundary, blink: stateViewProps === null || stateViewProps === void 0 ? void 0 : stateViewProps.blink, children: [renderLoaders({
|
|
496
|
+
uidInfo,
|
|
497
|
+
uidInfoRef,
|
|
498
|
+
loaders: node.loaders,
|
|
499
|
+
componentState,
|
|
500
|
+
memoedVarsRef,
|
|
501
|
+
//if it's an api bound container, we always use this container, otherwise use the parent if it's an implicit one
|
|
502
|
+
dispatch: apiBoundContainer ? containerDispatch : dispatch,
|
|
503
|
+
registerComponentApi: apiBoundContainer
|
|
504
|
+
? containerRegisterComponentApi
|
|
505
|
+
: registerComponentApi,
|
|
506
|
+
appContext,
|
|
507
|
+
lookupAction,
|
|
508
|
+
lookupSyncCallback,
|
|
509
|
+
cleanup,
|
|
510
|
+
}), stableRenderChild(node.children, layoutContextRef === null || layoutContextRef === void 0 ? void 0 : layoutContextRef.current, parentRenderContext, uidInfoRef)] })), !showContainer && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [renderLoaders({
|
|
511
|
+
uidInfo,
|
|
512
|
+
uidInfoRef,
|
|
513
|
+
loaders: node.loaders,
|
|
514
|
+
componentState,
|
|
515
|
+
memoedVarsRef,
|
|
516
|
+
//if it's an api bound container, we always use this container, otherwise use the parent if it's an implicit one
|
|
517
|
+
dispatch: apiBoundContainer ? containerDispatch : dispatch,
|
|
518
|
+
registerComponentApi: apiBoundContainer
|
|
519
|
+
? containerRegisterComponentApi
|
|
520
|
+
: registerComponentApi,
|
|
521
|
+
appContext,
|
|
522
|
+
lookupAction,
|
|
523
|
+
lookupSyncCallback,
|
|
524
|
+
cleanup,
|
|
525
|
+
}), stableRenderChild(node.children, layoutContextRef === null || layoutContextRef === void 0 ? void 0 : layoutContextRef.current, parentRenderContext, uidInfoRef)] }))] }, node.uid
|
|
526
|
+
? `${resolvedKey}>${(0, extractParam_1.extractParam)(componentState, node.uid, appContext, true)}`
|
|
527
|
+
: undefined));
|
|
528
|
+
}));
|
|
529
|
+
function renderLoaders({ uidInfo, uidInfoRef, loaders = constants_1.EMPTY_ARRAY, componentState, dispatch, appContext, registerComponentApi, lookupAction, lookupSyncCallback, cleanup, memoedVarsRef, }) {
|
|
530
|
+
return loaders.map((loader) => {
|
|
531
|
+
// --- Check for the uniqueness of UIDs
|
|
532
|
+
if (loader === null || loader === void 0 ? void 0 : loader.uid) {
|
|
533
|
+
if (uidInfo[loader.uid]) {
|
|
534
|
+
// --- We have a duplicated ID (another loader)
|
|
535
|
+
throw new Error(`Another ${uidInfo[loader.uid]} definition in this container already uses the uid '${loader.uid}'`);
|
|
536
|
+
}
|
|
537
|
+
uidInfo[loader.uid] = "loader";
|
|
538
|
+
uidInfoRef.current[loader.uid] = {
|
|
539
|
+
type: "loader",
|
|
540
|
+
value: "loaderValue",
|
|
541
|
+
uid: loader.uid,
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
// --- Render the current loader
|
|
545
|
+
const renderedLoader = renderLoader({
|
|
546
|
+
loader,
|
|
547
|
+
componentState,
|
|
548
|
+
dispatch,
|
|
549
|
+
appContext,
|
|
550
|
+
registerComponentApi,
|
|
551
|
+
lookupAction,
|
|
552
|
+
lookupSyncCallback,
|
|
553
|
+
memoedVarsRef,
|
|
554
|
+
cleanup,
|
|
555
|
+
});
|
|
556
|
+
// --- Skip loaders with rendering errors
|
|
557
|
+
if (renderedLoader === undefined) {
|
|
558
|
+
return undefined;
|
|
559
|
+
}
|
|
560
|
+
// --- Take care to use a key property for the loader
|
|
561
|
+
return (0, jsx_runtime_1.jsx)(react_1.Fragment, { children: renderedLoader }, loader.uid);
|
|
562
|
+
});
|
|
563
|
+
function renderLoader({ loader, componentState, dispatch, appContext, registerComponentApi, lookupAction, lookupSyncCallback, cleanup, memoedVarsRef, }) {
|
|
564
|
+
// --- For the sake of avoiding further issues
|
|
565
|
+
if (!loader) {
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
// --- Evaluate "when" to decide if the loader should be rendered
|
|
569
|
+
// --- Render only visible components
|
|
570
|
+
if (!(0, extractParam_1.shouldKeep)(loader.when, componentState, appContext)) {
|
|
571
|
+
return null;
|
|
572
|
+
}
|
|
573
|
+
// --- Use the loader type's renderer function
|
|
574
|
+
return ((0, jsx_runtime_1.jsx)(LoaderComponent_1.LoaderComponent, { onUnmount: cleanup, node: loader, state: componentState, dispatch: dispatch, registerComponentApi: registerComponentApi, lookupAction: lookupAction, lookupSyncCallback: lookupSyncCallback, memoedVarsRef: memoedVarsRef, appContext: appContext }));
|
|
575
|
+
}
|
|
576
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContainerWrapper = void 0;
|
|
4
|
+
exports.isContainerLike = isContainerLike;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const ErrorBoundary_1 = require("@components-core/rendering/ErrorBoundary");
|
|
7
|
+
const react_1 = require("react");
|
|
8
|
+
const StateContainer_1 = require("./StateContainer");
|
|
9
|
+
/**
|
|
10
|
+
* This function checks if a particular component needs a wrapping container to
|
|
11
|
+
* manage its internal state, which is closed from its external context but
|
|
12
|
+
* available to its children.
|
|
13
|
+
* @param node The component definition node to check
|
|
14
|
+
* @returns Tru, if the component needs a wrapping container
|
|
15
|
+
*/
|
|
16
|
+
function isContainerLike(node) {
|
|
17
|
+
if (node.type === "Container") {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
// --- If any of the following properties have a value, we need a container
|
|
21
|
+
return !!(node.loaders ||
|
|
22
|
+
node.vars ||
|
|
23
|
+
node.uses ||
|
|
24
|
+
node.contextVars ||
|
|
25
|
+
node.functions ||
|
|
26
|
+
node.scriptCollected);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* This component is a container that manages the state of its children. It
|
|
30
|
+
* provides a context for the children to access the state and the API of the
|
|
31
|
+
* parent component.
|
|
32
|
+
*/
|
|
33
|
+
exports.ContainerWrapper = (0, react_1.memo)((0, react_1.forwardRef)(function ContainerWrapper({ node, resolvedKey, parentState, parentStatePartChanged, parentRegisterComponentApi, parentDispatch, parentRenderContext, layoutContextRef, uidInfoRef, }, ref) {
|
|
34
|
+
// --- Make sure the component node is wrapped with a container
|
|
35
|
+
const containerizedNode = (0, react_1.useMemo)(() => getWrappedWithContainer(node), [node]);
|
|
36
|
+
return ((0, jsx_runtime_1.jsx)(ErrorBoundary_1.ErrorBoundary, { node: node, location: "container", children: (0, jsx_runtime_1.jsx)(StateContainer_1.StateContainer, { node: containerizedNode, resolvedKey: resolvedKey, parentState: parentState, parentStatePartChanged: parentStatePartChanged, parentRegisterComponentApi: parentRegisterComponentApi, parentDispatch: parentDispatch, parentRenderContext: parentRenderContext, layoutContextRef: layoutContextRef, uidInfoRef: uidInfoRef, isImplicit: node.type !== "Container" && containerizedNode.uses === undefined, ref: ref }) }));
|
|
37
|
+
}));
|
|
38
|
+
/**
|
|
39
|
+
* Wraps the specified component node with a container
|
|
40
|
+
* @param node The component node to wrap
|
|
41
|
+
* @returns A "Container" node
|
|
42
|
+
*/
|
|
43
|
+
const getWrappedWithContainer = (node) => {
|
|
44
|
+
var _a, _b;
|
|
45
|
+
if (node.type === "Container") {
|
|
46
|
+
// --- Already wrapped
|
|
47
|
+
return node;
|
|
48
|
+
}
|
|
49
|
+
// --- Clone the node and remove the properties that will be moved to the container
|
|
50
|
+
// --- Note: we need the "when" property in the ModalDialog component, so we don't remove it
|
|
51
|
+
const wrappedNode = Object.assign(Object.assign({}, node), { props: Object.assign({}, node.props) });
|
|
52
|
+
delete wrappedNode.loaders;
|
|
53
|
+
delete wrappedNode.vars;
|
|
54
|
+
delete wrappedNode.functions;
|
|
55
|
+
delete wrappedNode.script;
|
|
56
|
+
delete wrappedNode.scriptCollected;
|
|
57
|
+
delete wrappedNode.scriptError;
|
|
58
|
+
delete wrappedNode.uses;
|
|
59
|
+
(_a = wrappedNode.props) === null || _a === void 0 ? true : delete _a.uses;
|
|
60
|
+
delete wrappedNode.api;
|
|
61
|
+
delete wrappedNode.contextVars;
|
|
62
|
+
// --- Do the wrapping
|
|
63
|
+
return {
|
|
64
|
+
type: "Container",
|
|
65
|
+
uid: node.uid,
|
|
66
|
+
when: node.when,
|
|
67
|
+
loaders: node.loaders,
|
|
68
|
+
vars: node.vars,
|
|
69
|
+
functions: node.functions,
|
|
70
|
+
scriptCollected: node.scriptCollected,
|
|
71
|
+
scriptError: node.scriptError,
|
|
72
|
+
uses: node.uses,
|
|
73
|
+
api: node.api,
|
|
74
|
+
containerUid: node === null || node === void 0 ? void 0 : node.containerUid,
|
|
75
|
+
apiBoundContainer: node === null || node === void 0 ? void 0 : node.apiBoundContainer,
|
|
76
|
+
contextVars: node.contextVars,
|
|
77
|
+
props: {
|
|
78
|
+
debug: (_b = node.props) === null || _b === void 0 ? void 0 : _b.debug,
|
|
79
|
+
},
|
|
80
|
+
children: [wrappedNode],
|
|
81
|
+
};
|
|
82
|
+
};
|