cogsbox-state 0.5.489 → 0.5.491
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CogsState.d.ts +3 -50
- package/dist/CogsState.d.ts.map +1 -1
- package/dist/CogsState.js +931 -1049
- package/dist/CogsState.js.map +1 -1
- package/dist/Components.d.ts.map +1 -1
- package/dist/Components.js +85 -87
- package/dist/Components.js.map +1 -1
- package/dist/plugins.d.ts +4 -1
- package/dist/plugins.d.ts.map +1 -1
- package/dist/plugins.js.map +1 -1
- package/dist/store.d.ts +1 -20
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +180 -218
- package/dist/store.js.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +321 -645
- package/src/Components.tsx +45 -46
- package/src/plugins.ts +21 -15
- package/src/store.ts +2 -96
package/src/Components.tsx
CHANGED
|
@@ -22,7 +22,7 @@ import React, {
|
|
|
22
22
|
useMemo,
|
|
23
23
|
type ReactNode,
|
|
24
24
|
} from 'react';
|
|
25
|
-
import { getGlobalStore, ValidationError, ValidationSeverity } from './store';
|
|
25
|
+
import { getGlobalStore, ValidationError, ValidationSeverity } from './store';
|
|
26
26
|
import { useInView } from 'react-intersection-observer';
|
|
27
27
|
import { v4 as uuidv4 } from 'uuid';
|
|
28
28
|
import { isDeepEqual } from './utility';
|
|
@@ -272,7 +272,6 @@ export function FormElementWrapper({
|
|
|
272
272
|
|
|
273
273
|
useEffect(() => {
|
|
274
274
|
const { getShadowMetadata, setShadowMetadata } = getGlobalStore.getState();
|
|
275
|
-
console.log('FormElementWrapper effect running for:', stateKey, path);
|
|
276
275
|
|
|
277
276
|
// Initialize clientActivityState if needed
|
|
278
277
|
const currentMeta = getShadowMetadata(stateKey, path) || {};
|
|
@@ -304,7 +303,7 @@ export function FormElementWrapper({
|
|
|
304
303
|
inputType: formElementRef.current?.type,
|
|
305
304
|
mountedAt: Date.now(),
|
|
306
305
|
});
|
|
307
|
-
|
|
306
|
+
|
|
308
307
|
setShadowMetadata(stateKey, path, currentMeta);
|
|
309
308
|
|
|
310
309
|
// Subscribe to path updates
|
|
@@ -526,55 +525,55 @@ export function FormElementWrapper({
|
|
|
526
525
|
});
|
|
527
526
|
}, [localValue, setState, path, stateKey, componentId, globalStateValue]);
|
|
528
527
|
|
|
529
|
-
const baseState = rebuildStateShape({
|
|
530
|
-
path: path,
|
|
531
|
-
componentId: componentId,
|
|
532
|
-
meta: undefined,
|
|
533
|
-
});
|
|
534
|
-
const validationState = getShadowMetadata(stateKey, path)?.validation;
|
|
535
|
-
const validationStatus = validationState?.status || 'NOT_VALIDATED';
|
|
536
|
-
const allErrors = (validationState?.errors || []).map((err) => ({
|
|
537
|
-
...err,
|
|
538
|
-
path,
|
|
539
|
-
})) as ValidationError[];
|
|
540
|
-
const errorMessages = allErrors
|
|
541
|
-
.filter((err) => err.severity === 'error')
|
|
542
|
-
.map((err) => err.message);
|
|
543
|
-
const warningMessages = allErrors
|
|
544
|
-
.filter((err) => err.severity === 'warning')
|
|
545
|
-
.map((err) => err.message);
|
|
546
|
-
const validationMessage = errorMessages[0] || warningMessages[0] || '';
|
|
547
|
-
const validationSeverity: ValidationSeverity =
|
|
548
|
-
errorMessages.length > 0
|
|
549
|
-
? 'error'
|
|
550
|
-
: warningMessages.length > 0
|
|
551
|
-
? 'warning'
|
|
552
|
-
: undefined;
|
|
553
|
-
|
|
554
|
-
const stateWithInputProps = new Proxy(baseState, {
|
|
555
|
-
get(target, prop) {
|
|
556
|
-
if (prop === '$inputProps') {
|
|
557
|
-
return {
|
|
528
|
+
const baseState = rebuildStateShape({
|
|
529
|
+
path: path,
|
|
530
|
+
componentId: componentId,
|
|
531
|
+
meta: undefined,
|
|
532
|
+
});
|
|
533
|
+
const validationState = getShadowMetadata(stateKey, path)?.validation;
|
|
534
|
+
const validationStatus = validationState?.status || 'NOT_VALIDATED';
|
|
535
|
+
const allErrors = (validationState?.errors || []).map((err) => ({
|
|
536
|
+
...err,
|
|
537
|
+
path,
|
|
538
|
+
})) as ValidationError[];
|
|
539
|
+
const errorMessages = allErrors
|
|
540
|
+
.filter((err) => err.severity === 'error')
|
|
541
|
+
.map((err) => err.message);
|
|
542
|
+
const warningMessages = allErrors
|
|
543
|
+
.filter((err) => err.severity === 'warning')
|
|
544
|
+
.map((err) => err.message);
|
|
545
|
+
const validationMessage = errorMessages[0] || warningMessages[0] || '';
|
|
546
|
+
const validationSeverity: ValidationSeverity =
|
|
547
|
+
errorMessages.length > 0
|
|
548
|
+
? 'error'
|
|
549
|
+
: warningMessages.length > 0
|
|
550
|
+
? 'warning'
|
|
551
|
+
: undefined;
|
|
552
|
+
|
|
553
|
+
const stateWithInputProps = new Proxy(baseState, {
|
|
554
|
+
get(target, prop) {
|
|
555
|
+
if (prop === '$inputProps') {
|
|
556
|
+
return {
|
|
558
557
|
value: localValue ?? '',
|
|
559
558
|
onChange: (e: any) => {
|
|
560
559
|
debouncedUpdate(e.target.value);
|
|
561
560
|
},
|
|
562
561
|
onFocus: handleFocus,
|
|
563
562
|
onBlur: handleBlur,
|
|
564
|
-
ref: formElementRef,
|
|
565
|
-
};
|
|
566
|
-
}
|
|
567
|
-
if (prop === 'status') return validationStatus;
|
|
568
|
-
if (prop === 'severity') return validationSeverity;
|
|
569
|
-
if (prop === 'hasErrors') return errorMessages.length > 0;
|
|
570
|
-
if (prop === 'hasWarnings') return warningMessages.length > 0;
|
|
571
|
-
if (prop === 'allErrors') return allErrors;
|
|
572
|
-
if (prop === 'message') return validationMessage;
|
|
573
|
-
if (prop === 'getData') return () => getShadowValue(stateKey, path);
|
|
574
|
-
|
|
575
|
-
return target[prop];
|
|
576
|
-
},
|
|
577
|
-
});
|
|
563
|
+
ref: formElementRef,
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
if (prop === 'status') return validationStatus;
|
|
567
|
+
if (prop === 'severity') return validationSeverity;
|
|
568
|
+
if (prop === 'hasErrors') return errorMessages.length > 0;
|
|
569
|
+
if (prop === 'hasWarnings') return warningMessages.length > 0;
|
|
570
|
+
if (prop === 'allErrors') return allErrors;
|
|
571
|
+
if (prop === 'message') return validationMessage;
|
|
572
|
+
if (prop === 'getData') return () => getShadowValue(stateKey, path);
|
|
573
|
+
|
|
574
|
+
return target[prop];
|
|
575
|
+
},
|
|
576
|
+
});
|
|
578
577
|
|
|
579
578
|
const initialElement = renderFn(stateWithInputProps);
|
|
580
579
|
|
package/src/plugins.ts
CHANGED
|
@@ -29,6 +29,8 @@ export type ChainMethodContext<TOptions = any, THookReturn = any> = {
|
|
|
29
29
|
getFieldMetaData: () => any;
|
|
30
30
|
setFieldMetaData: (data: Record<string, any>) => void;
|
|
31
31
|
removeFieldMetaData: () => void;
|
|
32
|
+
watchPluginMeta: (scope?: string) => void;
|
|
33
|
+
notifyPluginMeta: (scope?: string) => void;
|
|
32
34
|
getFieldRefs: () => RefObject<any>[];
|
|
33
35
|
getFieldElements: () => HTMLElement[];
|
|
34
36
|
setFieldDisabled: (disabled: boolean) => void;
|
|
@@ -56,13 +58,17 @@ type ChainMethodCallable<THandler> = THandler extends (
|
|
|
56
58
|
? (...args: TArgs) => TReturn
|
|
57
59
|
: never;
|
|
58
60
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
61
|
+
type LiteralStringKeys<T> = string extends keyof T
|
|
62
|
+
? never
|
|
63
|
+
: Extract<keyof T, string>;
|
|
64
|
+
|
|
65
|
+
export type ChainMethodCallables<TMethods> = {
|
|
66
|
+
[K in LiteralStringKeys<TMethods> as K extends string
|
|
67
|
+
? `$${K}`
|
|
68
|
+
: never]: TMethods[K] extends ChainMethodDefinition<infer TFn>
|
|
69
|
+
? ChainMethodCallable<TFn>
|
|
70
|
+
: never;
|
|
71
|
+
};
|
|
66
72
|
|
|
67
73
|
export type KeyedTypes<TMap extends Record<string, any>> = {
|
|
68
74
|
__key: 'keyed';
|
|
@@ -472,14 +478,14 @@ type ZodObjOutput<T extends z.ZodObject<any>> = {
|
|
|
472
478
|
type OutputOf<T extends z.ZodTypeAny> =
|
|
473
479
|
T extends z.ZodObject<any> ? Prettify<ZodObjOutput<T>> : z.output<T>;
|
|
474
480
|
|
|
475
|
-
type MethodFactory = <TArgs extends any[], TReturn>(
|
|
476
|
-
handler: (
|
|
477
|
-
ctx: ChainMethodContext<any, any>,
|
|
478
|
-
...args: TArgs
|
|
479
|
-
) => TReturn
|
|
480
|
-
) => ChainMethodDefinition<
|
|
481
|
-
(ctx: ChainMethodContext<any, any>, ...args: TArgs) => TReturn
|
|
482
|
-
>;
|
|
481
|
+
type MethodFactory = <TArgs extends any[], TReturn>(
|
|
482
|
+
handler: (
|
|
483
|
+
ctx: ChainMethodContext<any, any>,
|
|
484
|
+
...args: TArgs
|
|
485
|
+
) => TReturn
|
|
486
|
+
) => ChainMethodDefinition<
|
|
487
|
+
(ctx: ChainMethodContext<any, any>, ...args: TArgs) => TReturn
|
|
488
|
+
>;
|
|
483
489
|
|
|
484
490
|
type PathMethodFactory = MethodFactory & {
|
|
485
491
|
array: MethodFactory;
|
package/src/store.ts
CHANGED
|
@@ -4,7 +4,6 @@ import type { RefObject } from 'react';
|
|
|
4
4
|
import type {
|
|
5
5
|
OptionsType,
|
|
6
6
|
ReactivityType,
|
|
7
|
-
SyncInfo,
|
|
8
7
|
UpdateTypeDetail,
|
|
9
8
|
} from './CogsState.js';
|
|
10
9
|
|
|
@@ -134,18 +133,14 @@ export type ShadowMetadata = {
|
|
|
134
133
|
value?: any;
|
|
135
134
|
id?: string;
|
|
136
135
|
typeInfo?: SchemaTypeInfo;
|
|
137
|
-
stateSource?: 'default' | 'server' | 'localStorage';
|
|
138
|
-
lastServerSync?: number;
|
|
139
|
-
isDirty?: boolean;
|
|
140
136
|
isRaw?: boolean;
|
|
141
|
-
baseServerState?: any;
|
|
142
137
|
arrayKeys?: string[];
|
|
143
138
|
fields?: Record<string, any>;
|
|
144
139
|
virtualizer?: {
|
|
145
140
|
itemHeight?: number;
|
|
146
141
|
domRef?: HTMLElement | null;
|
|
147
142
|
};
|
|
148
|
-
|
|
143
|
+
|
|
149
144
|
validation?: ValidationState;
|
|
150
145
|
features?: {
|
|
151
146
|
localStorageEnabled: boolean;
|
|
@@ -252,12 +247,6 @@ export type CogsGlobalState = {
|
|
|
252
247
|
dependencyPath: string[],
|
|
253
248
|
fullComponentId: string
|
|
254
249
|
) => void;
|
|
255
|
-
markAsDirty: (
|
|
256
|
-
key: string,
|
|
257
|
-
path: string[],
|
|
258
|
-
options: { bubble: boolean }
|
|
259
|
-
) => void;
|
|
260
|
-
|
|
261
250
|
pathSubscribers: Map<string, Set<(newValue: any) => void>>;
|
|
262
251
|
subscribeToPath: (
|
|
263
252
|
path: string,
|
|
@@ -278,23 +267,8 @@ export type CogsGlobalState = {
|
|
|
278
267
|
getInitialOptions: (key: string) => OptionsType | undefined;
|
|
279
268
|
setInitialStateOptions: (key: string, value: OptionsType) => void;
|
|
280
269
|
|
|
281
|
-
serverStateUpdates: Map<
|
|
282
|
-
string,
|
|
283
|
-
{
|
|
284
|
-
data: any;
|
|
285
|
-
status: 'loading' | 'success' | 'error';
|
|
286
|
-
timestamp: number;
|
|
287
|
-
}
|
|
288
|
-
>;
|
|
289
|
-
|
|
290
|
-
setServerStateUpdate: (key: string, serverState: any) => void;
|
|
291
|
-
|
|
292
270
|
stateLog: Map<string, Map<string, UpdateTypeDetail>>;
|
|
293
|
-
syncInfoStore: Map<string, SyncInfo>;
|
|
294
271
|
addStateLog: (updates: UpdateTypeDetail[]) => void;
|
|
295
|
-
|
|
296
|
-
setSyncInfo: (key: string, syncInfo: SyncInfo) => void;
|
|
297
|
-
getSyncInfo: (key: string) => SyncInfo | null;
|
|
298
272
|
};
|
|
299
273
|
function getTypeFromZodSchema(
|
|
300
274
|
schema: any,
|
|
@@ -787,9 +761,6 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
787
761
|
const {
|
|
788
762
|
components,
|
|
789
763
|
features,
|
|
790
|
-
lastServerSync,
|
|
791
|
-
stateSource,
|
|
792
|
-
baseServerState,
|
|
793
764
|
pathComponents,
|
|
794
765
|
signals,
|
|
795
766
|
validation,
|
|
@@ -797,9 +768,6 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
797
768
|
|
|
798
769
|
if (components) preservedMetadata.components = components;
|
|
799
770
|
if (features) preservedMetadata.features = features;
|
|
800
|
-
if (lastServerSync) preservedMetadata.lastServerSync = lastServerSync;
|
|
801
|
-
if (stateSource) preservedMetadata.stateSource = stateSource;
|
|
802
|
-
if (baseServerState) preservedMetadata.baseServerState = baseServerState;
|
|
803
771
|
if (pathComponents) preservedMetadata.pathComponents = pathComponents;
|
|
804
772
|
if (signals) preservedMetadata.signals = signals;
|
|
805
773
|
if (validation) preservedMetadata.validation = validation;
|
|
@@ -962,15 +930,9 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
962
930
|
const {
|
|
963
931
|
components,
|
|
964
932
|
features,
|
|
965
|
-
lastServerSync,
|
|
966
|
-
stateSource,
|
|
967
|
-
baseServerState,
|
|
968
933
|
} = existingRoot._meta;
|
|
969
934
|
if (components) preservedMetadata.components = components;
|
|
970
935
|
if (features) preservedMetadata.features = features;
|
|
971
|
-
if (lastServerSync) preservedMetadata.lastServerSync = lastServerSync;
|
|
972
|
-
if (stateSource) preservedMetadata.stateSource = stateSource;
|
|
973
|
-
if (baseServerState) preservedMetadata.baseServerState = baseServerState;
|
|
974
936
|
}
|
|
975
937
|
|
|
976
938
|
shadowStateStore.delete(key);
|
|
@@ -1467,55 +1429,6 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
1467
1429
|
}
|
|
1468
1430
|
},
|
|
1469
1431
|
|
|
1470
|
-
markAsDirty: (key, path, options = { bubble: true }) => {
|
|
1471
|
-
// Start at the root node once.
|
|
1472
|
-
let rootNode = get().getShadowNode(key, []);
|
|
1473
|
-
if (!rootNode) return;
|
|
1474
|
-
|
|
1475
|
-
// Navigate to the target node once.
|
|
1476
|
-
let currentNode = rootNode;
|
|
1477
|
-
for (const segment of path) {
|
|
1478
|
-
currentNode = currentNode[segment];
|
|
1479
|
-
if (!currentNode) return; // Path doesn't exist, nothing to mark.
|
|
1480
|
-
}
|
|
1481
|
-
|
|
1482
|
-
// Mark the target node as dirty.
|
|
1483
|
-
if (!currentNode._meta) currentNode._meta = {};
|
|
1484
|
-
currentNode._meta.isDirty = true;
|
|
1485
|
-
|
|
1486
|
-
// If bubbling is disabled, we are done.
|
|
1487
|
-
if (!options.bubble) return;
|
|
1488
|
-
|
|
1489
|
-
// Efficiently bubble up using the path segments.
|
|
1490
|
-
let parentNode = rootNode;
|
|
1491
|
-
for (let i = 0; i < path.length; i++) {
|
|
1492
|
-
// The current node in the loop is the parent of the next one.
|
|
1493
|
-
if (parentNode._meta?.isDirty) {
|
|
1494
|
-
// Optimization: If a parent is already dirty, all of its ancestors are too.
|
|
1495
|
-
// We can stop bubbling immediately.
|
|
1496
|
-
return;
|
|
1497
|
-
}
|
|
1498
|
-
if (!parentNode._meta) parentNode._meta = {};
|
|
1499
|
-
parentNode._meta.isDirty = true;
|
|
1500
|
-
parentNode = parentNode[path[i]!];
|
|
1501
|
-
}
|
|
1502
|
-
},
|
|
1503
|
-
|
|
1504
|
-
// Keep these in Zustand as they need React reactivity
|
|
1505
|
-
serverStateUpdates: new Map(),
|
|
1506
|
-
setServerStateUpdate: (key, serverState) => {
|
|
1507
|
-
set((state) => ({
|
|
1508
|
-
serverStateUpdates: new Map(state.serverStateUpdates).set(
|
|
1509
|
-
key,
|
|
1510
|
-
serverState
|
|
1511
|
-
),
|
|
1512
|
-
}));
|
|
1513
|
-
get().notifyPathSubscribers(key, {
|
|
1514
|
-
type: 'SERVER_STATE_UPDATE',
|
|
1515
|
-
serverState,
|
|
1516
|
-
});
|
|
1517
|
-
},
|
|
1518
|
-
|
|
1519
1432
|
pathSubscribers: new Map<string, Set<(newValue: any) => void>>(),
|
|
1520
1433
|
subscribeToPath: (path, callback) => {
|
|
1521
1434
|
const subscribers = get().pathSubscribers;
|
|
@@ -1654,14 +1567,7 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
1654
1567
|
}));
|
|
1655
1568
|
},
|
|
1656
1569
|
|
|
1657
|
-
|
|
1658
|
-
setSyncInfo: (key, syncInfo) =>
|
|
1659
|
-
set((state) => {
|
|
1660
|
-
const newMap = new Map(state.syncInfoStore);
|
|
1661
|
-
newMap.set(key, syncInfo);
|
|
1662
|
-
return { syncInfoStore: newMap };
|
|
1663
|
-
}),
|
|
1664
|
-
getSyncInfo: (key) => get().syncInfoStore.get(key) || null,
|
|
1570
|
+
// Removed: syncInfo is now owned by Shape Plugin
|
|
1665
1571
|
}));
|
|
1666
1572
|
|
|
1667
1573
|
export function getAllFieldElements(stateKey: string): HTMLElement[] {
|