a2uink 0.1.0
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/.eslintignore +4 -0
- package/.eslintrc.cjs +21 -0
- package/.gitattributes +5 -0
- package/.github/copilot-instructions.md +21 -0
- package/.github/workflows/ci.yml +31 -0
- package/.husky/pre-commit +6 -0
- package/.prettierignore +6 -0
- package/.prettierrc +7 -0
- package/README.md +44 -0
- package/dist/binding.d.ts +3 -0
- package/dist/binding.js +73 -0
- package/dist/catalog.d.ts +6 -0
- package/dist/catalog.js +165 -0
- package/dist/examples/demo.d.ts +1 -0
- package/dist/examples/demo.js +309 -0
- package/dist/focus.d.ts +15 -0
- package/dist/focus.js +68 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/renderer.d.ts +6 -0
- package/dist/renderer.js +144 -0
- package/dist/src/binding.d.ts +8 -0
- package/dist/src/binding.js +141 -0
- package/dist/src/catalog.d.ts +2 -0
- package/dist/src/catalog.js +1 -0
- package/dist/src/components/Box.d.ts +6 -0
- package/dist/src/components/Box.js +23 -0
- package/dist/src/components/Button.d.ts +7 -0
- package/dist/src/components/Button.js +71 -0
- package/dist/src/components/Chart.d.ts +5 -0
- package/dist/src/components/Chart.js +65 -0
- package/dist/src/components/Checkbox.d.ts +7 -0
- package/dist/src/components/Checkbox.js +51 -0
- package/dist/src/components/DateTimeInput.d.ts +1 -0
- package/dist/src/components/DateTimeInput.js +1 -0
- package/dist/src/components/Divider.d.ts +5 -0
- package/dist/src/components/Divider.js +7 -0
- package/dist/src/components/Image.d.ts +5 -0
- package/dist/src/components/Image.js +8 -0
- package/dist/src/components/Input.d.ts +7 -0
- package/dist/src/components/Input.js +124 -0
- package/dist/src/components/List.d.ts +5 -0
- package/dist/src/components/List.js +9 -0
- package/dist/src/components/Modal.d.ts +6 -0
- package/dist/src/components/Modal.js +13 -0
- package/dist/src/components/RadioGroup.d.ts +7 -0
- package/dist/src/components/RadioGroup.js +56 -0
- package/dist/src/components/Select.d.ts +7 -0
- package/dist/src/components/Select.js +66 -0
- package/dist/src/components/Slider.d.ts +7 -0
- package/dist/src/components/Slider.js +74 -0
- package/dist/src/components/Spacer.d.ts +1 -0
- package/dist/src/components/Spacer.js +1 -0
- package/dist/src/components/Table.d.ts +5 -0
- package/dist/src/components/Table.js +14 -0
- package/dist/src/components/Tabs.d.ts +7 -0
- package/dist/src/components/Tabs.js +56 -0
- package/dist/src/components/Text.d.ts +5 -0
- package/dist/src/components/Text.js +15 -0
- package/dist/src/components/helpers.d.ts +4 -0
- package/dist/src/components/helpers.js +39 -0
- package/dist/src/components/index.d.ts +16 -0
- package/dist/src/components/index.js +15 -0
- package/dist/src/components/renderNode.d.ts +4 -0
- package/dist/src/components/renderNode.js +61 -0
- package/dist/src/components/types.d.ts +7 -0
- package/dist/src/components/types.js +1 -0
- package/dist/src/components.d.ts +1 -0
- package/dist/src/components.js +1 -0
- package/dist/src/focus.d.ts +15 -0
- package/dist/src/focus.js +68 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +1 -0
- package/dist/src/renderer.d.ts +6 -0
- package/dist/src/renderer.js +673 -0
- package/dist/src/tree.d.ts +2 -0
- package/dist/src/tree.js +47 -0
- package/dist/src/types.d.ts +92 -0
- package/dist/src/types.js +1 -0
- package/dist/tree.d.ts +2 -0
- package/dist/tree.js +45 -0
- package/dist/types.d.ts +73 -0
- package/dist/types.js +1 -0
- package/docs/demo/README.md +90 -0
- package/docs/demo/app.js +268 -0
- package/docs/demo/index.html +14 -0
- package/docs/demo/package-lock.json +4512 -0
- package/docs/demo/package.json +32 -0
- package/docs/demo/src/App.tsx +1403 -0
- package/docs/demo/src/main.tsx +9 -0
- package/docs/demo/src/setEnv.ts +29 -0
- package/docs/demo/src/shims/fs.js +16 -0
- package/docs/demo/src/shims/process.js +10 -0
- package/docs/demo/src/styles.css +720 -0
- package/docs/demo/styles.css +1 -0
- package/docs/demo/tsconfig.json +14 -0
- package/docs/demo/vite-plugin-node-polyfills/shims/buffer +2 -0
- package/docs/demo/vite-plugin-node-polyfills/shims/global +2 -0
- package/docs/demo/vite-plugin-node-polyfills/shims/process +10 -0
- package/docs/demo/vite.config.js +200 -0
- package/docs/overview.md +277 -0
- package/examples/demo.d.ts +1 -0
- package/examples/demo.js +66 -0
- package/examples/demo.ts +315 -0
- package/package.json +48 -0
- package/src/binding.ts +191 -0
- package/src/catalog.ts +2 -0
- package/src/components/Box.ts +39 -0
- package/src/components/Button.ts +84 -0
- package/src/components/Checkbox.ts +66 -0
- package/src/components/DateTimeInput.ts +1 -0
- package/src/components/Divider.ts +8 -0
- package/src/components/Image.ts +15 -0
- package/src/components/Input.ts +148 -0
- package/src/components/List.ts +15 -0
- package/src/components/Modal.ts +21 -0
- package/src/components/RadioGroup.ts +77 -0
- package/src/components/Select.ts +94 -0
- package/src/components/Slider.ts +98 -0
- package/src/components/Spacer.ts +1 -0
- package/src/components/Table.ts +22 -0
- package/src/components/Tabs.ts +82 -0
- package/src/components/Text.ts +21 -0
- package/src/components/helpers.ts +42 -0
- package/src/components/index.ts +16 -0
- package/src/components/renderNode.ts +73 -0
- package/src/components/types.ts +8 -0
- package/src/components.ts +1 -0
- package/src/focus.ts +94 -0
- package/src/index.ts +12 -0
- package/src/renderer.ts +779 -0
- package/src/tree.ts +63 -0
- package/src/types.ts +110 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box, render, Text, useInput, useStdout } from "ink";
|
|
3
|
+
import { resolveBoundValue, setBoundValue } from "./binding.js";
|
|
4
|
+
import { FocusProvider, useFocusRegistry } from "./focus.js";
|
|
5
|
+
import { buildResolvedTree } from "./tree.js";
|
|
6
|
+
import { renderNode } from "./catalog.js";
|
|
7
|
+
export function createA2uiInkRenderer(options = {}) {
|
|
8
|
+
const surfaces = new Map();
|
|
9
|
+
let inkInstance = null;
|
|
10
|
+
const updateLocalDataModel = (surfaceId, path, value, node) => {
|
|
11
|
+
const surface = surfaces.get(surfaceId);
|
|
12
|
+
if (!surface) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
surface.dataModel = setBoundValue(path, surface.dataModel, node.bindingContext, value);
|
|
16
|
+
renderSurfaces();
|
|
17
|
+
};
|
|
18
|
+
const ensureSurface = (surfaceId) => {
|
|
19
|
+
const existing = surfaces.get(surfaceId);
|
|
20
|
+
if (existing) {
|
|
21
|
+
return existing;
|
|
22
|
+
}
|
|
23
|
+
const created = {
|
|
24
|
+
surfaceId,
|
|
25
|
+
components: {},
|
|
26
|
+
dataModel: {},
|
|
27
|
+
renderReady: false
|
|
28
|
+
};
|
|
29
|
+
surfaces.set(surfaceId, created);
|
|
30
|
+
return created;
|
|
31
|
+
};
|
|
32
|
+
const renderSurfaces = () => {
|
|
33
|
+
var _a, _b;
|
|
34
|
+
const surface = Array.from(surfaces.values()).find((entry) => entry.renderReady && entry.rootComponentId);
|
|
35
|
+
const element = React.createElement(A2uiRoot, {
|
|
36
|
+
surface: surface !== null && surface !== void 0 ? surface : null,
|
|
37
|
+
onUserAction: options.onUserAction,
|
|
38
|
+
onLocalDataModelUpdate: updateLocalDataModel
|
|
39
|
+
});
|
|
40
|
+
if (!inkInstance) {
|
|
41
|
+
const canPatchConsole = typeof console !== "undefined" && typeof console.Console === "function";
|
|
42
|
+
const renderOptions = {
|
|
43
|
+
exitOnCtrlC: (_a = options.exitOnCtrlC) !== null && _a !== void 0 ? _a : true,
|
|
44
|
+
patchConsole: (_b = options.patchConsole) !== null && _b !== void 0 ? _b : canPatchConsole
|
|
45
|
+
};
|
|
46
|
+
if (options.stdin) {
|
|
47
|
+
renderOptions.stdin = options.stdin;
|
|
48
|
+
}
|
|
49
|
+
if (options.stdout) {
|
|
50
|
+
renderOptions.stdout = options.stdout;
|
|
51
|
+
}
|
|
52
|
+
if (options.stderr) {
|
|
53
|
+
renderOptions.stderr = options.stderr;
|
|
54
|
+
}
|
|
55
|
+
inkInstance = render(element, renderOptions);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
inkInstance.clear();
|
|
59
|
+
inkInstance.rerender(element);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const handleMessage = (message) => {
|
|
63
|
+
switch (message.type) {
|
|
64
|
+
case "beginRendering": {
|
|
65
|
+
const surface = ensureSurface(message.surfaceId);
|
|
66
|
+
surface.catalogId = message.catalogId;
|
|
67
|
+
surface.renderReady = true;
|
|
68
|
+
renderSurfaces();
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case "surfaceUpdate": {
|
|
72
|
+
const surface = ensureSurface(message.surfaceId);
|
|
73
|
+
surface.rootComponentId = message.rootComponentId;
|
|
74
|
+
surface.components = message.components.reduce((acc, component) => {
|
|
75
|
+
const normalized = normalizeComponentDef(component);
|
|
76
|
+
if (normalized) {
|
|
77
|
+
acc[normalized.id] = normalized;
|
|
78
|
+
}
|
|
79
|
+
return acc;
|
|
80
|
+
}, {});
|
|
81
|
+
renderSurfaces();
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
case "dataModelUpdate": {
|
|
85
|
+
const surface = ensureSurface(message.surfaceId);
|
|
86
|
+
if (message.dataModel) {
|
|
87
|
+
surface.dataModel = mergeDataModel(surface.dataModel, message.dataModel);
|
|
88
|
+
}
|
|
89
|
+
else if (message.contents) {
|
|
90
|
+
surface.dataModel = applyDataModelUpdate(surface.dataModel, message.path, message.contents);
|
|
91
|
+
}
|
|
92
|
+
renderSurfaces();
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
case "deleteSurface": {
|
|
96
|
+
surfaces.delete(message.surfaceId);
|
|
97
|
+
renderSurfaces();
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
default:
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const dispose = () => {
|
|
105
|
+
inkInstance === null || inkInstance === void 0 ? void 0 : inkInstance.unmount();
|
|
106
|
+
inkInstance = null;
|
|
107
|
+
};
|
|
108
|
+
return { handleMessage, dispose };
|
|
109
|
+
}
|
|
110
|
+
const A2uiRoot = ({ surface, onUserAction, onLocalDataModelUpdate }) => {
|
|
111
|
+
if (!surface || !surface.rootComponentId) {
|
|
112
|
+
return React.createElement(Text, null, "No surface");
|
|
113
|
+
}
|
|
114
|
+
const tree = buildResolvedTree(surface.components, surface.rootComponentId, surface.dataModel);
|
|
115
|
+
if (!tree) {
|
|
116
|
+
return React.createElement(Text, null, "Invalid surface");
|
|
117
|
+
}
|
|
118
|
+
return React.createElement(FocusProvider, null, React.createElement(FocusInputHandler), React.createElement(RootContainer, null, React.createElement(RenderTree, {
|
|
119
|
+
surfaceId: surface.surfaceId,
|
|
120
|
+
tree,
|
|
121
|
+
dataModel: surface.dataModel,
|
|
122
|
+
onUserAction,
|
|
123
|
+
onLocalDataModelUpdate
|
|
124
|
+
})));
|
|
125
|
+
};
|
|
126
|
+
const FocusInputHandler = () => {
|
|
127
|
+
const focus = useFocusRegistry();
|
|
128
|
+
useInput((input, key) => {
|
|
129
|
+
if (key.tab) {
|
|
130
|
+
if (key.shift) {
|
|
131
|
+
focus.focusPrev();
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
focus.focusNext();
|
|
135
|
+
}
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
focus.handleKey(input, key);
|
|
139
|
+
});
|
|
140
|
+
return null;
|
|
141
|
+
};
|
|
142
|
+
const RootContainer = ({ children }) => {
|
|
143
|
+
var _a, _b;
|
|
144
|
+
const { stdout } = useStdout();
|
|
145
|
+
const width = (_a = stdout === null || stdout === void 0 ? void 0 : stdout.columns) !== null && _a !== void 0 ? _a : undefined;
|
|
146
|
+
const height = (_b = stdout === null || stdout === void 0 ? void 0 : stdout.rows) !== null && _b !== void 0 ? _b : undefined;
|
|
147
|
+
return React.createElement(Box, { width, height, flexDirection: "column" }, children);
|
|
148
|
+
};
|
|
149
|
+
const RenderTree = ({ surfaceId, tree, dataModel, onUserAction, onLocalDataModelUpdate }) => {
|
|
150
|
+
const dispatchAction = (action, node, value) => {
|
|
151
|
+
var _a, _b;
|
|
152
|
+
const context = {
|
|
153
|
+
...resolveActionContext(action.context, dataModel, node.bindingContext),
|
|
154
|
+
...(((_a = node.bindingContext) === null || _a === void 0 ? void 0 : _a.index) !== undefined ? { index: node.bindingContext.index } : {}),
|
|
155
|
+
...(((_b = node.bindingContext) === null || _b === void 0 ? void 0 : _b.item) !== undefined ? { item: node.bindingContext.item } : {})
|
|
156
|
+
};
|
|
157
|
+
onUserAction === null || onUserAction === void 0 ? void 0 : onUserAction({
|
|
158
|
+
type: "userAction",
|
|
159
|
+
surfaceId,
|
|
160
|
+
componentId: node.id,
|
|
161
|
+
actionId: action.actionId,
|
|
162
|
+
context,
|
|
163
|
+
value
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
const updateLocalDataModel = (path, value, node) => {
|
|
167
|
+
onLocalDataModelUpdate === null || onLocalDataModelUpdate === void 0 ? void 0 : onLocalDataModelUpdate(surfaceId, path, value, node);
|
|
168
|
+
};
|
|
169
|
+
return renderNode(tree, { dispatchAction, updateLocalDataModel });
|
|
170
|
+
};
|
|
171
|
+
function resolveActionContext(context, dataModel, bindingContext) {
|
|
172
|
+
if (!context) {
|
|
173
|
+
return {};
|
|
174
|
+
}
|
|
175
|
+
const resolved = {};
|
|
176
|
+
for (const [key, value] of Object.entries(context)) {
|
|
177
|
+
if (isBoundValueLike(value)) {
|
|
178
|
+
resolved[key] = resolveBoundValue(value, dataModel, bindingContext);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
resolved[key] = value;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return resolved;
|
|
185
|
+
}
|
|
186
|
+
function isBoundValueLike(value) {
|
|
187
|
+
if (!value || typeof value !== "object") {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
return ("path" in value ||
|
|
191
|
+
"literalString" in value ||
|
|
192
|
+
"literalNumber" in value ||
|
|
193
|
+
"literalBoolean" in value ||
|
|
194
|
+
"literalObject" in value ||
|
|
195
|
+
"literalArray" in value);
|
|
196
|
+
}
|
|
197
|
+
function mergeDataModel(base, update) {
|
|
198
|
+
const result = { ...base };
|
|
199
|
+
for (const [key, value] of Object.entries(update)) {
|
|
200
|
+
if (isPlainObject(value) && isPlainObject(result[key])) {
|
|
201
|
+
result[key] = mergeDataModel(result[key], value);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
result[key] = value;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return result;
|
|
208
|
+
}
|
|
209
|
+
function isPlainObject(value) {
|
|
210
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
211
|
+
}
|
|
212
|
+
function normalizeComponentDef(component) {
|
|
213
|
+
if (!component || typeof component !== "object") {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
const record = component;
|
|
217
|
+
if (typeof record.id !== "string") {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
if (typeof record.type === "string") {
|
|
221
|
+
const normalizedProps = normalizeBoundValuesDeep(record.props);
|
|
222
|
+
if (normalizedProps) {
|
|
223
|
+
if (normalizedProps.action && !normalizedProps.onPress && record.type === "Button") {
|
|
224
|
+
normalizedProps.onPress = normalizeAction(normalizedProps.action);
|
|
225
|
+
delete normalizedProps.action;
|
|
226
|
+
}
|
|
227
|
+
if (normalizedProps.action && !normalizedProps.onChange && (record.type === "Checkbox" || record.type === "CheckBox")) {
|
|
228
|
+
normalizedProps.onChange = normalizeAction(normalizedProps.action);
|
|
229
|
+
delete normalizedProps.action;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
id: record.id,
|
|
234
|
+
type: record.type,
|
|
235
|
+
props: normalizedProps,
|
|
236
|
+
children: normalizeChildren(record.children)
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
if (record.component && typeof record.component === "object") {
|
|
240
|
+
const [type, props] = extractComponentType(record.component);
|
|
241
|
+
if (!type) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
const { normalizedType, normalizedProps, children } = normalizeComponentShape(type, props);
|
|
245
|
+
if (!normalizedType) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
id: record.id,
|
|
250
|
+
type: normalizedType,
|
|
251
|
+
props: normalizedProps,
|
|
252
|
+
children
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
function extractComponentType(componentObject) {
|
|
258
|
+
var _a, _b, _c;
|
|
259
|
+
if (typeof componentObject.type === "string") {
|
|
260
|
+
return [componentObject.type, (_a = componentObject.props) !== null && _a !== void 0 ? _a : {}];
|
|
261
|
+
}
|
|
262
|
+
const entries = Object.entries(componentObject);
|
|
263
|
+
if (entries.length === 1) {
|
|
264
|
+
const [type, props] = entries[0];
|
|
265
|
+
return [type, (_b = props) !== null && _b !== void 0 ? _b : {}];
|
|
266
|
+
}
|
|
267
|
+
const candidate = entries.find(([key, value]) => typeof key === "string" && typeof value === "object");
|
|
268
|
+
if (candidate) {
|
|
269
|
+
return [candidate[0], (_c = candidate[1]) !== null && _c !== void 0 ? _c : {}];
|
|
270
|
+
}
|
|
271
|
+
return [null, {}];
|
|
272
|
+
}
|
|
273
|
+
function normalizeComponentShape(type, props) {
|
|
274
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
275
|
+
const nextProps = normalizeBoundValuesDeep({ ...(props !== null && props !== void 0 ? props : {}) });
|
|
276
|
+
let children = undefined;
|
|
277
|
+
if (nextProps.children) {
|
|
278
|
+
children = normalizeChildren(nextProps.children);
|
|
279
|
+
delete nextProps.children;
|
|
280
|
+
}
|
|
281
|
+
if (nextProps.child) {
|
|
282
|
+
children = normalizeChildren({ explicitList: [nextProps.child] });
|
|
283
|
+
delete nextProps.child;
|
|
284
|
+
}
|
|
285
|
+
if (nextProps.action && !nextProps.onPress && type === "Button") {
|
|
286
|
+
nextProps.onPress = normalizeAction(nextProps.action);
|
|
287
|
+
delete nextProps.action;
|
|
288
|
+
}
|
|
289
|
+
if (nextProps.action && !nextProps.onChange && (type === "Checkbox" || type === "CheckBox")) {
|
|
290
|
+
nextProps.onChange = normalizeAction(nextProps.action);
|
|
291
|
+
delete nextProps.action;
|
|
292
|
+
}
|
|
293
|
+
if (type === "Text" && nextProps.usageHint && nextProps.bold === undefined) {
|
|
294
|
+
const hint = String(nextProps.usageHint).toLowerCase();
|
|
295
|
+
if (hint === "h1" || hint === "h2" || hint === "h3") {
|
|
296
|
+
nextProps.bold = true;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (type === "Row" || type === "Column") {
|
|
300
|
+
const direction = type === "Row" ? "row" : "column";
|
|
301
|
+
const alignItems = mapAlignment(nextProps.alignment);
|
|
302
|
+
const justifyContent = mapDistribution(nextProps.distribution);
|
|
303
|
+
return {
|
|
304
|
+
normalizedType: "Box",
|
|
305
|
+
normalizedProps: {
|
|
306
|
+
...nextProps,
|
|
307
|
+
direction,
|
|
308
|
+
alignItems,
|
|
309
|
+
justifyContent
|
|
310
|
+
},
|
|
311
|
+
children
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
if (type === "Card") {
|
|
315
|
+
return {
|
|
316
|
+
normalizedType: "Box",
|
|
317
|
+
normalizedProps: {
|
|
318
|
+
direction: "column",
|
|
319
|
+
borderStyle: "round",
|
|
320
|
+
padding: 1,
|
|
321
|
+
...nextProps
|
|
322
|
+
},
|
|
323
|
+
children
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
if (type === "Divider") {
|
|
327
|
+
return {
|
|
328
|
+
normalizedType: "Divider",
|
|
329
|
+
normalizedProps: nextProps,
|
|
330
|
+
children: undefined
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
if (type === "Icon") {
|
|
334
|
+
return {
|
|
335
|
+
normalizedType: "Text",
|
|
336
|
+
normalizedProps: {
|
|
337
|
+
text: resolveIconText(nextProps.name)
|
|
338
|
+
},
|
|
339
|
+
children: undefined
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
if (type === "Image") {
|
|
343
|
+
return {
|
|
344
|
+
normalizedType: "Image",
|
|
345
|
+
normalizedProps: nextProps,
|
|
346
|
+
children: undefined
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
if (type === "TextField") {
|
|
350
|
+
const textValue = (_a = nextProps.value) !== null && _a !== void 0 ? _a : nextProps.text;
|
|
351
|
+
return {
|
|
352
|
+
normalizedType: "TextField",
|
|
353
|
+
normalizedProps: {
|
|
354
|
+
label: nextProps.label,
|
|
355
|
+
value: textValue,
|
|
356
|
+
placeholder: (_b = nextProps.placeholder) !== null && _b !== void 0 ? _b : resolveLiteralString(nextProps.label),
|
|
357
|
+
onChange: nextProps.onChange,
|
|
358
|
+
onSubmit: nextProps.onSubmit
|
|
359
|
+
},
|
|
360
|
+
children: undefined
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
if (type === "CheckBox") {
|
|
364
|
+
return {
|
|
365
|
+
normalizedType: "Checkbox",
|
|
366
|
+
normalizedProps: {
|
|
367
|
+
label: nextProps.label,
|
|
368
|
+
checked: (_c = nextProps.checked) !== null && _c !== void 0 ? _c : nextProps.value,
|
|
369
|
+
onChange: (_d = nextProps.onChange) !== null && _d !== void 0 ? _d : normalizeAction(nextProps.action)
|
|
370
|
+
},
|
|
371
|
+
children: undefined
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
if (type === "MultipleChoice") {
|
|
375
|
+
return {
|
|
376
|
+
normalizedType: "MultipleChoice",
|
|
377
|
+
normalizedProps: {
|
|
378
|
+
label: nextProps.label,
|
|
379
|
+
items: normalizeMultipleChoiceOptions((_e = nextProps.options) !== null && _e !== void 0 ? _e : []),
|
|
380
|
+
onSelect: normalizeAction(nextProps.action)
|
|
381
|
+
},
|
|
382
|
+
children: undefined
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
if (type === "Slider") {
|
|
386
|
+
return {
|
|
387
|
+
normalizedType: "Slider",
|
|
388
|
+
normalizedProps: {
|
|
389
|
+
label: nextProps.label,
|
|
390
|
+
min: (_f = nextProps.min) !== null && _f !== void 0 ? _f : nextProps.minValue,
|
|
391
|
+
max: (_g = nextProps.max) !== null && _g !== void 0 ? _g : nextProps.maxValue,
|
|
392
|
+
step: nextProps.step,
|
|
393
|
+
value: nextProps.value,
|
|
394
|
+
onChange: (_h = nextProps.onChange) !== null && _h !== void 0 ? _h : normalizeAction(nextProps.action)
|
|
395
|
+
},
|
|
396
|
+
children: undefined
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
if (type === "Tabs") {
|
|
400
|
+
const tabItems = Array.isArray(nextProps.tabItems) ? nextProps.tabItems : [];
|
|
401
|
+
const tabLabels = tabItems.map((item) => { var _a; return (_a = resolveLiteralString(item === null || item === void 0 ? void 0 : item.title)) !== null && _a !== void 0 ? _a : "Tab"; });
|
|
402
|
+
if (!children && tabItems.length) {
|
|
403
|
+
const childIds = tabItems
|
|
404
|
+
.map((item) => item === null || item === void 0 ? void 0 : item.child)
|
|
405
|
+
.filter((entry) => typeof entry === "string");
|
|
406
|
+
if (childIds.length) {
|
|
407
|
+
children = { explicitList: childIds };
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return {
|
|
411
|
+
normalizedType: "Tabs",
|
|
412
|
+
normalizedProps: {
|
|
413
|
+
tabs: tabLabels,
|
|
414
|
+
selectedIndex: (_j = nextProps.selectedIndex) !== null && _j !== void 0 ? _j : 0,
|
|
415
|
+
onChange: (_k = nextProps.onChange) !== null && _k !== void 0 ? _k : normalizeAction(nextProps.action)
|
|
416
|
+
},
|
|
417
|
+
children
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
if (type === "Modal") {
|
|
421
|
+
return {
|
|
422
|
+
normalizedType: "Modal",
|
|
423
|
+
normalizedProps: nextProps,
|
|
424
|
+
children
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
return {
|
|
428
|
+
normalizedType: type,
|
|
429
|
+
normalizedProps: nextProps,
|
|
430
|
+
children
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
function normalizeChildren(children) {
|
|
434
|
+
if (!children || typeof children !== "object")
|
|
435
|
+
return children;
|
|
436
|
+
const record = children;
|
|
437
|
+
if (Array.isArray(record.explicitList)) {
|
|
438
|
+
return { explicitList: record.explicitList };
|
|
439
|
+
}
|
|
440
|
+
if (record.template && typeof record.template === "object") {
|
|
441
|
+
const template = record.template;
|
|
442
|
+
const dataBinding = template.dataBinding;
|
|
443
|
+
return {
|
|
444
|
+
template: {
|
|
445
|
+
componentId: template.componentId,
|
|
446
|
+
dataBinding: typeof dataBinding === "string" ? dataBinding : dataBinding
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
return children;
|
|
451
|
+
}
|
|
452
|
+
function normalizeAction(action) {
|
|
453
|
+
if (!action || typeof action !== "object")
|
|
454
|
+
return undefined;
|
|
455
|
+
const record = action;
|
|
456
|
+
if (record.actionId && typeof record.actionId === "string") {
|
|
457
|
+
return { actionId: record.actionId, context: record.context };
|
|
458
|
+
}
|
|
459
|
+
if (record.name && typeof record.name === "string") {
|
|
460
|
+
return {
|
|
461
|
+
actionId: record.name,
|
|
462
|
+
context: normalizeActionContext(record.context)
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
return undefined;
|
|
466
|
+
}
|
|
467
|
+
function normalizeActionContext(context) {
|
|
468
|
+
if (!context)
|
|
469
|
+
return undefined;
|
|
470
|
+
if (Array.isArray(context)) {
|
|
471
|
+
const result = {};
|
|
472
|
+
context.forEach((entry) => {
|
|
473
|
+
var _a, _b;
|
|
474
|
+
if (!entry || typeof entry !== "object")
|
|
475
|
+
return;
|
|
476
|
+
const record = entry;
|
|
477
|
+
if (!record.key)
|
|
478
|
+
return;
|
|
479
|
+
result[String(record.key)] = (_b = (_a = record.value) !== null && _a !== void 0 ? _a : record.literal) !== null && _b !== void 0 ? _b : record;
|
|
480
|
+
});
|
|
481
|
+
return result;
|
|
482
|
+
}
|
|
483
|
+
if (typeof context === "object") {
|
|
484
|
+
return context;
|
|
485
|
+
}
|
|
486
|
+
return undefined;
|
|
487
|
+
}
|
|
488
|
+
function normalizeBoundValuesDeep(value) {
|
|
489
|
+
if (!value || typeof value !== "object") {
|
|
490
|
+
return value;
|
|
491
|
+
}
|
|
492
|
+
if (Array.isArray(value)) {
|
|
493
|
+
return value.map((item) => normalizeBoundValuesDeep(item));
|
|
494
|
+
}
|
|
495
|
+
if (isBoundValueLike(value)) {
|
|
496
|
+
return value;
|
|
497
|
+
}
|
|
498
|
+
const result = {};
|
|
499
|
+
Object.entries(value).forEach(([key, entry]) => {
|
|
500
|
+
result[key] = normalizeBoundValuesDeep(entry);
|
|
501
|
+
});
|
|
502
|
+
return result;
|
|
503
|
+
}
|
|
504
|
+
function resolveLiteralString(value) {
|
|
505
|
+
if (!value || typeof value !== "object")
|
|
506
|
+
return undefined;
|
|
507
|
+
const record = value;
|
|
508
|
+
if (typeof record.literalString === "string") {
|
|
509
|
+
return record.literalString;
|
|
510
|
+
}
|
|
511
|
+
return undefined;
|
|
512
|
+
}
|
|
513
|
+
function normalizeMultipleChoiceOptions(options) {
|
|
514
|
+
if (!Array.isArray(options)) {
|
|
515
|
+
return options;
|
|
516
|
+
}
|
|
517
|
+
return options.map((option) => {
|
|
518
|
+
var _a;
|
|
519
|
+
if (!option || typeof option !== "object") {
|
|
520
|
+
return option;
|
|
521
|
+
}
|
|
522
|
+
const record = option;
|
|
523
|
+
const label = (_a = resolveLiteralString(record.label)) !== null && _a !== void 0 ? _a : record.label;
|
|
524
|
+
return {
|
|
525
|
+
...record,
|
|
526
|
+
label
|
|
527
|
+
};
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
function resolveIconText(nameBinding) {
|
|
531
|
+
var _a;
|
|
532
|
+
const map = {
|
|
533
|
+
flight: "✈",
|
|
534
|
+
airplane: "✈",
|
|
535
|
+
plane: "✈",
|
|
536
|
+
calendar: "📅",
|
|
537
|
+
time: "⏰",
|
|
538
|
+
favorite: "★",
|
|
539
|
+
star: "★"
|
|
540
|
+
};
|
|
541
|
+
if (!nameBinding || typeof nameBinding !== "object") {
|
|
542
|
+
return { literalString: "•" };
|
|
543
|
+
}
|
|
544
|
+
const record = nameBinding;
|
|
545
|
+
if (typeof record.literalString === "string") {
|
|
546
|
+
const key = record.literalString.toLowerCase();
|
|
547
|
+
return { literalString: (_a = map[key]) !== null && _a !== void 0 ? _a : record.literalString };
|
|
548
|
+
}
|
|
549
|
+
if (typeof record.path === "string") {
|
|
550
|
+
return { path: record.path };
|
|
551
|
+
}
|
|
552
|
+
return { literalString: "•" };
|
|
553
|
+
}
|
|
554
|
+
function mapAlignment(alignment) {
|
|
555
|
+
if (!alignment)
|
|
556
|
+
return undefined;
|
|
557
|
+
const normalized = alignment.toLowerCase();
|
|
558
|
+
switch (normalized) {
|
|
559
|
+
case "start":
|
|
560
|
+
case "flexstart":
|
|
561
|
+
case "flex-start":
|
|
562
|
+
return "flex-start";
|
|
563
|
+
case "end":
|
|
564
|
+
case "flexend":
|
|
565
|
+
case "flex-end":
|
|
566
|
+
return "flex-end";
|
|
567
|
+
case "center":
|
|
568
|
+
return "center";
|
|
569
|
+
case "stretch":
|
|
570
|
+
return "stretch";
|
|
571
|
+
default:
|
|
572
|
+
return undefined;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
function mapDistribution(distribution) {
|
|
576
|
+
if (!distribution)
|
|
577
|
+
return undefined;
|
|
578
|
+
const normalized = distribution.toLowerCase();
|
|
579
|
+
switch (normalized) {
|
|
580
|
+
case "spacebetween":
|
|
581
|
+
case "space-between":
|
|
582
|
+
return "space-between";
|
|
583
|
+
case "spacearound":
|
|
584
|
+
case "space-around":
|
|
585
|
+
return "space-around";
|
|
586
|
+
case "center":
|
|
587
|
+
return "center";
|
|
588
|
+
case "start":
|
|
589
|
+
case "flexstart":
|
|
590
|
+
case "flex-start":
|
|
591
|
+
return "flex-start";
|
|
592
|
+
case "end":
|
|
593
|
+
case "flexend":
|
|
594
|
+
case "flex-end":
|
|
595
|
+
return "flex-end";
|
|
596
|
+
default:
|
|
597
|
+
return undefined;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
function applyDataModelUpdate(existing, path, contents) {
|
|
601
|
+
var _a;
|
|
602
|
+
const next = { ...(existing !== null && existing !== void 0 ? existing : {}) };
|
|
603
|
+
const updatedValue = buildValueFromContents(contents);
|
|
604
|
+
const parts = normalizePath(path);
|
|
605
|
+
if (!parts.length) {
|
|
606
|
+
if (isPlainObject(updatedValue)) {
|
|
607
|
+
return { ...next, ...updatedValue };
|
|
608
|
+
}
|
|
609
|
+
return (_a = updatedValue) !== null && _a !== void 0 ? _a : next;
|
|
610
|
+
}
|
|
611
|
+
let cursor = next;
|
|
612
|
+
for (let i = 0; i < parts.length - 1; i += 1) {
|
|
613
|
+
const key = parts[i];
|
|
614
|
+
if (!cursor[key] || typeof cursor[key] !== "object") {
|
|
615
|
+
cursor[key] = {};
|
|
616
|
+
}
|
|
617
|
+
cursor = cursor[key];
|
|
618
|
+
}
|
|
619
|
+
cursor[parts[parts.length - 1]] = updatedValue;
|
|
620
|
+
return next;
|
|
621
|
+
}
|
|
622
|
+
function normalizePath(path) {
|
|
623
|
+
if (!path || path === "/") {
|
|
624
|
+
return [];
|
|
625
|
+
}
|
|
626
|
+
const trimmed = String(path).replace(/^\/+/, "");
|
|
627
|
+
if (!trimmed) {
|
|
628
|
+
return [];
|
|
629
|
+
}
|
|
630
|
+
return trimmed.split("/").filter(Boolean);
|
|
631
|
+
}
|
|
632
|
+
function buildValueFromContents(contents) {
|
|
633
|
+
if (!Array.isArray(contents)) {
|
|
634
|
+
return contents;
|
|
635
|
+
}
|
|
636
|
+
const result = {};
|
|
637
|
+
contents.forEach((entry) => {
|
|
638
|
+
if (!entry || typeof entry !== "object") {
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
result[entry.key] = extractTypedValue(entry);
|
|
642
|
+
});
|
|
643
|
+
return result;
|
|
644
|
+
}
|
|
645
|
+
function extractTypedValue(entry) {
|
|
646
|
+
var _a, _b;
|
|
647
|
+
if ("valueString" in entry)
|
|
648
|
+
return entry.valueString;
|
|
649
|
+
if ("valueNumber" in entry)
|
|
650
|
+
return entry.valueNumber;
|
|
651
|
+
if ("valueBoolean" in entry)
|
|
652
|
+
return entry.valueBoolean;
|
|
653
|
+
if ("valueNull" in entry)
|
|
654
|
+
return null;
|
|
655
|
+
if ("valueMap" in entry)
|
|
656
|
+
return buildValueFromContents((_a = entry.valueMap) !== null && _a !== void 0 ? _a : []);
|
|
657
|
+
if ("valueArray" in entry)
|
|
658
|
+
return normalizeValueArray((_b = entry.valueArray) !== null && _b !== void 0 ? _b : []);
|
|
659
|
+
if ("value" in entry)
|
|
660
|
+
return entry.value;
|
|
661
|
+
return undefined;
|
|
662
|
+
}
|
|
663
|
+
function normalizeValueArray(valueArray) {
|
|
664
|
+
return valueArray.map((item) => {
|
|
665
|
+
if (item && typeof item === "object" && "key" in item) {
|
|
666
|
+
return extractTypedValue(item);
|
|
667
|
+
}
|
|
668
|
+
if (item && typeof item === "object" && ("valueString" in item || "valueNumber" in item || "valueBoolean" in item || "valueMap" in item || "valueArray" in item || "valueNull" in item)) {
|
|
669
|
+
return extractTypedValue(item);
|
|
670
|
+
}
|
|
671
|
+
return item;
|
|
672
|
+
});
|
|
673
|
+
}
|