@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.
Files changed (60) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/index.d.ts +1816 -0
  3. package/dist/index.js +1564 -0
  4. package/dist/index.js.map +1 -0
  5. package/eslint.config.cjs +14 -0
  6. package/package.json +30 -0
  7. package/src/assertions/basic.ts +58 -0
  8. package/src/assertions/containers.ts +76 -0
  9. package/src/assertions/index.ts +6 -0
  10. package/src/assertions/paths.ts +12 -0
  11. package/src/assertions/rich-text.ts +16 -0
  12. package/src/assertions/yjs.ts +25 -0
  13. package/src/data-objects/data-object.ts +34 -0
  14. package/src/data-objects/index.ts +3 -0
  15. package/src/data-objects/rich-text.ts +38 -0
  16. package/src/dynamic-components/fractional-indexing.ts +321 -0
  17. package/src/dynamic-components/index.ts +6 -0
  18. package/src/dynamic-components/paths.ts +194 -0
  19. package/src/dynamic-components/registry/chats.ts +24 -0
  20. package/src/dynamic-components/registry/content.ts +118 -0
  21. package/src/dynamic-components/registry/forms.ts +525 -0
  22. package/src/dynamic-components/registry/index.ts +6 -0
  23. package/src/dynamic-components/registry/layout.ts +86 -0
  24. package/src/dynamic-components/registry/uikit-dynamic-component.ts +84 -0
  25. package/src/dynamic-components/tools.ts +195 -0
  26. package/src/dynamic-components/types.ts +237 -0
  27. package/src/index.ts +7 -0
  28. package/src/paths/array-keys.ts +164 -0
  29. package/src/paths/array-ops.ts +124 -0
  30. package/src/paths/basic-ops.ts +181 -0
  31. package/src/paths/constants.ts +1 -0
  32. package/src/paths/index.ts +7 -0
  33. package/src/paths/tools.ts +42 -0
  34. package/src/paths/types.ts +133 -0
  35. package/src/y-components/index.ts +3 -0
  36. package/src/y-components/tools.ts +234 -0
  37. package/src/y-components/types.ts +19 -0
  38. package/src/y-tools/array-path-ops.ts +240 -0
  39. package/src/y-tools/basic-path-ops.ts +189 -0
  40. package/src/y-tools/index.ts +6 -0
  41. package/src/y-tools/tools.ts +122 -0
  42. package/src/y-tools/types.ts +32 -0
  43. package/src/y-tools/y-array-keys.ts +47 -0
  44. package/tests/assertions/basic-types.test.ts +78 -0
  45. package/tests/assertions/containers.test.ts +72 -0
  46. package/tests/assertions/paths.test.ts +23 -0
  47. package/tests/assertions/yjs.test.ts +33 -0
  48. package/tests/dynamic-components/paths.test.ts +171 -0
  49. package/tests/dynamic-components/tools.test.ts +121 -0
  50. package/tests/paths/array-keys.test.ts +182 -0
  51. package/tests/paths/array-ops.test.ts +164 -0
  52. package/tests/paths/basic-ops.test.ts +263 -0
  53. package/tests/paths/tools.test.ts +55 -0
  54. package/tests/y-components/tools.test.ts +198 -0
  55. package/tests/y-tools/array-base-ops.test.ts +55 -0
  56. package/tests/y-tools/array-path-ops.test.ts +95 -0
  57. package/tsconfig.json +13 -0
  58. package/tsconfig.lib.json +13 -0
  59. package/tsdown.config.ts +18 -0
  60. 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