3
3
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
4
4
5
5
import { DEV } from 'esm-env' ;
6
+ import { untrack } from 'svelte' ;
6
7
7
8
/**
8
9
* Sets a value in a nested object using a path string, not mutating the original object but returning a new object
@@ -174,19 +175,27 @@ export function deep_get(object, path) {
174
175
* Creates a proxy-based field accessor for form data
175
176
* @param {any } target - Function or empty POJO
176
177
* @param {() => Record<string, any> } get_input - Function to get current input data
178
+ * @param {(path: string) => void } depend - Function to make an effect depend on a specific field
177
179
* @param {(path: (string | number)[], value: any) => void } set_input - Function to set input data
178
180
* @param {() => Record<string, InternalRemoteFormIssue[]> } get_issues - Function to get current issues
179
181
* @param {(string | number)[] } path - Current access path
180
182
* @returns {any } Proxy object with name(), value(), and issues() methods
181
183
*/
182
- export function create_field_proxy ( target , get_input , set_input , get_issues , path = [ ] ) {
184
+ export function create_field_proxy ( target , get_input , depend , set_input , get_issues , path = [ ] ) {
185
+ const path_string = build_path_string ( path ) ;
186
+
187
+ const get_value = ( ) => {
188
+ depend ( path_string ) ;
189
+ return untrack ( ( ) => deep_get ( get_input ( ) , path ) ) ;
190
+ } ;
191
+
183
192
return new Proxy ( target , {
184
193
get ( target , prop ) {
185
194
if ( typeof prop === 'symbol' ) return target [ prop ] ;
186
195
187
196
// Handle array access like jobs[0]
188
197
if ( / ^ \d + $ / . test ( prop ) ) {
189
- return create_field_proxy ( { } , get_input , set_input , get_issues , [
198
+ return create_field_proxy ( { } , get_input , depend , set_input , get_issues , [
190
199
...path ,
191
200
parseInt ( prop , 10 )
192
201
] ) ;
@@ -199,18 +208,17 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
199
208
set_input ( path , newValue ) ;
200
209
return newValue ;
201
210
} ;
202
- return create_field_proxy ( set_func , get_input , set_input , get_issues , [ ...path , prop ] ) ;
211
+ return create_field_proxy ( set_func , get_input , depend , set_input , get_issues , [
212
+ ...path ,
213
+ prop
214
+ ] ) ;
203
215
}
204
216
205
217
if ( prop === 'value' ) {
206
- const value_func = function ( ) {
207
- // TODO Ideally we'd create a $derived just above and use it here but we can't because of push_reaction which prevents
208
- // changes to deriveds created within an effect to rerun the effect - an argument for
209
- // reverting that change in async mode?
210
- // TODO we did that in Svelte now; bump Svelte version and use $derived here
211
- return deep_get ( get_input ( ) , path ) ;
212
- } ;
213
- return create_field_proxy ( value_func , get_input , set_input , get_issues , [ ...path , prop ] ) ;
218
+ return create_field_proxy ( get_value , get_input , depend , set_input , get_issues , [
219
+ ...path ,
220
+ prop
221
+ ] ) ;
214
222
}
215
223
216
224
if ( prop === 'issues' || prop === 'allIssues' ) {
@@ -230,7 +238,10 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
230
238
} ) ) ;
231
239
} ;
232
240
233
- return create_field_proxy ( issues_func , get_input , set_input , get_issues , [ ...path , prop ] ) ;
241
+ return create_field_proxy ( issues_func , get_input , depend , set_input , get_issues , [
242
+ ...path ,
243
+ prop
244
+ ] ) ;
234
245
}
235
246
236
247
if ( prop === 'as' ) {
@@ -266,11 +277,11 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
266
277
base_props . type = type === 'file multiple' ? 'file' : type ;
267
278
}
268
279
269
- // Handle submit inputs
270
- if ( type === 'submit' ) {
280
+ // Handle submit and hidden inputs
281
+ if ( type === 'submit' || type === 'hidden' ) {
271
282
if ( DEV ) {
272
283
if ( ! input_value ) {
273
- throw new Error ( 'Submit inputs must have a value' ) ;
284
+ throw new Error ( `\` ${ type } \` inputs must have a value` ) ;
274
285
}
275
286
}
276
287
@@ -286,8 +297,7 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
286
297
value : {
287
298
enumerable : true ,
288
299
get ( ) {
289
- const input = get_input ( ) ;
290
- return deep_get ( input , path ) ;
300
+ return get_value ( ) ;
291
301
}
292
302
}
293
303
} ) ;
@@ -310,8 +320,7 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
310
320
checked : {
311
321
enumerable : true ,
312
322
get ( ) {
313
- const input = get_input ( ) ;
314
- const value = deep_get ( input , path ) ;
323
+ const value = get_value ( ) ;
315
324
316
325
if ( type === 'radio' ) {
317
326
return value === input_value ;
@@ -334,8 +343,7 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
334
343
files : {
335
344
enumerable : true ,
336
345
get ( ) {
337
- const input = get_input ( ) ;
338
- const value = deep_get ( input , path ) ;
346
+ const value = get_value ( ) ;
339
347
340
348
// Convert File/File[] to FileList-like object
341
349
if ( value instanceof File ) {
@@ -375,20 +383,21 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
375
383
value : {
376
384
enumerable : true ,
377
385
get ( ) {
378
- const input = get_input ( ) ;
379
- const value = deep_get ( input , path ) ;
380
-
386
+ const value = get_value ( ) ;
381
387
return value != null ? String ( value ) : '' ;
382
388
}
383
389
}
384
390
} ) ;
385
391
} ;
386
392
387
- return create_field_proxy ( as_func , get_input , set_input , get_issues , [ ...path , 'as' ] ) ;
393
+ return create_field_proxy ( as_func , get_input , depend , set_input , get_issues , [
394
+ ...path ,
395
+ 'as'
396
+ ] ) ;
388
397
}
389
398
390
399
// Handle property access (nested fields)
391
- return create_field_proxy ( { } , get_input , set_input , get_issues , [ ...path , prop ] ) ;
400
+ return create_field_proxy ( { } , get_input , depend , set_input , get_issues , [ ...path , prop ] ) ;
392
401
}
393
402
} ) ;
394
403
}
@@ -398,7 +407,7 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
398
407
* @param {(string | number)[] } path
399
408
* @returns {string }
400
409
*/
401
- function build_path_string ( path ) {
410
+ export function build_path_string ( path ) {
402
411
let result = '' ;
403
412
404
413
for ( const segment of path ) {
0 commit comments