@atlaskit/form 14.2.4 → 14.2.5

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,11 @@
1
1
  # @atlaskit/form
2
2
 
3
+ ## 14.2.5
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
3
9
  ## 14.2.4
4
10
 
5
11
  ### Patch Changes
@@ -51,6 +57,40 @@
51
57
  not a function as children, the HTML `form` element will be implicitly rendered with props passed
52
58
  down from the ADS form component.
53
59
 
60
+ #### New streamlined form
61
+
62
+ The majority of uses of our form component look like the following:
63
+
64
+ ```tsx
65
+ <Form onSubmit={(data) => console.log(data)}>
66
+ {({ formProps }) => (
67
+ <form {...formProps} name="form" id="form" data-attribute="abc">
68
+ {/* form contents */}
69
+ </form>
70
+ )}
71
+ </Form>
72
+ ```
73
+
74
+ We've provided a way to simplify these use cases. You can move the attributes on the HTML `<form>`
75
+ element up to the form component. If they aren't a top-level prop, you can use the `formProps` prop
76
+ on the form component. All of the contents will be wrapped within an HTML `<form>` element that
77
+ includes all necessary props, including those provided on the form component.
78
+
79
+ ```tsx
80
+ <Form
81
+ onSubmit={(data) => console.log(data)}
82
+ name="form"
83
+ id="form"
84
+ formProps={{
85
+ 'data-attribute': 'abc',
86
+ }}
87
+ >
88
+ {/* form contents */}
89
+ </Form>
90
+ ```
91
+
92
+ The original implementation still exists and works as it did previously.
93
+
54
94
  ### Patch Changes
55
95
 
56
96
  - Updated dependencies
@@ -200,24 +200,50 @@ const formElement = (
200
200
  import React from 'react';
201
201
  import Form from '@atlaskit/form';
202
202
 
203
+ import { fg } from '@atlaskit/platform-feature-flags';
204
+
203
205
  const FormComponent1 = () => (
204
- <Form onSubmit={() => {}}><input /></Form>
206
+ fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}}><input /></Form> : <Form onSubmit={() => {}}>
207
+ {({ formProps }) => (
208
+ <form {...formProps}>
209
+ <input />
210
+ </form>
211
+ )}
212
+ </Form>
205
213
  );
206
214
 
207
215
  const FormComponent2 = () => (
208
216
  <>
209
- <Form onSubmit={() => {}}><input /></Form>
217
+ {fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}}><input /></Form> : <Form onSubmit={() => {}}>
218
+ {({ formProps }) => (
219
+ <form {...formProps}>
220
+ <input />
221
+ </form>
222
+ )}
223
+ </Form>}
210
224
  </>
211
225
  );
212
226
 
213
227
  class FormComponent3 extends React.Component {
214
228
  render() {
215
- return (<Form onSubmit={() => {}}><input /></Form>);
229
+ return fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}}><input /></Form> : <Form onSubmit={() => {}}>
230
+ {({ formProps }) => (
231
+ <form {...formProps}>
232
+ <input />
233
+ </form>
234
+ )}
235
+ </Form>;
216
236
  }
217
237
  }
218
238
 
219
239
  const formElement = (
220
- <Form onSubmit={() => {}}><input /></Form>
240
+ fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}}><input /></Form> : <Form onSubmit={() => {}}>
241
+ {({ formProps }) => (
242
+ <form {...formProps}>
243
+ <input />
244
+ </form>
245
+ )}
246
+ </Form>
221
247
  );
222
248
  `,
223
249
  'should convert from function with no props on form',
@@ -280,24 +306,50 @@ const formElement = (
280
306
  import React from 'react';
281
307
  import Form from '@atlaskit/form';
282
308
 
309
+ import { fg } from '@atlaskit/platform-feature-flags';
310
+
283
311
  const FormComponent1 = () => (
284
- <Form onSubmit={() => {}}><input /></Form>
312
+ fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}}><input /></Form> : <Form onSubmit={() => {}}>
313
+ {({ formProps: renamed }) => (
314
+ <form {...renamed}>
315
+ <input />
316
+ </form>
317
+ )}
318
+ </Form>
285
319
  );
286
320
 
287
321
  const FormComponent2 = () => (
288
322
  <>
289
- <Form onSubmit={() => {}}><input /></Form>
323
+ {fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}}><input /></Form> : <Form onSubmit={() => {}}>
324
+ {({ formProps: renamed }) => (
325
+ <form {...renamed}>
326
+ <input />
327
+ </form>
328
+ )}
329
+ </Form>}
290
330
  </>
291
331
  );
292
332
 
293
333
  class FormComponent3 extends React.Component {
294
334
  render() {
295
- return (<Form onSubmit={() => {}}><input /></Form>);
335
+ return fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}}><input /></Form> : <Form onSubmit={() => {}}>
336
+ {({ formProps: renamed }) => (
337
+ <form {...renamed}>
338
+ <input />
339
+ </form>
340
+ )}
341
+ </Form>;
296
342
  }
297
343
  }
298
344
 
299
345
  const formElement = (
300
- <Form onSubmit={() => {}}><input /></Form>
346
+ fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}}><input /></Form> : <Form onSubmit={() => {}}>
347
+ {({ formProps: renamed }) => (
348
+ <form {...renamed}>
349
+ <input />
350
+ </form>
351
+ )}
352
+ </Form>
301
353
  );
302
354
  `,
303
355
  'should convert from function with no props on form',
@@ -360,45 +412,193 @@ const formElement = (
360
412
  import React from 'react';
361
413
  import Form from '@atlaskit/form';
362
414
 
415
+ import { fg } from '@atlaskit/platform-feature-flags';
416
+
363
417
  const FormComponent1 = () => (
364
- <Form
418
+ fg('platform-design_system_team-form_conversion') ? <Form
365
419
  onSubmit={() => {}}
366
420
  formProps={{
367
421
  foo: "bar"
368
- }}><input /></Form>
422
+ }}><input /></Form> : <Form onSubmit={() => {}}>
423
+ {({ formProps }) => (
424
+ <form {...formProps} foo="bar">
425
+ <input />
426
+ </form>
427
+ )}
428
+ </Form>
369
429
  );
370
430
 
371
431
  const FormComponent2 = () => (
372
432
  <>
373
- <Form
433
+ {fg('platform-design_system_team-form_conversion') ? <Form
374
434
  onSubmit={() => {}}
375
435
  formProps={{
376
436
  foo: "bar"
377
- }}><input /></Form>
437
+ }}><input /></Form> : <Form onSubmit={() => {}}>
438
+ {({ formProps }) => (
439
+ <form {...formProps} foo="bar">
440
+ <input />
441
+ </form>
442
+ )}
443
+ </Form>}
378
444
  </>
379
445
  );
380
446
 
381
447
  class FormComponent3 extends React.Component {
382
448
  render() {
383
- return (
384
- <Form
449
+ return fg('platform-design_system_team-form_conversion') ? <Form
450
+ onSubmit={() => {}}
451
+ formProps={{
452
+ foo: "bar"
453
+ }}><input /></Form> : <Form onSubmit={() => {}}>
454
+ {({ formProps }) => (
455
+ <form {...formProps} foo="bar">
456
+ <input />
457
+ </form>
458
+ )}
459
+ </Form>;
460
+ }
461
+ }
462
+
463
+ const formElement = (
464
+ fg('platform-design_system_team-form_conversion') ? <Form
465
+ onSubmit={() => {}}
466
+ formProps={{
467
+ foo: "bar"
468
+ }}><input /></Form> : <Form onSubmit={() => {}}>
469
+ {({ formProps }) => (
470
+ <form {...formProps} foo="bar">
471
+ <input />
472
+ </form>
473
+ )}
474
+ </Form>
475
+ );
476
+ `,
477
+ 'should convert from function with single prop on form',
478
+ );
479
+
480
+ defineInlineTest(
481
+ { default: transformer, parser: 'tsx' },
482
+ {},
483
+ `
484
+ import React from 'react';
485
+ import Form from '@atlaskit/form';
486
+
487
+ const FormComponent1 = () => shouldRender && (
488
+ <Form onSubmit={() => {}}>
489
+ {({ formProps }) => (
490
+ <form {...formProps} foo="bar">
491
+ <input />
492
+ </form>
493
+ )}
494
+ </Form>
495
+ );
496
+
497
+ const FormComponent2 = () => shouldRender && (
498
+ <>
499
+ <Form onSubmit={() => {}}>
500
+ {({ formProps }) => (
501
+ <form {...formProps} foo="bar">
502
+ <input />
503
+ </form>
504
+ )}
505
+ </Form>
506
+ </>
507
+ );
508
+
509
+ class FormComponent3 extends React.Component {
510
+ render() {
511
+ return shouldRender && (
512
+ <Form onSubmit={() => {}}>
513
+ {({ formProps }) => (
514
+ <form {...formProps} foo="bar">
515
+ <input />
516
+ </form>
517
+ )}
518
+ </Form>
519
+ );
520
+ }
521
+ }
522
+
523
+ const formElement = shouldRender && (
524
+ <Form onSubmit={() => {}}>
525
+ {({ formProps }) => (
526
+ <form {...formProps} foo="bar">
527
+ <input />
528
+ </form>
529
+ )}
530
+ </Form>
531
+ );
532
+ `,
533
+ `
534
+ import React from 'react';
535
+ import Form from '@atlaskit/form';
536
+
537
+ import { fg } from '@atlaskit/platform-feature-flags';
538
+
539
+ const FormComponent1 = () => shouldRender && (
540
+ (fg('platform-design_system_team-form_conversion') ? <Form
541
+ onSubmit={() => {}}
542
+ formProps={{
543
+ foo: "bar"
544
+ }}><input /></Form> : <Form onSubmit={() => {}}>
545
+ {({ formProps }) => (
546
+ <form {...formProps} foo="bar">
547
+ <input />
548
+ </form>
549
+ )}
550
+ </Form>)
551
+ );
552
+
553
+ const FormComponent2 = () => shouldRender && (
554
+ <>
555
+ {fg('platform-design_system_team-form_conversion') ? <Form
556
+ onSubmit={() => {}}
557
+ formProps={{
558
+ foo: "bar"
559
+ }}><input /></Form> : <Form onSubmit={() => {}}>
560
+ {({ formProps }) => (
561
+ <form {...formProps} foo="bar">
562
+ <input />
563
+ </form>
564
+ )}
565
+ </Form>}
566
+ </>
567
+ );
568
+
569
+ class FormComponent3 extends React.Component {
570
+ render() {
571
+ return shouldRender && (
572
+ (fg('platform-design_system_team-form_conversion') ? <Form
385
573
  onSubmit={() => {}}
386
574
  formProps={{
387
575
  foo: "bar"
388
- }}><input /></Form>
576
+ }}><input /></Form> : <Form onSubmit={() => {}}>
577
+ {({ formProps }) => (
578
+ <form {...formProps} foo="bar">
579
+ <input />
580
+ </form>
581
+ )}
582
+ </Form>)
389
583
  );
390
584
  }
391
585
  }
392
586
 
393
- const formElement = (
394
- <Form
587
+ const formElement = shouldRender && (
588
+ (fg('platform-design_system_team-form_conversion') ? <Form
395
589
  onSubmit={() => {}}
396
590
  formProps={{
397
591
  foo: "bar"
398
- }}><input /></Form>
592
+ }}><input /></Form> : <Form onSubmit={() => {}}>
593
+ {({ formProps }) => (
594
+ <form {...formProps} foo="bar">
595
+ <input />
596
+ </form>
597
+ )}
598
+ </Form>)
399
599
  );
400
600
  `,
401
- 'should convert from function with single prop on form',
601
+ 'should convert from function with single prop on form after conditional',
402
602
  );
403
603
 
404
604
  describe('Migrate existing props', () => {
@@ -459,24 +659,50 @@ const formElement = (
459
659
  import React from 'react';
460
660
  import Form from '@atlaskit/form';
461
661
 
662
+ import { fg } from '@atlaskit/platform-feature-flags';
663
+
462
664
  const FormComponent1 = () => (
463
- <Form onSubmit={() => {}} noValidate name="bar" id="foo" autocomplete="off"><input /></Form>
665
+ fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}} autocomplete="off" id="foo" name="bar" noValidate><input /></Form> : <Form onSubmit={() => {}}>
666
+ {({ formProps }) => (
667
+ <form {...formProps} autocomplete="off" id="foo" name="bar" noValidate>
668
+ <input />
669
+ </form>
670
+ )}
671
+ </Form>
464
672
  );
465
673
 
466
674
  const FormComponent2 = () => (
467
675
  <>
468
- <Form onSubmit={() => {}} noValidate name="bar" id="foo" autocomplete="off"><input /></Form>
676
+ {fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}} autocomplete="off" id="foo" name="bar" noValidate><input /></Form> : <Form onSubmit={() => {}}>
677
+ {({ formProps }) => (
678
+ <form {...formProps} autocomplete="off" id="foo" name="bar" noValidate>
679
+ <input />
680
+ </form>
681
+ )}
682
+ </Form>}
469
683
  </>
470
684
  );
471
685
 
472
686
  class FormComponent3 extends React.Component {
473
687
  render() {
474
- return (<Form onSubmit={() => {}} noValidate name="bar" id="foo" autocomplete="off"><input /></Form>);
688
+ return fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}} autocomplete="off" id="foo" name="bar" noValidate><input /></Form> : <Form onSubmit={() => {}}>
689
+ {({ formProps }) => (
690
+ <form {...formProps} autocomplete="off" id="foo" name="bar" noValidate>
691
+ <input />
692
+ </form>
693
+ )}
694
+ </Form>;
475
695
  }
476
696
  }
477
697
 
478
698
  const formElement = (
479
- <Form onSubmit={() => {}} noValidate name="bar" id="foo" autocomplete="off"><input /></Form>
699
+ fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}} autocomplete="off" id="foo" name="bar" noValidate><input /></Form> : <Form onSubmit={() => {}}>
700
+ {({ formProps }) => (
701
+ <form {...formProps} autocomplete="off" id="foo" name="bar" noValidate>
702
+ <input />
703
+ </form>
704
+ )}
705
+ </Form>
480
706
  );
481
707
  `,
482
708
  'should migrate existing props on `form` into their respective props on `Form`',
@@ -539,24 +765,50 @@ const formElement = (
539
765
  import React from 'react';
540
766
  import Form from '@atlaskit/form';
541
767
 
768
+ import { fg } from '@atlaskit/platform-feature-flags';
769
+
542
770
  const FormComponent1 = () => (
543
- <Form onSubmit={() => {}} labelId="bar" label="foo"><input /></Form>
771
+ fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}} label="foo" labelId="bar"><input /></Form> : <Form onSubmit={() => {}}>
772
+ {({ formProps }) => (
773
+ <form {...formProps} aria-label="foo" aria-labelledby="bar">
774
+ <input />
775
+ </form>
776
+ )}
777
+ </Form>
544
778
  );
545
779
 
546
780
  const FormComponent2 = () => (
547
781
  <>
548
- <Form onSubmit={() => {}} labelId="bar" label="foo"><input /></Form>
782
+ {fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}} label="foo" labelId="bar"><input /></Form> : <Form onSubmit={() => {}}>
783
+ {({ formProps }) => (
784
+ <form {...formProps} aria-label="foo" aria-labelledby="bar">
785
+ <input />
786
+ </form>
787
+ )}
788
+ </Form>}
549
789
  </>
550
790
  );
551
791
 
552
792
  class FormComponent3 extends React.Component {
553
793
  render() {
554
- return (<Form onSubmit={() => {}} labelId="bar" label="foo"><input /></Form>);
794
+ return fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}} label="foo" labelId="bar"><input /></Form> : <Form onSubmit={() => {}}>
795
+ {({ formProps }) => (
796
+ <form {...formProps} aria-label="foo" aria-labelledby="bar">
797
+ <input />
798
+ </form>
799
+ )}
800
+ </Form>;
555
801
  }
556
802
  }
557
803
 
558
804
  const formElement = (
559
- <Form onSubmit={() => {}} labelId="bar" label="foo"><input /></Form>
805
+ fg('platform-design_system_team-form_conversion') ? <Form onSubmit={() => {}} label="foo" labelId="bar"><input /></Form> : <Form onSubmit={() => {}}>
806
+ {({ formProps }) => (
807
+ <form {...formProps} aria-label="foo" aria-labelledby="bar">
808
+ <input />
809
+ </form>
810
+ )}
811
+ </Form>
560
812
  );
561
813
  `,
562
814
  'should migrate existing props on `form` into different names',
@@ -619,58 +871,82 @@ const formElement = (
619
871
  import React from 'react';
620
872
  import Form from '@atlaskit/form';
621
873
 
874
+ import { fg } from '@atlaskit/platform-feature-flags';
875
+
622
876
  const FormComponent1 = () => (
623
- <Form
877
+ fg('platform-design_system_team-form_conversion') ? <Form
624
878
  onSubmit={() => {}}
625
- noValidate
626
- name="bar"
627
- id="foo"
628
- autocomplete="off"
629
879
  formProps={{
630
880
  quu: "qux"
631
- }}><input /></Form>
881
+ }}
882
+ autocomplete="off"
883
+ id="foo"
884
+ name="bar"
885
+ noValidate><input /></Form> : <Form onSubmit={() => {}}>
886
+ {({ formProps }) => (
887
+ <form {...formProps} autocomplete="off" id="foo" name="bar" noValidate quu="qux">
888
+ <input />
889
+ </form>
890
+ )}
891
+ </Form>
632
892
  );
633
893
 
634
894
  const FormComponent2 = () => (
635
895
  <>
636
- <Form
896
+ {fg('platform-design_system_team-form_conversion') ? <Form
637
897
  onSubmit={() => {}}
638
- noValidate
639
- name="bar"
640
- id="foo"
641
- autocomplete="off"
642
898
  formProps={{
643
899
  quu: "qux"
644
- }}><input /></Form>
900
+ }}
901
+ autocomplete="off"
902
+ id="foo"
903
+ name="bar"
904
+ noValidate><input /></Form> : <Form onSubmit={() => {}}>
905
+ {({ formProps }) => (
906
+ <form {...formProps} autocomplete="off" id="foo" name="bar" noValidate quu="qux">
907
+ <input />
908
+ </form>
909
+ )}
910
+ </Form>}
645
911
  </>
646
912
  );
647
913
 
648
914
  class FormComponent3 extends React.Component {
649
915
  render() {
650
- return (
651
- <Form
652
- onSubmit={() => {}}
653
- noValidate
654
- name="bar"
655
- id="foo"
656
- autocomplete="off"
657
- formProps={{
658
- quu: "qux"
659
- }}><input /></Form>
660
- );
916
+ return fg('platform-design_system_team-form_conversion') ? <Form
917
+ onSubmit={() => {}}
918
+ formProps={{
919
+ quu: "qux"
920
+ }}
921
+ autocomplete="off"
922
+ id="foo"
923
+ name="bar"
924
+ noValidate><input /></Form> : <Form onSubmit={() => {}}>
925
+ {({ formProps }) => (
926
+ <form {...formProps} autocomplete="off" id="foo" name="bar" noValidate quu="qux">
927
+ <input />
928
+ </form>
929
+ )}
930
+ </Form>;
661
931
  }
662
932
  }
663
933
 
664
934
  const formElement = (
665
- <Form
935
+ fg('platform-design_system_team-form_conversion') ? <Form
666
936
  onSubmit={() => {}}
667
- noValidate
668
- name="bar"
669
- id="foo"
670
- autocomplete="off"
671
937
  formProps={{
672
938
  quu: "qux"
673
- }}><input /></Form>
939
+ }}
940
+ autocomplete="off"
941
+ id="foo"
942
+ name="bar"
943
+ noValidate><input /></Form> : <Form onSubmit={() => {}}>
944
+ {({ formProps }) => (
945
+ <form {...formProps} autocomplete="off" id="foo" name="bar" noValidate quu="qux">
946
+ <input />
947
+ </form>
948
+ )}
949
+ </Form>
674
950
  );
675
951
  `,
676
952
  'should migrate existing props on `form` into their respective props on `Form` and also use `formProps` if needed',
@@ -734,46 +1010,70 @@ const formElement = (
734
1010
  import React from 'react';
735
1011
  import Form from '@atlaskit/form';
736
1012
 
1013
+ import { fg } from '@atlaskit/platform-feature-flags';
1014
+
737
1015
  const FormComponent1 = () => (
738
- <Form
1016
+ fg('platform-design_system_team-form_conversion') ? <Form
739
1017
  onSubmit={() => {}}
740
1018
  formProps={{
741
1019
  foo: "bar",
742
1020
  baz: "qux"
743
- }}><input /></Form>
1021
+ }}><input /></Form> : <Form onSubmit={() => {}}>
1022
+ {({ formProps }) => (
1023
+ <form {...formProps} foo="bar" baz="qux">
1024
+ <input />
1025
+ </form>
1026
+ )}
1027
+ </Form>
744
1028
  );
745
1029
 
746
1030
  const FormComponent2 = () => (
747
1031
  <>
748
- <Form
1032
+ {fg('platform-design_system_team-form_conversion') ? <Form
749
1033
  onSubmit={() => {}}
750
1034
  formProps={{
751
1035
  foo: "bar",
752
1036
  baz: "qux"
753
- }}><input /></Form>
1037
+ }}><input /></Form> : <Form onSubmit={() => {}}>
1038
+ {({ formProps }) => (
1039
+ <form {...formProps} foo="bar" baz="qux">
1040
+ <input />
1041
+ </form>
1042
+ )}
1043
+ </Form>}
754
1044
  </>
755
1045
  );
756
1046
 
757
1047
  class FormComponent3 extends React.Component {
758
1048
  render() {
759
- return (
760
- <Form
761
- onSubmit={() => {}}
762
- formProps={{
763
- foo: "bar",
764
- baz: "qux"
765
- }}><input /></Form>
766
- );
1049
+ return fg('platform-design_system_team-form_conversion') ? <Form
1050
+ onSubmit={() => {}}
1051
+ formProps={{
1052
+ foo: "bar",
1053
+ baz: "qux"
1054
+ }}><input /></Form> : <Form onSubmit={() => {}}>
1055
+ {({ formProps }) => (
1056
+ <form {...formProps} foo="bar" baz="qux">
1057
+ <input />
1058
+ </form>
1059
+ )}
1060
+ </Form>;
767
1061
  }
768
1062
  }
769
1063
 
770
1064
  const formElement = (
771
- <Form
1065
+ fg('platform-design_system_team-form_conversion') ? <Form
772
1066
  onSubmit={() => {}}
773
1067
  formProps={{
774
1068
  foo: "bar",
775
1069
  baz: "qux"
776
- }}><input /></Form>
1070
+ }}><input /></Form> : <Form onSubmit={() => {}}>
1071
+ {({ formProps }) => (
1072
+ <form {...formProps} foo="bar" baz="qux">
1073
+ <input />
1074
+ </form>
1075
+ )}
1076
+ </Form>
777
1077
  );
778
1078
  `,
779
1079
  'should convert from function with multiple props on form',
@@ -835,46 +1135,70 @@ const formElement = (
835
1135
  import React from 'react';
836
1136
  import Form from '@atlaskit/form';
837
1137
 
1138
+ import { fg } from '@atlaskit/platform-feature-flags';
1139
+
838
1140
  const FormComponent1 = () => (
839
- <Form
1141
+ fg('platform-design_system_team-form_conversion') ? <Form
840
1142
  onSubmit={() => {}}
841
1143
  formProps={{
842
1144
  foo: 'bar',
843
1145
  baz: { qux: 'qux' }
844
- }}><input /></Form>
1146
+ }}><input /></Form> : <Form onSubmit={() => {}}>
1147
+ {({ formProps }) => (
1148
+ <form {...formProps} foo={'bar'} baz={{ qux: 'qux' }}>
1149
+ <input />
1150
+ </form>
1151
+ )}
1152
+ </Form>
845
1153
  );
846
1154
 
847
1155
  const FormComponent2 = () => (
848
1156
  <>
849
- <Form
1157
+ {fg('platform-design_system_team-form_conversion') ? <Form
850
1158
  onSubmit={() => {}}
851
1159
  formProps={{
852
1160
  foo: 'bar',
853
1161
  baz: { qux: 'qux' }
854
- }}><input /></Form>
1162
+ }}><input /></Form> : <Form onSubmit={() => {}}>
1163
+ {({ formProps }) => (
1164
+ <form {...formProps} foo={'bar'} baz={{ qux: 'qux' }}>
1165
+ <input />
1166
+ </form>
1167
+ )}
1168
+ </Form>}
855
1169
  </>
856
1170
  );
857
1171
 
858
1172
  class FormComponent3 extends React.Component {
859
1173
  render() {
860
- return (
861
- <Form
862
- onSubmit={() => {}}
863
- formProps={{
864
- foo: 'bar',
865
- baz: { qux: 'qux' }
866
- }}><input /></Form>
867
- );
1174
+ return fg('platform-design_system_team-form_conversion') ? <Form
1175
+ onSubmit={() => {}}
1176
+ formProps={{
1177
+ foo: 'bar',
1178
+ baz: { qux: 'qux' }
1179
+ }}><input /></Form> : <Form onSubmit={() => {}}>
1180
+ {({ formProps }) => (
1181
+ <form {...formProps} foo={'bar'} baz={{ qux: 'qux' }}>
1182
+ <input />
1183
+ </form>
1184
+ )}
1185
+ </Form>;
868
1186
  }
869
1187
  }
870
1188
 
871
1189
  const formElement = (
872
- <Form
1190
+ fg('platform-design_system_team-form_conversion') ? <Form
873
1191
  onSubmit={() => {}}
874
1192
  formProps={{
875
1193
  foo: 'bar',
876
1194
  baz: { qux: 'qux' }
877
- }}><input /></Form>
1195
+ }}><input /></Form> : <Form onSubmit={() => {}}>
1196
+ {({ formProps }) => (
1197
+ <form {...formProps} foo={'bar'} baz={{ qux: 'qux' }}>
1198
+ <input />
1199
+ </form>
1200
+ )}
1201
+ </Form>
878
1202
  );
879
1203
  `,
880
1204
  'should convert from function with multiple expression container props on form',
@@ -936,42 +1260,66 @@ const formElement = (
936
1260
  import React from 'react';
937
1261
  import Form from '@atlaskit/form';
938
1262
 
1263
+ import { fg } from '@atlaskit/platform-feature-flags';
1264
+
939
1265
  const FormComponent1 = () => (
940
- <Form
1266
+ fg('platform-design_system_team-form_conversion') ? <Form
941
1267
  onSubmit={() => {}}
942
1268
  formProps={{
943
1269
  foo: true
944
- }}><input /></Form>
1270
+ }}><input /></Form> : <Form onSubmit={() => {}}>
1271
+ {({ formProps }) => (
1272
+ <form {...formProps} foo>
1273
+ <input />
1274
+ </form>
1275
+ )}
1276
+ </Form>
945
1277
  );
946
1278
 
947
1279
  const FormComponent2 = () => (
948
1280
  <>
949
- <Form
1281
+ {fg('platform-design_system_team-form_conversion') ? <Form
950
1282
  onSubmit={() => {}}
951
1283
  formProps={{
952
1284
  foo: true
953
- }}><input /></Form>
1285
+ }}><input /></Form> : <Form onSubmit={() => {}}>
1286
+ {({ formProps }) => (
1287
+ <form {...formProps} foo>
1288
+ <input />
1289
+ </form>
1290
+ )}
1291
+ </Form>}
954
1292
  </>
955
1293
  );
956
1294
 
957
1295
  class FormComponent3 extends React.Component {
958
1296
  render() {
959
- return (
960
- <Form
961
- onSubmit={() => {}}
962
- formProps={{
963
- foo: true
964
- }}><input /></Form>
965
- );
1297
+ return fg('platform-design_system_team-form_conversion') ? <Form
1298
+ onSubmit={() => {}}
1299
+ formProps={{
1300
+ foo: true
1301
+ }}><input /></Form> : <Form onSubmit={() => {}}>
1302
+ {({ formProps }) => (
1303
+ <form {...formProps} foo>
1304
+ <input />
1305
+ </form>
1306
+ )}
1307
+ </Form>;
966
1308
  }
967
1309
  }
968
1310
 
969
1311
  const formElement = (
970
- <Form
1312
+ fg('platform-design_system_team-form_conversion') ? <Form
971
1313
  onSubmit={() => {}}
972
1314
  formProps={{
973
1315
  foo: true
974
- }}><input /></Form>
1316
+ }}><input /></Form> : <Form onSubmit={() => {}}>
1317
+ {({ formProps }) => (
1318
+ <form {...formProps} foo>
1319
+ <input />
1320
+ </form>
1321
+ )}
1322
+ </Form>
975
1323
  );
976
1324
  `,
977
1325
  'should convert from function with boolean props on form',
@@ -1,3 +1,6 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+
1
4
  import {
2
5
  type API,
3
6
  type Collection,
@@ -56,19 +59,42 @@ function hasImportDeclaration(
56
59
  return getImportDeclarationCollection(j, collection, importPath).length > 0;
57
60
  }
58
61
 
59
- function addJSXAttributeToJSXElement(
60
- j: JSCodeshift,
61
- jsxElementPath: any,
62
- attribute: JSXAttribute,
63
- position: number = 0,
64
- ): void {
65
- if (!jsxElementPath.node.openingElement.attributes) {
66
- jsxElementPath.node.openingElement.attributes = [];
62
+ // Currently unused but saving for field conversion
63
+ const generateFeatureFlag = (filePath: string): string => {
64
+ if (!filePath) {
65
+ return 'platform-design_system_team-form--unknown';
67
66
  }
68
- jsxElementPath.node.openingElement.attributes.splice(position, 0, attribute);
69
- }
70
67
 
71
- const convertToSimpleForm = (j: JSCodeshift, collection: Collection<any>) => {
68
+ let currentDir = path.dirname(filePath);
69
+
70
+ while (currentDir !== path.dirname(currentDir)) {
71
+ const packageJsonPath = path.join(currentDir, 'package.json');
72
+ if (fs.existsSync(packageJsonPath)) {
73
+ try {
74
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
75
+ const teamName = packageJson.atlassian?.team;
76
+ if (teamName) {
77
+ // Fit switcheroo requirements
78
+ const suffix = teamName
79
+ .toLowerCase()
80
+ .replace(/\s+/g, '-')
81
+ .replace(/[^a-z0-9-]/g, '');
82
+
83
+ const flag = `platform-design_system_team-form--${suffix}`;
84
+ return flag.length > 50 ? flag.substring(0, 50) : flag;
85
+ }
86
+ } catch (e) {
87
+ // Continue searching if JSON parsing fails
88
+ }
89
+ }
90
+ currentDir = path.dirname(currentDir);
91
+ }
92
+
93
+ // Fallback if no team found
94
+ return 'platform-design_system_team-form--unknown';
95
+ };
96
+
97
+ const convertToSimpleForm = (j: JSCodeshift, collection: Collection<any>, featureFlag: string) => {
72
98
  const importDeclarationCollection = getImportDeclarationCollection(j, collection, importPath);
73
99
  const defaultImport = getImportDefaultSpecifierCollection(j, importDeclarationCollection);
74
100
  const defaultImportName = getImportDefaultSpecifierName(defaultImport);
@@ -78,6 +104,8 @@ const convertToSimpleForm = (j: JSCodeshift, collection: Collection<any>) => {
78
104
  return;
79
105
  }
80
106
 
107
+ let transformationsMade = false;
108
+
81
109
  collection.findJSXElements(defaultImportName).forEach((jsxElementPath) => {
82
110
  const node = jsxElementPath.node;
83
111
  // If no children, exit early
@@ -85,7 +113,7 @@ const convertToSimpleForm = (j: JSCodeshift, collection: Collection<any>) => {
85
113
  return;
86
114
  }
87
115
 
88
- // if component but child is not a function, exit early
116
+ // if component but child is not an expression, exit early
89
117
  const children = node.children.filter((child) => child.type === 'JSXExpressionContainer');
90
118
  if (children.length === 0 || children.length > 1) {
91
119
  return;
@@ -101,8 +129,10 @@ const convertToSimpleForm = (j: JSCodeshift, collection: Collection<any>) => {
101
129
  }
102
130
 
103
131
  // if function child but more than just `formProps`, exit early
104
- const args = childFunction.expression.params
105
- .filter((arg) => arg.type === 'ObjectPattern' && 'properties' in arg)
132
+ const objectPatternArgs = childFunction.expression.params.filter(
133
+ (arg) => arg.type === 'ObjectPattern' && 'properties' in arg,
134
+ );
135
+ const args = objectPatternArgs
106
136
  .flatMap((arg) => arg.properties)
107
137
  .filter((property) => property.type === 'ObjectProperty');
108
138
  if (
@@ -197,36 +227,81 @@ const convertToSimpleForm = (j: JSCodeshift, collection: Collection<any>) => {
197
227
  return;
198
228
  }
199
229
 
230
+ // Clone the original Form element for the fallback
231
+ const originalForm = j.jsxElement(
232
+ j.jsxOpeningElement(j.jsxIdentifier(defaultImportName), [
233
+ ...(node.openingElement.attributes || []),
234
+ ]),
235
+ j.jsxClosingElement(j.jsxIdentifier(defaultImportName)),
236
+ [...node.children],
237
+ );
238
+
239
+ // Create the simplified Form element
240
+ const simplifiedForm = j.jsxElement(
241
+ j.jsxOpeningElement(j.jsxIdentifier(defaultImportName), [
242
+ ...(node.openingElement.attributes || []),
243
+ ]),
244
+ j.jsxClosingElement(j.jsxIdentifier(defaultImportName)),
245
+ [],
246
+ );
247
+
248
+ // Add formProps attribute if needed
200
249
  if (nonFormPropsAttributes.length !== 0) {
201
- // make new attribute for parent `Form` default import called `formProps` and set new attribute to new object
202
250
  const formPropsAttr = j.jsxAttribute(
203
251
  j.jsxIdentifier('formProps'),
204
252
  j.jsxExpressionContainer(j.objectExpression(nonFormPropsAttributes.filter(Boolean))),
205
253
  );
206
- addJSXAttributeToJSXElement(j, jsxElementPath, formPropsAttr, 1);
254
+ simplifiedForm.openingElement.attributes = simplifiedForm.openingElement.attributes || [];
255
+ simplifiedForm.openingElement.attributes.push(formPropsAttr);
207
256
  }
257
+
258
+ // Add existing form attributes to simplified form
208
259
  existingFormPropsAttributes.forEach((attr) => {
209
- // add existing props to new `Form`
210
260
  const fromName = attr.name.name;
211
261
  if (typeof fromName !== 'string') {
212
262
  return;
213
263
  }
214
264
  const toName = EXISTING_FORM_ATTRIBUTES[fromName];
215
- attr.name.name = toName;
216
- addJSXAttributeToJSXElement(j, jsxElementPath, attr, 1);
265
+ const newAttr = j.jsxAttribute(j.jsxIdentifier(toName), attr.value);
266
+ simplifiedForm.openingElement.attributes = simplifiedForm.openingElement.attributes || [];
267
+ simplifiedForm.openingElement.attributes.push(newAttr);
217
268
  });
218
269
 
219
- // replace functional child with inner (all children of HTML `form`)
270
+ // Add the children from the HTML form to simplified form
220
271
  const htmlFormChildren = htmlForm.children?.filter((child) => child.type !== 'JSXText');
221
- if (!htmlFormChildren) {
222
- return;
272
+ if (htmlFormChildren) {
273
+ simplifiedForm.children = [...htmlFormChildren];
223
274
  }
224
275
 
225
- node.children.splice(0);
226
- node.children.splice(0, 0, ...htmlFormChildren);
276
+ // Create the ternary expression: fg('flag') ? simplifiedForm : originalForm
277
+ const ternaryExpression = j.conditionalExpression(
278
+ j.callExpression(j.identifier('fg'), [j.literal(featureFlag)]),
279
+ simplifiedForm,
280
+ originalForm,
281
+ );
282
+
283
+ const isInsideJSXContext = (path: any): boolean => {
284
+ const parent = path.parent;
285
+ if (!parent) {
286
+ return false;
287
+ }
288
+
289
+ const parentType = parent.node?.type;
290
+ return parentType === 'JSXElement' || parentType === 'JSXFragment';
291
+ };
292
+
293
+ // Replace the original Form with the ternary expression
294
+ if (isInsideJSXContext(jsxElementPath)) {
295
+ // Inside JSX - wrap in JSX expression container
296
+ j(jsxElementPath).replaceWith(j.jsxExpressionContainer(ternaryExpression));
297
+ } else {
298
+ j(jsxElementPath).replaceWith(ternaryExpression);
299
+ }
300
+
301
+ transformationsMade = true;
227
302
  });
228
303
 
229
- return;
304
+ return transformationsMade;
230
305
  };
231
306
 
232
307
  export default function transformer(fileInfo: FileInfo, { jscodeshift: j }: API, options: Options) {
@@ -244,8 +319,34 @@ export default function transformer(fileInfo: FileInfo, { jscodeshift: j }: API,
244
319
  return source;
245
320
  }
246
321
 
322
+ // Leaving this here so that we don't get "unused" error, because I want to
323
+ // port this logic to the field codemod later
324
+ generateFeatureFlag(path);
325
+ const featureFlag = 'platform-design_system_team-form_conversion';
326
+
247
327
  // Convert form if possible
248
- convertToSimpleForm(j, collection);
328
+ const transformationsMade = convertToSimpleForm(j, collection, featureFlag);
329
+
330
+ // Only add import if transformations were made
331
+ if (transformationsMade) {
332
+ // Add import for fg function if not already present
333
+ const fgImportPath = '@atlaskit/platform-feature-flags';
334
+ if (!hasImportDeclaration(j, collection, fgImportPath)) {
335
+ const fgImport = j.importDeclaration(
336
+ [j.importSpecifier(j.identifier('fg'))],
337
+ j.literal(fgImportPath),
338
+ );
339
+
340
+ // Find the last import declaration and insert after it
341
+ const imports = collection.find(j.ImportDeclaration);
342
+ if (imports.length > 0) {
343
+ imports.at(-1).insertAfter(fgImport);
344
+ } else {
345
+ // If no imports, add at the beginning
346
+ collection.find(j.Program).get('body', 0).insertBefore(fgImport);
347
+ }
348
+ }
349
+ }
249
350
 
250
351
  return collection.toSource(options.printOptions || { quote: 'single' });
251
352
  }
@@ -55,8 +55,10 @@ export interface FormProps<FormValues> {
55
55
  */
56
56
  autocomplete?: 'off' | 'on';
57
57
  /**
58
- * The contents rendered inside of the form. This is a function where the props will be passed from the form. The function props you can access are `dirty`, `submitting` and `disabled`.
59
- * You can read more about these props in [react-final form documentation](https://final-form.org/docs/final-form/types/FormState).
58
+ * The contents rendered inside of the form. This is a function where the props will be passed from the form. The function props you can access are `dirty`, `submitting` and `disabled`.
59
+ * You can read more about these props in [react-final form documentation](https://final-form.org/docs/final-form/types/FormState).
60
+ *
61
+ * If you are only spreading `formProps` onto the HTML `<form>` element and not using any of the other props (like `submitting`, etc.), `children` can be plain JSX. All of the children will be wrapped within an HTML `<form>` element that includes all necessary props, including those provided on the form component.
60
62
  */
61
63
  children: ((args: FormChildrenArgs<FormValues>) => ReactNode) | (() => void) | ReactNode;
62
64
  /**
@@ -55,8 +55,10 @@ export interface FormProps<FormValues> {
55
55
  */
56
56
  autocomplete?: 'off' | 'on';
57
57
  /**
58
- * The contents rendered inside of the form. This is a function where the props will be passed from the form. The function props you can access are `dirty`, `submitting` and `disabled`.
59
- * You can read more about these props in [react-final form documentation](https://final-form.org/docs/final-form/types/FormState).
58
+ * The contents rendered inside of the form. This is a function where the props will be passed from the form. The function props you can access are `dirty`, `submitting` and `disabled`.
59
+ * You can read more about these props in [react-final form documentation](https://final-form.org/docs/final-form/types/FormState).
60
+ *
61
+ * If you are only spreading `formProps` onto the HTML `<form>` element and not using any of the other props (like `submitting`, etc.), `children` can be plain JSX. All of the children will be wrapped within an HTML `<form>` element that includes all necessary props, including those provided on the form component.
60
62
  */
61
63
  children: ((args: FormChildrenArgs<FormValues>) => ReactNode) | (() => void) | ReactNode;
62
64
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/form",
3
- "version": "14.2.4",
3
+ "version": "14.2.5",
4
4
  "description": "A form allows users to input information.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -26,12 +26,12 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "@atlaskit/css": "^0.15.0",
29
- "@atlaskit/ds-lib": "^5.1.0",
29
+ "@atlaskit/ds-lib": "^5.2.0",
30
30
  "@atlaskit/heading": "^5.2.0",
31
31
  "@atlaskit/icon": "^28.5.0",
32
32
  "@atlaskit/platform-feature-flags": "^1.1.0",
33
- "@atlaskit/primitives": "^16.0.0",
34
- "@atlaskit/tokens": "^7.0.0",
33
+ "@atlaskit/primitives": "^16.1.0",
34
+ "@atlaskit/tokens": "^8.0.0",
35
35
  "@babel/runtime": "^7.0.0",
36
36
  "final-form": "^4.20.3",
37
37
  "final-form-focus": "^1.1.2",
@@ -45,23 +45,23 @@
45
45
  "@af/integration-testing": "workspace:^",
46
46
  "@af/visual-regression": "workspace:^",
47
47
  "@atlaskit/banner": "^14.0.0",
48
- "@atlaskit/button": "^23.5.0",
48
+ "@atlaskit/button": "^23.6.0",
49
49
  "@atlaskit/checkbox": "^17.1.0",
50
50
  "@atlaskit/codemod-utils": "^4.2.0",
51
51
  "@atlaskit/datetime-picker": "^17.1.0",
52
52
  "@atlaskit/docs": "^11.2.0",
53
53
  "@atlaskit/link": "^3.2.0",
54
- "@atlaskit/lozenge": "^13.0.0",
55
- "@atlaskit/modal-dialog": "^14.5.0",
54
+ "@atlaskit/lozenge": "^13.1.0",
55
+ "@atlaskit/modal-dialog": "^14.6.0",
56
56
  "@atlaskit/radio": "^8.3.0",
57
57
  "@atlaskit/range": "^9.2.0",
58
- "@atlaskit/section-message": "^8.7.0",
58
+ "@atlaskit/section-message": "^8.9.0",
59
59
  "@atlaskit/select": "^21.3.0",
60
60
  "@atlaskit/textarea": "^8.0.0",
61
61
  "@atlaskit/textfield": "^8.0.0",
62
62
  "@atlaskit/toggle": "^15.1.0",
63
- "@atlassian/feature-flags-test-utils": "^0.3.0",
64
- "@atlassian/ssr-tests": "^0.3.0",
63
+ "@atlassian/feature-flags-test-utils": "^1.0.0",
64
+ "@atlassian/ssr-tests": "workspace:^",
65
65
  "@testing-library/react": "^13.4.0",
66
66
  "@testing-library/react-hooks": "^8.0.1",
67
67
  "@testing-library/user-event": "^14.4.3",