@sladg/apex-state 3.0.1 → 3.0.3
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 +228 -0
- package/dist/index.d.ts +79 -41
- package/dist/index.js +31 -24
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# @sladg/apex-state
|
|
2
|
+
|
|
3
|
+
Reactive state management for React built on [Valtio](https://github.com/pmndrs/valtio). Declare what your fields need — validation, conditional UI, sync, listeners — and the store handles the rest. Optional Rust/WASM accelerator for complex workloads (up to 367x faster).
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install @sladg/apex-state valtio zod react
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Example
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { createGenericStore } from '@sladg/apex-state'
|
|
13
|
+
import { z } from 'zod'
|
|
14
|
+
|
|
15
|
+
type OrderState = {
|
|
16
|
+
product: { name: string; quantity: number; price: number }
|
|
17
|
+
shipping: { address: string; express: boolean }
|
|
18
|
+
payment: { method: 'card' | 'cash'; cardNumber: string }
|
|
19
|
+
status: 'draft' | 'submitted'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const store = createGenericStore<OrderState>()
|
|
23
|
+
|
|
24
|
+
const OrderForm = () => {
|
|
25
|
+
// Declare side effects
|
|
26
|
+
store.useSideEffects('order', {
|
|
27
|
+
syncPaths: [['product.price', 'shipping.basePrice']],
|
|
28
|
+
flipPaths: [['shipping.express', 'shipping.standard']],
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
// Declare concerns — just data, no logic to test
|
|
32
|
+
store.useConcerns('order', {
|
|
33
|
+
'product.quantity': {
|
|
34
|
+
validationState: { schema: z.number().min(1).max(100) },
|
|
35
|
+
disabledWhen: { condition: { IS_EQUAL: ['status', 'submitted'] } },
|
|
36
|
+
},
|
|
37
|
+
'payment.cardNumber': {
|
|
38
|
+
validationState: { schema: z.string().regex(/^\d{16}$/) },
|
|
39
|
+
visibleWhen: { condition: { IS_EQUAL: ['payment.method', 'card'] } },
|
|
40
|
+
},
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const { value, setValue, validationState, disabledWhen } =
|
|
44
|
+
store.useFieldStore('product.quantity')
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<input
|
|
48
|
+
type="number"
|
|
49
|
+
value={value}
|
|
50
|
+
onChange={(e) => setValue(Number(e.target.value))}
|
|
51
|
+
disabled={disabledWhen}
|
|
52
|
+
className={validationState?.isError ? 'error' : ''}
|
|
53
|
+
/>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const App = () => (
|
|
58
|
+
<store.Provider initialState={{
|
|
59
|
+
product: { name: 'Widget', quantity: 1, price: 29.99 },
|
|
60
|
+
shipping: { address: '', express: false },
|
|
61
|
+
payment: { method: 'card', cardNumber: '' },
|
|
62
|
+
status: 'draft',
|
|
63
|
+
}}>
|
|
64
|
+
<OrderForm />
|
|
65
|
+
</store.Provider>
|
|
66
|
+
)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Features
|
|
70
|
+
|
|
71
|
+
| Feature | Description | Details |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| **Type-safe paths** | `DeepKey<T>` / `DeepValue<T, P>` — compile-time path safety | |
|
|
74
|
+
| **Concerns** | Validation, BoolLogic conditions, dynamic text | [Concerns Guide](docs/guides/CONCERNS_GUIDE.md) |
|
|
75
|
+
| **Side effects** | Sync paths, flip paths, aggregations, listeners | [Side Effects Guide](docs/SIDE_EFFECTS_GUIDE.md) |
|
|
76
|
+
| **WASM mode** | Rust-powered pipeline for bulk operations | [Architecture](docs/WASM_ARCHITECTURE.md) |
|
|
77
|
+
| **Composable hooks** | Buffered, throttled, transformed field wrappers | [Store & Hooks](docs/guides/STORE_HOOKS.md) |
|
|
78
|
+
| **Record/wildcard** | `Record<string, V>` with `[*]` wildcard paths | [Wildcard Guide](docs/WILD_FUNCTION_GUIDE.md) |
|
|
79
|
+
|
|
80
|
+
## Architecture
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
setValue("email", "alice@example.com")
|
|
84
|
+
│
|
|
85
|
+
├─[Legacy JS]──▶ sync → flip → listeners → applyBatch
|
|
86
|
+
│
|
|
87
|
+
└─[WASM/Rust]──▶ shadow state + sync + flip + BoolLogic (Rust)
|
|
88
|
+
│
|
|
89
|
+
▼
|
|
90
|
+
execute listeners + Zod validators (JS)
|
|
91
|
+
│
|
|
92
|
+
▼
|
|
93
|
+
pipelineFinalize → diff → final changes (Rust)
|
|
94
|
+
│
|
|
95
|
+
▼
|
|
96
|
+
valtio proxy → React re-render
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Dual-layer design:** JS/React owns reactivity and rendering. Rust/WASM owns heavy computation (graphs, diffing, pipeline orchestration). The boundary is thin: paths cross as strings, values as JSON. WASM decides the execution plan, JS executes user functions.
|
|
100
|
+
|
|
101
|
+
See [docs/WASM_ARCHITECTURE.md](docs/WASM_ARCHITECTURE.md) for the full specification.
|
|
102
|
+
|
|
103
|
+
## WASM Mode
|
|
104
|
+
|
|
105
|
+
WASM is the default. Pass `{ useLegacyImplementation: true }` for pure JS:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
const store = createGenericStore<MyState>() // WASM (default)
|
|
109
|
+
const store = createGenericStore<MyState>({ useLegacyImplementation: true }) // Legacy JS
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Performance
|
|
113
|
+
|
|
114
|
+
Benchmarked with 60 variants across 3 Record layers, 75 syncs, 40 flips, 100 BoolLogic conditions, 85 listeners:
|
|
115
|
+
|
|
116
|
+
| Operation | Legacy | WASM | Winner |
|
|
117
|
+
|---|---|---|---|
|
|
118
|
+
| Single field edit | **0.5us** | 1.4us | Legacy 2.6x |
|
|
119
|
+
| 7 changes + cascading listeners | 41.8ms | **0.11ms** | WASM 367x |
|
|
120
|
+
| 60 bulk price changes | 596ms | **2.9ms** | WASM 207x |
|
|
121
|
+
| 135 changes (full catalog refresh) | 621ms | **2.99ms** | WASM 208x |
|
|
122
|
+
|
|
123
|
+
Both modes produce **identical state** — verified across all 16 benchmark scenarios. See [docs/BENCHMARK_COMPARISON.md](docs/BENCHMARK_COMPARISON.md) for the full analysis.
|
|
124
|
+
|
|
125
|
+
### Why WASM is faster
|
|
126
|
+
|
|
127
|
+
- **Pre-computed topic routing** — listener dispatch is O(1) lookup vs O(changes x listeners) string matching
|
|
128
|
+
- **Shadow state diffing** — fast Rust HashMap vs valtio Proxy trap overhead
|
|
129
|
+
- **Single-pass pipeline** — aggregation + sync + flip + BoolLogic in one Rust call
|
|
130
|
+
- **BoolLogic in pipeline** — evaluated in Rust before listeners fire; Legacy defers to async `effect()`
|
|
131
|
+
|
|
132
|
+
### Why Legacy is faster for small ops
|
|
133
|
+
|
|
134
|
+
Every WASM call pays a fixed cost: JSON serialization, wasm-bindgen marshalling, and two round trips (`processChanges` + `pipelineFinalize`). When the actual work is trivial, this ~1us overhead dominates.
|
|
135
|
+
|
|
136
|
+
## API Quick Reference
|
|
137
|
+
|
|
138
|
+
### Store
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
const {
|
|
142
|
+
Provider, // React context — accepts initialState
|
|
143
|
+
useFieldStore, // { value, setValue, ...concerns } for a path
|
|
144
|
+
useStore, // [value, setValue] tuple for a path
|
|
145
|
+
useJitStore, // { proxyValue, setChanges, getState } for bulk ops
|
|
146
|
+
useSideEffects, // register sync/flip/aggregation/listeners
|
|
147
|
+
useConcerns, // register validation/BoolLogic/custom concerns
|
|
148
|
+
withConcerns, // typed concern selection
|
|
149
|
+
} = createGenericStore<MyState>(config?)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Concerns
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
useConcerns('id', {
|
|
156
|
+
'user.email': {
|
|
157
|
+
validationState: { schema: z.string().email() },
|
|
158
|
+
disabledWhen: { condition: { IS_EQUAL: ['tosAccepted', false] } },
|
|
159
|
+
visibleWhen: { condition: { AND: [{ EXISTS: 'user.name' }, { IS_EQUAL: ['step', 2] }] } },
|
|
160
|
+
},
|
|
161
|
+
})
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Built-in concerns: `validationState`, `disabledWhen`, `readonlyWhen`, `visibleWhen`, `dynamicLabel`, `dynamicTooltip`, `dynamicPlaceholder`.
|
|
165
|
+
|
|
166
|
+
BoolLogic operators: `IS_EQUAL`, `EXISTS`, `IS_EMPTY`, `GT`, `LT`, `GTE`, `LTE`, `IN`, `AND`, `OR`, `NOT`.
|
|
167
|
+
|
|
168
|
+
See [Concerns Guide](docs/guides/CONCERNS_GUIDE.md) for lifecycle, custom concerns, and testing.
|
|
169
|
+
|
|
170
|
+
### Side Effects
|
|
171
|
+
|
|
172
|
+
```tsx
|
|
173
|
+
useSideEffects('id', {
|
|
174
|
+
syncPaths: [['source', 'target']],
|
|
175
|
+
flipPaths: [['active', 'inactive']],
|
|
176
|
+
// Aggregation: target reflects the common value when all sources agree, null otherwise.
|
|
177
|
+
// Multiple pairs with the same target form a group.
|
|
178
|
+
// Currently supports consensus (all-equal) mode only — SUM, AVG, COUNT planned (see Roadmap).
|
|
179
|
+
aggregations: [['summary.price', 'legs.0.price'], ['summary.price', 'legs.1.price']],
|
|
180
|
+
listeners: [{ path: 'orders', scope: 'orders', fn: handler }],
|
|
181
|
+
})
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
See [Side Effects Guide](docs/SIDE_EFFECTS_GUIDE.md) for the full API.
|
|
185
|
+
|
|
186
|
+
## Development
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
npm install # Install dependencies
|
|
190
|
+
npm run wasm:build # Compile Rust -> WASM
|
|
191
|
+
npm run build # Bundle TypeScript + WASM
|
|
192
|
+
npm run test # Run tests
|
|
193
|
+
npm run code:check # Lint + type check
|
|
194
|
+
npm run wasm:check # Rust lint + check
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### WASM Prerequisites
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
# Rust toolchain
|
|
201
|
+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
|
202
|
+
rustup target add wasm32-unknown-unknown
|
|
203
|
+
cargo install wasm-pack
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Documentation
|
|
207
|
+
|
|
208
|
+
| Document | Covers |
|
|
209
|
+
|---|---|
|
|
210
|
+
| [WASM Architecture](docs/WASM_ARCHITECTURE.md) | JS/WASM boundary, data flow, ownership model |
|
|
211
|
+
| [Benchmark Comparison](docs/BENCHMARK_COMPARISON.md) | Legacy vs WASM performance with 16 scenarios |
|
|
212
|
+
| [Concerns Guide](docs/guides/CONCERNS_GUIDE.md) | Concern lifecycle, built-ins, custom concerns |
|
|
213
|
+
| [Side Effects Guide](docs/SIDE_EFFECTS_GUIDE.md) | Sync, flip, aggregation, listener API |
|
|
214
|
+
| [Store & Hooks](docs/guides/STORE_HOOKS.md) | Hook reference and patterns |
|
|
215
|
+
| [Debug Timing](docs/DEBUG_TIMING.md) | Performance debugging utilities |
|
|
216
|
+
| [Wildcard Paths](docs/WILD_FUNCTION_GUIDE.md) | `Wild()` template utility for Record types |
|
|
217
|
+
| [Record Migration](docs/RECORD_MIGRATION.md) | Migration patterns for dynamic Record types |
|
|
218
|
+
| [Full Index](docs/README.md) | Complete documentation index |
|
|
219
|
+
|
|
220
|
+
## Roadmap
|
|
221
|
+
|
|
222
|
+
- **Aggregation modes** — Aggregations currently use consensus (all-equal) mode. Planned: `SUM`, `AVG`, `COUNT`, `MIN`, `MAX`, and custom reducer functions, declared per-target alongside the source pairs.
|
|
223
|
+
- **Nested sub-stores** — Allow a parent store to contain child stores, enabling component-level state that participates in the parent's pipeline (concerns, listeners, sync).
|
|
224
|
+
- **Technical debt resolution** — See [TECHNICAL_DEBT.md](TECHNICAL_DEBT.md) for tracked items.
|
|
225
|
+
|
|
226
|
+
## License
|
|
227
|
+
|
|
228
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -223,6 +223,40 @@ type ArrayOfChanges<DATA, META extends GenericMeta = GenericMeta> = {
|
|
|
223
223
|
* their return types for proper type-safe concern registration and reading.
|
|
224
224
|
*/
|
|
225
225
|
|
|
226
|
+
/**
|
|
227
|
+
* Config type for the validationState concern at a specific path.
|
|
228
|
+
*
|
|
229
|
+
* Defined here (not in concerns/prebuilts/validation-state.ts) to avoid
|
|
230
|
+
* circular imports when used in ConcernRegistrationMap.
|
|
231
|
+
*
|
|
232
|
+
* Can be a schema for the path's own value type, or a scoped schema
|
|
233
|
+
* targeting a different path in the same state.
|
|
234
|
+
*/
|
|
235
|
+
type ValidationStateInput<DATA, PATH extends DeepKey<DATA>> = {
|
|
236
|
+
schema: z.ZodSchema<DeepValue<DATA, PATH>>;
|
|
237
|
+
} | {
|
|
238
|
+
[SCOPE in DeepKey<DATA>]: {
|
|
239
|
+
scope: SCOPE;
|
|
240
|
+
schema: z.ZodSchema<DeepValue<DATA, SCOPE>>;
|
|
241
|
+
};
|
|
242
|
+
}[DeepKey<DATA>];
|
|
243
|
+
/**
|
|
244
|
+
* Get the appropriate registration config type for a concern at a given path.
|
|
245
|
+
*
|
|
246
|
+
* - validationState: schema must match DeepValue<DATA, PATH> — path-dependent
|
|
247
|
+
* - BoolLogic-based concerns: boolLogic paths are typed against DATA
|
|
248
|
+
* - Template-based concerns: fixed { template: string }
|
|
249
|
+
* - Custom concerns: fall back to Record<string, unknown>
|
|
250
|
+
*/
|
|
251
|
+
type ConcernConfigFor<C, DATA extends object, PATH extends DeepKey<DATA>> = C extends {
|
|
252
|
+
name: 'validationState';
|
|
253
|
+
} ? ValidationStateInput<DATA, PATH> : C extends {
|
|
254
|
+
evaluate: (props: infer P) => any;
|
|
255
|
+
} ? P extends {
|
|
256
|
+
boolLogic: any;
|
|
257
|
+
} ? {
|
|
258
|
+
boolLogic: BoolLogic<DATA>;
|
|
259
|
+
} : Omit<P, 'state' | 'path' | 'value'> : Record<string, unknown>;
|
|
226
260
|
/**
|
|
227
261
|
* Extract the return type from a concern's evaluate function
|
|
228
262
|
*
|
|
@@ -261,8 +295,12 @@ type EvaluatedConcerns<CONCERNS extends readonly any[]> = {
|
|
|
261
295
|
/**
|
|
262
296
|
* Maps field paths to per-concern config objects.
|
|
263
297
|
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
298
|
+
* When CONCERNS is provided (e.g., from createGenericStore's CONCERNS generic),
|
|
299
|
+
* each concern config is type-checked against:
|
|
300
|
+
* - The concern's own EXTRA_PROPS (e.g., `{ boolLogic: ... }` for disabledWhen)
|
|
301
|
+
* - The path's value type for validationState (schema must match DeepValue<DATA, PATH>)
|
|
302
|
+
*
|
|
303
|
+
* Without CONCERNS (standalone usage), falls back to loose typing for backward compatibility.
|
|
266
304
|
*
|
|
267
305
|
* @example
|
|
268
306
|
* ```typescript
|
|
@@ -272,7 +310,13 @@ type EvaluatedConcerns<CONCERNS extends readonly any[]> = {
|
|
|
272
310
|
* }
|
|
273
311
|
* ```
|
|
274
312
|
*/
|
|
275
|
-
type ConcernRegistrationMap<DATA extends object> = Partial<
|
|
313
|
+
type ConcernRegistrationMap<DATA extends object, CONCERNS extends readonly any[] = readonly any[]> = Partial<{
|
|
314
|
+
[PATH in DeepKey<DATA>]: Partial<{
|
|
315
|
+
[C in CONCERNS[number] as C extends {
|
|
316
|
+
name: string;
|
|
317
|
+
} ? C['name'] : never]: ConcernConfigFor<C, DATA, PATH>;
|
|
318
|
+
}>;
|
|
319
|
+
}>;
|
|
276
320
|
|
|
277
321
|
/**
|
|
278
322
|
* DeepKeyFiltered - Filters paths by their resolved value type
|
|
@@ -384,8 +428,8 @@ interface BaseConcernProps<STATE, PATH extends string> {
|
|
|
384
428
|
path: PATH;
|
|
385
429
|
value: unknown;
|
|
386
430
|
}
|
|
387
|
-
interface ConcernType<EXTRA_PROPS = Record<string, unknown>, RETURN_TYPE = unknown> {
|
|
388
|
-
name:
|
|
431
|
+
interface ConcernType<NAME extends string = string, EXTRA_PROPS = Record<string, unknown>, RETURN_TYPE = unknown> {
|
|
432
|
+
name: NAME;
|
|
389
433
|
description: string;
|
|
390
434
|
/** Evaluated inside effect() - all state accesses are tracked */
|
|
391
435
|
evaluate: (props: BaseConcernProps<Record<string, unknown>, string> & EXTRA_PROPS) => RETURN_TYPE;
|
|
@@ -770,14 +814,6 @@ interface ValidationStateResult {
|
|
|
770
814
|
isError: boolean;
|
|
771
815
|
errors: ValidationError[];
|
|
772
816
|
}
|
|
773
|
-
type ValidationStateInput<SUB_STATE, PATH extends DeepKey<SUB_STATE>> = {
|
|
774
|
-
schema: z.ZodSchema<DeepValue<SUB_STATE, PATH>>;
|
|
775
|
-
} | {
|
|
776
|
-
[SCOPE in DeepKey<SUB_STATE>]: {
|
|
777
|
-
scope: SCOPE;
|
|
778
|
-
schema: z.ZodSchema<DeepValue<SUB_STATE, SCOPE>>;
|
|
779
|
-
};
|
|
780
|
-
}[DeepKey<SUB_STATE>];
|
|
781
817
|
interface ValidationStateConcern {
|
|
782
818
|
name: 'validationState';
|
|
783
819
|
description: string;
|
|
@@ -796,21 +832,21 @@ declare const findConcern: (name: string, concerns?: readonly any[]) => ConcernT
|
|
|
796
832
|
/**
|
|
797
833
|
* Default concerns provided by apex-state
|
|
798
834
|
*/
|
|
799
|
-
declare const defaultConcerns: readonly [ValidationStateConcern, ConcernType<{
|
|
835
|
+
declare const defaultConcerns: readonly [ValidationStateConcern, ConcernType<"disabledWhen", {
|
|
800
836
|
boolLogic: BoolLogic<any>;
|
|
801
|
-
}, boolean>, ConcernType<{
|
|
837
|
+
}, boolean>, ConcernType<"readonlyWhen", {
|
|
802
838
|
boolLogic: BoolLogic<any>;
|
|
803
|
-
}, boolean>, ConcernType<{
|
|
839
|
+
}, boolean>, ConcernType<"visibleWhen", {
|
|
804
840
|
boolLogic: BoolLogic<any>;
|
|
805
|
-
}, boolean>, ConcernType<{
|
|
841
|
+
}, boolean>, ConcernType<"dynamicTooltip", {
|
|
806
842
|
template: string;
|
|
807
|
-
}, string>, ConcernType<{
|
|
843
|
+
}, string>, ConcernType<"dynamicLabel", {
|
|
808
844
|
template: string;
|
|
809
|
-
}, string>, ConcernType<{
|
|
845
|
+
}, string>, ConcernType<"dynamicPlaceholder", {
|
|
810
846
|
template: string;
|
|
811
847
|
}, string>];
|
|
812
848
|
|
|
813
|
-
declare const disabledWhen: ConcernType<{
|
|
849
|
+
declare const disabledWhen: ConcernType<'disabledWhen', {
|
|
814
850
|
boolLogic: BoolLogic<any>;
|
|
815
851
|
}, boolean>;
|
|
816
852
|
|
|
@@ -833,7 +869,7 @@ declare const disabledWhen: ConcernType<{
|
|
|
833
869
|
* ```
|
|
834
870
|
*/
|
|
835
871
|
|
|
836
|
-
declare const readonlyWhen: ConcernType<{
|
|
872
|
+
declare const readonlyWhen: ConcernType<'readonlyWhen', {
|
|
837
873
|
boolLogic: BoolLogic<any>;
|
|
838
874
|
}, boolean>;
|
|
839
875
|
|
|
@@ -856,7 +892,7 @@ declare const readonlyWhen: ConcernType<{
|
|
|
856
892
|
* ```
|
|
857
893
|
*/
|
|
858
894
|
|
|
859
|
-
declare const visibleWhen: ConcernType<{
|
|
895
|
+
declare const visibleWhen: ConcernType<'visibleWhen', {
|
|
860
896
|
boolLogic: BoolLogic<any>;
|
|
861
897
|
}, boolean>;
|
|
862
898
|
|
|
@@ -879,7 +915,7 @@ declare const visibleWhen: ConcernType<{
|
|
|
879
915
|
* ```
|
|
880
916
|
*/
|
|
881
917
|
|
|
882
|
-
declare const dynamicLabel: ConcernType<{
|
|
918
|
+
declare const dynamicLabel: ConcernType<'dynamicLabel', {
|
|
883
919
|
template: string;
|
|
884
920
|
}, string>;
|
|
885
921
|
|
|
@@ -902,7 +938,7 @@ declare const dynamicLabel: ConcernType<{
|
|
|
902
938
|
* ```
|
|
903
939
|
*/
|
|
904
940
|
|
|
905
|
-
declare const dynamicPlaceholder: ConcernType<{
|
|
941
|
+
declare const dynamicPlaceholder: ConcernType<'dynamicPlaceholder', {
|
|
906
942
|
template: string;
|
|
907
943
|
}, string>;
|
|
908
944
|
|
|
@@ -925,24 +961,24 @@ declare const dynamicPlaceholder: ConcernType<{
|
|
|
925
961
|
* ```
|
|
926
962
|
*/
|
|
927
963
|
|
|
928
|
-
declare const dynamicTooltip: ConcernType<{
|
|
964
|
+
declare const dynamicTooltip: ConcernType<'dynamicTooltip', {
|
|
929
965
|
template: string;
|
|
930
966
|
}, string>;
|
|
931
967
|
|
|
932
968
|
/**
|
|
933
969
|
* All pre-built concerns as a tuple (for use with findConcern)
|
|
934
970
|
*/
|
|
935
|
-
declare const prebuilts: readonly [ValidationStateConcern, ConcernType<{
|
|
971
|
+
declare const prebuilts: readonly [ValidationStateConcern, ConcernType<"disabledWhen", {
|
|
936
972
|
boolLogic: BoolLogic<any>;
|
|
937
|
-
}, boolean>, ConcernType<{
|
|
973
|
+
}, boolean>, ConcernType<"readonlyWhen", {
|
|
938
974
|
boolLogic: BoolLogic<any>;
|
|
939
|
-
}, boolean>, ConcernType<{
|
|
975
|
+
}, boolean>, ConcernType<"visibleWhen", {
|
|
940
976
|
boolLogic: BoolLogic<any>;
|
|
941
|
-
}, boolean>, ConcernType<{
|
|
977
|
+
}, boolean>, ConcernType<"dynamicTooltip", {
|
|
942
978
|
template: string;
|
|
943
|
-
}, string>, ConcernType<{
|
|
979
|
+
}, string>, ConcernType<"dynamicLabel", {
|
|
944
980
|
template: string;
|
|
945
|
-
}, string>, ConcernType<{
|
|
981
|
+
}, string>, ConcernType<"dynamicPlaceholder", {
|
|
946
982
|
template: string;
|
|
947
983
|
}, string>];
|
|
948
984
|
/**
|
|
@@ -950,22 +986,22 @@ declare const prebuilts: readonly [ValidationStateConcern, ConcernType<{
|
|
|
950
986
|
*/
|
|
951
987
|
declare const prebuiltsNamespace: {
|
|
952
988
|
validationState: ValidationStateConcern;
|
|
953
|
-
disabledWhen: ConcernType<{
|
|
989
|
+
disabledWhen: ConcernType<"disabledWhen", {
|
|
954
990
|
boolLogic: BoolLogic<any>;
|
|
955
991
|
}, boolean>;
|
|
956
|
-
readonlyWhen: ConcernType<{
|
|
992
|
+
readonlyWhen: ConcernType<"readonlyWhen", {
|
|
957
993
|
boolLogic: BoolLogic<any>;
|
|
958
994
|
}, boolean>;
|
|
959
|
-
visibleWhen: ConcernType<{
|
|
995
|
+
visibleWhen: ConcernType<"visibleWhen", {
|
|
960
996
|
boolLogic: BoolLogic<any>;
|
|
961
997
|
}, boolean>;
|
|
962
|
-
dynamicTooltip: ConcernType<{
|
|
998
|
+
dynamicTooltip: ConcernType<"dynamicTooltip", {
|
|
963
999
|
template: string;
|
|
964
1000
|
}, string>;
|
|
965
|
-
dynamicLabel: ConcernType<{
|
|
1001
|
+
dynamicLabel: ConcernType<"dynamicLabel", {
|
|
966
1002
|
template: string;
|
|
967
1003
|
}, string>;
|
|
968
|
-
dynamicPlaceholder: ConcernType<{
|
|
1004
|
+
dynamicPlaceholder: ConcernType<"dynamicPlaceholder", {
|
|
969
1005
|
template: string;
|
|
970
1006
|
}, string>;
|
|
971
1007
|
};
|
|
@@ -1085,7 +1121,7 @@ interface SideEffects<DATA extends object, META extends GenericMeta = GenericMet
|
|
|
1085
1121
|
listeners?: ListenerRegistration<DATA, META>[];
|
|
1086
1122
|
}
|
|
1087
1123
|
|
|
1088
|
-
declare const createGenericStore: <DATA extends object, META extends GenericMeta = GenericMeta, CONCERNS extends readonly any[] = typeof defaultConcerns>(config?: StoreConfig) => {
|
|
1124
|
+
declare const createGenericStore: <DATA extends object, META extends GenericMeta = GenericMeta, CONCERNS extends readonly ConcernType<string, any, any>[] = typeof defaultConcerns>(config?: StoreConfig) => {
|
|
1089
1125
|
Provider: {
|
|
1090
1126
|
({ initialState: rawInitialState, children, }: ProviderProps<DATA>): react_jsx_runtime.JSX.Element | null;
|
|
1091
1127
|
displayName: string;
|
|
@@ -1101,12 +1137,14 @@ declare const createGenericStore: <DATA extends object, META extends GenericMeta
|
|
|
1101
1137
|
getState: () => DATA;
|
|
1102
1138
|
};
|
|
1103
1139
|
useSideEffects: (id: string, effects: SideEffects<DATA, META>) => void;
|
|
1104
|
-
useConcerns: (id: string, registration: ConcernRegistrationMap<DATA
|
|
1105
|
-
withConcerns: <SELECTION extends Partial<Record<
|
|
1140
|
+
useConcerns: <CUSTOM extends readonly ConcernType<string, any, any>[] = readonly []>(id: string, registration: ConcernRegistrationMap<DATA, readonly [...CONCERNS, ...CUSTOM]>, customConcerns?: CUSTOM) => void;
|
|
1141
|
+
withConcerns: <SELECTION extends Partial<Record<Extract<CONCERNS[number], {
|
|
1142
|
+
name: string;
|
|
1143
|
+
}>["name"], boolean>>>(selection: SELECTION) => {
|
|
1106
1144
|
useFieldStore: <P extends DeepKey<DATA>>(path: P) => {
|
|
1107
1145
|
value: DATA extends readonly any[] ? DATA[number] : P extends `${infer First}.${infer Rest}` ? First extends keyof DATA ? DeepValue<DATA[First], Rest> : string extends keyof DATA ? First extends "[*]" ? DeepValue<DATA[keyof DATA & string], Rest> : unknown : unknown : P extends "[*]" ? string extends keyof DATA ? DATA[keyof DATA & string] : unknown : P extends keyof DATA ? DATA[P] : unknown;
|
|
1108
1146
|
setValue: (newValue: DATA extends readonly any[] ? DATA[number] : P extends `${infer First}.${infer Rest}` ? First extends keyof DATA ? DeepValue<DATA[First], Rest> : string extends keyof DATA ? First extends "[*]" ? DeepValue<DATA[keyof DATA & string], Rest> : unknown : unknown : P extends "[*]" ? string extends keyof DATA ? DATA[keyof DATA & string] : unknown : P extends keyof DATA ? DATA[P] : unknown, meta?: META) => void;
|
|
1109
|
-
} & { [K in keyof SELECTION as SELECTION[K] extends true ? K : never]?: K extends CONCERNS
|
|
1147
|
+
} & { [K in keyof SELECTION as SELECTION[K] extends true ? K : never]?: K extends keyof EvaluatedConcerns<CONCERNS> ? EvaluatedConcerns<CONCERNS>[K] : never; };
|
|
1110
1148
|
};
|
|
1111
1149
|
};
|
|
1112
1150
|
|