@atlaskit/form 12.5.3 → 12.6.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atlaskit/form
2
2
 
3
+ ## 12.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`27fa43b33e35e`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/27fa43b33e35e) -
8
+ Add optional testId prop that applies a data-testid attribute to the underlying form element
9
+
10
+ ## 12.5.4
11
+
12
+ ### Patch Changes
13
+
14
+ - [`281cc603f5925`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/281cc603f5925) -
15
+ Improve typing within checkbox field
16
+
3
17
  ## 12.5.3
4
18
 
5
19
  ### Patch Changes
@@ -0,0 +1,607 @@
1
+ jest.autoMockOff();
2
+
3
+ import transformer from '../migrate-data-testid-to-testid-prop';
4
+
5
+ const defineInlineTest = require('jscodeshift/dist/testUtils').defineInlineTest;
6
+
7
+ // Test: No transformation when no @atlaskit/form import
8
+ defineInlineTest(
9
+ { default: transformer, parser: 'tsx' },
10
+ {},
11
+ `import React from 'react';
12
+
13
+ const MyComponent = () => (
14
+ <form data-testid="should-not-change">
15
+ <input type="text" />
16
+ </form>
17
+ );`,
18
+ `import React from 'react';
19
+
20
+ const MyComponent = () => (
21
+ <form data-testid="should-not-change">
22
+ <input type="text" />
23
+ </form>
24
+ );`,
25
+ 'should not transform if @atlaskit/form import is not present',
26
+ );
27
+
28
+ // Test: Basic transformation with default import as Form
29
+ defineInlineTest(
30
+ { default: transformer, parser: 'tsx' },
31
+ {},
32
+ `import Form from '@atlaskit/form';
33
+
34
+ const MyComponent = () => (
35
+ <Form onSubmit={handleSubmit}>
36
+ {({ formProps }) => (
37
+ <form {...formProps} data-testid="my-form">
38
+ <input type="text" />
39
+ </form>
40
+ )}
41
+ </Form>
42
+ );`,
43
+ `import Form from '@atlaskit/form';
44
+
45
+ const MyComponent = () => (
46
+ <Form onSubmit={handleSubmit} testId="my-form">
47
+ {({ formProps }) => (
48
+ <form {...formProps}>
49
+ <input type="text" />
50
+ </form>
51
+ )}
52
+ </Form>
53
+ );`,
54
+ 'should migrate string literal data-testid to testId prop with Form import',
55
+ );
56
+
57
+ // Test: Basic transformation with renamed default import
58
+ defineInlineTest(
59
+ { default: transformer, parser: 'tsx' },
60
+ {},
61
+ `import AkForm from '@atlaskit/form';
62
+
63
+ const MyComponent = () => (
64
+ <AkForm onSubmit={handleSubmit}>
65
+ {({ formProps }) => (
66
+ <form {...formProps} data-testid="my-form">
67
+ <input type="text" />
68
+ </form>
69
+ )}
70
+ </AkForm>
71
+ );`,
72
+ `import AkForm from '@atlaskit/form';
73
+
74
+ const MyComponent = () => (
75
+ <AkForm onSubmit={handleSubmit} testId="my-form">
76
+ {({ formProps }) => (
77
+ <form {...formProps}>
78
+ <input type="text" />
79
+ </form>
80
+ )}
81
+ </AkForm>
82
+ );`,
83
+ 'should migrate with renamed default import (AkForm)',
84
+ );
85
+
86
+ // Test: Expression data-testid with variable
87
+ defineInlineTest(
88
+ { default: transformer, parser: 'tsx' },
89
+ {},
90
+ `import Form from '@atlaskit/form';
91
+
92
+ const testId = 'dynamic-form';
93
+ const MyComponent = () => (
94
+ <Form onSubmit={handleSubmit}>
95
+ {({ formProps }) => (
96
+ <form {...formProps} data-testid={testId}>
97
+ <input type="text" />
98
+ </form>
99
+ )}
100
+ </Form>
101
+ );`,
102
+ `import Form from '@atlaskit/form';
103
+
104
+ const testId = 'dynamic-form';
105
+ const MyComponent = () => (
106
+ <Form onSubmit={handleSubmit} testId={testId}>
107
+ {({ formProps }) => (
108
+ <form {...formProps}>
109
+ <input type="text" />
110
+ </form>
111
+ )}
112
+ </Form>
113
+ );`,
114
+ 'should migrate expression data-testid with variable',
115
+ );
116
+
117
+ // Test: Expression data-testid with function call
118
+ defineInlineTest(
119
+ { default: transformer, parser: 'tsx' },
120
+ {},
121
+ `import Form from '@atlaskit/form';
122
+
123
+ const MyComponent = ({ id }) => (
124
+ <Form onSubmit={handleSubmit}>
125
+ {({ formProps }) => (
126
+ <form {...formProps} data-testid={getTestId(id)}>
127
+ <input type="text" />
128
+ </form>
129
+ )}
130
+ </Form>
131
+ );`,
132
+ `import Form from '@atlaskit/form';
133
+
134
+ const MyComponent = ({ id }) => (
135
+ <Form onSubmit={handleSubmit} testId={getTestId(id)}>
136
+ {({ formProps }) => (
137
+ <form {...formProps}>
138
+ <input type="text" />
139
+ </form>
140
+ )}
141
+ </Form>
142
+ );`,
143
+ 'should migrate expression data-testid with function call',
144
+ );
145
+
146
+ // Test: Multiple attributes on form element
147
+ defineInlineTest(
148
+ { default: transformer, parser: 'tsx' },
149
+ {},
150
+ `import Form from '@atlaskit/form';
151
+
152
+ const MyComponent = () => (
153
+ <Form onSubmit={handleSubmit}>
154
+ {({ formProps }) => (
155
+ <form noValidate {...formProps} id="my-form" data-testid="my-form" className="custom-form">
156
+ <input type="text" />
157
+ </form>
158
+ )}
159
+ </Form>
160
+ );`,
161
+ `import Form from '@atlaskit/form';
162
+
163
+ const MyComponent = () => (
164
+ <Form onSubmit={handleSubmit} testId="my-form">
165
+ {({ formProps }) => (
166
+ <form noValidate {...formProps} id="my-form" className="custom-form">
167
+ <input type="text" />
168
+ </form>
169
+ )}
170
+ </Form>
171
+ );`,
172
+ 'should migrate data-testid while preserving other attributes',
173
+ );
174
+
175
+ // Test: Renamed formProps parameter
176
+ defineInlineTest(
177
+ { default: transformer, parser: 'tsx' },
178
+ {},
179
+ `import Form from '@atlaskit/form';
180
+
181
+ const MyComponent = () => (
182
+ <Form onSubmit={handleSubmit}>
183
+ {({ formProps: customProps }) => (
184
+ <form {...customProps} data-testid="my-form">
185
+ <input type="text" />
186
+ </form>
187
+ )}
188
+ </Form>
189
+ );`,
190
+ `import Form from '@atlaskit/form';
191
+
192
+ const MyComponent = () => (
193
+ <Form onSubmit={handleSubmit} testId="my-form">
194
+ {({ formProps: customProps }) => (
195
+ <form {...customProps}>
196
+ <input type="text" />
197
+ </form>
198
+ )}
199
+ </Form>
200
+ );`,
201
+ 'should work with renamed formProps parameter',
202
+ );
203
+
204
+ // Test: Multiple destructured parameters
205
+ defineInlineTest(
206
+ { default: transformer, parser: 'tsx' },
207
+ {},
208
+ `import Form from '@atlaskit/form';
209
+
210
+ const MyComponent = () => (
211
+ <Form onSubmit={handleSubmit}>
212
+ {({ formProps, submitting, dirty }) => (
213
+ <form {...formProps} data-testid="my-form">
214
+ <input type="text" />
215
+ <button type="submit" disabled={submitting}>
216
+ {dirty ? 'Save Changes' : 'Submit'}
217
+ </button>
218
+ </form>
219
+ )}
220
+ </Form>
221
+ );`,
222
+ `import Form from '@atlaskit/form';
223
+
224
+ const MyComponent = () => (
225
+ <Form onSubmit={handleSubmit} testId="my-form">
226
+ {({ formProps, submitting, dirty }) => (
227
+ <form {...formProps}>
228
+ <input type="text" />
229
+ <button type="submit" disabled={submitting}>
230
+ {dirty ? 'Save Changes' : 'Submit'}
231
+ </button>
232
+ </form>
233
+ )}
234
+ </Form>
235
+ );`,
236
+ 'should work with multiple destructured parameters',
237
+ );
238
+
239
+ // Test: Nested form within wrapper div
240
+ defineInlineTest(
241
+ { default: transformer, parser: 'tsx' },
242
+ {},
243
+ `import Form from '@atlaskit/form';
244
+
245
+ const MyComponent = () => (
246
+ <Form onSubmit={handleSubmit}>
247
+ {({ formProps }) => (
248
+ <div className="form-wrapper">
249
+ <form {...formProps} data-testid="nested-form">
250
+ <input type="text" />
251
+ </form>
252
+ </div>
253
+ )}
254
+ </Form>
255
+ );`,
256
+ `import Form from '@atlaskit/form';
257
+
258
+ const MyComponent = () => (
259
+ <Form onSubmit={handleSubmit} testId="nested-form">
260
+ {({ formProps }) => (
261
+ <div className="form-wrapper">
262
+ <form {...formProps}>
263
+ <input type="text" />
264
+ </form>
265
+ </div>
266
+ )}
267
+ </Form>
268
+ );`,
269
+ 'should find form element nested within other elements',
270
+ );
271
+
272
+ // Test: Form with named imports and default import
273
+ defineInlineTest(
274
+ { default: transformer, parser: 'tsx' },
275
+ {},
276
+ `import Form, { Field, FormSection } from '@atlaskit/form';
277
+
278
+ const MyComponent = () => (
279
+ <Form onSubmit={handleSubmit}>
280
+ {({ formProps }) => (
281
+ <form {...formProps} data-testid="complete-form">
282
+ <FormSection>
283
+ <Field name="username">
284
+ {({ fieldProps }) => <input {...fieldProps} />}
285
+ </Field>
286
+ </FormSection>
287
+ </form>
288
+ )}
289
+ </Form>
290
+ );`,
291
+ `import Form, { Field, FormSection } from '@atlaskit/form';
292
+
293
+ const MyComponent = () => (
294
+ <Form onSubmit={handleSubmit} testId="complete-form">
295
+ {({ formProps }) => (
296
+ <form {...formProps}>
297
+ <FormSection>
298
+ <Field name="username">
299
+ {({ fieldProps }) => <input {...fieldProps} />}
300
+ </Field>
301
+ </FormSection>
302
+ </form>
303
+ )}
304
+ </Form>
305
+ );`,
306
+ 'should work with mixed default and named imports',
307
+ );
308
+
309
+ // Test: No transformation when testId already exists
310
+ defineInlineTest(
311
+ { default: transformer, parser: 'tsx' },
312
+ {},
313
+ `import Form from '@atlaskit/form';
314
+
315
+ const MyComponent = () => (
316
+ <Form testId="existing" onSubmit={handleSubmit}>
317
+ {({ formProps }) => (
318
+ <form {...formProps} data-testid="should-not-change">
319
+ <input type="text" />
320
+ </form>
321
+ )}
322
+ </Form>
323
+ );`,
324
+ `import Form from '@atlaskit/form';
325
+
326
+ const MyComponent = () => (
327
+ <Form testId="existing" onSubmit={handleSubmit}>
328
+ {({ formProps }) => (
329
+ <form {...formProps} data-testid="should-not-change">
330
+ <input type="text" />
331
+ </form>
332
+ )}
333
+ </Form>
334
+ );`,
335
+ 'should not migrate when testId prop already exists',
336
+ );
337
+
338
+ // Test: No transformation when no data-testid present
339
+ defineInlineTest(
340
+ { default: transformer, parser: 'tsx' },
341
+ {},
342
+ `import Form from '@atlaskit/form';
343
+
344
+ const MyComponent = () => (
345
+ <Form onSubmit={handleSubmit}>
346
+ {({ formProps }) => (
347
+ <form {...formProps} id="my-form">
348
+ <input type="text" />
349
+ </form>
350
+ )}
351
+ </Form>
352
+ );`,
353
+ `import Form from '@atlaskit/form';
354
+
355
+ const MyComponent = () => (
356
+ <Form onSubmit={handleSubmit}>
357
+ {({ formProps }) => (
358
+ <form {...formProps} id="my-form">
359
+ <input type="text" />
360
+ </form>
361
+ )}
362
+ </Form>
363
+ );`,
364
+ 'should not transform when no data-testid is present',
365
+ );
366
+
367
+ // Test: No transformation with JSX children (not function children)
368
+ defineInlineTest(
369
+ { default: transformer, parser: 'tsx' },
370
+ {},
371
+ `import Form from '@atlaskit/form';
372
+
373
+ const MyComponent = () => (
374
+ <Form onSubmit={handleSubmit}>
375
+ <div>JSX children instead of function</div>
376
+ </Form>
377
+ );`,
378
+ `import Form from '@atlaskit/form';
379
+
380
+ const MyComponent = () => (
381
+ <Form onSubmit={handleSubmit}>
382
+ <div>JSX children instead of function</div>
383
+ </Form>
384
+ );`,
385
+ 'should not transform JSX children (non-function children)',
386
+ );
387
+
388
+ // Test: No transformation without formProps parameter
389
+ defineInlineTest(
390
+ { default: transformer, parser: 'tsx' },
391
+ {},
392
+ `import Form from '@atlaskit/form';
393
+
394
+ const MyComponent = () => (
395
+ <Form onSubmit={handleSubmit}>
396
+ {({ submitting }) => (
397
+ <form data-testid="no-formprops">
398
+ <input type="text" />
399
+ <button disabled={submitting}>Submit</button>
400
+ </form>
401
+ )}
402
+ </Form>
403
+ );`,
404
+ `import Form from '@atlaskit/form';
405
+
406
+ const MyComponent = () => (
407
+ <Form onSubmit={handleSubmit}>
408
+ {({ submitting }) => (
409
+ <form data-testid="no-formprops">
410
+ <input type="text" />
411
+ <button disabled={submitting}>Submit</button>
412
+ </form>
413
+ )}
414
+ </Form>
415
+ );`,
416
+ 'should not transform when no formProps parameter exists',
417
+ );
418
+
419
+ // Test: No transformation when no form element found
420
+ defineInlineTest(
421
+ { default: transformer, parser: 'tsx' },
422
+ {},
423
+ `import Form from '@atlaskit/form';
424
+
425
+ const MyComponent = () => (
426
+ <Form onSubmit={handleSubmit}>
427
+ {({ formProps }) => (
428
+ <div {...formProps} data-testid="not-a-form">
429
+ <input type="text" />
430
+ </div>
431
+ )}
432
+ </Form>
433
+ );`,
434
+ `import Form from '@atlaskit/form';
435
+
436
+ const MyComponent = () => (
437
+ <Form onSubmit={handleSubmit}>
438
+ {({ formProps }) => (
439
+ <div {...formProps} data-testid="not-a-form">
440
+ <input type="text" />
441
+ </div>
442
+ )}
443
+ </Form>
444
+ );`,
445
+ 'should not transform when no HTML form element is found',
446
+ );
447
+
448
+ // Test: No transformation with only named imports (no default)
449
+ defineInlineTest(
450
+ { default: transformer, parser: 'tsx' },
451
+ {},
452
+ `import { Field, FormSection } from '@atlaskit/form';
453
+
454
+ const MyComponent = () => (
455
+ <div>
456
+ <Field name="test">
457
+ {({ fieldProps }) => <input {...fieldProps} />}
458
+ </Field>
459
+ </div>
460
+ );`,
461
+ `import { Field, FormSection } from '@atlaskit/form';
462
+
463
+ const MyComponent = () => (
464
+ <div>
465
+ <Field name="test">
466
+ {({ fieldProps }) => <input {...fieldProps} />}
467
+ </Field>
468
+ </div>
469
+ );`,
470
+ 'should not transform when only named imports exist (no default Form import)',
471
+ );
472
+
473
+ // Test: Multiple forms in same component - only transform the one with data-testid
474
+ defineInlineTest(
475
+ { default: transformer, parser: 'tsx' },
476
+ {},
477
+ `import Form from '@atlaskit/form';
478
+
479
+ const MyComponent = () => (
480
+ <div>
481
+ <Form onSubmit={handleSubmit1}>
482
+ {({ formProps }) => (
483
+ <form {...formProps} data-testid="first-form">
484
+ <input type="text" />
485
+ </form>
486
+ )}
487
+ </Form>
488
+ <Form onSubmit={handleSubmit2}>
489
+ {({ formProps }) => (
490
+ <form {...formProps} id="second-form">
491
+ <input type="text" />
492
+ </form>
493
+ )}
494
+ </Form>
495
+ </div>
496
+ );`,
497
+ `import Form from '@atlaskit/form';
498
+
499
+ const MyComponent = () => (
500
+ <div>
501
+ <Form onSubmit={handleSubmit1} testId="first-form">
502
+ {({ formProps }) => (
503
+ <form {...formProps}>
504
+ <input type="text" />
505
+ </form>
506
+ )}
507
+ </Form>
508
+ <Form onSubmit={handleSubmit2}>
509
+ {({ formProps }) => (
510
+ <form {...formProps} id="second-form">
511
+ <input type="text" />
512
+ </form>
513
+ )}
514
+ </Form>
515
+ </div>
516
+ );`,
517
+ 'should only transform forms with data-testid, leave others unchanged',
518
+ );
519
+
520
+ // Test: Complex real-world example like select-scopes
521
+ defineInlineTest(
522
+ { default: transformer, parser: 'tsx' },
523
+ {},
524
+ `import AkForm from '@atlaskit/form';
525
+
526
+ const MyComponent = () => (
527
+ <AkForm onSubmit={handleSubmit}>
528
+ {({ formProps }) => (
529
+ <form {...formProps} id="form-id" data-testid="my-test-id">
530
+ <input type="text" />
531
+ </form>
532
+ )}
533
+ </AkForm>
534
+ );`,
535
+ `import AkForm from '@atlaskit/form';
536
+
537
+ const MyComponent = () => (
538
+ <AkForm onSubmit={handleSubmit} testId="my-test-id">
539
+ {({ formProps }) => (
540
+ <form {...formProps} id="form-id">
541
+ <input type="text" />
542
+ </form>
543
+ )}
544
+ </AkForm>
545
+ );`,
546
+ 'should handle complex real-world example with AkForm and mixed attributes',
547
+ );
548
+
549
+ // Test: Different import styles from various packages should not transform
550
+ defineInlineTest(
551
+ { default: transformer, parser: 'tsx' },
552
+ {},
553
+ `import CustomForm from '@some/other-package';
554
+ import { Form } from '@another/package';
555
+
556
+ const MyComponent = () => (
557
+ <CustomForm onSubmit={handleSubmit}>
558
+ {({ formProps }) => (
559
+ <form {...formProps} data-testid="should-not-change">
560
+ <input type="text" />
561
+ </form>
562
+ )}
563
+ </CustomForm>
564
+ );`,
565
+ `import CustomForm from '@some/other-package';
566
+ import { Form } from '@another/package';
567
+
568
+ const MyComponent = () => (
569
+ <CustomForm onSubmit={handleSubmit}>
570
+ {({ formProps }) => (
571
+ <form {...formProps} data-testid="should-not-change">
572
+ <input type="text" />
573
+ </form>
574
+ )}
575
+ </CustomForm>
576
+ );`,
577
+ 'should not transform forms from other packages',
578
+ );
579
+
580
+ // Test: Preserve attribute order when adding testId
581
+ defineInlineTest(
582
+ { default: transformer, parser: 'tsx' },
583
+ {},
584
+ `import Form from '@atlaskit/form';
585
+
586
+ const MyComponent = () => (
587
+ <Form isDisabled onSubmit={handleSubmit}>
588
+ {({ formProps }) => (
589
+ <form {...formProps} data-testid="ordered-form">
590
+ <input type="text" />
591
+ </form>
592
+ )}
593
+ </Form>
594
+ );`,
595
+ `import Form from '@atlaskit/form';
596
+
597
+ const MyComponent = () => (
598
+ <Form isDisabled onSubmit={handleSubmit} testId="ordered-form">
599
+ {({ formProps }) => (
600
+ <form {...formProps}>
601
+ <input type="text" />
602
+ </form>
603
+ )}
604
+ </Form>
605
+ );`,
606
+ 'should preserve existing prop order when adding testId',
607
+ );
@@ -0,0 +1,160 @@
1
+ import {
2
+ type API,
3
+ type FileInfo,
4
+ type JSCodeshift,
5
+ type JSXElement,
6
+ type Options,
7
+ } from 'jscodeshift';
8
+ import { type Collection } from 'jscodeshift/src/Collection';
9
+
10
+ import {
11
+ addJSXAttributeToJSXElement,
12
+ getImportDeclarationCollection,
13
+ getImportDefaultSpecifierCollection,
14
+ getImportDefaultSpecifierName,
15
+ hasImportDeclaration,
16
+ } from './utils/helpers';
17
+
18
+ const importPath = '@atlaskit/form';
19
+
20
+ const migrateDataTestIdToTestIdProp = (j: JSCodeshift, collection: Collection<any>) => {
21
+ const importDeclarationCollection = getImportDeclarationCollection(j, collection, importPath);
22
+ const defaultImport = getImportDefaultSpecifierCollection(j, importDeclarationCollection);
23
+ const defaultImportName = getImportDefaultSpecifierName(defaultImport);
24
+
25
+ // if no default import is present, exit early
26
+ if (defaultImportName === null) {
27
+ return;
28
+ }
29
+
30
+ collection.findJSXElements(defaultImportName).forEach((jsxElementPath) => {
31
+ const node = jsxElementPath.node;
32
+
33
+ // If no children, exit early
34
+ if (!node.children || node.children.length === 0) {
35
+ return;
36
+ }
37
+
38
+ // Check if Form already has a testId prop - if so, skip to avoid conflicts
39
+ const existingTestIdProp = node.openingElement.attributes?.find(
40
+ (attr) => attr.type === 'JSXAttribute' && attr.name.name === 'testId',
41
+ );
42
+ if (existingTestIdProp) {
43
+ return;
44
+ }
45
+
46
+ // Find the function child
47
+ const children = node.children.filter((child) => child.type === 'JSXExpressionContainer');
48
+ if (children.length === 0 || children.length > 1) {
49
+ return;
50
+ }
51
+
52
+ const childFunction = children[0];
53
+ if (
54
+ childFunction.type !== 'JSXExpressionContainer' ||
55
+ childFunction.expression.type !== 'ArrowFunctionExpression'
56
+ ) {
57
+ return;
58
+ }
59
+
60
+ // Check if function has formProps parameter
61
+ const args = childFunction.expression.params
62
+ .filter((arg) => arg.type === 'ObjectPattern' && 'properties' in arg)
63
+ .flatMap((arg) => arg.properties)
64
+ .filter((property) => property.type === 'ObjectProperty');
65
+
66
+ const formPropsArg = args.find(
67
+ (arg) => arg.key.type === 'Identifier' && arg.key.name === 'formProps',
68
+ );
69
+
70
+ if (!formPropsArg || formPropsArg.value.type !== 'Identifier') {
71
+ return;
72
+ }
73
+
74
+ // Find the HTML form element inside the child function
75
+ const body = childFunction.expression.body;
76
+ let htmlForm: JSXElement | null = null;
77
+ const q: any[] = [body];
78
+
79
+ while (q.length > 0) {
80
+ const child = q.pop();
81
+ if (!child || child.type !== 'JSXElement') {
82
+ continue;
83
+ }
84
+ child.children?.forEach((el: any) => q.push(el));
85
+
86
+ if (child.type === 'JSXElement' && child.openingElement.name.name === 'form') {
87
+ htmlForm = child;
88
+ break;
89
+ }
90
+ }
91
+
92
+ // if no HTML form, exit early
93
+ if (htmlForm === null) {
94
+ return;
95
+ }
96
+
97
+ // Look for data-testid attribute on the form element
98
+ let dataTestIdAttr: any = null;
99
+ let dataTestIdValue: any = null;
100
+
101
+ htmlForm.openingElement.attributes?.forEach((attr, index) => {
102
+ // Find data-testid attribute
103
+ if (
104
+ attr.type === 'JSXAttribute' &&
105
+ attr.name.type === 'JSXIdentifier' &&
106
+ attr.name.name === 'data-testid'
107
+ ) {
108
+ dataTestIdAttr = attr;
109
+ dataTestIdValue = attr.value;
110
+ }
111
+ });
112
+
113
+ // If no data-testid found, exit early
114
+ if (!dataTestIdAttr || !dataTestIdValue) {
115
+ return;
116
+ }
117
+
118
+ // Extract the testId value
119
+ let testIdValue: any;
120
+ if (dataTestIdValue.type === 'StringLiteral' || dataTestIdValue.type === 'Literal') {
121
+ // String literal: data-testid="my-form"
122
+ testIdValue = dataTestIdValue;
123
+ } else if (dataTestIdValue.type === 'JSXExpressionContainer') {
124
+ // Expression: data-testid={someVariable}
125
+ testIdValue = j.jsxExpressionContainer(dataTestIdValue.expression);
126
+ } else {
127
+ // Unknown format, skip
128
+ return;
129
+ }
130
+
131
+ // Remove the data-testid attribute from the form element
132
+ const filteredAttributes = htmlForm.openingElement.attributes?.filter(
133
+ (attr) => attr !== dataTestIdAttr,
134
+ );
135
+ if (filteredAttributes) {
136
+ htmlForm.openingElement.attributes = filteredAttributes;
137
+ }
138
+
139
+ // Add testId prop to the Form component
140
+ const testIdProp = j.jsxAttribute(j.jsxIdentifier('testId'), testIdValue);
141
+ addJSXAttributeToJSXElement(j, jsxElementPath, testIdProp, 1);
142
+ });
143
+
144
+ return;
145
+ };
146
+
147
+ export default function transformer(fileInfo: FileInfo, { jscodeshift: j }: API, options: Options) {
148
+ const { source } = fileInfo;
149
+ const collection = j(source);
150
+
151
+ // If our component is not here, skip the file
152
+ if (!hasImportDeclaration(j, collection, importPath)) {
153
+ return source;
154
+ }
155
+
156
+ // Migrate data-testid to testId prop
157
+ migrateDataTestIdToTestIdProp(j, collection);
158
+
159
+ return collection.toSource(options.printOptions || { quote: 'single' });
160
+ }
@@ -14,9 +14,9 @@ var _react = _interopRequireWildcard(require("react"));
14
14
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
15
15
  var _field = _interopRequireDefault(require("./field"));
16
16
  var _excluded = ["children", "defaultIsChecked", "isDisabled", "isRequired", "label", "name", "value"],
17
- _excluded2 = ["value"],
17
+ _excluded2 = ["value", "onChange"],
18
18
  _excluded3 = ["fieldProps"],
19
- _excluded4 = ["value"],
19
+ _excluded4 = ["value", "onChange"],
20
20
  _excluded5 = ["fieldProps"];
21
21
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
22
22
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
@@ -45,46 +45,60 @@ var CheckboxField = function CheckboxField(_ref) {
45
45
  var currentValue = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
46
46
  return defaultIsChecked && value !== undefined ? [].concat((0, _toConsumableArray2.default)(currentValue), [value]) : currentValue;
47
47
  }, [value, defaultIsChecked]);
48
- return value !== undefined ? /*#__PURE__*/_react.default.createElement(_field.default, (0, _extends2.default)({}, (0, _platformFeatureFlags.fg)('platform_design-system-team_checkbox-field-spread') ? {} : _objectSpread({}, rest), {
48
+ return value !== undefined ? /*#__PURE__*/_react.default.createElement(_field.default
49
+ // eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
50
+ , (0, _extends2.default)({}, (0, _platformFeatureFlags.fg)('platform_design-system-team_checkbox-field-spread') ? {} : _objectSpread({}, rest), {
49
51
  defaultValue: defaultValue,
50
52
  isDisabled: isDisabled,
51
53
  isRequired: isRequired,
52
54
  label: label,
53
55
  name: name,
54
56
  transform: function transform(event, currentValue) {
55
- return event.currentTarget.checked && currentValue ? [].concat((0, _toConsumableArray2.default)(currentValue), [value]) : currentValue.filter(function (v) {
57
+ return !Array.isArray(event) && event.currentTarget.checked && currentValue ? [].concat((0, _toConsumableArray2.default)(currentValue), [value]) : currentValue.filter(function (v) {
56
58
  return v !== value;
57
59
  });
58
60
  }
59
61
  }), function (_ref2) {
60
62
  var _ref2$fieldProps = _ref2.fieldProps,
61
63
  fieldValue = _ref2$fieldProps.value,
64
+ _onChange = _ref2$fieldProps.onChange,
62
65
  otherFieldProps = (0, _objectWithoutProperties2.default)(_ref2$fieldProps, _excluded2),
63
66
  others = (0, _objectWithoutProperties2.default)(_ref2, _excluded3);
64
67
  return children(_objectSpread({
65
68
  fieldProps: _objectSpread(_objectSpread({}, otherFieldProps), {}, {
69
+ // Setting to any because it's typed weirdly at the field level
70
+ onChange: function onChange(v) {
71
+ return _onChange(v);
72
+ },
66
73
  isChecked: !!fieldValue.find(function (v) {
67
74
  return v === value;
68
75
  }),
69
76
  value: value
70
77
  })
71
78
  }, others));
72
- }) : /*#__PURE__*/_react.default.createElement(_field.default, (0, _extends2.default)({}, (0, _platformFeatureFlags.fg)('platform_design-system-team_checkbox-field-spread') ? {} : _objectSpread({}, rest), {
79
+ }) : /*#__PURE__*/_react.default.createElement(_field.default
80
+ // eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
81
+ , (0, _extends2.default)({}, (0, _platformFeatureFlags.fg)('platform_design-system-team_checkbox-field-spread') ? {} : _objectSpread({}, rest), {
73
82
  defaultValue: defaultIsChecked,
74
83
  isDisabled: isDisabled,
75
84
  isRequired: isRequired,
76
85
  label: label,
77
86
  name: name,
78
87
  transform: function transform(event) {
79
- return event.currentTarget.checked;
88
+ return typeof event === 'boolean' ? event : event.currentTarget.checked;
80
89
  }
81
90
  }), function (_ref3) {
82
91
  var _ref3$fieldProps = _ref3.fieldProps,
83
92
  fieldValue = _ref3$fieldProps.value,
93
+ _onChange2 = _ref3$fieldProps.onChange,
84
94
  otherFieldProps = (0, _objectWithoutProperties2.default)(_ref3$fieldProps, _excluded4),
85
95
  others = (0, _objectWithoutProperties2.default)(_ref3, _excluded5);
86
96
  return children(_objectSpread({
87
97
  fieldProps: _objectSpread(_objectSpread({}, otherFieldProps), {}, {
98
+ // Setting to any because it's typed weirdly at the field level
99
+ onChange: function onChange(v) {
100
+ return _onChange2(v);
101
+ },
88
102
  isChecked: fieldValue,
89
103
  value: value
90
104
  })
package/dist/cjs/form.js CHANGED
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "__esModule", {
8
8
  exports.IsDisabledContext = exports.FormContext = void 0;
9
9
  exports.default = Form;
10
10
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
11
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
12
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
12
13
  var _react = _interopRequireWildcard(require("react"));
13
14
  var _finalForm = require("final-form");
@@ -16,6 +17,8 @@ var _set = _interopRequireDefault(require("lodash/set"));
16
17
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
17
18
  var _utils = require("./utils");
18
19
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
20
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
21
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
19
22
  /**
20
23
  * __Form context__
21
24
  *
@@ -41,7 +44,8 @@ var FormContext = exports.FormContext = /*#__PURE__*/(0, _react.createContext)({
41
44
  var IsDisabledContext = exports.IsDisabledContext = /*#__PURE__*/(0, _react.createContext)(false);
42
45
  function Form(props) {
43
46
  var userProvidedFormProps = props.formProps,
44
- onSubmit = props.onSubmit;
47
+ onSubmit = props.onSubmit,
48
+ testId = props.testId;
45
49
  var formRef = (0, _react.useRef)(null);
46
50
  var onSubmitRef = (0, _react.useRef)(onSubmit);
47
51
  onSubmitRef.current = onSubmit;
@@ -144,11 +148,13 @@ function Form(props) {
144
148
  }, [registerField, getCurrentValue, form.subscribe]);
145
149
 
146
150
  // Abstracting so we can use the same for both rendering patterns
147
- var formProps = {
151
+ var formProps = _objectSpread({
148
152
  onKeyDown: handleKeyDown,
149
153
  onSubmit: handleSubmit,
150
154
  ref: formRef
151
- };
155
+ }, testId && {
156
+ 'data-testid': testId
157
+ });
152
158
  var childrenContent = function () {
153
159
  if (typeof children === 'function') {
154
160
  var result = children.length > 0 ? children({
@@ -23,7 +23,9 @@ const CheckboxField = ({
23
23
  }) => {
24
24
  // Maintains a memoised list of the default values
25
25
  const defaultValue = useCallback((currentValue = []) => defaultIsChecked && value !== undefined ? [...currentValue, value] : currentValue, [value, defaultIsChecked]);
26
- return value !== undefined ? /*#__PURE__*/React.createElement(Field, _extends({}, fg('platform_design-system-team_checkbox-field-spread') ? {} : {
26
+ return value !== undefined ? /*#__PURE__*/React.createElement(Field
27
+ // eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
28
+ , _extends({}, fg('platform_design-system-team_checkbox-field-spread') ? {} : {
27
29
  ...rest
28
30
  }, {
29
31
  defaultValue: defaultValue,
@@ -31,21 +33,26 @@ const CheckboxField = ({
31
33
  isRequired: isRequired,
32
34
  label: label,
33
35
  name: name,
34
- transform: (event, currentValue) => event.currentTarget.checked && currentValue ? [...currentValue, value] : currentValue.filter(v => v !== value)
36
+ transform: (event, currentValue) => !Array.isArray(event) && event.currentTarget.checked && currentValue ? [...currentValue, value] : currentValue.filter(v => v !== value)
35
37
  }), ({
36
38
  fieldProps: {
37
39
  value: fieldValue,
40
+ onChange,
38
41
  ...otherFieldProps
39
42
  },
40
43
  ...others
41
44
  }) => children({
42
45
  fieldProps: {
43
46
  ...otherFieldProps,
47
+ // Setting to any because it's typed weirdly at the field level
48
+ onChange: v => onChange(v),
44
49
  isChecked: !!fieldValue.find(v => v === value),
45
50
  value
46
51
  },
47
52
  ...others
48
- })) : /*#__PURE__*/React.createElement(Field, _extends({}, fg('platform_design-system-team_checkbox-field-spread') ? {} : {
53
+ })) : /*#__PURE__*/React.createElement(Field
54
+ // eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
55
+ , _extends({}, fg('platform_design-system-team_checkbox-field-spread') ? {} : {
49
56
  ...rest
50
57
  }, {
51
58
  defaultValue: defaultIsChecked,
@@ -53,16 +60,19 @@ const CheckboxField = ({
53
60
  isRequired: isRequired,
54
61
  label: label,
55
62
  name: name,
56
- transform: event => event.currentTarget.checked
63
+ transform: event => typeof event === 'boolean' ? event : event.currentTarget.checked
57
64
  }), ({
58
65
  fieldProps: {
59
66
  value: fieldValue,
67
+ onChange,
60
68
  ...otherFieldProps
61
69
  },
62
70
  ...others
63
71
  }) => children({
64
72
  fieldProps: {
65
73
  ...otherFieldProps,
74
+ // Setting to any because it's typed weirdly at the field level
75
+ onChange: v => onChange(v),
66
76
  isChecked: fieldValue,
67
77
  value
68
78
  },
@@ -29,7 +29,8 @@ export const IsDisabledContext = /*#__PURE__*/createContext(false);
29
29
  export default function Form(props) {
30
30
  const {
31
31
  formProps: userProvidedFormProps,
32
- onSubmit
32
+ onSubmit,
33
+ testId
33
34
  } = props;
34
35
  const formRef = useRef(null);
35
36
  const onSubmitRef = useRef(onSubmit);
@@ -128,7 +129,10 @@ export default function Form(props) {
128
129
  const formProps = {
129
130
  onKeyDown: handleKeyDown,
130
131
  onSubmit: handleSubmit,
131
- ref: formRef
132
+ ref: formRef,
133
+ ...(testId && {
134
+ 'data-testid': testId
135
+ })
132
136
  };
133
137
  const childrenContent = (() => {
134
138
  if (typeof children === 'function') {
@@ -3,9 +3,9 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
3
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
4
4
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
5
5
  var _excluded = ["children", "defaultIsChecked", "isDisabled", "isRequired", "label", "name", "value"],
6
- _excluded2 = ["value"],
6
+ _excluded2 = ["value", "onChange"],
7
7
  _excluded3 = ["fieldProps"],
8
- _excluded4 = ["value"],
8
+ _excluded4 = ["value", "onChange"],
9
9
  _excluded5 = ["fieldProps"];
10
10
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
11
11
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -36,46 +36,60 @@ var CheckboxField = function CheckboxField(_ref) {
36
36
  var currentValue = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
37
37
  return defaultIsChecked && value !== undefined ? [].concat(_toConsumableArray(currentValue), [value]) : currentValue;
38
38
  }, [value, defaultIsChecked]);
39
- return value !== undefined ? /*#__PURE__*/React.createElement(Field, _extends({}, fg('platform_design-system-team_checkbox-field-spread') ? {} : _objectSpread({}, rest), {
39
+ return value !== undefined ? /*#__PURE__*/React.createElement(Field
40
+ // eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
41
+ , _extends({}, fg('platform_design-system-team_checkbox-field-spread') ? {} : _objectSpread({}, rest), {
40
42
  defaultValue: defaultValue,
41
43
  isDisabled: isDisabled,
42
44
  isRequired: isRequired,
43
45
  label: label,
44
46
  name: name,
45
47
  transform: function transform(event, currentValue) {
46
- return event.currentTarget.checked && currentValue ? [].concat(_toConsumableArray(currentValue), [value]) : currentValue.filter(function (v) {
48
+ return !Array.isArray(event) && event.currentTarget.checked && currentValue ? [].concat(_toConsumableArray(currentValue), [value]) : currentValue.filter(function (v) {
47
49
  return v !== value;
48
50
  });
49
51
  }
50
52
  }), function (_ref2) {
51
53
  var _ref2$fieldProps = _ref2.fieldProps,
52
54
  fieldValue = _ref2$fieldProps.value,
55
+ _onChange = _ref2$fieldProps.onChange,
53
56
  otherFieldProps = _objectWithoutProperties(_ref2$fieldProps, _excluded2),
54
57
  others = _objectWithoutProperties(_ref2, _excluded3);
55
58
  return children(_objectSpread({
56
59
  fieldProps: _objectSpread(_objectSpread({}, otherFieldProps), {}, {
60
+ // Setting to any because it's typed weirdly at the field level
61
+ onChange: function onChange(v) {
62
+ return _onChange(v);
63
+ },
57
64
  isChecked: !!fieldValue.find(function (v) {
58
65
  return v === value;
59
66
  }),
60
67
  value: value
61
68
  })
62
69
  }, others));
63
- }) : /*#__PURE__*/React.createElement(Field, _extends({}, fg('platform_design-system-team_checkbox-field-spread') ? {} : _objectSpread({}, rest), {
70
+ }) : /*#__PURE__*/React.createElement(Field
71
+ // eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
72
+ , _extends({}, fg('platform_design-system-team_checkbox-field-spread') ? {} : _objectSpread({}, rest), {
64
73
  defaultValue: defaultIsChecked,
65
74
  isDisabled: isDisabled,
66
75
  isRequired: isRequired,
67
76
  label: label,
68
77
  name: name,
69
78
  transform: function transform(event) {
70
- return event.currentTarget.checked;
79
+ return typeof event === 'boolean' ? event : event.currentTarget.checked;
71
80
  }
72
81
  }), function (_ref3) {
73
82
  var _ref3$fieldProps = _ref3.fieldProps,
74
83
  fieldValue = _ref3$fieldProps.value,
84
+ _onChange2 = _ref3$fieldProps.onChange,
75
85
  otherFieldProps = _objectWithoutProperties(_ref3$fieldProps, _excluded4),
76
86
  others = _objectWithoutProperties(_ref3, _excluded5);
77
87
  return children(_objectSpread({
78
88
  fieldProps: _objectSpread(_objectSpread({}, otherFieldProps), {}, {
89
+ // Setting to any because it's typed weirdly at the field level
90
+ onChange: function onChange(v) {
91
+ return _onChange2(v);
92
+ },
79
93
  isChecked: fieldValue,
80
94
  value: value
81
95
  })
package/dist/esm/form.js CHANGED
@@ -1,5 +1,8 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
3
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
4
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
5
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
3
6
  import React, { createContext, useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
7
  import { createForm } from 'final-form';
5
8
  import createDecorator from 'final-form-focus';
@@ -31,7 +34,8 @@ export var FormContext = /*#__PURE__*/createContext({
31
34
  export var IsDisabledContext = /*#__PURE__*/createContext(false);
32
35
  export default function Form(props) {
33
36
  var userProvidedFormProps = props.formProps,
34
- onSubmit = props.onSubmit;
37
+ onSubmit = props.onSubmit,
38
+ testId = props.testId;
35
39
  var formRef = useRef(null);
36
40
  var onSubmitRef = useRef(onSubmit);
37
41
  onSubmitRef.current = onSubmit;
@@ -134,11 +138,13 @@ export default function Form(props) {
134
138
  }, [registerField, getCurrentValue, form.subscribe]);
135
139
 
136
140
  // Abstracting so we can use the same for both rendering patterns
137
- var formProps = {
141
+ var formProps = _objectSpread({
138
142
  onKeyDown: handleKeyDown,
139
143
  onSubmit: handleSubmit,
140
144
  ref: formRef
141
- };
145
+ }, testId && {
146
+ 'data-testid': testId
147
+ });
142
148
  var childrenContent = function () {
143
149
  if (typeof children === 'function') {
144
150
  var result = children.length > 0 ? children({
@@ -62,6 +62,10 @@ export interface FormProps<FormValues> {
62
62
  * Sets the form and its fields as disabled. Users cannot edit or focus on the fields.
63
63
  */
64
64
  isDisabled?: boolean;
65
+ /**
66
+ * A test identifier for the form element. This will be applied as `data-testid` attribute.
67
+ */
68
+ testId?: string;
65
69
  }
66
70
  export default function Form<FormValues extends Record<string, any> = {}>(props: FormProps<FormValues>): React.JSX.Element;
67
71
  export {};
@@ -62,6 +62,10 @@ export interface FormProps<FormValues> {
62
62
  * Sets the form and its fields as disabled. Users cannot edit or focus on the fields.
63
63
  */
64
64
  isDisabled?: boolean;
65
+ /**
66
+ * A test identifier for the form element. This will be applied as `data-testid` attribute.
67
+ */
68
+ testId?: string;
65
69
  }
66
70
  export default function Form<FormValues extends Record<string, any> = {}>(props: FormProps<FormValues>): React.JSX.Element;
67
71
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/form",
3
- "version": "12.5.3",
3
+ "version": "12.6.0",
4
4
  "description": "A form allows users to input information.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"