cogsbox-state 0.5.476 → 0.5.479
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 +92 -0
- package/dist/CogsState.d.ts +84 -74
- package/dist/CogsState.d.ts.map +1 -1
- package/dist/CogsState.js +920 -844
- package/dist/CogsState.js.map +1 -1
- package/dist/Components.d.ts.map +1 -1
- package/dist/Components.js +110 -108
- package/dist/Components.js.map +1 -1
- package/dist/PluginRunner.d.ts.map +1 -1
- package/dist/PluginRunner.js +0 -1
- package/dist/PluginRunner.js.map +1 -1
- package/dist/index.js +35 -34
- package/dist/plugins.d.ts +93 -294
- package/dist/plugins.d.ts.map +1 -1
- package/dist/plugins.js +191 -60
- package/dist/plugins.js.map +1 -1
- package/dist/store.d.ts +3 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +470 -417
- package/dist/store.js.map +1 -1
- package/dist/utility.d.ts +1 -3
- package/dist/utility.d.ts.map +1 -1
- package/dist/utility.js +63 -73
- package/dist/utility.js.map +1 -1
- package/package.json +3 -3
- package/src/CogsState.tsx +405 -115
- package/src/Components.tsx +3 -1
- package/src/PluginRunner.tsx +3 -3
- package/src/plugins.ts +822 -108
- package/src/store.ts +131 -3
- package/src/utility.ts +1 -33
package/src/CogsState.tsx
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { pluginStore } from './pluginStore';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
FormWrapperParams,
|
|
5
|
+
type ChainMethodCallables,
|
|
6
|
+
type CogsPlugin,
|
|
7
|
+
} from './plugins';
|
|
4
8
|
import {
|
|
5
9
|
createElement,
|
|
6
10
|
startTransition,
|
|
@@ -79,7 +83,8 @@ type CutFunctionType<T> = (
|
|
|
79
83
|
options?: { waitForSync?: boolean }
|
|
80
84
|
) => StateObject<T>;
|
|
81
85
|
|
|
82
|
-
export type InferArrayElement<T> =
|
|
86
|
+
export type InferArrayElement<T> =
|
|
87
|
+
NonNullable<T> extends (infer U)[] ? U : never;
|
|
83
88
|
|
|
84
89
|
export type FormControl<T> = (obj: FormElementParams<T>) => JSX.Element;
|
|
85
90
|
|
|
@@ -95,7 +100,15 @@ export type InsertTypeObj<T> = (payload: InsertParams<T>) => void;
|
|
|
95
100
|
type EffectFunction<T, R> = (state: T, deps: any[]) => R;
|
|
96
101
|
export type PerPathFormOptsType<
|
|
97
102
|
TState,
|
|
98
|
-
TPlugins extends readonly CogsPlugin<
|
|
103
|
+
TPlugins extends readonly CogsPlugin<
|
|
104
|
+
any,
|
|
105
|
+
any,
|
|
106
|
+
any,
|
|
107
|
+
any,
|
|
108
|
+
any,
|
|
109
|
+
any,
|
|
110
|
+
any
|
|
111
|
+
>[] = [],
|
|
99
112
|
> = Omit<FormOptsType, 'formElements'> & {
|
|
100
113
|
formElements?: FormsElementsType<TState, TPlugins>;
|
|
101
114
|
};
|
|
@@ -123,7 +136,15 @@ export type ArrayElementExtras<TParentArray = unknown> = {
|
|
|
123
136
|
// EndType - NO $cutThis here, it's purely contextual
|
|
124
137
|
export type EndType<
|
|
125
138
|
T,
|
|
126
|
-
TPlugins extends readonly CogsPlugin<
|
|
139
|
+
TPlugins extends readonly CogsPlugin<
|
|
140
|
+
any,
|
|
141
|
+
any,
|
|
142
|
+
any,
|
|
143
|
+
any,
|
|
144
|
+
any,
|
|
145
|
+
any,
|
|
146
|
+
any
|
|
147
|
+
>[] = [],
|
|
127
148
|
> = {
|
|
128
149
|
$getPluginMetaData: (pluginName: string) => Record<string, any>;
|
|
129
150
|
$addPluginMetaData: (key: string, data: Record<string, any>) => void;
|
|
@@ -175,6 +196,7 @@ export type EndType<
|
|
|
175
196
|
selectText: () => void;
|
|
176
197
|
};
|
|
177
198
|
$removeStorage: () => void;
|
|
199
|
+
$setRaw: (value: T) => void;
|
|
178
200
|
$sync: () => void;
|
|
179
201
|
$validationWrapper: ({
|
|
180
202
|
children,
|
|
@@ -190,12 +212,20 @@ export type EndType<
|
|
|
190
212
|
export type ArrayElementState<
|
|
191
213
|
TElement,
|
|
192
214
|
TParentArray,
|
|
193
|
-
TPlugins extends readonly CogsPlugin<
|
|
215
|
+
TPlugins extends readonly CogsPlugin<
|
|
216
|
+
any,
|
|
217
|
+
any,
|
|
218
|
+
any,
|
|
219
|
+
any,
|
|
220
|
+
any,
|
|
221
|
+
any,
|
|
222
|
+
any
|
|
223
|
+
>[] = [],
|
|
194
224
|
> = StateObject<TElement, TPlugins> & ArrayElementExtras<TParentArray>;
|
|
195
225
|
|
|
196
226
|
export type ArrayEndType<
|
|
197
227
|
TShape extends unknown,
|
|
198
|
-
TPlugins extends readonly CogsPlugin<any, any, any, any, any>[],
|
|
228
|
+
TPlugins extends readonly CogsPlugin<any, any, any, any, any, any, any>[],
|
|
199
229
|
> = {
|
|
200
230
|
(): TShape;
|
|
201
231
|
(newValue: TShape | ((prev: TShape) => TShape)): void;
|
|
@@ -299,24 +329,33 @@ export type ArrayEndType<
|
|
|
299
329
|
|
|
300
330
|
export type StateObject<
|
|
301
331
|
T,
|
|
302
|
-
TPlugins extends readonly CogsPlugin<
|
|
332
|
+
TPlugins extends readonly CogsPlugin<
|
|
333
|
+
any,
|
|
334
|
+
any,
|
|
335
|
+
any,
|
|
336
|
+
any,
|
|
337
|
+
any,
|
|
338
|
+
any,
|
|
339
|
+
any
|
|
340
|
+
>[] = [],
|
|
303
341
|
> = {
|
|
304
342
|
(): T;
|
|
305
343
|
(newValue: T | ((prev: T) => T)): void;
|
|
306
|
-
} & (T extends any[]
|
|
344
|
+
} & ([NonNullable<T>] extends [any[]] // <-- Wrap in brackets
|
|
307
345
|
? ArrayEndType<T, TPlugins>
|
|
308
|
-
: T extends Record<string, unknown> | object
|
|
309
|
-
? {
|
|
310
|
-
|
|
346
|
+
: [NonNullable<T>] extends [Record<string, unknown> | object] // <-- Wrap in brackets
|
|
347
|
+
? {
|
|
348
|
+
[K in keyof NonNullable<T>]-?: StateObject<NonNullable<T>[K], TPlugins>;
|
|
349
|
+
}
|
|
350
|
+
: {}) & // Fallback to {} since we intersect EndType below anyway
|
|
311
351
|
EndType<T, TPlugins> & {
|
|
312
|
-
|
|
313
|
-
$toggle: T extends boolean ? () => void : never;
|
|
352
|
+
$toggle: NonNullable<T> extends boolean ? () => void : never;
|
|
314
353
|
$validate: () => { success: boolean; data?: T; error?: any };
|
|
315
354
|
$_componentId: string | null;
|
|
316
355
|
$getComponents: () => ComponentsType;
|
|
317
356
|
$_initialState: T;
|
|
318
357
|
$updateInitialState: (newState: T | null) => {
|
|
319
|
-
fetchId: (field: keyof T) => string | number;
|
|
358
|
+
fetchId: (field: keyof NonNullable<T>) => string | number;
|
|
320
359
|
};
|
|
321
360
|
$initializeAndMergeShadowState: (newState: any | null) => void;
|
|
322
361
|
$_isLoading: boolean;
|
|
@@ -332,10 +371,23 @@ export type StateObject<
|
|
|
332
371
|
}) => void
|
|
333
372
|
) => void;
|
|
334
373
|
$getLocalStorage: (key: string) => LocalStorageData<T> | null;
|
|
335
|
-
}
|
|
336
|
-
|
|
374
|
+
} & PluginChainMethodCallables<TPlugins>;
|
|
337
375
|
export type CogsUpdate<T extends unknown> = UpdateType<T>;
|
|
338
376
|
|
|
377
|
+
type UnionToIntersection<T> = (
|
|
378
|
+
T extends any ? (arg: T) => void : never
|
|
379
|
+
) extends (arg: infer I) => void
|
|
380
|
+
? I
|
|
381
|
+
: never;
|
|
382
|
+
|
|
383
|
+
type PluginChainMethodCallables<
|
|
384
|
+
TPlugins extends readonly CogsPlugin<any, any, any, any, any, any, any>[],
|
|
385
|
+
> = UnionToIntersection<
|
|
386
|
+
TPlugins[number] extends CogsPlugin<any, any, any, any, any, infer TMethods>
|
|
387
|
+
? ChainMethodCallables<TMethods>
|
|
388
|
+
: {}
|
|
389
|
+
>;
|
|
390
|
+
|
|
339
391
|
type EffectiveSetStateArg<
|
|
340
392
|
T,
|
|
341
393
|
UpdateType extends 'update' | 'insert' | 'cut',
|
|
@@ -407,7 +459,15 @@ type SyncOptionsType<TApiParams> = {
|
|
|
407
459
|
|
|
408
460
|
export type CreateStateOptionsType<
|
|
409
461
|
T extends unknown = unknown,
|
|
410
|
-
TPlugins extends readonly CogsPlugin<
|
|
462
|
+
TPlugins extends readonly CogsPlugin<
|
|
463
|
+
any,
|
|
464
|
+
any,
|
|
465
|
+
any,
|
|
466
|
+
any,
|
|
467
|
+
any,
|
|
468
|
+
any,
|
|
469
|
+
any
|
|
470
|
+
>[] = [],
|
|
411
471
|
> = {
|
|
412
472
|
formElements?: FormsElementsType<T, TPlugins>;
|
|
413
473
|
validation?: ValidationOptionsType;
|
|
@@ -470,7 +530,15 @@ type ScopedPluginApi<THookReturn, TFieldMetaData> = {
|
|
|
470
530
|
};
|
|
471
531
|
export type FormsElementsType<
|
|
472
532
|
TState,
|
|
473
|
-
TPlugins extends readonly CogsPlugin<
|
|
533
|
+
TPlugins extends readonly CogsPlugin<
|
|
534
|
+
any,
|
|
535
|
+
any,
|
|
536
|
+
any,
|
|
537
|
+
any,
|
|
538
|
+
any,
|
|
539
|
+
any,
|
|
540
|
+
any
|
|
541
|
+
>[] = [],
|
|
474
542
|
> = {
|
|
475
543
|
// These optional, built-in wrappers are unchanged.
|
|
476
544
|
validation?: (options: {
|
|
@@ -504,16 +572,6 @@ export type FormsElementsType<
|
|
|
504
572
|
key?: string;
|
|
505
573
|
}) => React.ReactNode;
|
|
506
574
|
};
|
|
507
|
-
export type CogsInitialState<T> =
|
|
508
|
-
| {
|
|
509
|
-
initialState: T;
|
|
510
|
-
}
|
|
511
|
-
| CreateStateOptionsType<T>;
|
|
512
|
-
|
|
513
|
-
export type TransformedStateType<T> = {
|
|
514
|
-
[P in keyof T]: T[P] extends CogsInitialState<infer U> ? U : T[P];
|
|
515
|
-
};
|
|
516
|
-
|
|
517
575
|
const {
|
|
518
576
|
getInitialOptions,
|
|
519
577
|
updateInitialStateGlobal,
|
|
@@ -692,18 +750,8 @@ function setOptions<StateKey, Opt>({
|
|
|
692
750
|
|
|
693
751
|
return mergedOptions;
|
|
694
752
|
}
|
|
695
|
-
export function addStateOptions<T>(
|
|
696
|
-
initialState: T,
|
|
697
|
-
options: CreateStateOptionsType<T>
|
|
698
|
-
) {
|
|
699
|
-
return {
|
|
700
|
-
...options,
|
|
701
|
-
initialState,
|
|
702
|
-
_addStateOptions: true,
|
|
703
|
-
};
|
|
704
|
-
}
|
|
705
753
|
export type PluginData = {
|
|
706
|
-
plugin: CogsPlugin<any, any, any, any, any>;
|
|
754
|
+
plugin: CogsPlugin<any, any, any, any, any, any, any>;
|
|
707
755
|
options: any;
|
|
708
756
|
hookData?: any;
|
|
709
757
|
};
|
|
@@ -712,7 +760,15 @@ export type PluginData = {
|
|
|
712
760
|
|
|
713
761
|
export const createCogsState = <
|
|
714
762
|
State extends Record<string, unknown>,
|
|
715
|
-
const TPlugins extends readonly CogsPlugin<
|
|
763
|
+
const TPlugins extends readonly CogsPlugin<
|
|
764
|
+
string,
|
|
765
|
+
any,
|
|
766
|
+
any,
|
|
767
|
+
any,
|
|
768
|
+
any,
|
|
769
|
+
any,
|
|
770
|
+
any
|
|
771
|
+
>[] = [],
|
|
716
772
|
>(
|
|
717
773
|
initialState: State,
|
|
718
774
|
opt?: {
|
|
@@ -721,60 +777,92 @@ export const createCogsState = <
|
|
|
721
777
|
validation?: ValidationOptionsType;
|
|
722
778
|
}
|
|
723
779
|
) => {
|
|
724
|
-
type
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
any,
|
|
730
|
-
any
|
|
731
|
-
>
|
|
780
|
+
type ExtractPluginOptions<T> = T extends {
|
|
781
|
+
useHook?: (params: { options: infer O }) => any; // infers O here
|
|
782
|
+
}
|
|
783
|
+
? O
|
|
784
|
+
: T extends CogsPlugin<string, infer O, any, any, any, any, any> // AND here
|
|
732
785
|
? O
|
|
733
786
|
: never;
|
|
787
|
+
|
|
788
|
+
type PluginOptions = {
|
|
789
|
+
[K in TPlugins[number] as K['name']]?: ExtractPluginOptions<K>;
|
|
734
790
|
};
|
|
735
791
|
|
|
736
792
|
if (opt?.plugins) {
|
|
737
793
|
pluginStore.getState().setRegisteredPlugins(opt.plugins as any);
|
|
738
794
|
}
|
|
795
|
+
type UnionToIntersection<U> = (
|
|
796
|
+
U extends any ? (k: U) => void : never
|
|
797
|
+
) extends (k: infer I) => void
|
|
798
|
+
? I
|
|
799
|
+
: never;
|
|
800
|
+
|
|
801
|
+
// Extract plugin initial state from the CogsPlugin generic (7th param) first,
|
|
802
|
+
// falling back to structural inference from initialState() return type.
|
|
803
|
+
type ExtractPluginState<T> = T extends CogsPlugin<
|
|
804
|
+
string,
|
|
805
|
+
any,
|
|
806
|
+
any,
|
|
807
|
+
any,
|
|
808
|
+
any,
|
|
809
|
+
any,
|
|
810
|
+
infer S
|
|
811
|
+
>
|
|
812
|
+
? S extends Record<string, unknown>
|
|
813
|
+
? S
|
|
814
|
+
: {}
|
|
815
|
+
: T extends {
|
|
816
|
+
initialState?: () => infer S;
|
|
817
|
+
}
|
|
818
|
+
? S extends Record<string, unknown>
|
|
819
|
+
? S
|
|
820
|
+
: {}
|
|
821
|
+
: {};
|
|
822
|
+
|
|
823
|
+
// Extract the merged plugin states into a helper type
|
|
824
|
+
type PluginStates = UnionToIntersection<ExtractPluginState<TPlugins[number]>>;
|
|
825
|
+
|
|
826
|
+
// User keys win over plugin keys — omit overlapping plugin keys before merging.
|
|
827
|
+
type FullState = Prettify<
|
|
828
|
+
State & {
|
|
829
|
+
[K in keyof PluginStates as K extends keyof State
|
|
830
|
+
? never
|
|
831
|
+
: K]: PluginStates[K];
|
|
832
|
+
}
|
|
833
|
+
>;
|
|
834
|
+
const pluginState: Record<string, unknown> = {};
|
|
835
|
+
if (opt?.plugins) {
|
|
836
|
+
for (const plugin of opt.plugins) {
|
|
837
|
+
if (typeof plugin.initialState === 'function') {
|
|
838
|
+
Object.assign(pluginState, plugin.initialState());
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
const mergedInitialState = { ...pluginState, ...initialState } as FullState;
|
|
739
844
|
|
|
740
845
|
const [statePart, initialOptionsPart] =
|
|
741
|
-
transformStateFunc<
|
|
846
|
+
transformStateFunc<FullState>(mergedInitialState);
|
|
742
847
|
|
|
743
|
-
// FIX: Store options INCLUDING validation for each state key
|
|
744
848
|
Object.keys(statePart).forEach((key) => {
|
|
745
|
-
let
|
|
746
|
-
|
|
747
|
-
const mergedOptions: any = {
|
|
748
|
-
...existingOptions,
|
|
749
|
-
};
|
|
849
|
+
let mergedOptions: any = {};
|
|
750
850
|
|
|
751
851
|
if (opt?.formElements) {
|
|
752
|
-
mergedOptions.formElements =
|
|
753
|
-
...opt.formElements,
|
|
754
|
-
...(existingOptions.formElements || {}),
|
|
755
|
-
};
|
|
852
|
+
mergedOptions.formElements = opt.formElements;
|
|
756
853
|
}
|
|
757
854
|
|
|
758
855
|
mergedOptions.validation = {
|
|
759
856
|
onBlur: 'error',
|
|
760
857
|
...opt?.validation,
|
|
761
|
-
...(existingOptions.validation || {}),
|
|
762
858
|
};
|
|
763
859
|
|
|
764
|
-
if (opt?.validation?.key && !existingOptions.validation?.key) {
|
|
765
|
-
mergedOptions.validation.key = `${opt.validation.key}.${key}`;
|
|
766
|
-
}
|
|
767
|
-
|
|
768
860
|
const existingGlobalOptions = getInitialOptions(key);
|
|
769
861
|
|
|
770
862
|
const finalOptions = existingGlobalOptions
|
|
771
863
|
? {
|
|
772
864
|
...existingGlobalOptions,
|
|
773
|
-
|
|
774
|
-
formElements: {
|
|
775
|
-
...existingGlobalOptions.formElements,
|
|
776
|
-
...mergedOptions.formElements,
|
|
777
|
-
},
|
|
865
|
+
formElements: opt?.formElements,
|
|
778
866
|
validation: {
|
|
779
867
|
...existingGlobalOptions.validation,
|
|
780
868
|
...mergedOptions.validation,
|
|
@@ -782,35 +870,56 @@ export const createCogsState = <
|
|
|
782
870
|
}
|
|
783
871
|
: mergedOptions;
|
|
784
872
|
|
|
785
|
-
|
|
873
|
+
if (Object.keys(finalOptions).length > 0) {
|
|
874
|
+
setInitialStateOptions(key, finalOptions);
|
|
875
|
+
}
|
|
786
876
|
});
|
|
787
877
|
|
|
788
878
|
Object.keys(statePart).forEach((key) => {
|
|
789
879
|
initializeShadowState(key, statePart[key]);
|
|
790
880
|
});
|
|
791
|
-
type
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
type
|
|
881
|
+
type StateKeys = keyof FullState;
|
|
882
|
+
|
|
883
|
+
// Flattens the 4x spam into a single clean object
|
|
884
|
+
type CleanIntersection<T> = T extends object ? { [K in keyof T]: T[K] } : T;
|
|
885
|
+
|
|
886
|
+
// Helper to find which keys are "keyed" (like queryParams)
|
|
887
|
+
type KeyedKeys<P> = {
|
|
888
|
+
[K in keyof P]-?: NonNullable<P[K]> extends { __key: 'keyed'; map: any }
|
|
889
|
+
? K
|
|
890
|
+
: never;
|
|
891
|
+
}[keyof P];
|
|
892
|
+
|
|
893
|
+
type StateSlice<StateKey extends StateKeys> = FullState[StateKey];
|
|
795
894
|
|
|
796
895
|
const useCogsState = <StateKey extends StateKeys>(
|
|
797
896
|
stateKey: StateKey,
|
|
798
897
|
options?: Prettify<
|
|
799
|
-
OptionsType<
|
|
898
|
+
OptionsType<StateSlice<StateKey>, never> & {
|
|
800
899
|
[PName in keyof PluginOptions]?: PluginOptions[PName] extends infer P
|
|
801
900
|
? P extends Record<string, any>
|
|
802
|
-
?
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
901
|
+
? Prettify<
|
|
902
|
+
Partial<Pick<P, Exclude<keyof P, KeyedKeys<P>>>> & {
|
|
903
|
+
[K in KeyedKeys<P> as StateKey extends keyof NonNullable<
|
|
904
|
+
P[K]
|
|
905
|
+
>['map']
|
|
906
|
+
? NonNullable<P[K]>['map'][StateKey] extends undefined
|
|
907
|
+
? never
|
|
908
|
+
: keyof NonNullable<P[K]>['map'][StateKey] extends never
|
|
909
|
+
? never
|
|
910
|
+
: K
|
|
911
|
+
: never]: CleanIntersection<
|
|
912
|
+
StateKey extends keyof NonNullable<P[K]>['map']
|
|
913
|
+
? NonNullable<P[K]>['map'][StateKey]
|
|
914
|
+
: never
|
|
915
|
+
>;
|
|
916
|
+
}
|
|
917
|
+
>
|
|
809
918
|
: P
|
|
810
919
|
: never;
|
|
811
920
|
}
|
|
812
921
|
>
|
|
813
|
-
) => {
|
|
922
|
+
): StateObject<StateSlice<StateKey>> => {
|
|
814
923
|
const [componentId] = useState(options?.componentId ?? uuidv4());
|
|
815
924
|
|
|
816
925
|
const currentOptions = setOptions({
|
|
@@ -825,21 +934,18 @@ export const createCogsState = <
|
|
|
825
934
|
const thiState =
|
|
826
935
|
getShadowValue(stateKey as string, []) || statePart[stateKey as string];
|
|
827
936
|
|
|
828
|
-
const updater = useCogsStateFn<(
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
serverState: options?.serverState,
|
|
841
|
-
}
|
|
842
|
-
);
|
|
937
|
+
const updater = useCogsStateFn<StateSlice<StateKey>>(thiState, {
|
|
938
|
+
stateKey: stateKey as string,
|
|
939
|
+
syncUpdate: options?.syncUpdate,
|
|
940
|
+
componentId,
|
|
941
|
+
localStorage: options?.localStorage,
|
|
942
|
+
middleware: options?.middleware,
|
|
943
|
+
reactiveType: options?.reactiveType,
|
|
944
|
+
reactiveDeps: options?.reactiveDeps,
|
|
945
|
+
defaultState: options?.defaultState as any,
|
|
946
|
+
dependencies: options?.dependencies,
|
|
947
|
+
serverState: options?.serverState,
|
|
948
|
+
});
|
|
843
949
|
|
|
844
950
|
useEffect(() => {
|
|
845
951
|
if (options) {
|
|
@@ -858,14 +964,14 @@ export const createCogsState = <
|
|
|
858
964
|
};
|
|
859
965
|
}, [stateKey, updater]);
|
|
860
966
|
|
|
861
|
-
return updater
|
|
967
|
+
return updater as StateObject<StateSlice<StateKey>>;
|
|
862
968
|
};
|
|
863
969
|
|
|
864
970
|
function setCogsOptionsByKey<StateKey extends StateKeys>(
|
|
865
971
|
stateKey: StateKey,
|
|
866
|
-
options: CreateStateOptionsType<
|
|
972
|
+
options: CreateStateOptionsType<StateSlice<StateKey>, TPlugins> &
|
|
867
973
|
Omit<
|
|
868
|
-
OptionsType<
|
|
974
|
+
OptionsType<StateSlice<StateKey>>,
|
|
869
975
|
keyof CreateStateOptionsType
|
|
870
976
|
>
|
|
871
977
|
) {
|
|
@@ -984,6 +1090,18 @@ const loadFromLocalStorage = (localStorageKey: string) => {
|
|
|
984
1090
|
return null;
|
|
985
1091
|
}
|
|
986
1092
|
};
|
|
1093
|
+
|
|
1094
|
+
const removeFromLocalStorage = (localStorageKey?: string) => {
|
|
1095
|
+
if (!localStorageKey) return;
|
|
1096
|
+
|
|
1097
|
+
try {
|
|
1098
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
1099
|
+
window.localStorage.removeItem(localStorageKey);
|
|
1100
|
+
}
|
|
1101
|
+
} catch (error) {
|
|
1102
|
+
console.error('Error removing from localStorage:', error);
|
|
1103
|
+
}
|
|
1104
|
+
};
|
|
987
1105
|
const loadAndApplyLocalStorage = (stateKey: string, options: any) => {
|
|
988
1106
|
const currentState = getShadowValue(stateKey, []);
|
|
989
1107
|
const { sessionId } = useCogsConfig();
|
|
@@ -1210,7 +1328,7 @@ function getComponentNotifications(
|
|
|
1210
1328
|
const pathMeta = getShadowMetadata(stateKey, currentPath);
|
|
1211
1329
|
|
|
1212
1330
|
if (pathMeta?.pathComponents) {
|
|
1213
|
-
pathMeta.pathComponents.forEach((componentId
|
|
1331
|
+
pathMeta.pathComponents.forEach((componentId) => {
|
|
1214
1332
|
const component = rootMeta.components?.get(componentId);
|
|
1215
1333
|
if (component) {
|
|
1216
1334
|
componentsToNotify.add(component);
|
|
@@ -1499,7 +1617,15 @@ function createEffectiveSetState<T>(
|
|
|
1499
1617
|
|
|
1500
1618
|
export function useCogsStateFn<
|
|
1501
1619
|
TStateObject extends unknown,
|
|
1502
|
-
const TPlugins extends readonly CogsPlugin<
|
|
1620
|
+
const TPlugins extends readonly CogsPlugin<
|
|
1621
|
+
any,
|
|
1622
|
+
any,
|
|
1623
|
+
any,
|
|
1624
|
+
any,
|
|
1625
|
+
any,
|
|
1626
|
+
any,
|
|
1627
|
+
any
|
|
1628
|
+
>[] = [],
|
|
1503
1629
|
>(
|
|
1504
1630
|
stateObject: TStateObject,
|
|
1505
1631
|
{
|
|
@@ -1959,9 +2085,72 @@ function getScopedData(stateKey: string, path: string[], meta?: MetaData) {
|
|
|
1959
2085
|
};
|
|
1960
2086
|
}
|
|
1961
2087
|
|
|
2088
|
+
function pathMatchesPattern(path: string[], pattern?: string[]) {
|
|
2089
|
+
if (!pattern) return true;
|
|
2090
|
+
if (path.length !== pattern.length) return false;
|
|
2091
|
+
|
|
2092
|
+
return pattern.every((segment, index) => {
|
|
2093
|
+
return segment === '*' || segment === path[index];
|
|
2094
|
+
});
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
function valueMatchesChainTarget(value: any, target: string) {
|
|
2098
|
+
if (target === 'any') return true;
|
|
2099
|
+
if (target === 'array') return Array.isArray(value);
|
|
2100
|
+
if (target === 'boolean') return typeof value === 'boolean';
|
|
2101
|
+
if (target === 'object') {
|
|
2102
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
2103
|
+
}
|
|
2104
|
+
if (target === 'primitive') {
|
|
2105
|
+
return (
|
|
2106
|
+
value === null || (typeof value !== 'object' && !Array.isArray(value))
|
|
2107
|
+
);
|
|
2108
|
+
}
|
|
2109
|
+
return false;
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2112
|
+
function getFieldRefsForPath(stateKey: string, path: string[]) {
|
|
2113
|
+
const meta = getGlobalStore.getState().getShadowMetadata(stateKey, path);
|
|
2114
|
+
if (!meta?.clientActivityState?.elements) return [];
|
|
2115
|
+
const refs: RefObject<any>[] = [];
|
|
2116
|
+
meta.clientActivityState.elements.forEach((entry: any) => {
|
|
2117
|
+
if (entry.domRef?.current) refs.push(entry.domRef);
|
|
2118
|
+
});
|
|
2119
|
+
return refs;
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
function getFieldElementsForPath(stateKey: string, path: string[]) {
|
|
2123
|
+
const refs = getFieldRefsForPath(stateKey, path);
|
|
2124
|
+
return refs.map((ref) => ref.current).filter(Boolean);
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
function setFieldDisabledForPath(
|
|
2128
|
+
stateKey: string,
|
|
2129
|
+
path: string[],
|
|
2130
|
+
disabled: boolean
|
|
2131
|
+
) {
|
|
2132
|
+
getFieldElementsForPath(stateKey, path).forEach((el: any) => {
|
|
2133
|
+
if ('disabled' in el) {
|
|
2134
|
+
el.disabled = disabled;
|
|
2135
|
+
return;
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
el.style.pointerEvents = disabled ? 'none' : '';
|
|
2139
|
+
el.setAttribute('aria-disabled', String(disabled));
|
|
2140
|
+
});
|
|
2141
|
+
}
|
|
2142
|
+
|
|
1962
2143
|
function createProxyHandler<
|
|
1963
2144
|
T,
|
|
1964
|
-
const TPlugins extends readonly CogsPlugin<
|
|
2145
|
+
const TPlugins extends readonly CogsPlugin<
|
|
2146
|
+
any,
|
|
2147
|
+
any,
|
|
2148
|
+
any,
|
|
2149
|
+
any,
|
|
2150
|
+
any,
|
|
2151
|
+
any,
|
|
2152
|
+
any
|
|
2153
|
+
>[],
|
|
1965
2154
|
>(
|
|
1966
2155
|
stateKey: string,
|
|
1967
2156
|
effectiveSetState: EffectiveSetState<T>,
|
|
@@ -1979,6 +2168,11 @@ function createProxyHandler<
|
|
|
1979
2168
|
componentId: string;
|
|
1980
2169
|
meta?: MetaData;
|
|
1981
2170
|
}): any {
|
|
2171
|
+
const rawMeta = getShadowMetadata(stateKey, path);
|
|
2172
|
+
if (rawMeta?.isRaw) {
|
|
2173
|
+
return getShadowValue(stateKey, path);
|
|
2174
|
+
}
|
|
2175
|
+
|
|
1982
2176
|
const derivationSignature = meta
|
|
1983
2177
|
? JSON.stringify(meta.arrayViews || meta.transforms)
|
|
1984
2178
|
: '';
|
|
@@ -2055,6 +2249,91 @@ function createProxyHandler<
|
|
|
2055
2249
|
}
|
|
2056
2250
|
|
|
2057
2251
|
if (typeof prop === 'string' && !prop.startsWith('$')) {
|
|
2252
|
+
const { value } = getScopedData(stateKey, path, meta);
|
|
2253
|
+
const hasStateChild =
|
|
2254
|
+
value !== null &&
|
|
2255
|
+
typeof value === 'object' &&
|
|
2256
|
+
!Array.isArray(value) &&
|
|
2257
|
+
Object.prototype.hasOwnProperty.call(value, prop);
|
|
2258
|
+
|
|
2259
|
+
if (hasStateChild) {
|
|
2260
|
+
const nextPath = [...path, prop];
|
|
2261
|
+
return rebuildStateShape({
|
|
2262
|
+
path: nextPath,
|
|
2263
|
+
componentId: componentId!,
|
|
2264
|
+
meta,
|
|
2265
|
+
});
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
const registeredPlugins = pluginStore.getState().registeredPlugins;
|
|
2269
|
+
for (const plugin of registeredPlugins) {
|
|
2270
|
+
const chainMethod = (plugin.chainMethods as any)?.[prop];
|
|
2271
|
+
if (!chainMethod) continue;
|
|
2272
|
+
if (!pathMatchesPattern(path, chainMethod.pathPattern)) continue;
|
|
2273
|
+
if (!valueMatchesChainTarget(value, chainMethod.target)) continue;
|
|
2274
|
+
|
|
2275
|
+
return (...args: any[]) => {
|
|
2276
|
+
const store = pluginStore.getState();
|
|
2277
|
+
const options = store.pluginOptions
|
|
2278
|
+
.get(stateKey)
|
|
2279
|
+
?.get(plugin.name);
|
|
2280
|
+
const hookData = store.getHookResult(stateKey, plugin.name);
|
|
2281
|
+
|
|
2282
|
+
return chainMethod.handler(
|
|
2283
|
+
{
|
|
2284
|
+
stateKey,
|
|
2285
|
+
path,
|
|
2286
|
+
pluginName: plugin.name,
|
|
2287
|
+
options,
|
|
2288
|
+
hookData,
|
|
2289
|
+
$get: () => getScopedData(stateKey, path, meta).value,
|
|
2290
|
+
$update: (payload: any) => {
|
|
2291
|
+
effectiveSetState(payload, path, {
|
|
2292
|
+
updateType: 'update',
|
|
2293
|
+
});
|
|
2294
|
+
|
|
2295
|
+
return {
|
|
2296
|
+
synced: () => {
|
|
2297
|
+
const shadowMeta = getGlobalStore
|
|
2298
|
+
.getState()
|
|
2299
|
+
.getShadowMetadata(stateKey, path);
|
|
2300
|
+
|
|
2301
|
+
setShadowMetadata(stateKey, path, {
|
|
2302
|
+
...shadowMeta,
|
|
2303
|
+
isDirty: false,
|
|
2304
|
+
stateSource: 'server',
|
|
2305
|
+
lastServerSync: Date.now(),
|
|
2306
|
+
});
|
|
2307
|
+
},
|
|
2308
|
+
};
|
|
2309
|
+
},
|
|
2310
|
+
$applyOperation: (
|
|
2311
|
+
operation: UpdateTypeDetail,
|
|
2312
|
+
metaData?: Record<string, any>
|
|
2313
|
+
) => {
|
|
2314
|
+
effectiveSetState(operation.newValue, operation.path, {
|
|
2315
|
+
updateType: operation.updateType,
|
|
2316
|
+
itemId: operation.itemId,
|
|
2317
|
+
metaData,
|
|
2318
|
+
});
|
|
2319
|
+
},
|
|
2320
|
+
getFieldMetaData: () =>
|
|
2321
|
+
getPluginMetaDataMap(stateKey, path)?.get(plugin.name),
|
|
2322
|
+
setFieldMetaData: (data: Record<string, any>) =>
|
|
2323
|
+
setPluginMetaData(stateKey, path, plugin.name, data),
|
|
2324
|
+
removeFieldMetaData: () =>
|
|
2325
|
+
removePluginMetaData(stateKey, path, plugin.name),
|
|
2326
|
+
getFieldRefs: () => getFieldRefsForPath(stateKey, path),
|
|
2327
|
+
getFieldElements: () =>
|
|
2328
|
+
getFieldElementsForPath(stateKey, path),
|
|
2329
|
+
setFieldDisabled: (disabled: boolean) =>
|
|
2330
|
+
setFieldDisabledForPath(stateKey, path, disabled),
|
|
2331
|
+
},
|
|
2332
|
+
...args
|
|
2333
|
+
);
|
|
2334
|
+
};
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2058
2337
|
const nextPath = [...path, prop];
|
|
2059
2338
|
return rebuildStateShape({
|
|
2060
2339
|
path: nextPath,
|
|
@@ -2171,8 +2450,18 @@ function createProxyHandler<
|
|
|
2171
2450
|
const localKey = isFunction(initalOptionsGet?.localStorage?.key)
|
|
2172
2451
|
? initalOptionsGet.localStorage.key(initialState)
|
|
2173
2452
|
: initalOptionsGet?.localStorage?.key;
|
|
2174
|
-
const storageKey =
|
|
2175
|
-
|
|
2453
|
+
const storageKey =
|
|
2454
|
+
sessionId && localKey
|
|
2455
|
+
? `${sessionId}-${stateKey}-${localKey}`
|
|
2456
|
+
: undefined;
|
|
2457
|
+
removeFromLocalStorage(storageKey);
|
|
2458
|
+
};
|
|
2459
|
+
}
|
|
2460
|
+
if (prop === '$setRaw') {
|
|
2461
|
+
return (value: any) => {
|
|
2462
|
+
const currentMeta = getShadowMetadata(stateKey, path) || {};
|
|
2463
|
+
setShadowMetadata(stateKey, path, { ...currentMeta, isRaw: true });
|
|
2464
|
+
effectiveSetState(value, path, { updateType: 'update' });
|
|
2176
2465
|
};
|
|
2177
2466
|
}
|
|
2178
2467
|
|
|
@@ -3323,10 +3612,11 @@ function createProxyHandler<
|
|
|
3323
3612
|
const localKey = isFunction(initalOptionsGet?.localStorage?.key)
|
|
3324
3613
|
? initalOptionsGet?.localStorage?.key(revertState)
|
|
3325
3614
|
: initalOptionsGet?.localStorage?.key;
|
|
3326
|
-
const storageKey =
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3615
|
+
const storageKey =
|
|
3616
|
+
sessionId && localKey
|
|
3617
|
+
? `${sessionId}-${stateKey}-${localKey}`
|
|
3618
|
+
: undefined;
|
|
3619
|
+
removeFromLocalStorage(storageKey);
|
|
3330
3620
|
|
|
3331
3621
|
notifyComponents(stateKey);
|
|
3332
3622
|
|
|
@@ -3350,11 +3640,11 @@ function createProxyHandler<
|
|
|
3350
3640
|
? initalOptionsGet?.localStorage?.key(initialState)
|
|
3351
3641
|
: initalOptionsGet?.localStorage?.key;
|
|
3352
3642
|
|
|
3353
|
-
const storageKey =
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3643
|
+
const storageKey =
|
|
3644
|
+
sessionId && localKey
|
|
3645
|
+
? `${sessionId}-${stateKey}-${localKey}`
|
|
3646
|
+
: undefined;
|
|
3647
|
+
removeFromLocalStorage(storageKey);
|
|
3358
3648
|
startTransition(() => {
|
|
3359
3649
|
updateInitialStateGlobal(stateKey, newState);
|
|
3360
3650
|
initializeShadowState(stateKey, newState);
|