@inertiajs/react 2.2.21 → 2.3.1

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/index.esm.js CHANGED
@@ -175,7 +175,7 @@ async function createInertiaApp({
175
175
  createElement2("script", {
176
176
  "data-page": id,
177
177
  type: "application/json",
178
- dangerouslySetInnerHTML: { __html: JSON.stringify(initialPage) }
178
+ dangerouslySetInnerHTML: { __html: JSON.stringify(initialPage).replace(/\//g, "\\/") }
179
179
  }),
180
180
  createElement2("div", { id }, reactApp)
181
181
  );
@@ -242,7 +242,8 @@ import {
242
242
  formDataToObject,
243
243
  isUrlMethodPair,
244
244
  mergeDataIntoQueryString,
245
- resetFormFields
245
+ resetFormFields,
246
+ UseFormUtils as UseFormUtils2
246
247
  } from "@inertiajs/core";
247
248
  import { isEqual as isEqual2 } from "lodash-es";
248
249
  import React2, {
@@ -257,8 +258,14 @@ import React2, {
257
258
 
258
259
  // src/useForm.ts
259
260
  import {
260
- router as router5
261
+ router as router5,
262
+ UseFormUtils
261
263
  } from "@inertiajs/core";
264
+ import {
265
+ createValidator,
266
+ resolveName,
267
+ toSimpleValidationErrors
268
+ } from "laravel-precognition";
262
269
  import { cloneDeep, get, has, isEqual, set } from "lodash-es";
263
270
  import { useCallback, useEffect as useEffect5, useMemo as useMemo3, useRef, useState as useState4 } from "react";
264
271
 
@@ -283,11 +290,13 @@ function useRemember(initialState, key) {
283
290
  }
284
291
 
285
292
  // src/useForm.ts
286
- function useForm(rememberKeyOrInitialValues, maybeInitialValues) {
293
+ function useForm(...args) {
287
294
  const isMounted = useRef(false);
288
- const rememberKey = typeof rememberKeyOrInitialValues === "string" ? rememberKeyOrInitialValues : null;
295
+ const parsedArgs = UseFormUtils.parseUseFormArguments(...args);
296
+ const { rememberKey, data: initialData } = parsedArgs;
297
+ const precognitionEndpoint = useRef(parsedArgs.precognitionEndpoint);
289
298
  const [defaults, setDefaults] = useState4(
290
- (typeof rememberKeyOrInitialValues === "string" ? maybeInitialValues : rememberKeyOrInitialValues) || {}
299
+ typeof initialData === "function" ? cloneDeep(initialData()) : cloneDeep(initialData)
291
300
  );
292
301
  const cancelToken = useRef(null);
293
302
  const recentlySuccessfulTimeoutId = useRef(void 0);
@@ -300,6 +309,11 @@ function useForm(rememberKeyOrInitialValues, maybeInitialValues) {
300
309
  const [recentlySuccessful, setRecentlySuccessful] = useState4(false);
301
310
  const transform = useRef((data2) => data2);
302
311
  const isDirty = useMemo3(() => !isEqual(data, defaults), [data, defaults]);
312
+ const validatorRef = useRef(null);
313
+ const [validating, setValidating] = useState4(false);
314
+ const [touchedFields, setTouchedFields] = useState4([]);
315
+ const [validFields, setValidFields] = useState4([]);
316
+ const withAllErrors = useRef(false);
303
317
  useEffect5(() => {
304
318
  isMounted.current = true;
305
319
  return () => {
@@ -308,11 +322,8 @@ function useForm(rememberKeyOrInitialValues, maybeInitialValues) {
308
322
  }, []);
309
323
  const setDefaultsCalledInOnSuccess = useRef(false);
310
324
  const submit = useCallback(
311
- (...args) => {
312
- const objectPassed = args[0] !== null && typeof args[0] === "object";
313
- const method = objectPassed ? args[0].method : args[0];
314
- const url = objectPassed ? args[0].url : args[1];
315
- const options = (objectPassed ? args[1] : args[2]) ?? {};
325
+ (...args2) => {
326
+ const { method, url, options } = UseFormUtils.parseSubmitArguments(args2, precognitionEndpoint.current);
316
327
  setDefaultsCalledInOnSuccess.current = false;
317
328
  const _options = {
318
329
  ...options,
@@ -425,14 +436,18 @@ function useForm(rememberKeyOrInitialValues, maybeInitialValues) {
425
436
  const setDefaultsFunction = useCallback(
426
437
  (fieldOrFields, maybeValue) => {
427
438
  setDefaultsCalledInOnSuccess.current = true;
439
+ let newDefaults = {};
428
440
  if (typeof fieldOrFields === "undefined") {
441
+ newDefaults = { ...dataRef.current };
429
442
  setDefaults(dataRef.current);
430
443
  setDataAsDefaults(true);
431
444
  } else {
432
445
  setDefaults((defaults2) => {
433
- return typeof fieldOrFields === "string" ? set(cloneDeep(defaults2), fieldOrFields, maybeValue) : Object.assign(cloneDeep(defaults2), fieldOrFields);
446
+ newDefaults = typeof fieldOrFields === "string" ? set(cloneDeep(defaults2), fieldOrFields, maybeValue) : Object.assign(cloneDeep(defaults2), fieldOrFields);
447
+ return newDefaults;
434
448
  });
435
449
  }
450
+ validatorRef.current?.defaults(newDefaults);
436
451
  },
437
452
  [setDefaults]
438
453
  );
@@ -459,6 +474,7 @@ function useForm(rememberKeyOrInitialValues, maybeInitialValues) {
459
474
  )
460
475
  );
461
476
  }
477
+ validatorRef.current?.reset(...fields);
462
478
  },
463
479
  [setData, defaults]
464
480
  );
@@ -470,6 +486,7 @@ function useForm(rememberKeyOrInitialValues, maybeInitialValues) {
470
486
  ...typeof fieldOrFields === "string" ? { [fieldOrFields]: maybeValue } : fieldOrFields
471
487
  };
472
488
  setHasErrors(Object.keys(newErrors).length > 0);
489
+ validatorRef.current?.setErrors(newErrors);
473
490
  return newErrors;
474
491
  });
475
492
  },
@@ -486,6 +503,13 @@ function useForm(rememberKeyOrInitialValues, maybeInitialValues) {
486
503
  {}
487
504
  );
488
505
  setHasErrors(Object.keys(newErrors).length > 0);
506
+ if (validatorRef.current) {
507
+ if (fields.length === 0) {
508
+ validatorRef.current.setErrors({});
509
+ } else {
510
+ fields.forEach(validatorRef.current.forgetError);
511
+ }
512
+ }
489
513
  return newErrors;
490
514
  });
491
515
  },
@@ -514,7 +538,7 @@ function useForm(rememberKeyOrInitialValues, maybeInitialValues) {
514
538
  const transformFunction = useCallback((callback) => {
515
539
  transform.current = callback;
516
540
  }, []);
517
- return {
541
+ const form = {
518
542
  data,
519
543
  setData: setDataFunction,
520
544
  isDirty,
@@ -538,6 +562,88 @@ function useForm(rememberKeyOrInitialValues, maybeInitialValues) {
538
562
  delete: deleteMethod,
539
563
  cancel
540
564
  };
565
+ const tap = (value, callback) => {
566
+ callback(value);
567
+ return value;
568
+ };
569
+ const valid = useCallback(
570
+ (field) => validFields.includes(field),
571
+ [validFields]
572
+ );
573
+ const invalid = useCallback((field) => field in errors, [errors]);
574
+ const touched = useCallback(
575
+ (field) => typeof field === "string" ? touchedFields.includes(field) : touchedFields.length > 0,
576
+ [touchedFields]
577
+ );
578
+ const validate = (field, config2) => {
579
+ if (typeof field === "object" && !("target" in field)) {
580
+ config2 = field;
581
+ field = void 0;
582
+ }
583
+ if (field === void 0) {
584
+ validatorRef.current.validate(config2);
585
+ } else {
586
+ const fieldName = resolveName(field);
587
+ const currentData = dataRef.current;
588
+ const transformedData = transform.current(currentData);
589
+ validatorRef.current.validate(fieldName, get(transformedData, fieldName), config2);
590
+ }
591
+ return form;
592
+ };
593
+ const withPrecognition = (...args2) => {
594
+ precognitionEndpoint.current = UseFormUtils.createWayfinderCallback(...args2);
595
+ if (!validatorRef.current) {
596
+ const validator = createValidator((client) => {
597
+ const { method, url } = precognitionEndpoint.current();
598
+ const currentData = dataRef.current;
599
+ const transformedData = transform.current(currentData);
600
+ return client[method](url, transformedData);
601
+ }, cloneDeep(defaults));
602
+ validatorRef.current = validator;
603
+ validator.on("validatingChanged", () => {
604
+ setValidating(validator.validating());
605
+ }).on("validatedChanged", () => {
606
+ setValidFields(validator.valid());
607
+ }).on("touchedChanged", () => {
608
+ setTouchedFields(validator.touched());
609
+ }).on("errorsChanged", () => {
610
+ const validationErrors = withAllErrors.current ? validator.errors() : toSimpleValidationErrors(validator.errors());
611
+ setErrors(validationErrors);
612
+ setHasErrors(Object.keys(validationErrors).length > 0);
613
+ setValidFields(validator.valid());
614
+ });
615
+ }
616
+ const precognitiveForm = Object.assign(form, {
617
+ validating,
618
+ validator: () => validatorRef.current,
619
+ valid,
620
+ invalid,
621
+ touched,
622
+ withoutFileValidation: () => tap(precognitiveForm, () => validatorRef.current?.withoutFileValidation()),
623
+ touch: (field, ...fields) => {
624
+ if (Array.isArray(field)) {
625
+ validatorRef.current?.touch(field);
626
+ } else if (typeof field === "string") {
627
+ validatorRef.current?.touch([field, ...fields]);
628
+ } else {
629
+ validatorRef.current?.touch(field);
630
+ }
631
+ return precognitiveForm;
632
+ },
633
+ withAllErrors: () => tap(precognitiveForm, () => withAllErrors.current = true),
634
+ setValidationTimeout: (duration) => tap(precognitiveForm, () => validatorRef.current?.setTimeout(duration)),
635
+ validateFiles: () => tap(precognitiveForm, () => validatorRef.current?.validateFiles()),
636
+ validate,
637
+ setErrors: (errors2) => tap(precognitiveForm, () => form.setError(errors2)),
638
+ forgetError: (field) => tap(
639
+ precognitiveForm,
640
+ () => form.clearErrors(resolveName(field))
641
+ )
642
+ });
643
+ return precognitiveForm;
644
+ };
645
+ form.withPrecognition = withPrecognition;
646
+ return precognitionEndpoint.current ? form.withPrecognition(precognitionEndpoint.current) : form;
541
647
  }
542
648
 
543
649
  // src/Form.ts
@@ -569,10 +675,27 @@ var Form = forwardRef(
569
675
  resetOnSuccess = false,
570
676
  setDefaultsOnSuccess = false,
571
677
  invalidateCacheTags = [],
678
+ validateFiles = false,
679
+ validationTimeout = 1500,
680
+ withAllErrors = false,
572
681
  children,
573
682
  ...props
574
683
  }, ref) => {
575
- const form = useForm({});
684
+ const getTransformedData = () => {
685
+ const [_url, data] = getUrlAndData();
686
+ return transform(data);
687
+ };
688
+ const form = useForm({}).withPrecognition(
689
+ () => resolvedMethod,
690
+ () => getUrlAndData()[0]
691
+ ).setValidationTimeout(validationTimeout);
692
+ if (validateFiles) {
693
+ form.validateFiles();
694
+ }
695
+ if (withAllErrors) {
696
+ form.withAllErrors();
697
+ }
698
+ form.transform(getTransformedData);
576
699
  const formElement = useRef2(void 0);
577
700
  const resolvedMethod = useMemo4(() => {
578
701
  return isUrlMethodPair(action) ? action.method : method.toLowerCase();
@@ -581,22 +704,48 @@ var Form = forwardRef(
581
704
  const defaultData = useRef2(new FormData());
582
705
  const getFormData = () => new FormData(formElement.current);
583
706
  const getData = () => formDataToObject(getFormData());
707
+ const getUrlAndData = () => {
708
+ return mergeDataIntoQueryString(
709
+ resolvedMethod,
710
+ isUrlMethodPair(action) ? action.url : action,
711
+ getData(),
712
+ queryStringArrayFormat
713
+ );
714
+ };
584
715
  const updateDirtyState = (event) => deferStateUpdate(
585
716
  () => setIsDirty(event.type === "reset" ? false : !isEqual2(getData(), formDataToObject(defaultData.current)))
586
717
  );
718
+ const clearErrors = (...names) => {
719
+ form.clearErrors(...names);
720
+ return form;
721
+ };
587
722
  useEffect6(() => {
588
723
  defaultData.current = getFormData();
724
+ form.setDefaults(getData());
589
725
  const formEvents = ["input", "change", "reset"];
590
726
  formEvents.forEach((e) => formElement.current.addEventListener(e, updateDirtyState));
591
- return () => formEvents.forEach((e) => formElement.current?.removeEventListener(e, updateDirtyState));
727
+ return () => {
728
+ formEvents.forEach((e) => formElement.current?.removeEventListener(e, updateDirtyState));
729
+ };
592
730
  }, []);
731
+ useEffect6(() => {
732
+ form.setValidationTimeout(validationTimeout);
733
+ }, [validationTimeout]);
734
+ useEffect6(() => {
735
+ if (validateFiles) {
736
+ form.validateFiles();
737
+ } else {
738
+ form.withoutFileValidation();
739
+ }
740
+ }, [validateFiles]);
593
741
  const reset = (...fields) => {
594
742
  if (formElement.current) {
595
743
  resetFormFields(formElement.current, defaultData.current, fields);
596
744
  }
745
+ form.reset(...fields);
597
746
  };
598
747
  const resetAndClearErrors = (...fields) => {
599
- form.clearErrors(...fields);
748
+ clearErrors(...fields);
600
749
  reset(...fields);
601
750
  };
602
751
  const maybeReset = (resetOption) => {
@@ -610,12 +759,7 @@ var Form = forwardRef(
610
759
  }
611
760
  };
612
761
  const submit = () => {
613
- const [url, _data] = mergeDataIntoQueryString(
614
- resolvedMethod,
615
- isUrlMethodPair(action) ? action.url : action,
616
- getData(),
617
- queryStringArrayFormat
618
- );
762
+ const [url, _data] = getUrlAndData();
619
763
  const submitOptions = {
620
764
  headers,
621
765
  queryStringArrayFormat,
@@ -645,7 +789,6 @@ var Form = forwardRef(
645
789
  },
646
790
  ...options
647
791
  };
648
- form.transform(() => transform(_data));
649
792
  form.submit(resolvedMethod, url, submitOptions);
650
793
  };
651
794
  const defaults = () => {
@@ -660,14 +803,22 @@ var Form = forwardRef(
660
803
  wasSuccessful: form.wasSuccessful,
661
804
  recentlySuccessful: form.recentlySuccessful,
662
805
  isDirty,
663
- clearErrors: form.clearErrors,
806
+ clearErrors,
664
807
  resetAndClearErrors,
665
808
  setError: form.setError,
666
809
  reset,
667
810
  submit,
668
811
  defaults,
669
812
  getData,
670
- getFormData
813
+ getFormData,
814
+ // Precognition
815
+ validator: () => form.validator(),
816
+ validating: form.validating,
817
+ valid: form.valid,
818
+ invalid: form.invalid,
819
+ validate: (field, config2) => form.validate(...UseFormUtils2.mergeHeadersForValidation(field, config2, headers)),
820
+ touch: form.touch,
821
+ touched: form.touched
671
822
  });
672
823
  useImperativeHandle(ref, exposed, [form, isDirty, submit]);
673
824
  return createElement3(
@@ -1328,27 +1479,22 @@ function usePrefetch(options = {}) {
1328
1479
 
1329
1480
  // src/WhenVisible.ts
1330
1481
  import { router as router9 } from "@inertiajs/core";
1331
- import { createElement as createElement6, useCallback as useCallback3, useEffect as useEffect12, useRef as useRef6, useState as useState9 } from "react";
1482
+ import { createElement as createElement6, useCallback as useCallback3, useEffect as useEffect12, useMemo as useMemo8, useRef as useRef6, useState as useState9 } from "react";
1332
1483
  var WhenVisible = ({ children, data, params, buffer, as, always, fallback }) => {
1333
1484
  always = always ?? false;
1334
1485
  as = as ?? "div";
1335
1486
  fallback = fallback ?? null;
1336
- const [loaded, setLoaded] = useState9(false);
1487
+ const pageProps = usePage().props;
1488
+ const keys = useMemo8(() => data ? Array.isArray(data) ? data : [data] : [], [data]);
1489
+ const [loaded, setLoaded] = useState9(() => keys.length > 0 && keys.every((key) => pageProps[key] !== void 0));
1337
1490
  const fetching = useRef6(false);
1338
1491
  const ref = useRef6(null);
1339
1492
  const observer = useRef6(null);
1340
- const page = usePage();
1341
1493
  useEffect12(() => {
1342
- if (Array.isArray(data)) {
1343
- if (data.some((key) => page.props[key] === void 0)) {
1344
- setLoaded(false);
1345
- }
1346
- } else if (data) {
1347
- if (page.props[data] === void 0) {
1348
- setLoaded(false);
1349
- }
1494
+ if (keys.length > 0) {
1495
+ setLoaded(keys.every((key) => pageProps[key] !== void 0));
1350
1496
  }
1351
- }, [data, ...Array.isArray(data) ? data.map((key) => page.props[key]) : [page.props[data]]]);
1497
+ }, [pageProps, keys]);
1352
1498
  const getReloadParams = useCallback3(() => {
1353
1499
  if (data) {
1354
1500
  return {
@@ -1401,11 +1547,14 @@ var WhenVisible = ({ children, data, params, buffer, as, always, fallback }) =>
1401
1547
  if (!ref.current) {
1402
1548
  return;
1403
1549
  }
1550
+ if (loaded && !always) {
1551
+ return;
1552
+ }
1404
1553
  registerObserver();
1405
1554
  return () => {
1406
1555
  observer.current?.disconnect();
1407
1556
  };
1408
- }, [loaded, ref, getReloadParams, buffer]);
1557
+ }, [always, loaded, ref, getReloadParams, buffer]);
1409
1558
  const resolveChildren = () => typeof children === "function" ? children() : children;
1410
1559
  const resolveFallback = () => typeof fallback === "function" ? fallback() : fallback;
1411
1560
  if (always || !loaded) {