@conform-to/react 1.8.2 → 1.9.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.
@@ -1,4 +1,5 @@
1
- export { unstable_isDirty as isDirty } from '@conform-to/dom';
2
- export { useControl, useFormData } from './hooks';
3
- export type { Control } from './hooks';
1
+ export type { FormValue, FormError } from '@conform-to/dom/future';
2
+ export { parseSubmission, report, isDirty } from '@conform-to/dom/future';
3
+ export type { Control, FormOptions, Fieldset, DefaultValue } from './types';
4
+ export { FormProvider, useControl, useField, useForm, useFormData, useFormMetadata, useIntent, } from './hooks';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -2,14 +2,27 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var dom = require('@conform-to/dom');
5
+ var future = require('@conform-to/dom/future');
6
6
  var hooks = require('./hooks.js');
7
7
 
8
8
 
9
9
 
10
10
  Object.defineProperty(exports, 'isDirty', {
11
11
  enumerable: true,
12
- get: function () { return dom.unstable_isDirty; }
12
+ get: function () { return future.isDirty; }
13
13
  });
14
+ Object.defineProperty(exports, 'parseSubmission', {
15
+ enumerable: true,
16
+ get: function () { return future.parseSubmission; }
17
+ });
18
+ Object.defineProperty(exports, 'report', {
19
+ enumerable: true,
20
+ get: function () { return future.report; }
21
+ });
22
+ exports.FormProvider = hooks.FormProvider;
14
23
  exports.useControl = hooks.useControl;
24
+ exports.useField = hooks.useField;
25
+ exports.useForm = hooks.useForm;
15
26
  exports.useFormData = hooks.useFormData;
27
+ exports.useFormMetadata = hooks.useFormMetadata;
28
+ exports.useIntent = hooks.useIntent;
@@ -1,2 +1,2 @@
1
- export { unstable_isDirty as isDirty } from '@conform-to/dom';
2
- export { useControl, useFormData } from './hooks.mjs';
1
+ export { isDirty, parseSubmission, report } from '@conform-to/dom/future';
2
+ export { FormProvider, useControl, useField, useForm, useFormData, useFormMetadata, useIntent } from './hooks.mjs';
@@ -0,0 +1,35 @@
1
+ import type { FormValue, Submission } from '@conform-to/dom/future';
2
+ import type { ActionHandler, IntentDispatcher, UnknownIntent } from './types';
3
+ /**
4
+ * Serializes intent to string format: "type" or "type(payload)".
5
+ */
6
+ export declare function serializeIntent<Intent extends UnknownIntent = UnknownIntent>(intent: Intent): string;
7
+ /**
8
+ * Parses serialized intent string back to intent object.
9
+ */
10
+ export declare function deserializeIntent(value: string): UnknownIntent;
11
+ /**
12
+ * Applies intent transformation to submission payload.
13
+ * Returns modified payload or null for reset intent.
14
+ */
15
+ export declare function applyIntent(submission: Submission, options?: {
16
+ handlers?: Record<string, ActionHandler>;
17
+ }): Record<string, FormValue> | null;
18
+ export declare function insertItem<Item>(list: Array<Item>, item: Item, index: number): void;
19
+ export declare function removeItem(list: Array<unknown>, index: number): void;
20
+ export declare function reorderItems(list: Array<unknown>, fromIndex: number, toIndex: number): void;
21
+ /**
22
+ * Updates list keys by removing child keys and optionally transforming remaining keys.
23
+ */
24
+ export declare function updateListKeys(keys: Record<string, string[]> | undefined, keyToBeRemoved: string, updateKey?: (key: string) => string | null): Record<string, string[]>;
25
+ /**
26
+ * Built-in action handlers for form intents:
27
+ * - reset: clears form data
28
+ * - validate: marks fields as touched for validation display
29
+ * - update: updates specific field values
30
+ * - insert/remove/reorder: manages array field operations
31
+ */
32
+ export declare const actionHandlers: {
33
+ [Type in keyof IntentDispatcher]: IntentDispatcher[Type] extends (payload: any) => void ? ActionHandler<IntentDispatcher[Type]> : never;
34
+ };
35
+ //# sourceMappingURL=intent.d.ts.map
@@ -0,0 +1,305 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _rollupPluginBabelHelpers = require('../_virtual/_rollupPluginBabelHelpers.js');
6
+ var future = require('@conform-to/dom/future');
7
+ var util = require('./util.js');
8
+ var state = require('./state.js');
9
+
10
+ /**
11
+ * Serializes intent to string format: "type" or "type(payload)".
12
+ */
13
+ function serializeIntent(intent) {
14
+ if (!intent.payload) {
15
+ return intent.type;
16
+ }
17
+ return "".concat(intent.type, "(").concat(JSON.stringify(intent.payload), ")");
18
+ }
19
+
20
+ /**
21
+ * Parses serialized intent string back to intent object.
22
+ */
23
+ function deserializeIntent(value) {
24
+ var type = value;
25
+ var payload;
26
+ var serializedPayload;
27
+ var openParenIndex = value.indexOf('(');
28
+ if (openParenIndex > 0 && value[value.length - 1] === ')') {
29
+ type = value.slice(0, openParenIndex);
30
+ serializedPayload = value.slice(openParenIndex + 1, -1);
31
+ }
32
+ if (serializedPayload) {
33
+ try {
34
+ payload = JSON.parse(serializedPayload);
35
+ } catch (_unused) {
36
+ // Ignore the error
37
+ }
38
+ }
39
+ return {
40
+ type,
41
+ payload
42
+ };
43
+ }
44
+
45
+ /**
46
+ * Applies intent transformation to submission payload.
47
+ * Returns modified payload or null for reset intent.
48
+ */
49
+ function applyIntent(submission, options) {
50
+ var _options$handlers, _handler$validatePayl, _handler$validatePayl2;
51
+ if (!submission.intent) {
52
+ return submission.payload;
53
+ }
54
+ var intent = deserializeIntent(submission.intent);
55
+ var handlers = (_options$handlers = options === null || options === void 0 ? void 0 : options.handlers) !== null && _options$handlers !== void 0 ? _options$handlers : actionHandlers;
56
+ var handler = handlers[intent.type];
57
+ if (handler && handler.onApply && ((_handler$validatePayl = (_handler$validatePayl2 = handler.validatePayload) === null || _handler$validatePayl2 === void 0 ? void 0 : _handler$validatePayl2.call(handler, intent.payload)) !== null && _handler$validatePayl !== void 0 ? _handler$validatePayl : true)) {
58
+ return handler.onApply(submission.payload, intent.payload);
59
+ }
60
+ return submission.payload;
61
+ }
62
+ function insertItem(list, item, index) {
63
+ list.splice(index, 0, item);
64
+ }
65
+ function removeItem(list, index) {
66
+ list.splice(index, 1);
67
+ }
68
+ function reorderItems(list, fromIndex, toIndex) {
69
+ list.splice(toIndex, 0, ...list.splice(fromIndex, 1));
70
+ }
71
+
72
+ /**
73
+ * Updates list keys by removing child keys and optionally transforming remaining keys.
74
+ */
75
+ function updateListKeys() {
76
+ var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
77
+ var keyToBeRemoved = arguments.length > 1 ? arguments[1] : undefined;
78
+ var updateKey = arguments.length > 2 ? arguments[2] : undefined;
79
+ var basePath = future.getPathSegments(keyToBeRemoved);
80
+ return util.transformKeys(keys, field => {
81
+ var _updateKey;
82
+ return future.getRelativePath(field, basePath) !== null ? null : (_updateKey = updateKey === null || updateKey === void 0 ? void 0 : updateKey(field)) !== null && _updateKey !== void 0 ? _updateKey : field;
83
+ });
84
+ }
85
+
86
+ /**
87
+ * Built-in action handlers for form intents:
88
+ * - reset: clears form data
89
+ * - validate: marks fields as touched for validation display
90
+ * - update: updates specific field values
91
+ * - insert/remove/reorder: manages array field operations
92
+ */
93
+ var actionHandlers = {
94
+ reset: {
95
+ onApply() {
96
+ return null;
97
+ }
98
+ },
99
+ validate: {
100
+ validatePayload(name) {
101
+ return util.isOptional(name, util.isString);
102
+ },
103
+ onUpdate(state, _ref) {
104
+ var _intent$payload;
105
+ var {
106
+ submission,
107
+ intent,
108
+ error
109
+ } = _ref;
110
+ var name = (_intent$payload = intent.payload) !== null && _intent$payload !== void 0 ? _intent$payload : '';
111
+ var basePath = future.getPathSegments(name);
112
+ var touchedFields = util.appendUniqueItem(state.touchedFields, name);
113
+ for (var field of submission.fields) {
114
+ // Add all child fields to the touched fields too
115
+ if (future.getRelativePath(field, basePath) !== null) {
116
+ touchedFields = util.appendUniqueItem(touchedFields, field);
117
+ }
118
+ }
119
+
120
+ // We couldn't find out all the fields from the FormData, e.g. unchecked checkboxes.
121
+ // or fieldsets without any fields, but we can at least include missing
122
+ // required fields based on the form error
123
+ if (name === '' && error) {
124
+ for (var _name of Object.keys(error.fieldErrors)) {
125
+ touchedFields = util.appendUniqueItem(touchedFields, _name);
126
+ }
127
+ }
128
+ return util.merge(state, {
129
+ touchedFields
130
+ });
131
+ }
132
+ },
133
+ update: {
134
+ validatePayload(options) {
135
+ return future.isPlainObject(options) && util.isOptional(options.name, util.isString) && util.isOptional(options.index, util.isNumber) && !util.isUndefined(options.value);
136
+ },
137
+ onApply(value, options) {
138
+ return util.updateValueAtPath(value, future.appendPathSegment(options.name, options.index), options.value);
139
+ },
140
+ onUpdate(state, _ref2) {
141
+ var {
142
+ type,
143
+ submission,
144
+ intent
145
+ } = _ref2;
146
+ var listKeys = state.listKeys;
147
+
148
+ // Update the keys only for client updates to avoid double updates if there is no client validation
149
+ if (type === 'client') {
150
+ // TODO: Do we really need to update the keys here?
151
+ var name = future.appendPathSegment(intent.payload.name, intent.payload.index);
152
+ // Remove all child keys
153
+ listKeys = name === '' ? {} : updateListKeys(state.listKeys, name);
154
+ }
155
+ var basePath = future.getPathSegments(intent.payload.name);
156
+ var touchedFields = state.touchedFields;
157
+ for (var field of submission.fields) {
158
+ if (basePath.length === 0 || future.getRelativePath(field, basePath) !== null) {
159
+ touchedFields = util.appendUniqueItem(touchedFields, field);
160
+ }
161
+ }
162
+ return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, state), {}, {
163
+ listKeys,
164
+ touchedFields
165
+ });
166
+ }
167
+ },
168
+ insert: {
169
+ validatePayload(options) {
170
+ return future.isPlainObject(options) && util.isString(options.name) && util.isOptional(options.index, util.isNumber);
171
+ },
172
+ onApply(value, options) {
173
+ var _options$index;
174
+ var list = Array.from(util.getArrayAtPath(value, options.name));
175
+ insertItem(list, options.defaultValue, (_options$index = options.index) !== null && _options$index !== void 0 ? _options$index : list.length);
176
+ return util.updateValueAtPath(value, options.name, list);
177
+ },
178
+ onUpdate(state$1, _ref3) {
179
+ var _intent$payload$index;
180
+ var {
181
+ type,
182
+ submission,
183
+ intent
184
+ } = _ref3;
185
+ var currentValue = submission.payload;
186
+ var list = util.getArrayAtPath(currentValue, intent.payload.name);
187
+ var index = (_intent$payload$index = intent.payload.index) !== null && _intent$payload$index !== void 0 ? _intent$payload$index : list.length;
188
+ var updateListIndex = util.createPathIndexUpdater(intent.payload.name, currentIndex => index <= currentIndex ? currentIndex + 1 : currentIndex);
189
+ var touchedFields = util.appendUniqueItem(util.compactMap(state$1.touchedFields, updateListIndex), intent.payload.name);
190
+ var keys = state$1.listKeys;
191
+
192
+ // Update the keys only for client updates to avoid double updates if there is no client validation
193
+ if (type === 'client') {
194
+ var _state$listKeys$inten;
195
+ var listKeys = Array.from((_state$listKeys$inten = state$1.listKeys[intent.payload.name]) !== null && _state$listKeys$inten !== void 0 ? _state$listKeys$inten : state.getDefaultListKey(state$1.resetKey, currentValue, intent.payload.name));
196
+ insertItem(listKeys, util.generateUniqueKey(), index);
197
+ keys = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, updateListKeys(state$1.listKeys, future.appendPathSegment(intent.payload.name, index), updateListIndex)), {}, {
198
+ // Update existing list keys
199
+ [intent.payload.name]: listKeys
200
+ });
201
+ }
202
+ return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, state$1), {}, {
203
+ listKeys: keys,
204
+ touchedFields
205
+ });
206
+ }
207
+ },
208
+ remove: {
209
+ validatePayload(options) {
210
+ return future.isPlainObject(options) && util.isString(options.name) && util.isNumber(options.index);
211
+ },
212
+ onApply(value, options) {
213
+ var list = Array.from(util.getArrayAtPath(value, options.name));
214
+ removeItem(list, options.index);
215
+ return util.updateValueAtPath(value, options.name, list);
216
+ },
217
+ onUpdate(state$1, _ref4) {
218
+ var {
219
+ type,
220
+ submission,
221
+ intent
222
+ } = _ref4;
223
+ var currentValue = submission.payload;
224
+ var updateListIndex = util.createPathIndexUpdater(intent.payload.name, currentIndex => {
225
+ if (intent.payload.index === currentIndex) {
226
+ return null;
227
+ }
228
+ return intent.payload.index < currentIndex ? currentIndex - 1 : currentIndex;
229
+ });
230
+ var touchedFields = util.appendUniqueItem(util.compactMap(state$1.touchedFields, updateListIndex), intent.payload.name);
231
+ var keys = state$1.listKeys;
232
+
233
+ // Update the keys only for client updates to avoid double updates if there is no client validation
234
+ if (type === 'client') {
235
+ var _state$listKeys$inten2;
236
+ var listKeys = Array.from((_state$listKeys$inten2 = state$1.listKeys[intent.payload.name]) !== null && _state$listKeys$inten2 !== void 0 ? _state$listKeys$inten2 : state.getDefaultListKey(state$1.resetKey, currentValue, intent.payload.name));
237
+ removeItem(listKeys, intent.payload.index);
238
+ keys = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, updateListKeys(state$1.listKeys, future.appendPathSegment(intent.payload.name, intent.payload.index), updateListIndex)), {}, {
239
+ // Update existing list keys
240
+ [intent.payload.name]: listKeys
241
+ });
242
+ }
243
+ return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, state$1), {}, {
244
+ listKeys: keys,
245
+ touchedFields
246
+ });
247
+ }
248
+ },
249
+ reorder: {
250
+ validatePayload(options) {
251
+ return future.isPlainObject(options) && util.isString(options.name) && util.isNumber(options.from) && util.isNumber(options.to);
252
+ },
253
+ onApply(value, options) {
254
+ var list = Array.from(util.getArrayAtPath(value, options.name));
255
+ reorderItems(list, options.from, options.to);
256
+ return util.updateValueAtPath(value, options.name, list);
257
+ },
258
+ onUpdate(state$1, _ref5) {
259
+ var {
260
+ type,
261
+ submission,
262
+ intent
263
+ } = _ref5;
264
+ var currentValue = submission.payload;
265
+ var updateListIndex = util.createPathIndexUpdater(intent.payload.name, currentIndex => {
266
+ if (intent.payload.from === intent.payload.to) {
267
+ return currentIndex;
268
+ }
269
+ if (currentIndex === intent.payload.from) {
270
+ return intent.payload.to;
271
+ }
272
+ if (intent.payload.from < intent.payload.to) {
273
+ return currentIndex > intent.payload.from && currentIndex <= intent.payload.to ? currentIndex - 1 : currentIndex;
274
+ }
275
+ return currentIndex >= intent.payload.to && currentIndex < intent.payload.from ? currentIndex + 1 : currentIndex;
276
+ });
277
+ var touchedFields = util.appendUniqueItem(util.compactMap(state$1.touchedFields, updateListIndex), intent.payload.name);
278
+ var keys = state$1.listKeys;
279
+
280
+ // Update the keys only for client updates to avoid double updates if there is no client validation
281
+ if (type === 'client') {
282
+ var _state$listKeys$inten3;
283
+ var listKeys = Array.from((_state$listKeys$inten3 = state$1.listKeys[intent.payload.name]) !== null && _state$listKeys$inten3 !== void 0 ? _state$listKeys$inten3 : state.getDefaultListKey(state$1.resetKey, currentValue, intent.payload.name));
284
+ reorderItems(listKeys, intent.payload.from, intent.payload.to);
285
+ keys = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, updateListKeys(state$1.listKeys, future.appendPathSegment(intent.payload.name, intent.payload.from), updateListIndex)), {}, {
286
+ // Update existing list keys
287
+ [intent.payload.name]: listKeys
288
+ });
289
+ }
290
+ return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, state$1), {}, {
291
+ listKeys: keys,
292
+ touchedFields
293
+ });
294
+ }
295
+ }
296
+ };
297
+
298
+ exports.actionHandlers = actionHandlers;
299
+ exports.applyIntent = applyIntent;
300
+ exports.deserializeIntent = deserializeIntent;
301
+ exports.insertItem = insertItem;
302
+ exports.removeItem = removeItem;
303
+ exports.reorderItems = reorderItems;
304
+ exports.serializeIntent = serializeIntent;
305
+ exports.updateListKeys = updateListKeys;
@@ -0,0 +1,294 @@
1
+ import { objectSpread2 as _objectSpread2 } from '../_virtual/_rollupPluginBabelHelpers.mjs';
2
+ import { getPathSegments, getRelativePath, isPlainObject, appendPathSegment } from '@conform-to/dom/future';
3
+ import { isOptional, appendUniqueItem, merge, isUndefined, updateValueAtPath, isString, getArrayAtPath, createPathIndexUpdater, compactMap, generateUniqueKey, isNumber, transformKeys } from './util.mjs';
4
+ import { getDefaultListKey } from './state.mjs';
5
+
6
+ /**
7
+ * Serializes intent to string format: "type" or "type(payload)".
8
+ */
9
+ function serializeIntent(intent) {
10
+ if (!intent.payload) {
11
+ return intent.type;
12
+ }
13
+ return "".concat(intent.type, "(").concat(JSON.stringify(intent.payload), ")");
14
+ }
15
+
16
+ /**
17
+ * Parses serialized intent string back to intent object.
18
+ */
19
+ function deserializeIntent(value) {
20
+ var type = value;
21
+ var payload;
22
+ var serializedPayload;
23
+ var openParenIndex = value.indexOf('(');
24
+ if (openParenIndex > 0 && value[value.length - 1] === ')') {
25
+ type = value.slice(0, openParenIndex);
26
+ serializedPayload = value.slice(openParenIndex + 1, -1);
27
+ }
28
+ if (serializedPayload) {
29
+ try {
30
+ payload = JSON.parse(serializedPayload);
31
+ } catch (_unused) {
32
+ // Ignore the error
33
+ }
34
+ }
35
+ return {
36
+ type,
37
+ payload
38
+ };
39
+ }
40
+
41
+ /**
42
+ * Applies intent transformation to submission payload.
43
+ * Returns modified payload or null for reset intent.
44
+ */
45
+ function applyIntent(submission, options) {
46
+ var _options$handlers, _handler$validatePayl, _handler$validatePayl2;
47
+ if (!submission.intent) {
48
+ return submission.payload;
49
+ }
50
+ var intent = deserializeIntent(submission.intent);
51
+ var handlers = (_options$handlers = options === null || options === void 0 ? void 0 : options.handlers) !== null && _options$handlers !== void 0 ? _options$handlers : actionHandlers;
52
+ var handler = handlers[intent.type];
53
+ if (handler && handler.onApply && ((_handler$validatePayl = (_handler$validatePayl2 = handler.validatePayload) === null || _handler$validatePayl2 === void 0 ? void 0 : _handler$validatePayl2.call(handler, intent.payload)) !== null && _handler$validatePayl !== void 0 ? _handler$validatePayl : true)) {
54
+ return handler.onApply(submission.payload, intent.payload);
55
+ }
56
+ return submission.payload;
57
+ }
58
+ function insertItem(list, item, index) {
59
+ list.splice(index, 0, item);
60
+ }
61
+ function removeItem(list, index) {
62
+ list.splice(index, 1);
63
+ }
64
+ function reorderItems(list, fromIndex, toIndex) {
65
+ list.splice(toIndex, 0, ...list.splice(fromIndex, 1));
66
+ }
67
+
68
+ /**
69
+ * Updates list keys by removing child keys and optionally transforming remaining keys.
70
+ */
71
+ function updateListKeys() {
72
+ var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
73
+ var keyToBeRemoved = arguments.length > 1 ? arguments[1] : undefined;
74
+ var updateKey = arguments.length > 2 ? arguments[2] : undefined;
75
+ var basePath = getPathSegments(keyToBeRemoved);
76
+ return transformKeys(keys, field => {
77
+ var _updateKey;
78
+ return getRelativePath(field, basePath) !== null ? null : (_updateKey = updateKey === null || updateKey === void 0 ? void 0 : updateKey(field)) !== null && _updateKey !== void 0 ? _updateKey : field;
79
+ });
80
+ }
81
+
82
+ /**
83
+ * Built-in action handlers for form intents:
84
+ * - reset: clears form data
85
+ * - validate: marks fields as touched for validation display
86
+ * - update: updates specific field values
87
+ * - insert/remove/reorder: manages array field operations
88
+ */
89
+ var actionHandlers = {
90
+ reset: {
91
+ onApply() {
92
+ return null;
93
+ }
94
+ },
95
+ validate: {
96
+ validatePayload(name) {
97
+ return isOptional(name, isString);
98
+ },
99
+ onUpdate(state, _ref) {
100
+ var _intent$payload;
101
+ var {
102
+ submission,
103
+ intent,
104
+ error
105
+ } = _ref;
106
+ var name = (_intent$payload = intent.payload) !== null && _intent$payload !== void 0 ? _intent$payload : '';
107
+ var basePath = getPathSegments(name);
108
+ var touchedFields = appendUniqueItem(state.touchedFields, name);
109
+ for (var field of submission.fields) {
110
+ // Add all child fields to the touched fields too
111
+ if (getRelativePath(field, basePath) !== null) {
112
+ touchedFields = appendUniqueItem(touchedFields, field);
113
+ }
114
+ }
115
+
116
+ // We couldn't find out all the fields from the FormData, e.g. unchecked checkboxes.
117
+ // or fieldsets without any fields, but we can at least include missing
118
+ // required fields based on the form error
119
+ if (name === '' && error) {
120
+ for (var _name of Object.keys(error.fieldErrors)) {
121
+ touchedFields = appendUniqueItem(touchedFields, _name);
122
+ }
123
+ }
124
+ return merge(state, {
125
+ touchedFields
126
+ });
127
+ }
128
+ },
129
+ update: {
130
+ validatePayload(options) {
131
+ return isPlainObject(options) && isOptional(options.name, isString) && isOptional(options.index, isNumber) && !isUndefined(options.value);
132
+ },
133
+ onApply(value, options) {
134
+ return updateValueAtPath(value, appendPathSegment(options.name, options.index), options.value);
135
+ },
136
+ onUpdate(state, _ref2) {
137
+ var {
138
+ type,
139
+ submission,
140
+ intent
141
+ } = _ref2;
142
+ var listKeys = state.listKeys;
143
+
144
+ // Update the keys only for client updates to avoid double updates if there is no client validation
145
+ if (type === 'client') {
146
+ // TODO: Do we really need to update the keys here?
147
+ var name = appendPathSegment(intent.payload.name, intent.payload.index);
148
+ // Remove all child keys
149
+ listKeys = name === '' ? {} : updateListKeys(state.listKeys, name);
150
+ }
151
+ var basePath = getPathSegments(intent.payload.name);
152
+ var touchedFields = state.touchedFields;
153
+ for (var field of submission.fields) {
154
+ if (basePath.length === 0 || getRelativePath(field, basePath) !== null) {
155
+ touchedFields = appendUniqueItem(touchedFields, field);
156
+ }
157
+ }
158
+ return _objectSpread2(_objectSpread2({}, state), {}, {
159
+ listKeys,
160
+ touchedFields
161
+ });
162
+ }
163
+ },
164
+ insert: {
165
+ validatePayload(options) {
166
+ return isPlainObject(options) && isString(options.name) && isOptional(options.index, isNumber);
167
+ },
168
+ onApply(value, options) {
169
+ var _options$index;
170
+ var list = Array.from(getArrayAtPath(value, options.name));
171
+ insertItem(list, options.defaultValue, (_options$index = options.index) !== null && _options$index !== void 0 ? _options$index : list.length);
172
+ return updateValueAtPath(value, options.name, list);
173
+ },
174
+ onUpdate(state, _ref3) {
175
+ var _intent$payload$index;
176
+ var {
177
+ type,
178
+ submission,
179
+ intent
180
+ } = _ref3;
181
+ var currentValue = submission.payload;
182
+ var list = getArrayAtPath(currentValue, intent.payload.name);
183
+ var index = (_intent$payload$index = intent.payload.index) !== null && _intent$payload$index !== void 0 ? _intent$payload$index : list.length;
184
+ var updateListIndex = createPathIndexUpdater(intent.payload.name, currentIndex => index <= currentIndex ? currentIndex + 1 : currentIndex);
185
+ var touchedFields = appendUniqueItem(compactMap(state.touchedFields, updateListIndex), intent.payload.name);
186
+ var keys = state.listKeys;
187
+
188
+ // Update the keys only for client updates to avoid double updates if there is no client validation
189
+ if (type === 'client') {
190
+ var _state$listKeys$inten;
191
+ var listKeys = Array.from((_state$listKeys$inten = state.listKeys[intent.payload.name]) !== null && _state$listKeys$inten !== void 0 ? _state$listKeys$inten : getDefaultListKey(state.resetKey, currentValue, intent.payload.name));
192
+ insertItem(listKeys, generateUniqueKey(), index);
193
+ keys = _objectSpread2(_objectSpread2({}, updateListKeys(state.listKeys, appendPathSegment(intent.payload.name, index), updateListIndex)), {}, {
194
+ // Update existing list keys
195
+ [intent.payload.name]: listKeys
196
+ });
197
+ }
198
+ return _objectSpread2(_objectSpread2({}, state), {}, {
199
+ listKeys: keys,
200
+ touchedFields
201
+ });
202
+ }
203
+ },
204
+ remove: {
205
+ validatePayload(options) {
206
+ return isPlainObject(options) && isString(options.name) && isNumber(options.index);
207
+ },
208
+ onApply(value, options) {
209
+ var list = Array.from(getArrayAtPath(value, options.name));
210
+ removeItem(list, options.index);
211
+ return updateValueAtPath(value, options.name, list);
212
+ },
213
+ onUpdate(state, _ref4) {
214
+ var {
215
+ type,
216
+ submission,
217
+ intent
218
+ } = _ref4;
219
+ var currentValue = submission.payload;
220
+ var updateListIndex = createPathIndexUpdater(intent.payload.name, currentIndex => {
221
+ if (intent.payload.index === currentIndex) {
222
+ return null;
223
+ }
224
+ return intent.payload.index < currentIndex ? currentIndex - 1 : currentIndex;
225
+ });
226
+ var touchedFields = appendUniqueItem(compactMap(state.touchedFields, updateListIndex), intent.payload.name);
227
+ var keys = state.listKeys;
228
+
229
+ // Update the keys only for client updates to avoid double updates if there is no client validation
230
+ if (type === 'client') {
231
+ var _state$listKeys$inten2;
232
+ var listKeys = Array.from((_state$listKeys$inten2 = state.listKeys[intent.payload.name]) !== null && _state$listKeys$inten2 !== void 0 ? _state$listKeys$inten2 : getDefaultListKey(state.resetKey, currentValue, intent.payload.name));
233
+ removeItem(listKeys, intent.payload.index);
234
+ keys = _objectSpread2(_objectSpread2({}, updateListKeys(state.listKeys, appendPathSegment(intent.payload.name, intent.payload.index), updateListIndex)), {}, {
235
+ // Update existing list keys
236
+ [intent.payload.name]: listKeys
237
+ });
238
+ }
239
+ return _objectSpread2(_objectSpread2({}, state), {}, {
240
+ listKeys: keys,
241
+ touchedFields
242
+ });
243
+ }
244
+ },
245
+ reorder: {
246
+ validatePayload(options) {
247
+ return isPlainObject(options) && isString(options.name) && isNumber(options.from) && isNumber(options.to);
248
+ },
249
+ onApply(value, options) {
250
+ var list = Array.from(getArrayAtPath(value, options.name));
251
+ reorderItems(list, options.from, options.to);
252
+ return updateValueAtPath(value, options.name, list);
253
+ },
254
+ onUpdate(state, _ref5) {
255
+ var {
256
+ type,
257
+ submission,
258
+ intent
259
+ } = _ref5;
260
+ var currentValue = submission.payload;
261
+ var updateListIndex = createPathIndexUpdater(intent.payload.name, currentIndex => {
262
+ if (intent.payload.from === intent.payload.to) {
263
+ return currentIndex;
264
+ }
265
+ if (currentIndex === intent.payload.from) {
266
+ return intent.payload.to;
267
+ }
268
+ if (intent.payload.from < intent.payload.to) {
269
+ return currentIndex > intent.payload.from && currentIndex <= intent.payload.to ? currentIndex - 1 : currentIndex;
270
+ }
271
+ return currentIndex >= intent.payload.to && currentIndex < intent.payload.from ? currentIndex + 1 : currentIndex;
272
+ });
273
+ var touchedFields = appendUniqueItem(compactMap(state.touchedFields, updateListIndex), intent.payload.name);
274
+ var keys = state.listKeys;
275
+
276
+ // Update the keys only for client updates to avoid double updates if there is no client validation
277
+ if (type === 'client') {
278
+ var _state$listKeys$inten3;
279
+ var listKeys = Array.from((_state$listKeys$inten3 = state.listKeys[intent.payload.name]) !== null && _state$listKeys$inten3 !== void 0 ? _state$listKeys$inten3 : getDefaultListKey(state.resetKey, currentValue, intent.payload.name));
280
+ reorderItems(listKeys, intent.payload.from, intent.payload.to);
281
+ keys = _objectSpread2(_objectSpread2({}, updateListKeys(state.listKeys, appendPathSegment(intent.payload.name, intent.payload.from), updateListIndex)), {}, {
282
+ // Update existing list keys
283
+ [intent.payload.name]: listKeys
284
+ });
285
+ }
286
+ return _objectSpread2(_objectSpread2({}, state), {}, {
287
+ listKeys: keys,
288
+ touchedFields
289
+ });
290
+ }
291
+ }
292
+ };
293
+
294
+ export { actionHandlers, applyIntent, deserializeIntent, insertItem, removeItem, reorderItems, serializeIntent, updateListKeys };