@pcg/dynamic-components 1.0.0-alpha.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/CHANGELOG.md +7 -0
- package/dist/index.d.ts +1816 -0
- package/dist/index.js +1564 -0
- package/dist/index.js.map +1 -0
- package/eslint.config.cjs +14 -0
- package/package.json +30 -0
- package/src/assertions/basic.ts +58 -0
- package/src/assertions/containers.ts +76 -0
- package/src/assertions/index.ts +6 -0
- package/src/assertions/paths.ts +12 -0
- package/src/assertions/rich-text.ts +16 -0
- package/src/assertions/yjs.ts +25 -0
- package/src/data-objects/data-object.ts +34 -0
- package/src/data-objects/index.ts +3 -0
- package/src/data-objects/rich-text.ts +38 -0
- package/src/dynamic-components/fractional-indexing.ts +321 -0
- package/src/dynamic-components/index.ts +6 -0
- package/src/dynamic-components/paths.ts +194 -0
- package/src/dynamic-components/registry/chats.ts +24 -0
- package/src/dynamic-components/registry/content.ts +118 -0
- package/src/dynamic-components/registry/forms.ts +525 -0
- package/src/dynamic-components/registry/index.ts +6 -0
- package/src/dynamic-components/registry/layout.ts +86 -0
- package/src/dynamic-components/registry/uikit-dynamic-component.ts +84 -0
- package/src/dynamic-components/tools.ts +195 -0
- package/src/dynamic-components/types.ts +237 -0
- package/src/index.ts +7 -0
- package/src/paths/array-keys.ts +164 -0
- package/src/paths/array-ops.ts +124 -0
- package/src/paths/basic-ops.ts +181 -0
- package/src/paths/constants.ts +1 -0
- package/src/paths/index.ts +7 -0
- package/src/paths/tools.ts +42 -0
- package/src/paths/types.ts +133 -0
- package/src/y-components/index.ts +3 -0
- package/src/y-components/tools.ts +234 -0
- package/src/y-components/types.ts +19 -0
- package/src/y-tools/array-path-ops.ts +240 -0
- package/src/y-tools/basic-path-ops.ts +189 -0
- package/src/y-tools/index.ts +6 -0
- package/src/y-tools/tools.ts +122 -0
- package/src/y-tools/types.ts +32 -0
- package/src/y-tools/y-array-keys.ts +47 -0
- package/tests/assertions/basic-types.test.ts +78 -0
- package/tests/assertions/containers.test.ts +72 -0
- package/tests/assertions/paths.test.ts +23 -0
- package/tests/assertions/yjs.test.ts +33 -0
- package/tests/dynamic-components/paths.test.ts +171 -0
- package/tests/dynamic-components/tools.test.ts +121 -0
- package/tests/paths/array-keys.test.ts +182 -0
- package/tests/paths/array-ops.test.ts +164 -0
- package/tests/paths/basic-ops.test.ts +263 -0
- package/tests/paths/tools.test.ts +55 -0
- package/tests/y-components/tools.test.ts +198 -0
- package/tests/y-tools/array-base-ops.test.ts +55 -0
- package/tests/y-tools/array-path-ops.test.ts +95 -0
- package/tsconfig.json +13 -0
- package/tsconfig.lib.json +13 -0
- package/tsdown.config.ts +18 -0
- package/vitest.config.ts +19 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1564 @@
|
|
|
1
|
+
import * as Y from "yjs";
|
|
2
|
+
import { yXmlFragmentToProsemirrorJSON } from "y-prosemirror";
|
|
3
|
+
|
|
4
|
+
//#region src/assertions/basic.ts
|
|
5
|
+
/**
|
|
6
|
+
* Checks if the given parameter is callable (a function).
|
|
7
|
+
* @param {unknown} fn - The function to check.
|
|
8
|
+
* @returns {boolean} Returns true if `fn` is a function, false otherwise.
|
|
9
|
+
* @example
|
|
10
|
+
* isCallable(() => {}); // Returns true
|
|
11
|
+
* isCallable('Hello'); // Returns false
|
|
12
|
+
*/
|
|
13
|
+
const isCallable = (fn) => {
|
|
14
|
+
return typeof fn === "function";
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Checks if the given value is a string.
|
|
18
|
+
* @param {unknown} val - The value to check.
|
|
19
|
+
* @returns {boolean} Returns true if `val` is a string, false otherwise.
|
|
20
|
+
* @example
|
|
21
|
+
* isString('Hello'); // Returns true
|
|
22
|
+
* isString(123); // Returns false
|
|
23
|
+
*/
|
|
24
|
+
const isString = (val) => typeof val === "string";
|
|
25
|
+
/**
|
|
26
|
+
* Checks if the given value is a number.
|
|
27
|
+
* @param {unknown} val - The value to check.
|
|
28
|
+
* @returns {boolean} Returns true if `val` is a number, false otherwise.
|
|
29
|
+
* @example
|
|
30
|
+
* isNumber(123); // Returns true
|
|
31
|
+
* isNumber('Hello'); // Returns false
|
|
32
|
+
*/
|
|
33
|
+
const isNumber = (val) => typeof val === "number";
|
|
34
|
+
/**
|
|
35
|
+
* Checks if a given value can be used as an index (a non-negative integer).
|
|
36
|
+
* @param {unknown} value - The value to check.
|
|
37
|
+
* @returns {boolean} Returns true if `value` can be used as an index, false otherwise.
|
|
38
|
+
* @example
|
|
39
|
+
* isIndex(2); // Returns true
|
|
40
|
+
* isIndex('2'); // Returns true
|
|
41
|
+
* isIndex(-1); // Returns false
|
|
42
|
+
*/
|
|
43
|
+
const isIndex = (value) => {
|
|
44
|
+
return (isNumber(value) || isString(value)) && Number(value) >= 0;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Checks if the given value is null or undefined.
|
|
48
|
+
* @param {unknown} value - The value to check.
|
|
49
|
+
* @returns {boolean} Returns true if `value` is null or undefined, false otherwise.
|
|
50
|
+
* @example
|
|
51
|
+
* isNullOrUndefined(null); // Returns true
|
|
52
|
+
* isNullOrUndefined(undefined); // Returns true
|
|
53
|
+
* isNullOrUndefined('Hello'); // Returns false
|
|
54
|
+
*/
|
|
55
|
+
const isNullOrUndefined = (value) => {
|
|
56
|
+
return value === null || value === void 0;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/assertions/containers.ts
|
|
61
|
+
/**
|
|
62
|
+
* Checks if the given value is an empty array.
|
|
63
|
+
* @param {unknown} arr - The array to check.
|
|
64
|
+
* @returns {boolean} Returns true if `arr` is an empty array, false otherwise.
|
|
65
|
+
* @example
|
|
66
|
+
* isEmptyArray([]); // Returns true
|
|
67
|
+
* isEmptyArray([1, 2, 3]); // Returns false
|
|
68
|
+
*/
|
|
69
|
+
const isEmptyArray = (arr) => {
|
|
70
|
+
return Array.isArray(arr) && arr.length === 0;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Gets the keys of the given object.
|
|
74
|
+
* @param {T} arr - The object to get the keys from.
|
|
75
|
+
* @returns {Array<keyof T>} Returns an array of keys of the given object.
|
|
76
|
+
* @example
|
|
77
|
+
* keysOf({ a: 1, b: 2 }); // Returns ['a', 'b']
|
|
78
|
+
*/
|
|
79
|
+
const keysOf = (arr) => Object.keys(arr);
|
|
80
|
+
/**
|
|
81
|
+
* Gets the entries of the given object.
|
|
82
|
+
* @param {T} arr - The object to get the entries from.
|
|
83
|
+
* @returns {Entries<T>} Returns an array of entries of the given object.
|
|
84
|
+
* @example
|
|
85
|
+
* entriesOf({ a: 1, b: 2 }); // Returns [['a', 1], ['b', 2]]
|
|
86
|
+
*/
|
|
87
|
+
const entriesOf = (arr) => Object.entries(arr);
|
|
88
|
+
/**
|
|
89
|
+
* Checks if the given value is an object (not an array).
|
|
90
|
+
* @param {unknown} obj - The value to check.
|
|
91
|
+
* @returns {boolean} Returns true if `obj` is an object, false otherwise.
|
|
92
|
+
* @example
|
|
93
|
+
* isObject({ a: 1 }); // Returns true
|
|
94
|
+
* isObject([1, 2, 3]); // Returns false
|
|
95
|
+
*/
|
|
96
|
+
const isObject = (obj) => obj !== null && !!obj && typeof obj === "object" && !Array.isArray(obj);
|
|
97
|
+
/**
|
|
98
|
+
* Checks if the given value is a container (an object or an array).
|
|
99
|
+
* @param {unknown} value - The value to check.
|
|
100
|
+
* @returns {boolean} Returns true if `value` is a container, false otherwise.
|
|
101
|
+
* @example
|
|
102
|
+
* isContainerValue({ a: 1 }); // Returns true
|
|
103
|
+
* isContainerValue([1, 2, 3]); // Returns true
|
|
104
|
+
* isContainerValue('Hello'); // Returns false
|
|
105
|
+
*/
|
|
106
|
+
const isContainerValue = (value) => {
|
|
107
|
+
return isObject(value) || Array.isArray(value);
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Checks if the given value is an empty container (an empty object or array).
|
|
111
|
+
* @param {unknown} value - The value to check.
|
|
112
|
+
* @returns {boolean} Returns true if `value` is an empty container, false otherwise.
|
|
113
|
+
* @example
|
|
114
|
+
* isEmptyContainer({}); // Returns true
|
|
115
|
+
* isEmptyContainer([]); // Returns true
|
|
116
|
+
* isEmptyContainer({ a: 1 }); // Returns false
|
|
117
|
+
* isEmptyContainer([1, 2, 3]); // Returns false
|
|
118
|
+
*/
|
|
119
|
+
const isEmptyContainer = (value) => {
|
|
120
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
121
|
+
return isObject(value) && Object.keys(value).length === 0;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region src/assertions/paths.ts
|
|
126
|
+
/**
|
|
127
|
+
* Checks if two paths are equal.
|
|
128
|
+
* @param {(string | number)[]} path - The first path to compare.
|
|
129
|
+
* @param {(string | number)[]} toPath - The second path to compare.
|
|
130
|
+
* @returns {boolean} Returns true if both paths are of the same length and all corresponding elements are equal, false otherwise.
|
|
131
|
+
* @example
|
|
132
|
+
* isEqualPath(['items', 'id:xxx', 'name'], ['items', 'id:xxx', 'name']); // Returns true
|
|
133
|
+
* isEqualPath(['items', 'id:yyy', 'name'], ['items', 'id:xxx', 'name']); // Returns false
|
|
134
|
+
*/
|
|
135
|
+
const isEqualPath = (path, toPath) => {
|
|
136
|
+
return path.length === toPath.length && path.every((v, index) => v === toPath[index]);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
//#endregion
|
|
140
|
+
//#region src/assertions/rich-text.ts
|
|
141
|
+
/**
|
|
142
|
+
* Checks if the given value is a RichText object.
|
|
143
|
+
* @param {unknown} value - The value to check.
|
|
144
|
+
* @returns {boolean} Returns true if `value` is a RichText object, false otherwise.
|
|
145
|
+
* @example
|
|
146
|
+
* isRichText({ id: 'xx', ... type: 'RichText' }); // Returns true
|
|
147
|
+
*/
|
|
148
|
+
const isRichText = (value) => {
|
|
149
|
+
if (typeof value === "object" && value !== null) return "type" in value && value.type === "RichText";
|
|
150
|
+
return false;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
//#endregion
|
|
154
|
+
//#region src/assertions/yjs.ts
|
|
155
|
+
/**
|
|
156
|
+
* Checks if the given value is a Yjs Map.
|
|
157
|
+
* @param {unknown} yMap - The value to check.
|
|
158
|
+
* @returns {boolean} Returns true if `yMap` is a Yjs Map, false otherwise.
|
|
159
|
+
* @example
|
|
160
|
+
* const yMap = new Y.Map();
|
|
161
|
+
* isYMap(yMap); // Returns true
|
|
162
|
+
*/
|
|
163
|
+
const isYMap = (yMap) => {
|
|
164
|
+
return yMap instanceof Y.Map;
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* Checks if the given value is a Yjs Array.
|
|
168
|
+
* @param {unknown} yArray - The value to check.
|
|
169
|
+
* @returns {boolean} Returns true if `yArray` is a Yjs Array, false otherwise.
|
|
170
|
+
* @example
|
|
171
|
+
* const yArray = new Y.Array();
|
|
172
|
+
* isYArray(yArray); // Returns true
|
|
173
|
+
*/
|
|
174
|
+
const isYArray = (yArray) => {
|
|
175
|
+
return yArray instanceof Y.Array;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
//#endregion
|
|
179
|
+
//#region src/data-objects/data-object.ts
|
|
180
|
+
/**
|
|
181
|
+
* Gets the key of the data object. The key is a string combining `type` and `id` of the data object, separated by a colon.
|
|
182
|
+
* @param {BaseDataObject} dataObject - The data object to get the key from.
|
|
183
|
+
* @returns {string} Returns the key of the data object.
|
|
184
|
+
* @example
|
|
185
|
+
* getDataObjectKey({ id: 'xxx', type: 'RichText' }); // Returns 'RichText:xxx'
|
|
186
|
+
*/
|
|
187
|
+
const getDataObjectKey = (dataObject) => {
|
|
188
|
+
return `${dataObject.type}:${dataObject.id}`;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
//#endregion
|
|
192
|
+
//#region src/dynamic-components/fractional-indexing.ts
|
|
193
|
+
const BASE_62_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
194
|
+
const SMALLEST_INTEGER = "A00000000000000000000000000";
|
|
195
|
+
const INTEGER_ZERO = "a0";
|
|
196
|
+
/**
|
|
197
|
+
* @param {string} a
|
|
198
|
+
* @param {string | null} b
|
|
199
|
+
* @param {string} digits
|
|
200
|
+
* @returns {string}
|
|
201
|
+
*/
|
|
202
|
+
const midpoint = (a, b, digits) => {
|
|
203
|
+
if (b !== null && a >= b) throw new Error(a + " >= " + b);
|
|
204
|
+
if (a.slice(-1) === "0" || b && b.slice(-1) === "0") throw new Error("trailing zero");
|
|
205
|
+
if (b) {
|
|
206
|
+
let n = 0;
|
|
207
|
+
while ((a[n] || "0") === b[n]) n++;
|
|
208
|
+
if (n > 0) return b.slice(0, n) + midpoint(a.slice(n), b.slice(n), digits);
|
|
209
|
+
}
|
|
210
|
+
const digitA = a ? digits.indexOf(a[0]) : 0;
|
|
211
|
+
const digitB = b !== null ? digits.indexOf(b[0]) : digits.length;
|
|
212
|
+
if (digitB - digitA > 1) return digits[Math.round(.5 * (digitA + digitB))];
|
|
213
|
+
else {
|
|
214
|
+
if (b && b.length > 1) return b.slice(0, 1);
|
|
215
|
+
return digits[digitA] + midpoint(a.slice(1), null, digits);
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* @param {string} int
|
|
220
|
+
* @return {void}
|
|
221
|
+
*/
|
|
222
|
+
const validateInteger = (int) => {
|
|
223
|
+
if (int.length !== getIntegerLength(int[0])) throw new Error("invalid integer part of order key: " + int);
|
|
224
|
+
};
|
|
225
|
+
/**
|
|
226
|
+
* @param {string} head
|
|
227
|
+
* @return {number}
|
|
228
|
+
*/
|
|
229
|
+
const getIntegerLength = (head) => {
|
|
230
|
+
if (head >= "a" && head <= "z") return head.charCodeAt(0) - "a".charCodeAt(0) + 2;
|
|
231
|
+
else if (head >= "A" && head <= "Z") return "Z".charCodeAt(0) - head.charCodeAt(0) + 2;
|
|
232
|
+
else throw new Error("invalid order key head: " + head);
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* @param {string} key
|
|
236
|
+
* @return {string}
|
|
237
|
+
*/
|
|
238
|
+
const getIntegerPart = (key) => {
|
|
239
|
+
const integerPartLength = getIntegerLength(key[0]);
|
|
240
|
+
if (integerPartLength > key.length) throw new Error("invalid order key: " + key);
|
|
241
|
+
return key.slice(0, integerPartLength);
|
|
242
|
+
};
|
|
243
|
+
/**
|
|
244
|
+
* @param {string} key
|
|
245
|
+
* @return {void}
|
|
246
|
+
*/
|
|
247
|
+
const validateOrderKey = (key) => {
|
|
248
|
+
if (key === SMALLEST_INTEGER) throw new Error("invalid order key: " + key);
|
|
249
|
+
const i = getIntegerPart(key);
|
|
250
|
+
if (key.slice(i.length).slice(-1) === "0") throw new Error("invalid order key: " + key);
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* @param {string} x
|
|
254
|
+
* @param {string} digits
|
|
255
|
+
* @return {string | null}
|
|
256
|
+
*/
|
|
257
|
+
const incrementInteger = (x, digits) => {
|
|
258
|
+
validateInteger(x);
|
|
259
|
+
const [head, ...digs] = x.split("");
|
|
260
|
+
let carry = true;
|
|
261
|
+
for (let i = digs.length - 1; carry && i >= 0; i--) {
|
|
262
|
+
const d = digits.indexOf(digs[i]) + 1;
|
|
263
|
+
if (d === digits.length) digs[i] = "0";
|
|
264
|
+
else {
|
|
265
|
+
digs[i] = digits[d];
|
|
266
|
+
carry = false;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (carry) {
|
|
270
|
+
if (head === "Z") return "a0";
|
|
271
|
+
if (head === "z") return null;
|
|
272
|
+
const h = String.fromCharCode(head.charCodeAt(0) + 1);
|
|
273
|
+
if (h > "a") digs.push("0");
|
|
274
|
+
else digs.pop();
|
|
275
|
+
return h + digs.join("");
|
|
276
|
+
} else return head + digs.join("");
|
|
277
|
+
};
|
|
278
|
+
/**
|
|
279
|
+
* @param {string} x
|
|
280
|
+
* @param {string} digits
|
|
281
|
+
* @return {string | null}
|
|
282
|
+
*/
|
|
283
|
+
const decrementInteger = (x, digits) => {
|
|
284
|
+
validateInteger(x);
|
|
285
|
+
const [head, ...digs] = x.split("");
|
|
286
|
+
let borrow = true;
|
|
287
|
+
for (let i = digs.length - 1; borrow && i >= 0; i--) {
|
|
288
|
+
const d = digits.indexOf(digs[i]) - 1;
|
|
289
|
+
if (d === -1) digs[i] = digits.slice(-1);
|
|
290
|
+
else {
|
|
291
|
+
digs[i] = digits[d];
|
|
292
|
+
borrow = false;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (borrow) {
|
|
296
|
+
if (head === "a") return "Z" + digits.slice(-1);
|
|
297
|
+
if (head === "A") return null;
|
|
298
|
+
const h = String.fromCharCode(head.charCodeAt(0) - 1);
|
|
299
|
+
if (h < "Z") digs.push(digits.slice(-1));
|
|
300
|
+
else digs.pop();
|
|
301
|
+
return h + digs.join("");
|
|
302
|
+
} else return head + digs.join("");
|
|
303
|
+
};
|
|
304
|
+
/**
|
|
305
|
+
* @param {string | null} a
|
|
306
|
+
* @param {string | null} b
|
|
307
|
+
* @param {string=} digits
|
|
308
|
+
* @return {string}
|
|
309
|
+
*/
|
|
310
|
+
const generateKeyBetween = (a, b, digits = BASE_62_DIGITS) => {
|
|
311
|
+
if (a !== null) validateOrderKey(a);
|
|
312
|
+
if (b !== null) validateOrderKey(b);
|
|
313
|
+
if (a !== null && b !== null && a >= b) throw new Error(a + " >= " + b);
|
|
314
|
+
if (a === null) {
|
|
315
|
+
if (b === null) return INTEGER_ZERO;
|
|
316
|
+
const ib$1 = getIntegerPart(b);
|
|
317
|
+
const fb$1 = b.slice(ib$1.length);
|
|
318
|
+
if (ib$1 === SMALLEST_INTEGER) return ib$1 + midpoint("", fb$1, digits);
|
|
319
|
+
if (ib$1 < b) return ib$1;
|
|
320
|
+
const res = decrementInteger(ib$1, digits);
|
|
321
|
+
if (res === null) throw new Error("cannot decrement any more");
|
|
322
|
+
return res;
|
|
323
|
+
}
|
|
324
|
+
if (b === null) {
|
|
325
|
+
const ia$1 = getIntegerPart(a);
|
|
326
|
+
const fa$1 = a.slice(ia$1.length);
|
|
327
|
+
const i$1 = incrementInteger(ia$1, digits);
|
|
328
|
+
return i$1 === null ? ia$1 + midpoint(fa$1, null, digits) : i$1;
|
|
329
|
+
}
|
|
330
|
+
const ia = getIntegerPart(a);
|
|
331
|
+
const fa = a.slice(ia.length);
|
|
332
|
+
const ib = getIntegerPart(b);
|
|
333
|
+
const fb = b.slice(ib.length);
|
|
334
|
+
if (ia === ib) return ia + midpoint(fa, fb, digits);
|
|
335
|
+
const i = incrementInteger(ia, digits);
|
|
336
|
+
if (i === null) throw new Error("cannot increment any more");
|
|
337
|
+
if (i < b) return i;
|
|
338
|
+
return ia + midpoint(fa, null, digits);
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
//#endregion
|
|
342
|
+
//#region src/paths/array-keys.ts
|
|
343
|
+
/**
|
|
344
|
+
* In the system you are using, two types of keys are used to identify elements in an array: ID keys and position keys.
|
|
345
|
+
* These keys provide a flexible and robust way to refer to specific elements in an array, particularly when dealing with arrays of objects.
|
|
346
|
+
*
|
|
347
|
+
* 1. **ID Keys:**
|
|
348
|
+
* These keys have a prefix of 'id:' and are followed by the unique identifier of an object in the array.
|
|
349
|
+
* For example, in your array `items: [{ id: 'xxx', name: 'John' }]`, you can refer to the object with `id: 'xxx'` using the ID key 'id:xxx'.
|
|
350
|
+
* This is particularly useful when you have a unique identifier for each object in your array.
|
|
351
|
+
* With this, even if objects move around in the array, you can always accurately refer to a specific object using its unique ID.
|
|
352
|
+
*
|
|
353
|
+
* 2. **Position Keys:**
|
|
354
|
+
* These keys have a prefix of 'pos:' and are followed by a position indicator.
|
|
355
|
+
* Position keys provide a way to refer to an object in an array based on its position rather than its content.
|
|
356
|
+
* This can be useful when the position of an object in an array is significant and you want to refer to an object based on where it is in the array.
|
|
357
|
+
*
|
|
358
|
+
* In your path system, you can use either type of key as part of the path to refer to specific elements in an array.
|
|
359
|
+
* For example, if you have an object like `{ items: [{ id: 'xxx', name: 'John' }] }`,
|
|
360
|
+
* you can refer to the name of the first item in the array using either an ID key or a position key in the path:
|
|
361
|
+
*
|
|
362
|
+
* - Using an ID key: `['items', 'id:xxx', 'name']`
|
|
363
|
+
* - Using a position key: `['items', 'pos:0', 'name']`
|
|
364
|
+
*
|
|
365
|
+
* This system of using ID and position keys in paths gives you a powerful and flexible way to refer to specific elements in complex, nested objects.
|
|
366
|
+
*/
|
|
367
|
+
const POSITION_ARRAY_KEY_PREFIX = "pos:";
|
|
368
|
+
/**
|
|
369
|
+
* Checks if the given key is a position array key.
|
|
370
|
+
* @param {unknown} key - The key to check.
|
|
371
|
+
* @returns {boolean} Returns true if `key` is a position array key, false otherwise.
|
|
372
|
+
* @example
|
|
373
|
+
* isPositionArrayKey('pos:0'); // Returns true
|
|
374
|
+
* isPositionArrayKey('id:0'); // Returns false
|
|
375
|
+
*/
|
|
376
|
+
const isPositionArrayKey = (key) => {
|
|
377
|
+
return isString(key) && key.startsWith(POSITION_ARRAY_KEY_PREFIX);
|
|
378
|
+
};
|
|
379
|
+
/**
|
|
380
|
+
* Creates a position array key.
|
|
381
|
+
* @param {string} position - The position to create the key for.
|
|
382
|
+
* @returns {string} Returns the created position array key.
|
|
383
|
+
* @example
|
|
384
|
+
* createPositionArrayKey('0'); // Returns 'pos:0'
|
|
385
|
+
*/
|
|
386
|
+
const createPositionArrayKey = (position) => {
|
|
387
|
+
return `${POSITION_ARRAY_KEY_PREFIX}${position}`;
|
|
388
|
+
};
|
|
389
|
+
/**
|
|
390
|
+
* Extracts the position from a position array key.
|
|
391
|
+
* @param {string} key - The position array key to extract the position from.
|
|
392
|
+
* @returns {string} Returns the extracted position.
|
|
393
|
+
* @example
|
|
394
|
+
* extractPositionFromArrayKey('pos:0'); // Returns '0'
|
|
395
|
+
*/
|
|
396
|
+
const extractPositionFromArrayKey = (key) => {
|
|
397
|
+
if (!isPositionArrayKey(key)) throw new Error(`Invalid array key ${key}. Must be "pos:xxxxx"`);
|
|
398
|
+
return key.split(POSITION_ARRAY_KEY_PREFIX)[1];
|
|
399
|
+
};
|
|
400
|
+
const ID_PATH_KEY_PREFIX = "id:";
|
|
401
|
+
/**
|
|
402
|
+
* Checks if the given key is an ID array key.
|
|
403
|
+
* @param {unknown} key - The key to check.
|
|
404
|
+
* @returns {boolean} Returns true if `key` is an ID array key, false otherwise.
|
|
405
|
+
* @example
|
|
406
|
+
* isIdArrayKey('id:123'); // Returns true
|
|
407
|
+
* isIdArrayKey('pos:0'); // Returns false
|
|
408
|
+
*/
|
|
409
|
+
const isIdArrayKey = (key) => {
|
|
410
|
+
return isString(key) && key.startsWith(ID_PATH_KEY_PREFIX);
|
|
411
|
+
};
|
|
412
|
+
/**
|
|
413
|
+
* Creates an ID array key.
|
|
414
|
+
* @param {string} id - The ID to create the key for.
|
|
415
|
+
* @returns {string} Returns the created ID array key.
|
|
416
|
+
* @example
|
|
417
|
+
* createIdArrayKey('123'); // Returns 'id:123'
|
|
418
|
+
*/
|
|
419
|
+
const createIdArrayKey = (id) => {
|
|
420
|
+
return `${ID_PATH_KEY_PREFIX}${id}`;
|
|
421
|
+
};
|
|
422
|
+
/**
|
|
423
|
+
* Extracts the ID from an ID array key.
|
|
424
|
+
* @param {string} key - The ID array key to extract the ID from.
|
|
425
|
+
* @returns {string} Returns the extracted ID.
|
|
426
|
+
* @example
|
|
427
|
+
* extractIdFromArrayKey('id:123'); // Returns '123'
|
|
428
|
+
*/
|
|
429
|
+
const extractIdFromArrayKey = (key) => {
|
|
430
|
+
if (!isIdArrayKey(key)) throw new Error(`Invalid array key ${key}. Must be "id:xxxxx"`);
|
|
431
|
+
return key.split(ID_PATH_KEY_PREFIX)[1];
|
|
432
|
+
};
|
|
433
|
+
/**
|
|
434
|
+
* Checks if the given key is an array key (either a position array key or an ID array key).
|
|
435
|
+
* @param {unknown} key - The key to check.
|
|
436
|
+
* @returns {boolean} Returns true if `key` is an array key, false otherwise.
|
|
437
|
+
* @example
|
|
438
|
+
* isArrayKey('id:123'); // Returns true
|
|
439
|
+
* isArrayKey('pos:0'); // Returns true
|
|
440
|
+
* isArrayKey('abc'); // Returns false
|
|
441
|
+
*/
|
|
442
|
+
const isArrayKey = (key) => isString(key) && (isPositionArrayKey(key) || isIdArrayKey(key));
|
|
443
|
+
/**
|
|
444
|
+
* Extracts the index from an array key in a given array.
|
|
445
|
+
* @param {unknown} array - The array to extract the index from.
|
|
446
|
+
* @param {string} key - The array key to extract the index from.
|
|
447
|
+
* @returns {number} Returns the extracted index.
|
|
448
|
+
* @example
|
|
449
|
+
* getIndexByArrayKey(['a', 'b', 'c'], 'pos:1'); // Returns 1
|
|
450
|
+
*/
|
|
451
|
+
const getIndexByArrayKey = (array, key) => {
|
|
452
|
+
if (!Array.isArray(array)) {
|
|
453
|
+
console.error(`Non-array type`, array);
|
|
454
|
+
throw new Error(`Can't use array key in non array type (${key})`);
|
|
455
|
+
}
|
|
456
|
+
if (!isArrayKey(key)) throw new Error(`Unknown array key type (${key})`);
|
|
457
|
+
if (array.length === 0) return 0;
|
|
458
|
+
if (isIdArrayKey(key)) {
|
|
459
|
+
const id = extractIdFromArrayKey(key);
|
|
460
|
+
const index = array.findIndex((it) => isObject(it) && it.id === id);
|
|
461
|
+
if (index === -1) throw new Error(`Can't find index by id ${id} (${key})`);
|
|
462
|
+
return index;
|
|
463
|
+
} else if (isPositionArrayKey(key)) {
|
|
464
|
+
const position = extractPositionFromArrayKey(key);
|
|
465
|
+
const index = array.findIndex((it) => it.position === position);
|
|
466
|
+
if (index === -1) throw new Error(`Can't find index by position ${position} (${key})`);
|
|
467
|
+
return index;
|
|
468
|
+
}
|
|
469
|
+
return 0;
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
//#endregion
|
|
473
|
+
//#region src/paths/basic-ops.ts
|
|
474
|
+
/**
|
|
475
|
+
* Gets a nested property value from an object using a path.
|
|
476
|
+
* @param {NestedRecord | undefined} object - The object to get the value from.
|
|
477
|
+
* @param {(string | number)[]} path - The path to the value in the object.
|
|
478
|
+
* @returns {TValue | undefined} Returns the value at the specified path in the object.
|
|
479
|
+
* @example
|
|
480
|
+
* getFromPath({ items: [{ name: 'John' }] }, ['items', 0, 'name']); // Returns 'John'
|
|
481
|
+
*/
|
|
482
|
+
const getFromPath = (object, path) => {
|
|
483
|
+
if (!object) return;
|
|
484
|
+
if (path.length === 0) return object;
|
|
485
|
+
return path.reduce((acc, propKey) => {
|
|
486
|
+
const key = isArrayKey(propKey) ? getIndexByArrayKey(acc, propKey) : propKey;
|
|
487
|
+
if (isContainerValue(acc) && key in acc) return acc[key];
|
|
488
|
+
}, object);
|
|
489
|
+
};
|
|
490
|
+
/**
|
|
491
|
+
* Sets a nested property value in a path, creates the path properties if they don't exist.
|
|
492
|
+
* @param {NestedRecord} object - The object to set the value in.
|
|
493
|
+
* @param {(string | number)[]} path - The path to the value in the object.
|
|
494
|
+
* @param {unknown} value - The value to set.
|
|
495
|
+
* @example
|
|
496
|
+
* let obj = { items: [{ name: 'John' }] };
|
|
497
|
+
* setInPath(obj, ['items', 0, 'name'], 'Jane'); // obj is now { items: [{ name: 'Jane' }] }
|
|
498
|
+
*/
|
|
499
|
+
const setInPath = (object, path, value) => {
|
|
500
|
+
let acc = object;
|
|
501
|
+
for (const [i, rawKey] of path.entries()) {
|
|
502
|
+
const key = isArrayKey(rawKey) ? getIndexByArrayKey(acc, rawKey) : rawKey;
|
|
503
|
+
if (Array.isArray(acc)) {
|
|
504
|
+
const index = Number(key);
|
|
505
|
+
if (i === path.length - 1) {
|
|
506
|
+
acc[index] = value;
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
if (!(index in acc) || isNullOrUndefined(acc[index])) {
|
|
510
|
+
const nextRawKey = path[i + 1];
|
|
511
|
+
acc[index] = isIndex(isArrayKey(nextRawKey) ? getIndexByArrayKey(acc, nextRawKey) : nextRawKey) ? [] : {};
|
|
512
|
+
}
|
|
513
|
+
acc = acc[index];
|
|
514
|
+
} else {
|
|
515
|
+
if (i === path.length - 1) {
|
|
516
|
+
acc[key] = value;
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
if (!(key in acc) || isNullOrUndefined(acc[key])) {
|
|
520
|
+
const nextRawKey = path[i + 1];
|
|
521
|
+
acc[key] = isIndex(isArrayKey(nextRawKey) ? getIndexByArrayKey(acc, nextRawKey) : nextRawKey) ? [] : {};
|
|
522
|
+
}
|
|
523
|
+
acc = acc[key];
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
const unset = (object, key) => {
|
|
528
|
+
if (Array.isArray(object) && isIndex(key)) {
|
|
529
|
+
object.splice(Number(key), 1);
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
if (isObject(object)) delete object[key];
|
|
533
|
+
};
|
|
534
|
+
/**
|
|
535
|
+
* Removes a nested property from an object using a path.
|
|
536
|
+
* @param {NestedRecord} object - The object to remove the value from.
|
|
537
|
+
* @param {(string | number)[]} path - The path to the value in the object.
|
|
538
|
+
* @example
|
|
539
|
+
* let obj = { items: [{ name: 'John' }] };
|
|
540
|
+
* unsetPath(obj, ['items', 0, 'name']); // obj is now { items: [{}] }
|
|
541
|
+
*/
|
|
542
|
+
const unsetPath = (object, path) => {
|
|
543
|
+
let acc = object;
|
|
544
|
+
for (const [i, rawKey] of path.entries()) {
|
|
545
|
+
const key = isArrayKey(rawKey) ? getIndexByArrayKey(acc, rawKey) : rawKey;
|
|
546
|
+
if (i === path.length - 1) {
|
|
547
|
+
unset(acc, key);
|
|
548
|
+
break;
|
|
549
|
+
}
|
|
550
|
+
if (Array.isArray(acc)) {
|
|
551
|
+
const index = Number(key);
|
|
552
|
+
if (!(key in acc) || isNullOrUndefined(acc[index])) break;
|
|
553
|
+
acc = acc[index];
|
|
554
|
+
} else {
|
|
555
|
+
if (!(key in acc) || isNullOrUndefined(acc[key])) break;
|
|
556
|
+
acc = acc[key];
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
/** Checks if a nested property exists in an object using a path.
|
|
561
|
+
* @param {NestedRecord | undefined} object - The object to check the value in.
|
|
562
|
+
* @param {(string | number)[]} path - The path to the value in the object.
|
|
563
|
+
* @returns {boolean} Returns true if the value exists at the specified path, false otherwise.
|
|
564
|
+
* @example
|
|
565
|
+
* existsInPath({ items: [{ name: 'John' }] }, ['items', 0, 'name']); // Returns true
|
|
566
|
+
* existsInPath({ items: [{ name: 'John' }] }, ['items', 1, 'name']); // Returns false
|
|
567
|
+
*/
|
|
568
|
+
const existsInPath = (object, path) => {
|
|
569
|
+
return getFromPath(object, path) !== void 0;
|
|
570
|
+
};
|
|
571
|
+
/** * Compares two paths for equality.
|
|
572
|
+
* @param {(string | number)[]} pathA - The first path to compare.
|
|
573
|
+
* @param {(string | number)[]} pathB - The second path to compare.
|
|
574
|
+
* @returns {boolean} Returns true if the paths are equal, false otherwise.
|
|
575
|
+
* @example
|
|
576
|
+
* isSamePath(['items', 0, 'name'], ['items', 0, 'name']); // Returns true
|
|
577
|
+
* isSamePath(['items', 0, 'name'], ['items', 1, 'name']); // Returns false
|
|
578
|
+
*/
|
|
579
|
+
const isSamePath = (pathA, pathB) => {
|
|
580
|
+
if (pathA.length !== pathB.length) return false;
|
|
581
|
+
for (let i = 0; i < pathA.length; i++) if (pathA[i] !== pathB[i]) return false;
|
|
582
|
+
return true;
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
//#endregion
|
|
586
|
+
//#region src/paths/array-ops.ts
|
|
587
|
+
/**
|
|
588
|
+
* Pushes a value into a nested array in an object using a path.
|
|
589
|
+
* @param {NestedRecord} object - The object to push the value into.
|
|
590
|
+
* @param {(string | number)[]} path - The path to the array in the object.
|
|
591
|
+
* @param {unknown} value - The value to push.
|
|
592
|
+
* @example
|
|
593
|
+
* let obj = { items: ['John'] };
|
|
594
|
+
* pushInPath(obj, ['items'], 'Jane'); // obj is now { items: ['John', 'Jane'] }
|
|
595
|
+
*/
|
|
596
|
+
const pushInPath = (object, path, value) => {
|
|
597
|
+
const array = getFromPath(object, path);
|
|
598
|
+
if (!Array.isArray(array)) setInPath(object, path, [value]);
|
|
599
|
+
else array.push(value);
|
|
600
|
+
};
|
|
601
|
+
/**
|
|
602
|
+
* Inserts values into a nested array in an object at a specified index or key using a path.
|
|
603
|
+
* @param {NestedRecord} object - The object to insert the values into.
|
|
604
|
+
* @param {(string | number)[]} path - The path to the array in the object.
|
|
605
|
+
* @param {string | number} keyOrIndex - The index or key at which to insert the values.
|
|
606
|
+
* @param {unknown[]} values - The values to insert.
|
|
607
|
+
* @example
|
|
608
|
+
* let obj = { items: ['John', 'Jane'] };
|
|
609
|
+
* insertInPath(obj, ['items'], 1, ['Joe']); // obj is now { items: ['John', 'Joe', 'Jane'] }
|
|
610
|
+
*/
|
|
611
|
+
const insertInPath = (object, path, keyOrIndex, values) => {
|
|
612
|
+
const array = getFromPath(object, path);
|
|
613
|
+
if (Array.isArray(array)) {
|
|
614
|
+
if (isIndex(keyOrIndex)) array.splice(keyOrIndex, 0, ...values);
|
|
615
|
+
else if (isArrayKey(keyOrIndex)) {
|
|
616
|
+
const index = getIndexByArrayKey(array, keyOrIndex);
|
|
617
|
+
array.splice(index, 0, ...values);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
/**
|
|
622
|
+
* Removes a value from a nested array in an object at a specified index or array key using a path.
|
|
623
|
+
* @param {NestedRecord} object - The object to remove the value from.
|
|
624
|
+
* @param {(string | number)[]} path - The path to the array in the object.
|
|
625
|
+
* @param {string | number} key - The index or key at which to remove the value.
|
|
626
|
+
* @example
|
|
627
|
+
* let obj = { items: ['John', 'Joe', 'Jane'] };
|
|
628
|
+
* pullFromPath(obj, ['items'], 1); // obj is now { items: ['John', 'Jane'] }
|
|
629
|
+
*/
|
|
630
|
+
const pullFromPath = (object, path, key) => {
|
|
631
|
+
const array = getFromPath(object, path);
|
|
632
|
+
if (Array.isArray(array)) {
|
|
633
|
+
if (isIndex(key)) array.splice(key, 1);
|
|
634
|
+
else if (isArrayKey(key)) {
|
|
635
|
+
const index = getIndexByArrayKey(array, key);
|
|
636
|
+
array.splice(index, 1);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
const printPosition$1 = (array) => array.map((it) => isObject(it) ? it.position ?? "no-position" : "not-object");
|
|
641
|
+
/**
|
|
642
|
+
* Moves an item to a new position relative to another item in the array or object at the specified path.
|
|
643
|
+
*
|
|
644
|
+
* @example
|
|
645
|
+
* moveInYPath(values, ['components'], 'a0', 'b1', 'after');
|
|
646
|
+
*/
|
|
647
|
+
const moveInPath = (object, path, oldPosition, relativePosition, insert) => {
|
|
648
|
+
const array = getFromPath(object, path);
|
|
649
|
+
if (!Array.isArray(array)) throw new Error(`Can't move. Target item is not array in path ${JSON.stringify(path)}`);
|
|
650
|
+
const item = array.find((it) => isObject(it) && it.position === oldPosition);
|
|
651
|
+
const relativeItemIndex = array.findIndex((it) => isObject(it) && it.position === relativePosition);
|
|
652
|
+
if (!isObject(item)) throw new Error(`Can't move. Item in position ${oldPosition} not found. ${printPosition$1(array)}`);
|
|
653
|
+
if (relativeItemIndex === -1) throw new Error(`Can't move. Relative item in position ${relativePosition} not found. ${printPosition$1(array)}`);
|
|
654
|
+
const relativeItem = array[relativeItemIndex];
|
|
655
|
+
if (!isObject(relativeItem)) throw new Error(`Can't move. Relative item in position ${relativePosition} must be an object. ${printPosition$1(array)}`);
|
|
656
|
+
if (insert === "before") {
|
|
657
|
+
const left = array[relativeItemIndex - 1];
|
|
658
|
+
const newPosition$1 = generateKeyBetween(isObject(left) ? left.position ?? null : null, relativeItem.position);
|
|
659
|
+
item.position = newPosition$1;
|
|
660
|
+
return newPosition$1;
|
|
661
|
+
}
|
|
662
|
+
const right = array[relativeItemIndex + 1];
|
|
663
|
+
const rightPosition = isObject(right) ? right.position ?? null : null;
|
|
664
|
+
const newPosition = generateKeyBetween(relativeItem.position, rightPosition);
|
|
665
|
+
item.position = newPosition;
|
|
666
|
+
return newPosition;
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
//#endregion
|
|
670
|
+
//#region src/paths/constants.ts
|
|
671
|
+
const PATH_REGEXP = /\.|\[(\d+)\]/;
|
|
672
|
+
|
|
673
|
+
//#endregion
|
|
674
|
+
//#region src/paths/tools.ts
|
|
675
|
+
/**
|
|
676
|
+
* Joins a path with additional items.
|
|
677
|
+
* @param {(string | number)[]} path - The initial path.
|
|
678
|
+
* @param {...(string | number)[]} items - The items to add to the path.
|
|
679
|
+
* @returns {(string | number)[]} Returns the joined path.
|
|
680
|
+
* @throws {Error} If `path` is not an array or if any of `items` are not a string or an integer.
|
|
681
|
+
* @example
|
|
682
|
+
* joinPath(['items', 'id:xxx'], 'name'); // Returns ['items', 'id:xxx', 'name']
|
|
683
|
+
*/
|
|
684
|
+
const joinPath = (path, ...items) => {
|
|
685
|
+
if (!Array.isArray(path)) throw new Error(`path must be array: ${path}`);
|
|
686
|
+
for (const item of items) if (!isString(item) && !Number.isInteger(item)) throw new Error(`Invalid path item: ${item}`);
|
|
687
|
+
return path.concat(items);
|
|
688
|
+
};
|
|
689
|
+
/**
|
|
690
|
+
* Compares two fractional-based position strings for sorting.
|
|
691
|
+
* @param {string} aPosition - The first fractional-based position string.
|
|
692
|
+
* @param {string} bPosition - The second fractional-based position string.
|
|
693
|
+
* @returns {number} Returns -1 if `aPosition` comes before `bPosition`, 1 if `aPosition` comes after `bPosition`, or 0 if they are equal.
|
|
694
|
+
* @example
|
|
695
|
+
* sortByPosition('a1', 'a2'); // Returns -1
|
|
696
|
+
*/
|
|
697
|
+
const sortByPosition = (aPosition, bPosition) => {
|
|
698
|
+
if (aPosition < bPosition) return -1;
|
|
699
|
+
else if (aPosition > bPosition) return 1;
|
|
700
|
+
return 0;
|
|
701
|
+
};
|
|
702
|
+
|
|
703
|
+
//#endregion
|
|
704
|
+
//#region src/dynamic-components/registry/chats.ts
|
|
705
|
+
const isChatTextMessageComponent = (component) => component.component === "chat-text-message";
|
|
706
|
+
const isChatMessageDelayComponent = (component) => component.component === "chat-message-delay";
|
|
707
|
+
|
|
708
|
+
//#endregion
|
|
709
|
+
//#region src/dynamic-components/registry/content.ts
|
|
710
|
+
const isRichTextComponent = (component) => component.component === "rich-text";
|
|
711
|
+
const isEmbedCodeComponent = (component) => {
|
|
712
|
+
return component.component === "embed-code";
|
|
713
|
+
};
|
|
714
|
+
const isImageComponent = (component) => component.component === "image";
|
|
715
|
+
const isLegacyContentComponent = (component) => component.component === "legacy-content";
|
|
716
|
+
const isBibleQuoteComponent = (component) => component.component === "bible-quote";
|
|
717
|
+
const isBiblePassageComponent = (component) => component.component === "bible-passage";
|
|
718
|
+
const isTestComponent = (component) => component.component === "test";
|
|
719
|
+
const isStatementComponent = (component) => component.component === "statement";
|
|
720
|
+
const isPracticeComponent = (component) => component.component === "practice";
|
|
721
|
+
|
|
722
|
+
//#endregion
|
|
723
|
+
//#region src/dynamic-components/registry/forms.ts
|
|
724
|
+
let IImageRenditionType = /* @__PURE__ */ function(IImageRenditionType$1) {
|
|
725
|
+
IImageRenditionType$1["ORIGINAL"] = "ORIGINAL";
|
|
726
|
+
IImageRenditionType$1["MAIN_2X"] = "MAIN_2X";
|
|
727
|
+
IImageRenditionType$1["MAIN"] = "MAIN";
|
|
728
|
+
IImageRenditionType$1["SMALL"] = "SMALL";
|
|
729
|
+
IImageRenditionType$1["MAIN_LEGACY"] = "MAIN_LEGACY";
|
|
730
|
+
return IImageRenditionType$1;
|
|
731
|
+
}({});
|
|
732
|
+
const isComputedValueComponent = (component) => component.component === "computed-value";
|
|
733
|
+
const isTextInputComponent = (component) => component.component === "text-input";
|
|
734
|
+
const isConfirmDeletionInputComponent = (component) => component.component === "confirm-deletion-input";
|
|
735
|
+
const isTextareaComponent = (component) => component.component === "textarea";
|
|
736
|
+
const isHeadingComponent = (component) => component.component === "heading";
|
|
737
|
+
const isRichTextEditorComponent = (component) => component.component === "rich-text-editor";
|
|
738
|
+
const isDateTimePickerComponent = (component) => {
|
|
739
|
+
return component.component === "date-time-picker";
|
|
740
|
+
};
|
|
741
|
+
const isNumberInputComponent = (component) => {
|
|
742
|
+
return component.component === "number-input";
|
|
743
|
+
};
|
|
744
|
+
const isSlugComponent = (component) => {
|
|
745
|
+
return component.component === "slug";
|
|
746
|
+
};
|
|
747
|
+
const isImageUploaderComponent = (component) => {
|
|
748
|
+
return component.component === "image-uploader";
|
|
749
|
+
};
|
|
750
|
+
const isRawImageUploaderComponent = (component) => {
|
|
751
|
+
return component.component === "raw-image-uploader";
|
|
752
|
+
};
|
|
753
|
+
const isRawImagesUploaderComponent = (component) => {
|
|
754
|
+
return component.component === "raw-images-uploader";
|
|
755
|
+
};
|
|
756
|
+
const isSimpleImageUploaderComponent = (component) => {
|
|
757
|
+
return component.component === "simple-image-uploader";
|
|
758
|
+
};
|
|
759
|
+
const isRadioGroupComponent = (component) => {
|
|
760
|
+
return component.component === "radio-group";
|
|
761
|
+
};
|
|
762
|
+
const isSelectComponent = (cmp) => cmp.component === "select";
|
|
763
|
+
const isEntitySelectComponent = (cmp) => cmp.component === "entity-select";
|
|
764
|
+
const isCheckboxComponent = (component) => {
|
|
765
|
+
return component.component === "checkbox";
|
|
766
|
+
};
|
|
767
|
+
const isCheckboxGroupComponent = (component) => {
|
|
768
|
+
return component.component === "checkbox";
|
|
769
|
+
};
|
|
770
|
+
const isSwitchComponent = (component) => {
|
|
771
|
+
return component.component === "switch";
|
|
772
|
+
};
|
|
773
|
+
const isFileUploaderComponent = (component) => {
|
|
774
|
+
return component.component === "file-uploader";
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
//#endregion
|
|
778
|
+
//#region src/dynamic-components/registry/layout.ts
|
|
779
|
+
const isColumnComponent = (component) => {
|
|
780
|
+
return component.component === "column";
|
|
781
|
+
};
|
|
782
|
+
const isRowComponent = (component) => {
|
|
783
|
+
return component.component === "row";
|
|
784
|
+
};
|
|
785
|
+
const isCollectionComponent = (component) => {
|
|
786
|
+
return component.component === "collection";
|
|
787
|
+
};
|
|
788
|
+
const isRepeatableCollectionComponent = (component) => {
|
|
789
|
+
return component.component === "repeatable-collection";
|
|
790
|
+
};
|
|
791
|
+
const isRowSettingsComponent = (component) => {
|
|
792
|
+
return component.component === "row-settings";
|
|
793
|
+
};
|
|
794
|
+
|
|
795
|
+
//#endregion
|
|
796
|
+
//#region src/dynamic-components/paths.ts
|
|
797
|
+
/**
|
|
798
|
+
* Get array with components founded by rpath
|
|
799
|
+
*
|
|
800
|
+
* @example
|
|
801
|
+
* const components = [
|
|
802
|
+
* {
|
|
803
|
+
* id: "xxx",
|
|
804
|
+
* component: "collection",
|
|
805
|
+
* props: {
|
|
806
|
+
* components: [
|
|
807
|
+
* {
|
|
808
|
+
* id: "yyy",
|
|
809
|
+
* component: "text-input",
|
|
810
|
+
* props: {
|
|
811
|
+
* label: "Title"
|
|
812
|
+
* }
|
|
813
|
+
* }
|
|
814
|
+
* ]
|
|
815
|
+
* }
|
|
816
|
+
* }
|
|
817
|
+
* ]
|
|
818
|
+
*
|
|
819
|
+
* const { pathWithComponents } = getComponentsSubtreeByRPath(components, ['xxx', 'yyy']);
|
|
820
|
+
*
|
|
821
|
+
* // pathWithComponents
|
|
822
|
+
* // [
|
|
823
|
+
* // {
|
|
824
|
+
* // id: "xxx",
|
|
825
|
+
* // component: "collection",
|
|
826
|
+
* // ...
|
|
827
|
+
* // },
|
|
828
|
+
* // {
|
|
829
|
+
* // id: "yyy",
|
|
830
|
+
* // component: "text-input",
|
|
831
|
+
* // ...
|
|
832
|
+
* // }
|
|
833
|
+
* // ]
|
|
834
|
+
*
|
|
835
|
+
*/
|
|
836
|
+
const getComponentsSubtreeByRPath = (components, rpath) => {
|
|
837
|
+
const pathWithComponents = [];
|
|
838
|
+
deepGetComponentsSubtreeByRPath(components, rpath, pathWithComponents);
|
|
839
|
+
return {
|
|
840
|
+
pathWithComponents,
|
|
841
|
+
complete: pathWithComponents.length === rpath.length
|
|
842
|
+
};
|
|
843
|
+
};
|
|
844
|
+
const deepGetComponentsSubtreeByRPath = (components, rpath, pathWithComponents) => {
|
|
845
|
+
const id = rpath[0];
|
|
846
|
+
const component = components.find((cmp) => cmp.id === id);
|
|
847
|
+
if (!component) return;
|
|
848
|
+
pathWithComponents.push(component);
|
|
849
|
+
if (!Array.isArray(component.props.components)) return;
|
|
850
|
+
deepGetComponentsSubtreeByRPath(component.props.components, rpath.slice(1), pathWithComponents);
|
|
851
|
+
};
|
|
852
|
+
/**
|
|
853
|
+
* Get array with components founded by values path.
|
|
854
|
+
*
|
|
855
|
+
* @example
|
|
856
|
+
* const components = [
|
|
857
|
+
* {
|
|
858
|
+
* id: "xxx",
|
|
859
|
+
* component: "collection",
|
|
860
|
+
* props: {
|
|
861
|
+
* name: "seo",
|
|
862
|
+
* components: [
|
|
863
|
+
* {
|
|
864
|
+
* id: "yyy",
|
|
865
|
+
* component: "text-input",
|
|
866
|
+
* props: {
|
|
867
|
+
* label: "Title",
|
|
868
|
+
* name: "title",
|
|
869
|
+
* }
|
|
870
|
+
* }
|
|
871
|
+
* ]
|
|
872
|
+
* }
|
|
873
|
+
* }
|
|
874
|
+
* ]
|
|
875
|
+
*
|
|
876
|
+
* const { pathWithComponents } = getComponentsSubtreeByPath(components, ['seo', 'title']);
|
|
877
|
+
*
|
|
878
|
+
* // pathWithComponents
|
|
879
|
+
* // [
|
|
880
|
+
* // {
|
|
881
|
+
* // id: "xxx",
|
|
882
|
+
* // component: "collection",
|
|
883
|
+
* // ...
|
|
884
|
+
* // },
|
|
885
|
+
* // {
|
|
886
|
+
* // id: "yyy",
|
|
887
|
+
* // component: "text-input",
|
|
888
|
+
* // ...
|
|
889
|
+
* // }
|
|
890
|
+
* // ]
|
|
891
|
+
*
|
|
892
|
+
*/
|
|
893
|
+
const getComponentsSubtreeByPath = (components, path) => {
|
|
894
|
+
const pathWithComponents = [];
|
|
895
|
+
const complete = true;
|
|
896
|
+
deepGetComponentsSubtreeByPath(components, path, pathWithComponents, complete);
|
|
897
|
+
return {
|
|
898
|
+
pathWithComponents,
|
|
899
|
+
complete
|
|
900
|
+
};
|
|
901
|
+
};
|
|
902
|
+
const deepFindComponentPathKey = (components, key) => {
|
|
903
|
+
for (const component of components) {
|
|
904
|
+
if (component.props.name && component.props.name === key || component.id === key) return component;
|
|
905
|
+
if (isRowComponent(component) || isColumnComponent(component)) {
|
|
906
|
+
const result = deepFindComponentPathKey(component.props.components, key);
|
|
907
|
+
if (result) return result;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
return null;
|
|
911
|
+
};
|
|
912
|
+
const deepGetComponentsSubtreeByPath = (components, path, pathWithComponents, complete) => {
|
|
913
|
+
const key = path[0];
|
|
914
|
+
if (!isString(key)) {
|
|
915
|
+
complete = false;
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
const component = deepFindComponentPathKey(components, key);
|
|
919
|
+
if (!component) {
|
|
920
|
+
complete = false;
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
pathWithComponents.push(component);
|
|
924
|
+
/**
|
|
925
|
+
* Deep dive if repeatable collection.
|
|
926
|
+
*
|
|
927
|
+
* If next key is array key find in props.components next key after array key
|
|
928
|
+
*
|
|
929
|
+
* @example
|
|
930
|
+
* path = ['fields', 'id:xxx', 'title']
|
|
931
|
+
*
|
|
932
|
+
* cpnst key = 'fields';
|
|
933
|
+
* const nextKey = 'id:xxx', // array key
|
|
934
|
+
* const nextKeyAfterArrayKey = 'title';
|
|
935
|
+
*/
|
|
936
|
+
if (isRepeatableCollectionComponent(component)) {
|
|
937
|
+
const nextKey = path[1];
|
|
938
|
+
if (isArrayKey(nextKey) && path[2]) deepGetComponentsSubtreeByPath(component.props.components, path.slice(2), pathWithComponents, complete);
|
|
939
|
+
}
|
|
940
|
+
if (isCollectionComponent(component)) deepGetComponentsSubtreeByPath(component.props.components, path.slice(1), pathWithComponents, complete);
|
|
941
|
+
};
|
|
942
|
+
|
|
943
|
+
//#endregion
|
|
944
|
+
//#region src/dynamic-components/tools.ts
|
|
945
|
+
const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
|
|
946
|
+
const customAlphabet = (alphabet, defaultSize = 21) => {
|
|
947
|
+
return (size = defaultSize) => {
|
|
948
|
+
let id = "";
|
|
949
|
+
let i = size;
|
|
950
|
+
while (i--) id += alphabet[Math.random() * alphabet.length | 0];
|
|
951
|
+
return id;
|
|
952
|
+
};
|
|
953
|
+
};
|
|
954
|
+
const uid = customAlphabet("1234567890abcdefg", 5);
|
|
955
|
+
/**
|
|
956
|
+
* Gets the path to a property in a component.
|
|
957
|
+
* @param {(string | number)[]} componentPath - The path to the component.
|
|
958
|
+
* @param {string} name - The name of the property.
|
|
959
|
+
* @returns {(string | number)[]} Returns the path to the property.
|
|
960
|
+
* @example
|
|
961
|
+
* getComponentPropertyPath(['components', 0], 'name'); // Returns ['components', 0, 'props', 'name']
|
|
962
|
+
*/
|
|
963
|
+
const getComponentPropertyPath = (componentPath, name) => [
|
|
964
|
+
...componentPath,
|
|
965
|
+
"props",
|
|
966
|
+
name
|
|
967
|
+
];
|
|
968
|
+
/**
|
|
969
|
+
* Creates a copy of a dynamic component.
|
|
970
|
+
* @param {DynamicComponent} component - The component to copy.
|
|
971
|
+
* @param {Y.Doc} yDoc - The Yjs document to update with the copied component.
|
|
972
|
+
* @returns {DynamicComponent} Returns the copied component.
|
|
973
|
+
*/
|
|
974
|
+
const copyDynamicComponent = (component, yDoc) => {
|
|
975
|
+
const { id, props, coordinates, inputs, outputs,...extras } = component;
|
|
976
|
+
const componentCopy = {
|
|
977
|
+
...extras,
|
|
978
|
+
id: uid(),
|
|
979
|
+
props: {}
|
|
980
|
+
};
|
|
981
|
+
if (coordinates) componentCopy.coordinates = [coordinates[0] + 10, coordinates[1] + 10];
|
|
982
|
+
if (inputs) componentCopy.inputs = inputs.map((input) => ({
|
|
983
|
+
...input,
|
|
984
|
+
id: uid()
|
|
985
|
+
}));
|
|
986
|
+
if (outputs) componentCopy.outputs = outputs.map((output) => ({
|
|
987
|
+
...output,
|
|
988
|
+
id: uid()
|
|
989
|
+
}));
|
|
990
|
+
for (const [key, value] of Object.entries(props)) if (key === "components" && Array.isArray(value)) componentCopy.props.components = value.map((cmp) => copyDynamicComponent(cmp));
|
|
991
|
+
else if (isRichText(value)) {
|
|
992
|
+
const oldKey = `${value.type}:${value.id}`;
|
|
993
|
+
const newRichText = {
|
|
994
|
+
...value,
|
|
995
|
+
id: uid()
|
|
996
|
+
};
|
|
997
|
+
const newKey = `${value.type}:${newRichText.id}`;
|
|
998
|
+
if (yDoc) {
|
|
999
|
+
const yXmlFragment = yDoc.getXmlFragment(oldKey);
|
|
1000
|
+
const newYXmlFragment = yDoc.getXmlFragment(newKey);
|
|
1001
|
+
const clones = [];
|
|
1002
|
+
for (const item of yXmlFragment.toArray()) if (item instanceof Y.XmlElement || item instanceof Y.XmlText) clones.push(item.clone());
|
|
1003
|
+
newYXmlFragment.insert(0, clones);
|
|
1004
|
+
}
|
|
1005
|
+
componentCopy.props[key] = newRichText;
|
|
1006
|
+
} else componentCopy.props[key] = value;
|
|
1007
|
+
return componentCopy;
|
|
1008
|
+
};
|
|
1009
|
+
/**
|
|
1010
|
+
* Sorts an array of dynamic components and generates a position for each one.
|
|
1011
|
+
* @param {DynamicComponent[]} components - The components to sort.
|
|
1012
|
+
* @returns {DynamicComponentWithPosition[]} Returns the sorted components with positions.
|
|
1013
|
+
*/
|
|
1014
|
+
const sortDynamicComponents = (components) => {
|
|
1015
|
+
return components.reduce((acc, component, i) => {
|
|
1016
|
+
const prev = acc[i - 1];
|
|
1017
|
+
const { position, props: { components: components$1,...baseProps },...baseFields } = component;
|
|
1018
|
+
const props = baseProps;
|
|
1019
|
+
if (components$1) props.components = sortDynamicComponents(components$1);
|
|
1020
|
+
acc.push({
|
|
1021
|
+
...baseFields,
|
|
1022
|
+
position: position ?? generateKeyBetween(prev?.position ?? null, null),
|
|
1023
|
+
props
|
|
1024
|
+
});
|
|
1025
|
+
return acc;
|
|
1026
|
+
}, []);
|
|
1027
|
+
};
|
|
1028
|
+
/**
|
|
1029
|
+
* Searches for a dynamic component in a tree that matches a condition.
|
|
1030
|
+
* @param {DynamicComponent[]} components - The tree of components to search.
|
|
1031
|
+
* @param {(cmp: DynamicComponent) => boolean} isMatches - The condition to match.
|
|
1032
|
+
* @returns {DynamicComponent | null} Returns the matching component, or null if no match was found.
|
|
1033
|
+
*/
|
|
1034
|
+
const searchDynamicComponentInTree = (components, isMatches) => {
|
|
1035
|
+
for (const component of components) {
|
|
1036
|
+
if (isMatches(component)) return component;
|
|
1037
|
+
if (Array.isArray(component.props.components)) {
|
|
1038
|
+
const result = searchDynamicComponentInTree(component.props.components, isMatches);
|
|
1039
|
+
if (result) return result;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
return null;
|
|
1043
|
+
};
|
|
1044
|
+
const getRelativePoint = (point, relative) => [point[0] - relative[0], point[1] - relative[1]];
|
|
1045
|
+
/**
|
|
1046
|
+
* Creates a copy of a dynamic component and set its position (fractional-index) rely on the index of the component.
|
|
1047
|
+
* @param components - The components without positions.
|
|
1048
|
+
*/
|
|
1049
|
+
const makeDynamicComponentsWithPosition = (components) => {
|
|
1050
|
+
return sortDynamicComponents(components.slice(0));
|
|
1051
|
+
};
|
|
1052
|
+
|
|
1053
|
+
//#endregion
|
|
1054
|
+
//#region src/dynamic-components/types.ts
|
|
1055
|
+
/**
|
|
1056
|
+
* Defines a DynamicComponent.
|
|
1057
|
+
* @param {T} component - The component to define.
|
|
1058
|
+
* @returns {T} Returns the defined component.
|
|
1059
|
+
*/
|
|
1060
|
+
const defineDynamicComponent = (component) => component;
|
|
1061
|
+
/**
|
|
1062
|
+
* Defines an array of DynamicComponents.
|
|
1063
|
+
* @param {T[]} components - The components to define.
|
|
1064
|
+
* @returns {T[]} Returns the defined components.
|
|
1065
|
+
*/
|
|
1066
|
+
const defineDynamicComponents = (components) => components.map((component) => defineDynamicComponent(component));
|
|
1067
|
+
|
|
1068
|
+
//#endregion
|
|
1069
|
+
//#region src/y-tools/y-array-keys.ts
|
|
1070
|
+
/**
|
|
1071
|
+
* Returns the index of an item in a Y.Array based on its key.
|
|
1072
|
+
* The key can represent either the id or the position of the item in the array.
|
|
1073
|
+
*
|
|
1074
|
+
* @example
|
|
1075
|
+
* let yArray = new Y.Array();
|
|
1076
|
+
* let yMap = new Y.Map();
|
|
1077
|
+
* yMap.set('id', '123');
|
|
1078
|
+
* yMap.set('position', 'a0');
|
|
1079
|
+
* yArray.push([yMap]);
|
|
1080
|
+
* const index = getYArrayIndexByArrayKey(yArray, 'id:123');
|
|
1081
|
+
* const index = getYArrayIndexByArrayKey(yArray, 'pos:a0');
|
|
1082
|
+
* // index is now: 0
|
|
1083
|
+
*/
|
|
1084
|
+
const getYArrayIndexByArrayKey = (yArray, key) => {
|
|
1085
|
+
if (!isYArray(yArray)) {
|
|
1086
|
+
console.error(`Non-YArray type`, yArray);
|
|
1087
|
+
throw new Error(`Can't use array key in non YArray type (${key})`);
|
|
1088
|
+
}
|
|
1089
|
+
if (isIdArrayKey(key)) {
|
|
1090
|
+
const id = extractIdFromArrayKey(key);
|
|
1091
|
+
const index = yArray.toArray().findIndex((it) => isYMap(it) && it.get("id") === id);
|
|
1092
|
+
if (index === -1) throw new Error(`Can't find index by id ${id} (${key})`);
|
|
1093
|
+
return index;
|
|
1094
|
+
} else if (isPositionArrayKey(key)) {
|
|
1095
|
+
const position = extractPositionFromArrayKey(key);
|
|
1096
|
+
const index = yArray.toArray().findIndex((it) => isYMap(it) && it.get("position") === position);
|
|
1097
|
+
if (index === -1) throw new Error(`Can't find index by position ${position} (${key})`);
|
|
1098
|
+
return index;
|
|
1099
|
+
}
|
|
1100
|
+
throw new Error(`Unknown array key type (${key})`);
|
|
1101
|
+
};
|
|
1102
|
+
|
|
1103
|
+
//#endregion
|
|
1104
|
+
//#region src/y-tools/basic-path-ops.ts
|
|
1105
|
+
/**
|
|
1106
|
+
* Sets a value at a given path within a Y.Map or Y.Array.
|
|
1107
|
+
*
|
|
1108
|
+
* @example
|
|
1109
|
+
* let ymap = new Y.Map();
|
|
1110
|
+
* setInYPath(ymap, ['key'], 'value');
|
|
1111
|
+
* // ymap now looks like: { key: 'value' }
|
|
1112
|
+
*/
|
|
1113
|
+
const setInYPath = (ymap, path, value) => {
|
|
1114
|
+
let acc = ymap;
|
|
1115
|
+
for (const [i, rawKey] of path.entries()) {
|
|
1116
|
+
const key = isArrayKey(rawKey) ? getYArrayIndexByArrayKey(acc, rawKey) : rawKey;
|
|
1117
|
+
if (isYArray(acc) && isIndex(key)) {
|
|
1118
|
+
const index = key;
|
|
1119
|
+
if (i === path.length - 1) {
|
|
1120
|
+
acc.delete(index);
|
|
1121
|
+
acc.push([value]);
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
if (isNullOrUndefined(acc.get(index))) {
|
|
1125
|
+
const nextRawKey = path[i + 1];
|
|
1126
|
+
const nextKey = isArrayKey(nextRawKey) ? getYArrayIndexByArrayKey(acc, nextRawKey) : nextRawKey;
|
|
1127
|
+
acc.delete(index);
|
|
1128
|
+
acc.insert(index, [isIndex(nextKey) ? new Y.Array() : new Y.Map()]);
|
|
1129
|
+
}
|
|
1130
|
+
acc = acc.get(index);
|
|
1131
|
+
} else if (isYMap(acc) && isString(key)) {
|
|
1132
|
+
if (i === path.length - 1) {
|
|
1133
|
+
acc.set(key, value);
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1136
|
+
if (!acc.has(key) || isNullOrUndefined(acc.get(key))) {
|
|
1137
|
+
const nextRawKey = path[i + 1];
|
|
1138
|
+
const nextKey = isArrayKey(nextRawKey) ? getYArrayIndexByArrayKey(acc, nextRawKey) : nextRawKey;
|
|
1139
|
+
acc.set(key, isIndex(nextKey) ? new Y.Array() : new Y.Map());
|
|
1140
|
+
}
|
|
1141
|
+
acc = acc.get(key);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
};
|
|
1145
|
+
const yUnset = (yType, key) => {
|
|
1146
|
+
if (yType instanceof Y.Array && isIndex(key)) yType.delete(Number(key));
|
|
1147
|
+
else if (yType instanceof Y.Map && isString(key)) yType.delete(key);
|
|
1148
|
+
};
|
|
1149
|
+
/**
|
|
1150
|
+
* Removes a nested property from a Y.Map or Y.Array.
|
|
1151
|
+
*
|
|
1152
|
+
* @example
|
|
1153
|
+
* let ymap = new Y.Map();
|
|
1154
|
+
* ymap.set('key', 'value');
|
|
1155
|
+
* unsetYPath(ymap, ['key']);
|
|
1156
|
+
* // ymap now looks like: {}
|
|
1157
|
+
*/
|
|
1158
|
+
const unsetYPath = (yType, path) => {
|
|
1159
|
+
let acc = yType;
|
|
1160
|
+
for (const [i, rawKey] of path.entries()) {
|
|
1161
|
+
const key = isArrayKey(rawKey) ? getYArrayIndexByArrayKey(acc, rawKey) : rawKey;
|
|
1162
|
+
if (i === path.length - 1) {
|
|
1163
|
+
yUnset(acc, key);
|
|
1164
|
+
break;
|
|
1165
|
+
}
|
|
1166
|
+
if (acc instanceof Y.Array && isIndex(key)) {
|
|
1167
|
+
const index = Number(key);
|
|
1168
|
+
if (isNullOrUndefined(acc.get(index))) break;
|
|
1169
|
+
acc = acc.get(index);
|
|
1170
|
+
} else if (acc instanceof Y.Map && isString(key)) {
|
|
1171
|
+
if (!acc.has(key) || isNullOrUndefined(acc.get(key))) break;
|
|
1172
|
+
acc = acc.get(key);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
};
|
|
1176
|
+
/**
|
|
1177
|
+
* Retrieves a nested property value from a Y.Map or Y.Array.
|
|
1178
|
+
*
|
|
1179
|
+
* @example
|
|
1180
|
+
* let ymap = new Y.Map();
|
|
1181
|
+
* ymap.set('key', 'value');
|
|
1182
|
+
* const value = getFromYPath(ymap, ['key']);
|
|
1183
|
+
* // value is now: 'value'
|
|
1184
|
+
*/
|
|
1185
|
+
const getFromYPath = (entry, path) => {
|
|
1186
|
+
if (!entry) return;
|
|
1187
|
+
if (path.length === 0) return entry;
|
|
1188
|
+
let ref = entry;
|
|
1189
|
+
for (const rawKey of path) {
|
|
1190
|
+
const key = isArrayKey(rawKey) ? getYArrayIndexByArrayKey(ref, rawKey) : rawKey;
|
|
1191
|
+
if (isYArray(ref)) {
|
|
1192
|
+
if (!isIndex(key)) {
|
|
1193
|
+
console.warn(`Can't use non index key in YArray ${key}: ${JSON.stringify(path)}`);
|
|
1194
|
+
return null;
|
|
1195
|
+
}
|
|
1196
|
+
ref = ref.get(key);
|
|
1197
|
+
continue;
|
|
1198
|
+
} else if (isYMap(ref)) {
|
|
1199
|
+
if (!isString(key)) {
|
|
1200
|
+
console.warn(`Can't use non string key in YMap ${key}: ${JSON.stringify(path)}`);
|
|
1201
|
+
return null;
|
|
1202
|
+
}
|
|
1203
|
+
ref = ref.get(key);
|
|
1204
|
+
} else {
|
|
1205
|
+
console.warn(`Non supported YType on ${key}: ${JSON.stringify(path)}`);
|
|
1206
|
+
return null;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
return ref;
|
|
1210
|
+
};
|
|
1211
|
+
|
|
1212
|
+
//#endregion
|
|
1213
|
+
//#region src/y-tools/tools.ts
|
|
1214
|
+
/**
|
|
1215
|
+
* Returns the index of the first item in a Y.Array that matches a condition.
|
|
1216
|
+
*
|
|
1217
|
+
* @example
|
|
1218
|
+
* let yArray = new Y.Array();
|
|
1219
|
+
* yArray.push(['item1', 'item2', 'item3']);
|
|
1220
|
+
* const index = findIndexInYArray(yArray, (item) => item === 'item2');
|
|
1221
|
+
* // index is now: 1
|
|
1222
|
+
*/
|
|
1223
|
+
const findIndexInYArray = (yArray, isMatches) => {
|
|
1224
|
+
return yArray.toArray().findIndex(isMatches);
|
|
1225
|
+
};
|
|
1226
|
+
/**
|
|
1227
|
+
* Returns the first item in a Y.Array that matches a condition.
|
|
1228
|
+
*
|
|
1229
|
+
* @example
|
|
1230
|
+
* let yArray = new Y.Array();
|
|
1231
|
+
* yArray.push(['item1', 'item2', 'item3']);
|
|
1232
|
+
* const item = findInYArray(yArray, (item) => item === 'item2');
|
|
1233
|
+
* // item is now: 'item2'
|
|
1234
|
+
*/
|
|
1235
|
+
const findInYArray = (yArray, isMatches) => {
|
|
1236
|
+
const index = findIndexInYArray(yArray, isMatches);
|
|
1237
|
+
if (index === -1) return null;
|
|
1238
|
+
return yArray.get(index);
|
|
1239
|
+
};
|
|
1240
|
+
/**
|
|
1241
|
+
* Converts an object to a Y.Map.
|
|
1242
|
+
*
|
|
1243
|
+
* @example
|
|
1244
|
+
* const object = { key: 'value' };
|
|
1245
|
+
* const yMap = objectToYMap(object);
|
|
1246
|
+
* // yMap now looks like: { key: 'value' }
|
|
1247
|
+
*/
|
|
1248
|
+
const objectToYMap = (values) => {
|
|
1249
|
+
const entries = Object.entries(values).map(([key, value]) => {
|
|
1250
|
+
if (Array.isArray(value)) return [key, arrayToYArray(value)];
|
|
1251
|
+
else if (isObject(value)) return [key, objectToYMap(value)];
|
|
1252
|
+
else return [key, value];
|
|
1253
|
+
});
|
|
1254
|
+
return new Y.Map(entries);
|
|
1255
|
+
};
|
|
1256
|
+
/**
|
|
1257
|
+
* Converts an array to a Y.Array.
|
|
1258
|
+
*
|
|
1259
|
+
* @example
|
|
1260
|
+
* const array = ['item1', 'item2', 'item3'];
|
|
1261
|
+
* const yArray = arrayToYArray(array);
|
|
1262
|
+
* // yArray now looks like: ['item1', 'item2', 'item3']
|
|
1263
|
+
*/
|
|
1264
|
+
const arrayToYArray = (array, yArray = new Y.Array()) => {
|
|
1265
|
+
const items = array.map((it) => isObject(it) ? objectToYMap(it) : it);
|
|
1266
|
+
yArray.insert(0, items);
|
|
1267
|
+
return yArray;
|
|
1268
|
+
};
|
|
1269
|
+
/**
|
|
1270
|
+
* Returns a sorted Y.Array based on the position of each Y.Map in it.
|
|
1271
|
+
*
|
|
1272
|
+
* @example
|
|
1273
|
+
* let yArray = new Y.Array();
|
|
1274
|
+
* let yMap1 = new Y.Map();
|
|
1275
|
+
* let yMap2 = new Y.Map();
|
|
1276
|
+
* yMap1.set('position', 'a0');
|
|
1277
|
+
* yMap2.set('position', 'b0');
|
|
1278
|
+
* yArray.push([yMap2, yMap1]);
|
|
1279
|
+
* const sortedYArray = getSortedYArray(yArray);
|
|
1280
|
+
* // sortedYArray now looks like: [ yMap1, yMap2 ]
|
|
1281
|
+
*/
|
|
1282
|
+
const getSortedYArray = (yArray) => yArray.toArray().sort((a, b) => sortByPosition(a.get("position"), b.get("position")));
|
|
1283
|
+
/**
|
|
1284
|
+
* Returns references to a Y.Map and its neighbors in a Y.Array based on its position.
|
|
1285
|
+
*
|
|
1286
|
+
* @example
|
|
1287
|
+
* let yArray = new Y.Array();
|
|
1288
|
+
* let yMap1 = new Y.Map();
|
|
1289
|
+
* let yMap2 = new Y.Map();
|
|
1290
|
+
* yMap1.set('position', 'a0');
|
|
1291
|
+
* yMap2.set('position', 'b0');
|
|
1292
|
+
* yArray.push([yMap2, yMap1]);
|
|
1293
|
+
* const refs = getYArrayRefsByPosition(yArray, 'a0');
|
|
1294
|
+
* // refs now looks like: { index: 0, ref: yMap1, right: yMap2, left: undefined, sortedArray: [yMap1, yMap2] }
|
|
1295
|
+
*/
|
|
1296
|
+
const getYArrayRefsByPosition = (yArray, position) => {
|
|
1297
|
+
const sortedArray = getSortedYArray(yArray);
|
|
1298
|
+
const index = sortedArray.findIndex((it) => it.get("position") === position);
|
|
1299
|
+
if (index === -1) {
|
|
1300
|
+
console.error("sortedArray", sortedArray);
|
|
1301
|
+
throw new Error(`Relative item with position ${position} not found`);
|
|
1302
|
+
}
|
|
1303
|
+
return {
|
|
1304
|
+
index,
|
|
1305
|
+
ref: sortedArray[index],
|
|
1306
|
+
right: sortedArray[index + 1],
|
|
1307
|
+
left: sortedArray[index - 1],
|
|
1308
|
+
sortedArray
|
|
1309
|
+
};
|
|
1310
|
+
};
|
|
1311
|
+
|
|
1312
|
+
//#endregion
|
|
1313
|
+
//#region src/y-tools/array-path-ops.ts
|
|
1314
|
+
/**
|
|
1315
|
+
* Pushes a value to the end of the Y.Array at the specified path.
|
|
1316
|
+
*
|
|
1317
|
+
* @example
|
|
1318
|
+
* let yMap = new Y.Map();
|
|
1319
|
+
* yMap.set('names', new Y.Array());
|
|
1320
|
+
* pushInYPath(yMap, ['names'], 'John');
|
|
1321
|
+
* // yMap now looks like: { names: ['John'] }
|
|
1322
|
+
*/
|
|
1323
|
+
const pushInYPath = (entry, path, value) => {
|
|
1324
|
+
const yArray = getFromYPath(entry, path);
|
|
1325
|
+
if (!isYArray(yArray)) setInYPath(entry, path, Y.Array.from([value]));
|
|
1326
|
+
else yArray.push([value]);
|
|
1327
|
+
};
|
|
1328
|
+
const printPosition = (array) => array.map((it) => isYMap(it) ? it.get("position") ?? "no-position" : "not-ymap");
|
|
1329
|
+
/**
|
|
1330
|
+
* Moves an item to a new position relative to another item in the Y.Array or Y.Map at the specified path.
|
|
1331
|
+
*
|
|
1332
|
+
* @example
|
|
1333
|
+
* moveInYPath(yMap, ['components'], 'a0', 'b1', 'after');
|
|
1334
|
+
*/
|
|
1335
|
+
const moveInYPath = (entry, path, oldPosition, relativePosition, insert) => {
|
|
1336
|
+
const yArray = getFromYPath(entry, path);
|
|
1337
|
+
if (!isYArray(yArray)) throw new Error(`Can't move. Target item is not yArray in path ${JSON.stringify(path)}`);
|
|
1338
|
+
const array = yArray.toArray();
|
|
1339
|
+
const item = array.find((it) => isYMap(it) && it.get("position") === oldPosition);
|
|
1340
|
+
const relativeItemIndex = array.findIndex((it) => isYMap(it) && it.get("position") === relativePosition);
|
|
1341
|
+
if (!isYMap(item)) throw new Error(`Can't move. Item in position ${oldPosition} not found. ${printPosition(array)}`);
|
|
1342
|
+
if (relativeItemIndex === -1) throw new Error(`Can't move. Relative item in position ${relativePosition} not found. ${printPosition(array)}`);
|
|
1343
|
+
const relativeItem = array[relativeItemIndex];
|
|
1344
|
+
if (!isYMap(relativeItem)) throw new Error(`Can't move. Relative item in position ${relativePosition} must be YMap. ${printPosition(array)}`);
|
|
1345
|
+
if (insert === "before") {
|
|
1346
|
+
const left = array[relativeItemIndex - 1];
|
|
1347
|
+
const newPosition$1 = generateKeyBetween(isYMap(left) ? left.get("position") ?? null : null, relativeItem.get("position"));
|
|
1348
|
+
item.set("position", newPosition$1);
|
|
1349
|
+
return newPosition$1;
|
|
1350
|
+
}
|
|
1351
|
+
const right = array[relativeItemIndex + 1];
|
|
1352
|
+
const rightPosition = isYMap(right) ? right.get("position") ?? null : null;
|
|
1353
|
+
const newPosition = generateKeyBetween(relativeItem.get("position"), rightPosition);
|
|
1354
|
+
item.set("position", newPosition);
|
|
1355
|
+
return newPosition;
|
|
1356
|
+
};
|
|
1357
|
+
/**
|
|
1358
|
+
* Removes an item from the Y.Array or Y.Map at the specified path.
|
|
1359
|
+
*
|
|
1360
|
+
* @example
|
|
1361
|
+
* let yArray = new Y.Array();
|
|
1362
|
+
* yArray.push(['item1', 'item2', 'item3']);
|
|
1363
|
+
* pullFromYPath(yArray, [1]);
|
|
1364
|
+
* // yArray now looks like: ['item1', 'item3']
|
|
1365
|
+
*/
|
|
1366
|
+
const pullFromYPath = (entry, path, key) => {
|
|
1367
|
+
const yArray = getFromYPath(entry, path);
|
|
1368
|
+
if (isYArray(yArray)) {
|
|
1369
|
+
if (isIndex(key)) {
|
|
1370
|
+
yArray.delete(key);
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1373
|
+
const index = getYArrayIndexByArrayKey(yArray, key);
|
|
1374
|
+
yArray.delete(index);
|
|
1375
|
+
}
|
|
1376
|
+
};
|
|
1377
|
+
/**
|
|
1378
|
+
* Moves a Y.Map to the start of a Y.Array.
|
|
1379
|
+
* */
|
|
1380
|
+
const moveYMapToStart = ({ yArray, yMap }) => {
|
|
1381
|
+
const first = getSortedYArray(yArray)[0];
|
|
1382
|
+
const rightIndex = first ? first.get("position") : null;
|
|
1383
|
+
yMap.set("position", generateKeyBetween(null, rightIndex));
|
|
1384
|
+
};
|
|
1385
|
+
/**
|
|
1386
|
+
* Moves a Y.Map to the end of a Y.Array.
|
|
1387
|
+
* */
|
|
1388
|
+
const moveYMapToEnd = ({ yArray, yMap }) => {
|
|
1389
|
+
const sortedArray = getSortedYArray(yArray);
|
|
1390
|
+
const last = sortedArray[sortedArray.length - 1];
|
|
1391
|
+
const leftIndex = last ? last.get("position") : null;
|
|
1392
|
+
yMap.set("position", generateKeyBetween(leftIndex, null));
|
|
1393
|
+
};
|
|
1394
|
+
/**
|
|
1395
|
+
* Moves a Y.Map before another Y.Map in a Y.Array.
|
|
1396
|
+
* */
|
|
1397
|
+
const moveYMapBefore = ({ yArray, yMap, relativePosition }) => {
|
|
1398
|
+
const { ref: relative, left } = getYArrayRefsByPosition(yArray, relativePosition);
|
|
1399
|
+
const right = relative;
|
|
1400
|
+
const rightIndex = right ? right.get("position") : null;
|
|
1401
|
+
const leftIndex = left ? left.get("position") : null;
|
|
1402
|
+
yMap.set("position", generateKeyBetween(leftIndex, rightIndex));
|
|
1403
|
+
};
|
|
1404
|
+
/**
|
|
1405
|
+
* Moves a Y.Map after another Y.Map in a Y.Array.
|
|
1406
|
+
* */
|
|
1407
|
+
const moveYMapAfter = ({ yArray, yMap, relativePosition }) => {
|
|
1408
|
+
const { ref: relative, right } = getYArrayRefsByPosition(yArray, relativePosition);
|
|
1409
|
+
const left = relative;
|
|
1410
|
+
const rightIndex = right ? right.get("position") : null;
|
|
1411
|
+
const leftIndex = left ? left.get("position") : null;
|
|
1412
|
+
yMap.set("position", generateKeyBetween(leftIndex, rightIndex));
|
|
1413
|
+
};
|
|
1414
|
+
/**
|
|
1415
|
+
* Inserts a Y.Map to the end of a Y.Array.
|
|
1416
|
+
* */
|
|
1417
|
+
const insertYMapToEnd = (opts) => {
|
|
1418
|
+
moveYMapToEnd(opts);
|
|
1419
|
+
opts.yArray.push([opts.yMap]);
|
|
1420
|
+
};
|
|
1421
|
+
/**
|
|
1422
|
+
* Inserts a Y.Map before another Y.Map in a Y.Array.
|
|
1423
|
+
* */
|
|
1424
|
+
const insertYMapBefore = (opts) => {
|
|
1425
|
+
moveYMapBefore(opts);
|
|
1426
|
+
opts.yArray.push([opts.yMap]);
|
|
1427
|
+
};
|
|
1428
|
+
/**
|
|
1429
|
+
* Inserts a Y.Map before another Y.Map in a Y.Array.
|
|
1430
|
+
* */
|
|
1431
|
+
const insertYMapAfter = (opts) => {
|
|
1432
|
+
moveYMapAfter(opts);
|
|
1433
|
+
opts.yArray.push([opts.yMap]);
|
|
1434
|
+
};
|
|
1435
|
+
|
|
1436
|
+
//#endregion
|
|
1437
|
+
//#region src/y-components/tools.ts
|
|
1438
|
+
/**
|
|
1439
|
+
* This function converts dynamic component properties to Y.Map representation.
|
|
1440
|
+
*/
|
|
1441
|
+
const dynamicComponentPropsToYComponentProps = (props) => {
|
|
1442
|
+
const entries = Object.entries(props).map(([key, value]) => {
|
|
1443
|
+
if (key === "content" && isObject(value) && value.content?.type === "doc") return [key, value.content];
|
|
1444
|
+
else if (Array.isArray(value)) return [key, arrayToYArray(value)];
|
|
1445
|
+
else if (isObject(value)) return [key, objectToYMap(value)];
|
|
1446
|
+
else return [key, value];
|
|
1447
|
+
});
|
|
1448
|
+
return new Y.Map(entries);
|
|
1449
|
+
};
|
|
1450
|
+
/**
|
|
1451
|
+
* This function converts a dynamic component to Y.Map representation.
|
|
1452
|
+
*/
|
|
1453
|
+
const dynamicComponentToYMap = (component, yMap = new Y.Map()) => {
|
|
1454
|
+
const { props: propsWithComponents,...fields } = component;
|
|
1455
|
+
const { components,...props } = propsWithComponents ?? {};
|
|
1456
|
+
for (const [key, value] of Object.entries(fields)) yMap.set(key, value);
|
|
1457
|
+
const yProps = props ? objectToYMap(props) : new Y.Map();
|
|
1458
|
+
if (Array.isArray(components)) yProps.set("components", dynamicComponentsToYArray(components));
|
|
1459
|
+
yMap.set("props", yProps);
|
|
1460
|
+
return yMap;
|
|
1461
|
+
};
|
|
1462
|
+
/**
|
|
1463
|
+
* This function converts an array of dynamic components to Y.Array representation.
|
|
1464
|
+
*/
|
|
1465
|
+
const dynamicComponentsToYArray = (components, yArray = new Y.Array()) => {
|
|
1466
|
+
yArray.push(sortDynamicComponents(components).map((cmp) => dynamicComponentToYMap(cmp)));
|
|
1467
|
+
return yArray;
|
|
1468
|
+
};
|
|
1469
|
+
/**
|
|
1470
|
+
* This function checks if a given Y.Map object is a YComponent.
|
|
1471
|
+
*/
|
|
1472
|
+
const isYComponent = (yComponent) => {
|
|
1473
|
+
return isYMap(yComponent) && isString(yComponent.get("component")) && isString(yComponent.get("id"));
|
|
1474
|
+
};
|
|
1475
|
+
/**
|
|
1476
|
+
* This function converts a YComponent to a dynamic component.
|
|
1477
|
+
*/
|
|
1478
|
+
const yComponentToDynamicComponent = (yComponent, extractContent = false) => {
|
|
1479
|
+
const component = { props: {} };
|
|
1480
|
+
for (const [key, value] of yComponent.entries()) if (key === "props") {
|
|
1481
|
+
if (!isYMap(value)) throw new Error("Component props must be YMap");
|
|
1482
|
+
const yComponentProps = value;
|
|
1483
|
+
const props = {};
|
|
1484
|
+
for (const [prop, value$1] of yComponentProps.entries()) if (prop === "components") {
|
|
1485
|
+
if (!isYArray(value$1)) throw new Error("Component props.components array must be YArray");
|
|
1486
|
+
props.components = value$1.toArray().map((it) => yComponentToDynamicComponent(it));
|
|
1487
|
+
} else if (extractContent && yComponent.doc && isYMap(value$1) && value$1.get("type") === "RichText" && typeof value$1.get("id") === "string") {
|
|
1488
|
+
const id = value$1.get("id");
|
|
1489
|
+
props[prop] = {
|
|
1490
|
+
...value$1.toJSON(),
|
|
1491
|
+
tiptap: yXmlFragmentToProsemirrorJSON(yComponent.doc.getXmlFragment(`RichText:${id}`))
|
|
1492
|
+
};
|
|
1493
|
+
} else if (value$1 instanceof Y.AbstractType) props[prop] = value$1.toJSON();
|
|
1494
|
+
else props[prop] = value$1;
|
|
1495
|
+
component.props = props;
|
|
1496
|
+
} else if (isYArray(value)) component[key] = value.toArray();
|
|
1497
|
+
else if (isYMap(value)) component[key] = value.toJSON();
|
|
1498
|
+
else component[key] = value;
|
|
1499
|
+
return component;
|
|
1500
|
+
};
|
|
1501
|
+
/**
|
|
1502
|
+
* This function converts a dynamic component to YComponent.
|
|
1503
|
+
*/
|
|
1504
|
+
const dynamicComponentToYComponent = (component) => {
|
|
1505
|
+
return dynamicComponentToYMap(component);
|
|
1506
|
+
};
|
|
1507
|
+
/**
|
|
1508
|
+
* This function retrieves the properties of a YComponent.
|
|
1509
|
+
*/
|
|
1510
|
+
const getYComponentProps = (yComponent) => {
|
|
1511
|
+
const props = yComponent.get("props");
|
|
1512
|
+
if (!isYMap(props)) throw new Error(`Component hasn't "props" property. It must have to be defined as Y.Map (component: ${yComponent.get("id")})`);
|
|
1513
|
+
return props;
|
|
1514
|
+
};
|
|
1515
|
+
/**
|
|
1516
|
+
* This function retrieves the array of components of a YComponent.
|
|
1517
|
+
*/
|
|
1518
|
+
const getYComponentComponentsArray = (yComponent) => {
|
|
1519
|
+
const yComponents = getYComponentProps(yComponent).get("components");
|
|
1520
|
+
if (!isYArray(yComponents)) throw new Error(`Component hasn't "props.components" property. It must be defined as Y.Array (component: ${yComponent.get("id")})`);
|
|
1521
|
+
return yComponents;
|
|
1522
|
+
};
|
|
1523
|
+
/**
|
|
1524
|
+
* This function checks if a YComponent has a components array.
|
|
1525
|
+
* @example
|
|
1526
|
+
* // component
|
|
1527
|
+
* {
|
|
1528
|
+
* id: "column",
|
|
1529
|
+
* component: "column",
|
|
1530
|
+
* props: {
|
|
1531
|
+
* components: [...] <= has components array
|
|
1532
|
+
* }
|
|
1533
|
+
* }
|
|
1534
|
+
*/
|
|
1535
|
+
const yComponentHasComponentsYArray = (yComponent) => {
|
|
1536
|
+
return isYArray(getYComponentProps(yComponent).get("components"));
|
|
1537
|
+
};
|
|
1538
|
+
/**
|
|
1539
|
+
* This function retrieves the parent component of a YArray of YComponents.
|
|
1540
|
+
* @example
|
|
1541
|
+
* // parent component
|
|
1542
|
+
* {
|
|
1543
|
+
* id: "column",
|
|
1544
|
+
* component: "column",
|
|
1545
|
+
* props: {
|
|
1546
|
+
* components: [...] <= components array
|
|
1547
|
+
* }
|
|
1548
|
+
* }
|
|
1549
|
+
*/
|
|
1550
|
+
const getYComponentsArrayParentComponent = (yArray) => {
|
|
1551
|
+
return yArray.parent?.parent ?? null;
|
|
1552
|
+
};
|
|
1553
|
+
/**
|
|
1554
|
+
* This function finds a Y.Component in a Y.Array by its ID.
|
|
1555
|
+
*/
|
|
1556
|
+
const findYComponentInArray = (yArray, componentId) => {
|
|
1557
|
+
const yComponent = yArray.toArray().find((it) => it.get("id") === componentId);
|
|
1558
|
+
if (!yComponent) throw new Error(`Component with id ${componentId} not found in yArray`);
|
|
1559
|
+
return yComponent;
|
|
1560
|
+
};
|
|
1561
|
+
|
|
1562
|
+
//#endregion
|
|
1563
|
+
export { ID_PATH_KEY_PREFIX, IImageRenditionType, PATH_REGEXP, POSITION_ARRAY_KEY_PREFIX, arrayToYArray, copyDynamicComponent, createIdArrayKey, createPositionArrayKey, customAlphabet, defineDynamicComponent, defineDynamicComponents, dynamicComponentPropsToYComponentProps, dynamicComponentToYComponent, dynamicComponentToYMap, dynamicComponentsToYArray, entriesOf, existsInPath, extractIdFromArrayKey, extractPositionFromArrayKey, findInYArray, findIndexInYArray, findYComponentInArray, generateKeyBetween, getComponentPropertyPath, getComponentsSubtreeByPath, getComponentsSubtreeByRPath, getDataObjectKey, getFromPath, getFromYPath, getIndexByArrayKey, getRelativePoint, getSortedYArray, getYArrayIndexByArrayKey, getYArrayRefsByPosition, getYComponentComponentsArray, getYComponentProps, getYComponentsArrayParentComponent, insertInPath, insertYMapAfter, insertYMapBefore, insertYMapToEnd, isArrayKey, isBiblePassageComponent, isBibleQuoteComponent, isCallable, isChatMessageDelayComponent, isChatTextMessageComponent, isCheckboxComponent, isCheckboxGroupComponent, isCollectionComponent, isColumnComponent, isComputedValueComponent, isConfirmDeletionInputComponent, isContainerValue, isDateTimePickerComponent, isEmbedCodeComponent, isEmptyArray, isEmptyContainer, isEntitySelectComponent, isEqualPath, isFileUploaderComponent, isHeadingComponent, isIdArrayKey, isImageComponent, isImageUploaderComponent, isIndex, isLegacyContentComponent, isNullOrUndefined, isNumber, isNumberInputComponent, isObject, isPositionArrayKey, isPracticeComponent, isRadioGroupComponent, isRawImageUploaderComponent, isRawImagesUploaderComponent, isRepeatableCollectionComponent, isRichText, isRichTextComponent, isRichTextEditorComponent, isRowComponent, isRowSettingsComponent, isSamePath, isSelectComponent, isSimpleImageUploaderComponent, isSlugComponent, isStatementComponent, isString, isSwitchComponent, isTestComponent, isTextInputComponent, isTextareaComponent, isYArray, isYComponent, isYMap, joinPath, keysOf, makeDynamicComponentsWithPosition, moveInPath, moveInYPath, moveYMapAfter, moveYMapBefore, moveYMapToEnd, moveYMapToStart, objectToYMap, pullFromPath, pullFromYPath, pushInPath, pushInYPath, searchDynamicComponentInTree, setInPath, setInYPath, sortByPosition, sortDynamicComponents, uid, unsetPath, unsetYPath, urlAlphabet, yComponentHasComponentsYArray, yComponentToDynamicComponent };
|
|
1564
|
+
//# sourceMappingURL=index.js.map
|