cogsbox-state 0.5.465 → 0.5.466
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/README.md +3 -3
- package/dist/CogsState.d.ts +1 -0
- package/dist/CogsState.d.ts.map +1 -1
- package/dist/CogsState.jsx +1011 -1270
- package/dist/CogsState.jsx.map +1 -1
- package/dist/Components.d.ts +39 -0
- package/dist/Components.d.ts.map +1 -0
- package/dist/Components.jsx +281 -0
- package/dist/Components.jsx.map +1 -0
- package/dist/index.js +11 -12
- package/dist/store.d.ts +2 -5
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +261 -219
- package/dist/store.js.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +151 -707
- package/src/Components.tsx +541 -0
- package/src/store.ts +178 -141
- package/dist/Functions.d.ts +0 -11
- package/dist/Functions.d.ts.map +0 -1
- package/dist/Functions.jsx +0 -29
- package/dist/Functions.jsx.map +0 -1
- package/src/Functions.tsx +0 -66
package/src/store.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
UpdateTypeDetail,
|
|
8
8
|
} from './CogsState.js';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { type ReactNode } from 'react';
|
|
11
11
|
|
|
12
12
|
export type FreshValuesObject = {
|
|
13
13
|
pathsToValues?: string[];
|
|
@@ -28,7 +28,6 @@ export type FormRefStoreState = {
|
|
|
28
28
|
registerFormRef: (id: string, ref: React.RefObject<any>) => void;
|
|
29
29
|
getFormRef: (id: string) => React.RefObject<any> | undefined;
|
|
30
30
|
removeFormRef: (id: string) => void;
|
|
31
|
-
// New method to get all refs for a stateKey
|
|
32
31
|
getFormRefsByStateKey: (
|
|
33
32
|
stateKey: string
|
|
34
33
|
) => Map<string, React.RefObject<any>>;
|
|
@@ -53,7 +52,6 @@ export const formRefStore = create<FormRefStoreState>((set, get) => ({
|
|
|
53
52
|
return { formRefs: newRefs };
|
|
54
53
|
}),
|
|
55
54
|
|
|
56
|
-
// Get all refs that start with the stateKey prefix
|
|
57
55
|
getFormRefsByStateKey: (stateKey) => {
|
|
58
56
|
const allRefs = get().formRefs;
|
|
59
57
|
const stateKeyPrefix = stateKey + '.';
|
|
@@ -83,26 +81,25 @@ export type ComponentsType = {
|
|
|
83
81
|
};
|
|
84
82
|
|
|
85
83
|
export type ValidationStatus =
|
|
86
|
-
| 'NOT_VALIDATED'
|
|
87
|
-
| 'VALIDATING'
|
|
88
|
-
| 'VALID'
|
|
89
|
-
| 'INVALID';
|
|
84
|
+
| 'NOT_VALIDATED'
|
|
85
|
+
| 'VALIDATING'
|
|
86
|
+
| 'VALID'
|
|
87
|
+
| 'INVALID';
|
|
90
88
|
|
|
91
89
|
export type ValidationError = {
|
|
92
90
|
source: 'client' | 'sync_engine' | 'api';
|
|
93
91
|
message: string;
|
|
94
|
-
severity: 'warning' | 'error';
|
|
95
|
-
code?: string;
|
|
92
|
+
severity: 'warning' | 'error';
|
|
93
|
+
code?: string;
|
|
96
94
|
};
|
|
97
95
|
|
|
98
96
|
export type ValidationState = {
|
|
99
97
|
status: ValidationStatus;
|
|
100
98
|
errors: ValidationError[];
|
|
101
99
|
lastValidated?: number;
|
|
102
|
-
validatedValue?: any;
|
|
100
|
+
validatedValue?: any;
|
|
103
101
|
};
|
|
104
102
|
|
|
105
|
-
// This is the new definition for the metadata object
|
|
106
103
|
export type ShadowMetadata = {
|
|
107
104
|
id?: string;
|
|
108
105
|
stateSource?: 'default' | 'server' | 'localStorage';
|
|
@@ -156,28 +153,23 @@ export type ShadowMetadata = {
|
|
|
156
153
|
>;
|
|
157
154
|
} & ComponentsType;
|
|
158
155
|
|
|
159
|
-
// The shadow node itself can have a value and the metadata object.
|
|
160
156
|
type ShadowNode = {
|
|
161
157
|
value?: any;
|
|
162
158
|
_meta?: ShadowMetadata;
|
|
163
|
-
[key: string]: any;
|
|
159
|
+
[key: string]: any;
|
|
164
160
|
};
|
|
165
161
|
|
|
166
162
|
export type CogsGlobalState = {
|
|
167
163
|
// NEW shadow store
|
|
168
|
-
shadowStateStore: Map<string, ShadowNode>;
|
|
164
|
+
shadowStateStore: Map<string, ShadowNode>;
|
|
169
165
|
setTransformCache: (
|
|
170
166
|
key: string,
|
|
171
167
|
path: string[],
|
|
172
168
|
cacheKey: string,
|
|
173
169
|
cacheData: any
|
|
174
170
|
) => void;
|
|
175
|
-
// NEW functions
|
|
176
171
|
initializeShadowState: (key: string, initialState: any) => void;
|
|
177
|
-
|
|
178
|
-
// REFACTORED: getShadowNode gets the whole object (data + _meta)
|
|
179
172
|
getShadowNode: (key: string, path: string[]) => ShadowNode | undefined;
|
|
180
|
-
// REFACTORED: getShadowMetadata now returns just the _meta field
|
|
181
173
|
getShadowMetadata: (
|
|
182
174
|
key: string,
|
|
183
175
|
path: string[]
|
|
@@ -191,6 +183,18 @@ export type CogsGlobalState = {
|
|
|
191
183
|
log?: boolean
|
|
192
184
|
) => any;
|
|
193
185
|
updateShadowAtPath: (key: string, path: string[], newValue: any) => void;
|
|
186
|
+
insertManyShadowArrayElements: (
|
|
187
|
+
key: string,
|
|
188
|
+
arrayPath: string[],
|
|
189
|
+
newItems: any[],
|
|
190
|
+
index?: number
|
|
191
|
+
) => void;
|
|
192
|
+
addItemsToArrayNode: (
|
|
193
|
+
key: string,
|
|
194
|
+
arrayPath: string[],
|
|
195
|
+
newItems: any,
|
|
196
|
+
newKeys: string[]
|
|
197
|
+
) => void;
|
|
194
198
|
insertShadowArrayElement: (
|
|
195
199
|
key: string,
|
|
196
200
|
arrayPath: string[],
|
|
@@ -209,13 +213,11 @@ export type CogsGlobalState = {
|
|
|
209
213
|
dependencyPath: string[],
|
|
210
214
|
fullComponentId: string
|
|
211
215
|
) => void;
|
|
212
|
-
|
|
213
216
|
markAsDirty: (
|
|
214
217
|
key: string,
|
|
215
218
|
path: string[],
|
|
216
219
|
options: { bubble: boolean }
|
|
217
220
|
) => void;
|
|
218
|
-
// These method signatures stay the same
|
|
219
221
|
|
|
220
222
|
pathSubscribers: Map<string, Set<(newValue: any) => void>>;
|
|
221
223
|
subscribeToPath: (
|
|
@@ -230,12 +232,8 @@ export type CogsGlobalState = {
|
|
|
230
232
|
clearSelectedIndex: ({ arrayKey }: { arrayKey: string }) => void;
|
|
231
233
|
clearSelectedIndexesForState: (stateKey: string) => void;
|
|
232
234
|
|
|
233
|
-
// --- Core State and Updaters ---
|
|
234
|
-
|
|
235
235
|
initialStateOptions: { [key: string]: OptionsType };
|
|
236
|
-
|
|
237
236
|
initialStateGlobal: { [key: string]: StateValue };
|
|
238
|
-
|
|
239
237
|
updateInitialStateGlobal: (key: string, newState: StateValue) => void;
|
|
240
238
|
|
|
241
239
|
getInitialOptions: (key: string) => OptionsType | undefined;
|
|
@@ -260,46 +258,35 @@ export type CogsGlobalState = {
|
|
|
260
258
|
getSyncInfo: (key: string) => SyncInfo | null;
|
|
261
259
|
};
|
|
262
260
|
|
|
263
|
-
// ✅ CHANGE 1: `METADATA_KEYS` now only contains `_meta` and `value`.
|
|
264
|
-
// The other keys are now properties of the `ShadowMetadata` type.
|
|
265
|
-
export const METADATA_KEYS = new Set(['_meta', 'value']);
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* The single source of truth for converting a regular JS value/object
|
|
269
|
-
* into the shadow state tree format with the new `_meta` structure.
|
|
270
|
-
*/
|
|
271
|
-
// ✅ CHANGE 2: `buildShadowNode` now creates the `_meta` field.
|
|
272
261
|
export function buildShadowNode(value: any): ShadowNode {
|
|
273
|
-
// Primitives and null are wrapped.
|
|
274
262
|
if (value === null || typeof value !== 'object') {
|
|
275
263
|
return { value };
|
|
276
264
|
}
|
|
277
265
|
|
|
278
|
-
// Arrays are converted to an object with id-keyed children and metadata in `_meta`.
|
|
279
266
|
if (Array.isArray(value)) {
|
|
280
|
-
const arrayNode: ShadowNode = { _meta: { arrayKeys: [] } };
|
|
267
|
+
const arrayNode: ShadowNode = { _meta: { arrayKeys: [] } };
|
|
281
268
|
const idKeys: string[] = [];
|
|
269
|
+
|
|
282
270
|
value.forEach((item) => {
|
|
283
271
|
const itemId = `id:${ulid()}`;
|
|
284
|
-
arrayNode[itemId] = buildShadowNode(item);
|
|
272
|
+
arrayNode[itemId] = buildShadowNode(item);
|
|
285
273
|
idKeys.push(itemId);
|
|
286
274
|
});
|
|
287
|
-
|
|
275
|
+
|
|
276
|
+
arrayNode._meta!.arrayKeys = idKeys;
|
|
288
277
|
return arrayNode;
|
|
289
278
|
}
|
|
290
279
|
|
|
291
|
-
// Plain objects are recursively processed.
|
|
292
280
|
if (value.constructor === Object) {
|
|
293
|
-
const objectNode: ShadowNode = { _meta: {} };
|
|
281
|
+
const objectNode: ShadowNode = { _meta: {} };
|
|
294
282
|
for (const key in value) {
|
|
295
283
|
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
296
|
-
objectNode[key] = buildShadowNode(value[key]);
|
|
284
|
+
objectNode[key] = buildShadowNode(value[key]);
|
|
297
285
|
}
|
|
298
286
|
}
|
|
299
287
|
return objectNode;
|
|
300
288
|
}
|
|
301
289
|
|
|
302
|
-
// Fallback for other object types (Date, etc.) - treat them as primitives.
|
|
303
290
|
return { value };
|
|
304
291
|
}
|
|
305
292
|
|
|
@@ -312,7 +299,6 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
312
299
|
cacheKey: string,
|
|
313
300
|
cacheData: any
|
|
314
301
|
) => {
|
|
315
|
-
// This function now uses setShadowMetadata which correctly places the data.
|
|
316
302
|
const metadata = get().getShadowMetadata(key, path) || {};
|
|
317
303
|
if (!metadata.transformCaches) {
|
|
318
304
|
metadata.transformCaches = new Map();
|
|
@@ -350,7 +336,7 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
350
336
|
newShadowStore.delete(`[${key}`);
|
|
351
337
|
|
|
352
338
|
const newRoot = buildShadowNode(initialState);
|
|
353
|
-
|
|
339
|
+
|
|
354
340
|
if (!newRoot._meta) newRoot._meta = {};
|
|
355
341
|
Object.assign(newRoot._meta, preservedMetadata);
|
|
356
342
|
|
|
@@ -361,7 +347,6 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
361
347
|
});
|
|
362
348
|
},
|
|
363
349
|
|
|
364
|
-
// ✅ NEW HELPER: Gets the entire node (data and metadata).
|
|
365
350
|
getShadowNode: (key: string, path: string[]): ShadowNode | undefined => {
|
|
366
351
|
const store = get().shadowStateStore;
|
|
367
352
|
let current: any = store.get(key) || store.get(`[${key}`);
|
|
@@ -377,7 +362,6 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
377
362
|
return current;
|
|
378
363
|
},
|
|
379
364
|
|
|
380
|
-
// ✅ REFACTORED: Returns only the `_meta` part of a node.
|
|
381
365
|
getShadowMetadata: (
|
|
382
366
|
key: string,
|
|
383
367
|
path: string[]
|
|
@@ -386,7 +370,6 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
386
370
|
return node?._meta;
|
|
387
371
|
},
|
|
388
372
|
|
|
389
|
-
// ✅ REFACTORED: Sets data within the `_meta` object.
|
|
390
373
|
setShadowMetadata: (
|
|
391
374
|
key: string,
|
|
392
375
|
path: string[],
|
|
@@ -408,11 +391,10 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
408
391
|
let current = clonedRoot;
|
|
409
392
|
for (const segment of path) {
|
|
410
393
|
const nextNode = current[segment] || {};
|
|
411
|
-
current[segment] = { ...nextNode };
|
|
394
|
+
current[segment] = { ...nextNode };
|
|
412
395
|
current = current[segment];
|
|
413
396
|
}
|
|
414
397
|
|
|
415
|
-
// Ensure _meta object exists and merge the new metadata into it
|
|
416
398
|
current._meta = { ...(current._meta || {}), ...newMetadata };
|
|
417
399
|
|
|
418
400
|
return { shadowStateStore: newStore };
|
|
@@ -430,9 +412,6 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
430
412
|
|
|
431
413
|
const nodeKeys = Object.keys(node);
|
|
432
414
|
|
|
433
|
-
// ✅ FIX: A node is a primitive wrapper ONLY if its keys are 'value' and/or '_meta'.
|
|
434
|
-
// This prevents objects in your data that happen to have a "value" property from being
|
|
435
|
-
// incorrectly treated as wrappers.
|
|
436
415
|
const isPrimitiveWrapper =
|
|
437
416
|
Object.prototype.hasOwnProperty.call(node, 'value') &&
|
|
438
417
|
nodeKeys.every((k) => k === 'value' || k === '_meta');
|
|
@@ -456,61 +435,77 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
456
435
|
);
|
|
457
436
|
}
|
|
458
437
|
|
|
459
|
-
// Object Reconstruction (This part is also correct)
|
|
460
438
|
const result: any = {};
|
|
461
439
|
for (const propKey of nodeKeys) {
|
|
462
|
-
// We correctly ignore metadata and array item keys here.
|
|
463
440
|
if (propKey !== '_meta' && !propKey.startsWith('id:')) {
|
|
464
441
|
result[propKey] = get().getShadowValue(key, [...path, propKey]);
|
|
465
442
|
}
|
|
466
443
|
}
|
|
467
444
|
return result;
|
|
468
445
|
},
|
|
469
|
-
|
|
470
|
-
// ✅ REFACTORED: Correctly preserves `_meta` on updates.
|
|
471
446
|
updateShadowAtPath: (key, path, newValue) => {
|
|
472
447
|
set((state) => {
|
|
473
448
|
const newStore = new Map(state.shadowStateStore);
|
|
474
449
|
const rootKey = newStore.has(`[${key}`) ? `[${key}` : key;
|
|
475
450
|
let root = newStore.get(rootKey);
|
|
476
|
-
|
|
477
451
|
if (!root) return state;
|
|
478
|
-
|
|
479
452
|
const clonedRoot: any = { ...root };
|
|
480
453
|
newStore.set(rootKey, clonedRoot);
|
|
454
|
+
let parentNode = clonedRoot;
|
|
455
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
456
|
+
parentNode[path[i]!] = { ...(parentNode[path[i]!] || {}) };
|
|
457
|
+
parentNode = parentNode[path[i]!];
|
|
458
|
+
}
|
|
459
|
+
const targetNode =
|
|
460
|
+
path.length === 0 ? parentNode : parentNode[path[path.length - 1]!];
|
|
461
|
+
|
|
462
|
+
if (!targetNode) {
|
|
463
|
+
parentNode[path[path.length - 1]!] = buildShadowNode(newValue);
|
|
464
|
+
return { shadowStateStore: newStore };
|
|
465
|
+
}
|
|
481
466
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
467
|
+
function intelligentMerge(nodeToUpdate: any, plainValue: any) {
|
|
468
|
+
if (
|
|
469
|
+
typeof plainValue !== 'object' ||
|
|
470
|
+
plainValue === null ||
|
|
471
|
+
Array.isArray(plainValue)
|
|
472
|
+
) {
|
|
473
|
+
const oldMeta = nodeToUpdate._meta;
|
|
474
|
+
const newNode = buildShadowNode(plainValue);
|
|
475
|
+
if (oldMeta) {
|
|
476
|
+
newNode._meta = { ...oldMeta, ...(newNode._meta || {}) };
|
|
477
|
+
}
|
|
478
|
+
Object.keys(nodeToUpdate).forEach((key) => delete nodeToUpdate[key]);
|
|
479
|
+
Object.assign(nodeToUpdate, newNode);
|
|
480
|
+
return;
|
|
490
481
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
482
|
+
|
|
483
|
+
const plainValueKeys = new Set(Object.keys(plainValue));
|
|
484
|
+
|
|
485
|
+
for (const propKey of plainValueKeys) {
|
|
486
|
+
const childValue = plainValue[propKey];
|
|
487
|
+
if (nodeToUpdate[propKey]) {
|
|
488
|
+
intelligentMerge(nodeToUpdate[propKey], childValue);
|
|
489
|
+
} else {
|
|
490
|
+
nodeToUpdate[propKey] = buildShadowNode(childValue);
|
|
491
|
+
}
|
|
498
492
|
}
|
|
499
493
|
|
|
500
|
-
const
|
|
501
|
-
|
|
502
|
-
|
|
494
|
+
for (const nodeKey in nodeToUpdate) {
|
|
495
|
+
if (
|
|
496
|
+
nodeKey === '_meta' ||
|
|
497
|
+
!Object.prototype.hasOwnProperty.call(nodeToUpdate, nodeKey)
|
|
498
|
+
)
|
|
499
|
+
continue;
|
|
503
500
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
...(newNodeStructure._meta || {}),
|
|
508
|
-
...existingNode._meta,
|
|
509
|
-
};
|
|
501
|
+
if (!plainValueKeys.has(nodeKey)) {
|
|
502
|
+
delete nodeToUpdate[nodeKey];
|
|
503
|
+
}
|
|
510
504
|
}
|
|
511
|
-
current[lastSegment] = newNodeStructure;
|
|
512
505
|
}
|
|
513
506
|
|
|
507
|
+
intelligentMerge(targetNode, newValue);
|
|
508
|
+
|
|
514
509
|
get().notifyPathSubscribers([key, ...path].join('.'), {
|
|
515
510
|
type: 'UPDATE',
|
|
516
511
|
newValue,
|
|
@@ -518,8 +513,33 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
518
513
|
return { shadowStateStore: newStore };
|
|
519
514
|
});
|
|
520
515
|
},
|
|
516
|
+
addItemsToArrayNode: (key, arrayPath, newItems, newKeys) => {
|
|
517
|
+
set((state) => {
|
|
518
|
+
const newStore = new Map(state.shadowStateStore);
|
|
519
|
+
const rootKey = newStore.has(`[${key}`) ? `[${key}` : key;
|
|
520
|
+
let root = newStore.get(rootKey);
|
|
521
|
+
if (!root) {
|
|
522
|
+
console.error('Root not found for state key:', key);
|
|
523
|
+
return state;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
const clonedRoot = { ...root };
|
|
527
|
+
newStore.set(rootKey, clonedRoot);
|
|
528
|
+
|
|
529
|
+
let current = clonedRoot;
|
|
530
|
+
for (const segment of arrayPath) {
|
|
531
|
+
const nextNode = current[segment] || {};
|
|
532
|
+
current[segment] = { ...nextNode };
|
|
533
|
+
current = current[segment];
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
Object.assign(current, newItems);
|
|
537
|
+
current._meta = { ...(current._meta || {}), arrayKeys: newKeys };
|
|
538
|
+
|
|
539
|
+
return { shadowStateStore: newStore };
|
|
540
|
+
});
|
|
541
|
+
},
|
|
521
542
|
|
|
522
|
-
// ✅ REFACTORED: Works with `_meta.arrayKeys`.
|
|
523
543
|
insertShadowArrayElement: (key, arrayPath, newItem, index) => {
|
|
524
544
|
const arrayNode = get().getShadowNode(key, arrayPath);
|
|
525
545
|
if (!arrayNode?._meta?.arrayKeys) {
|
|
@@ -530,53 +550,67 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
530
550
|
}
|
|
531
551
|
|
|
532
552
|
const newItemId = `id:${ulid()}`;
|
|
533
|
-
const
|
|
553
|
+
const itemsToAdd = { [newItemId]: buildShadowNode(newItem) };
|
|
534
554
|
|
|
535
|
-
// Update the `arrayKeys` in the metadata
|
|
536
555
|
const currentKeys = arrayNode._meta.arrayKeys;
|
|
537
556
|
const newKeys = [...currentKeys];
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
557
|
+
const insertionPoint =
|
|
558
|
+
index !== undefined && index >= 0 && index <= newKeys.length
|
|
559
|
+
? index
|
|
560
|
+
: newKeys.length;
|
|
561
|
+
newKeys.splice(insertionPoint, 0, newItemId);
|
|
562
|
+
|
|
563
|
+
get().addItemsToArrayNode(key, arrayPath, itemsToAdd, newKeys);
|
|
564
|
+
|
|
565
|
+
const arrayKey = [key, ...arrayPath].join('.');
|
|
566
|
+
get().notifyPathSubscribers(arrayKey, {
|
|
567
|
+
type: 'INSERT',
|
|
568
|
+
path: arrayKey,
|
|
569
|
+
itemKey: `${arrayKey}.${newItemId}`,
|
|
570
|
+
index: insertionPoint,
|
|
571
|
+
});
|
|
572
|
+
},
|
|
573
|
+
insertManyShadowArrayElements: (key, arrayPath, newItems, index) => {
|
|
574
|
+
if (!newItems || newItems.length === 0) {
|
|
575
|
+
return;
|
|
542
576
|
}
|
|
543
577
|
|
|
544
|
-
|
|
545
|
-
if (arrayNode
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
);
|
|
551
|
-
if (matchesFilters) {
|
|
552
|
-
cache.validIds = [...cache.validIds];
|
|
553
|
-
if (index !== undefined) {
|
|
554
|
-
cache.validIds.splice(index, 0, newItemId);
|
|
555
|
-
} else {
|
|
556
|
-
cache.validIds.push(newItemId);
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
});
|
|
578
|
+
const arrayNode = get().getShadowNode(key, arrayPath);
|
|
579
|
+
if (!arrayNode?._meta?.arrayKeys) {
|
|
580
|
+
console.error(
|
|
581
|
+
`Array not found at path: ${[key, ...arrayPath].join('.')}`
|
|
582
|
+
);
|
|
583
|
+
return;
|
|
561
584
|
}
|
|
562
585
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
arrayNode._meta.arrayKeys = newKeys;
|
|
586
|
+
const itemsToAdd: Record<string, any> = {};
|
|
587
|
+
const newIds: string[] = [];
|
|
566
588
|
|
|
567
|
-
|
|
589
|
+
newItems.forEach((item) => {
|
|
590
|
+
const newItemId = `id:${ulid()}`;
|
|
591
|
+
newIds.push(newItemId);
|
|
592
|
+
itemsToAdd[newItemId] = buildShadowNode(item);
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
const currentKeys = arrayNode._meta.arrayKeys;
|
|
596
|
+
const finalKeys = [...currentKeys];
|
|
597
|
+
const insertionPoint =
|
|
598
|
+
index !== undefined && index >= 0 && index <= finalKeys.length
|
|
599
|
+
? index
|
|
600
|
+
: finalKeys.length;
|
|
601
|
+
finalKeys.splice(insertionPoint, 0, ...newIds);
|
|
602
|
+
|
|
603
|
+
get().addItemsToArrayNode(key, arrayPath, itemsToAdd, finalKeys);
|
|
568
604
|
|
|
569
|
-
// Trigger notifications
|
|
570
605
|
const arrayKey = [key, ...arrayPath].join('.');
|
|
571
606
|
get().notifyPathSubscribers(arrayKey, {
|
|
572
|
-
type: '
|
|
607
|
+
type: 'INSERT_MANY',
|
|
573
608
|
path: arrayKey,
|
|
574
|
-
|
|
575
|
-
index:
|
|
609
|
+
count: newItems.length,
|
|
610
|
+
index: insertionPoint,
|
|
576
611
|
});
|
|
577
612
|
},
|
|
578
613
|
|
|
579
|
-
// ✅ REFACTORED: Works with `_meta.arrayKeys`.
|
|
580
614
|
removeShadowArrayElement: (key, itemPath) => {
|
|
581
615
|
if (itemPath.length === 0) return;
|
|
582
616
|
|
|
@@ -587,13 +621,9 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
587
621
|
const arrayNode = get().getShadowNode(key, arrayPath);
|
|
588
622
|
if (!arrayNode?._meta?.arrayKeys) return;
|
|
589
623
|
|
|
590
|
-
// Filter the item's ID from the `arrayKeys` metadata
|
|
591
624
|
const newKeys = arrayNode._meta.arrayKeys.filter((k) => k !== itemId);
|
|
592
|
-
|
|
593
|
-
// Delete the item's data from the node
|
|
594
625
|
delete arrayNode[itemId];
|
|
595
626
|
|
|
596
|
-
// Persist the modified array node back to the store
|
|
597
627
|
get().setShadowMetadata(key, arrayPath, { arrayKeys: newKeys });
|
|
598
628
|
|
|
599
629
|
const arrayKey = [key, ...arrayPath].join('.');
|
|
@@ -604,9 +634,6 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
604
634
|
});
|
|
605
635
|
},
|
|
606
636
|
|
|
607
|
-
// The rest of the functions are updated to use the new helpers (`getShadowMetadata`, `setShadowMetadata`)
|
|
608
|
-
// which abstracts away the `_meta` implementation detail.
|
|
609
|
-
|
|
610
637
|
addPathComponent: (stateKey, dependencyPath, fullComponentId) => {
|
|
611
638
|
const metadata = get().getShadowMetadata(stateKey, dependencyPath) || {};
|
|
612
639
|
const newPathComponents = new Set(metadata.pathComponents);
|
|
@@ -646,15 +673,14 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
646
673
|
}
|
|
647
674
|
},
|
|
648
675
|
|
|
649
|
-
// ✅ REFACTORED: `markAsDirty` now correctly writes to `_meta.isDirty`.
|
|
650
676
|
markAsDirty: (key, path, options = { bubble: true }) => {
|
|
651
677
|
const setDirtyOnPath = (pathToMark: string[]) => {
|
|
652
678
|
const node = get().getShadowNode(key, pathToMark);
|
|
653
679
|
if (node?._meta?.isDirty) {
|
|
654
|
-
return true;
|
|
680
|
+
return true;
|
|
655
681
|
}
|
|
656
682
|
get().setShadowMetadata(key, pathToMark, { isDirty: true });
|
|
657
|
-
return false;
|
|
683
|
+
return false;
|
|
658
684
|
};
|
|
659
685
|
|
|
660
686
|
setDirtyOnPath(path);
|
|
@@ -664,7 +690,7 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
664
690
|
while (parentPath.length > 0) {
|
|
665
691
|
parentPath.pop();
|
|
666
692
|
if (setDirtyOnPath(parentPath)) {
|
|
667
|
-
break;
|
|
693
|
+
break;
|
|
668
694
|
}
|
|
669
695
|
}
|
|
670
696
|
}
|
|
@@ -708,7 +734,6 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
708
734
|
subs.forEach((callback) => callback(newValue));
|
|
709
735
|
}
|
|
710
736
|
},
|
|
711
|
-
|
|
712
737
|
selectedIndicesMap: new Map<string, string>(),
|
|
713
738
|
getSelectedIndex: (arrayKey, validIds) => {
|
|
714
739
|
const itemKey = get().selectedIndicesMap.get(arrayKey);
|
|
@@ -723,39 +748,51 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
723
748
|
return arrayKeys ? arrayKeys.indexOf(itemKey) : -1;
|
|
724
749
|
},
|
|
725
750
|
|
|
726
|
-
setSelectedIndex: (arrayKey, itemKey) => {
|
|
751
|
+
setSelectedIndex: (arrayKey: string, itemKey: string | undefined) => {
|
|
727
752
|
set((state) => {
|
|
728
|
-
const newMap = new Map(state.selectedIndicesMap);
|
|
729
|
-
const oldSelection = newMap.get(arrayKey);
|
|
730
|
-
if (oldSelection) {
|
|
731
|
-
get().notifyPathSubscribers(oldSelection, { type: 'THIS_UNSELECTED' });
|
|
732
|
-
}
|
|
753
|
+
const newMap = new Map(state.selectedIndicesMap); // CREATE A NEW MAP!
|
|
733
754
|
|
|
734
755
|
if (itemKey === undefined) {
|
|
735
756
|
newMap.delete(arrayKey);
|
|
736
757
|
} else {
|
|
758
|
+
if (newMap.has(arrayKey)) {
|
|
759
|
+
get().notifyPathSubscribers(newMap.get(arrayKey)!, {
|
|
760
|
+
type: 'THIS_UNSELECTED',
|
|
761
|
+
});
|
|
762
|
+
}
|
|
737
763
|
newMap.set(arrayKey, itemKey);
|
|
738
764
|
get().notifyPathSubscribers(itemKey, { type: 'THIS_SELECTED' });
|
|
739
765
|
}
|
|
740
766
|
|
|
741
767
|
get().notifyPathSubscribers(arrayKey, { type: 'GET_SELECTED' });
|
|
742
|
-
|
|
768
|
+
|
|
769
|
+
return {
|
|
770
|
+
...state,
|
|
771
|
+
selectedIndicesMap: newMap,
|
|
772
|
+
};
|
|
743
773
|
});
|
|
744
774
|
},
|
|
745
775
|
|
|
746
|
-
clearSelectedIndex: ({ arrayKey }) => {
|
|
776
|
+
clearSelectedIndex: ({ arrayKey }: { arrayKey: string }): void => {
|
|
747
777
|
set((state) => {
|
|
748
|
-
const newMap = new Map(state.selectedIndicesMap);
|
|
778
|
+
const newMap = new Map(state.selectedIndicesMap); // CREATE A NEW MAP!
|
|
749
779
|
const actualKey = newMap.get(arrayKey);
|
|
750
780
|
if (actualKey) {
|
|
751
|
-
get().notifyPathSubscribers(actualKey, {
|
|
781
|
+
get().notifyPathSubscribers(actualKey, {
|
|
782
|
+
type: 'CLEAR_SELECTION',
|
|
783
|
+
});
|
|
752
784
|
}
|
|
785
|
+
|
|
753
786
|
newMap.delete(arrayKey);
|
|
754
|
-
get().notifyPathSubscribers(arrayKey, {
|
|
755
|
-
|
|
787
|
+
get().notifyPathSubscribers(arrayKey, {
|
|
788
|
+
type: 'CLEAR_SELECTION',
|
|
789
|
+
});
|
|
790
|
+
return {
|
|
791
|
+
...state,
|
|
792
|
+
selectedIndicesMap: newMap,
|
|
793
|
+
};
|
|
756
794
|
});
|
|
757
795
|
},
|
|
758
|
-
|
|
759
796
|
clearSelectedIndexesForState: (stateKey) => {
|
|
760
797
|
set((state) => {
|
|
761
798
|
const newMap = new Map(state.selectedIndicesMap);
|
package/dist/Functions.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { FormOptsType } from './CogsState';
|
|
2
|
-
import { default as React } from 'react';
|
|
3
|
-
|
|
4
|
-
export type ValidationWrapperProps = {
|
|
5
|
-
formOpts?: FormOptsType;
|
|
6
|
-
path: string[];
|
|
7
|
-
stateKey: string;
|
|
8
|
-
children: React.ReactNode;
|
|
9
|
-
};
|
|
10
|
-
export declare function ValidationWrapper({ formOpts, path, stateKey, children, }: ValidationWrapperProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
-
//# sourceMappingURL=Functions.d.ts.map
|
package/dist/Functions.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Functions.d.ts","sourceRoot":"","sources":["../src/Functions.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,QAAQ,GACT,EAAE,sBAAsB,2CAgDxB"}
|
package/dist/Functions.jsx
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { jsx as o, Fragment as w } from "react/jsx-runtime";
|
|
2
|
-
import d from "react";
|
|
3
|
-
import { getGlobalStore as M } from "./store.js";
|
|
4
|
-
function F({
|
|
5
|
-
formOpts: a,
|
|
6
|
-
path: e,
|
|
7
|
-
stateKey: s,
|
|
8
|
-
children: n
|
|
9
|
-
}) {
|
|
10
|
-
const { getInitialOptions: c, getShadowMetadata: v, getShadowValue: S } = M.getState(), i = c(s), g = v(s, e)?.validation, f = g?.status || "NOT_VALIDATED", r = (g?.errors || []).map((t) => ({
|
|
11
|
-
...t,
|
|
12
|
-
path: e
|
|
13
|
-
})), l = r.filter((t) => t.severity === "error").map((t) => t.message), m = r.filter((t) => t.severity === "warning").map((t) => t.message), h = l[0] || m[0];
|
|
14
|
-
return /* @__PURE__ */ o(w, { children: i?.formElements?.validation && !a?.validation?.disable ? i.formElements.validation({
|
|
15
|
-
children: /* @__PURE__ */ o(d.Fragment, { children: n }, e.toString()),
|
|
16
|
-
status: f,
|
|
17
|
-
// Now passes the new ValidationStatus type
|
|
18
|
-
message: a?.validation?.hideMessage ? "" : a?.validation?.message || h || "",
|
|
19
|
-
hasErrors: l.length > 0,
|
|
20
|
-
hasWarnings: m.length > 0,
|
|
21
|
-
allErrors: r,
|
|
22
|
-
path: e,
|
|
23
|
-
getData: () => S(s, e)
|
|
24
|
-
}) : /* @__PURE__ */ o(d.Fragment, { children: n }, e.toString()) });
|
|
25
|
-
}
|
|
26
|
-
export {
|
|
27
|
-
F as ValidationWrapper
|
|
28
|
-
};
|
|
29
|
-
//# sourceMappingURL=Functions.jsx.map
|
package/dist/Functions.jsx.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Functions.jsx","sources":["../src/Functions.tsx"],"sourcesContent":["import { type FormOptsType } from './CogsState';\r\nimport React from 'react';\r\nimport { getGlobalStore, ValidationError } from './store';\r\nimport { get } from 'http';\r\n\r\nexport type ValidationWrapperProps = {\r\n formOpts?: FormOptsType;\r\n path: string[];\r\n stateKey: string;\r\n children: React.ReactNode;\r\n};\r\n\r\nexport function ValidationWrapper({\r\n formOpts,\r\n path,\r\n stateKey,\r\n children,\r\n}: ValidationWrapperProps) {\r\n const { getInitialOptions, getShadowMetadata, getShadowValue } =\r\n getGlobalStore.getState();\r\n const thisStateOpts = getInitialOptions(stateKey!);\r\n\r\n const shadowMeta = getShadowMetadata(stateKey!, path);\r\n const validationState = shadowMeta?.validation;\r\n\r\n const status = validationState?.status || 'NOT_VALIDATED';\r\n\r\n const errors = (validationState?.errors || []).map((err) => ({\r\n ...err,\r\n path: path,\r\n })) as ValidationError[];\r\n const errorMessages = errors\r\n .filter((err) => err.severity === 'error')\r\n .map((err) => err.message);\r\n const warningMessages = errors\r\n .filter((err) => err.severity === 'warning')\r\n .map((err) => err.message);\r\n\r\n // Use first error, or first warning if no errors\r\n const message = errorMessages[0] || warningMessages[0];\r\n\r\n return (\r\n <>\r\n {thisStateOpts?.formElements?.validation &&\r\n !formOpts?.validation?.disable ? (\r\n thisStateOpts.formElements!.validation!({\r\n children: (\r\n <React.Fragment key={path.toString()}>{children}</React.Fragment>\r\n ),\r\n status, // Now passes the new ValidationStatus type\r\n message: formOpts?.validation?.hideMessage\r\n ? ''\r\n : formOpts?.validation?.message || message || '',\r\n\r\n hasErrors: errorMessages.length > 0,\r\n hasWarnings: warningMessages.length > 0,\r\n allErrors: errors,\r\n path: path,\r\n getData: () => getShadowValue(stateKey!, path),\r\n })\r\n ) : (\r\n <React.Fragment key={path.toString()}>{children}</React.Fragment>\r\n )}\r\n </>\r\n );\r\n}\r\n"],"names":["ValidationWrapper","formOpts","path","stateKey","children","getInitialOptions","getShadowMetadata","getShadowValue","getGlobalStore","thisStateOpts","validationState","status","errors","err","errorMessages","warningMessages","message","jsx","Fragment","React"],"mappings":";;;AAYO,SAASA,EAAkB;AAAA,EAChC,UAAAC;AAAA,EACA,MAAAC;AAAA,EACA,UAAAC;AAAA,EACA,UAAAC;AACF,GAA2B;AACzB,QAAM,EAAE,mBAAAC,GAAmB,mBAAAC,GAAmB,gBAAAC,EAAA,IAC5CC,EAAe,SAAA,GACXC,IAAgBJ,EAAkBF,CAAS,GAG3CO,IADaJ,EAAkBH,GAAWD,CAAI,GAChB,YAE9BS,IAASD,GAAiB,UAAU,iBAEpCE,KAAUF,GAAiB,UAAU,CAAA,GAAI,IAAI,CAACG,OAAS;AAAA,IAC3D,GAAGA;AAAA,IACH,MAAAX;AAAA,EAAA,EACA,GACIY,IAAgBF,EACnB,OAAO,CAACC,MAAQA,EAAI,aAAa,OAAO,EACxC,IAAI,CAACA,MAAQA,EAAI,OAAO,GACrBE,IAAkBH,EACrB,OAAO,CAACC,MAAQA,EAAI,aAAa,SAAS,EAC1C,IAAI,CAACA,MAAQA,EAAI,OAAO,GAGrBG,IAAUF,EAAc,CAAC,KAAKC,EAAgB,CAAC;AAErD,SACE,gBAAAE,EAAAC,GAAA,EACG,UAAAT,GAAe,cAAc,cAC9B,CAACR,GAAU,YAAY,UACrBQ,EAAc,aAAc,WAAY;AAAA,IACtC,4BACGU,EAAM,UAAN,EAAsC,UAAAf,KAAlBF,EAAK,UAAsB;AAAA,IAElD,QAAAS;AAAA;AAAA,IACA,SAASV,GAAU,YAAY,cAC3B,KACAA,GAAU,YAAY,WAAWe,KAAW;AAAA,IAEhD,WAAWF,EAAc,SAAS;AAAA,IAClC,aAAaC,EAAgB,SAAS;AAAA,IACtC,WAAWH;AAAA,IACX,MAAAV;AAAA,IACA,SAAS,MAAMK,EAAeJ,GAAWD,CAAI;AAAA,EAAA,CAC9C,IAED,gBAAAe,EAACE,EAAM,UAAN,EAAsC,UAAAf,EAAA,GAAlBF,EAAK,SAAA,CAAsB,GAEpD;AAEJ;"}
|