@atlaskit/form 14.1.0 → 14.2.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 +7 -0
- package/codemods/__tests__/not-yet-migrate-to-simplified-form.test.tsx +276 -0
- package/codemods/not-yet-migrate-to-simplified-form.tsx +30 -2
- package/dist/cjs/form.js +45 -10
- package/dist/es2019/form.js +42 -7
- package/dist/esm/form.js +44 -8
- package/dist/types/form.d.ts +53 -5
- package/dist/types-ts4.5/form.d.ts +53 -5
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# @atlaskit/form
|
|
2
2
|
|
|
3
|
+
## 14.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`10985771cb1e5`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/10985771cb1e5) -
|
|
8
|
+
Add props to form component for more transparent prop application to underlying HTML form element.
|
|
9
|
+
|
|
3
10
|
## 14.1.0
|
|
4
11
|
|
|
5
12
|
### Minor Changes
|
|
@@ -401,6 +401,282 @@ const formElement = (
|
|
|
401
401
|
'should convert from function with single prop on form',
|
|
402
402
|
);
|
|
403
403
|
|
|
404
|
+
describe('Migrate existing props', () => {
|
|
405
|
+
defineInlineTest(
|
|
406
|
+
{ default: transformer, parser: 'tsx' },
|
|
407
|
+
{},
|
|
408
|
+
`
|
|
409
|
+
import React from 'react';
|
|
410
|
+
import Form from '@atlaskit/form';
|
|
411
|
+
|
|
412
|
+
const FormComponent1 = () => (
|
|
413
|
+
<Form onSubmit={() => {}}>
|
|
414
|
+
{({ formProps }) => (
|
|
415
|
+
<form {...formProps} autocomplete="off" id="foo" name="bar" noValidate>
|
|
416
|
+
<input />
|
|
417
|
+
</form>
|
|
418
|
+
)}
|
|
419
|
+
</Form>
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
const FormComponent2 = () => (
|
|
423
|
+
<>
|
|
424
|
+
<Form onSubmit={() => {}}>
|
|
425
|
+
{({ formProps }) => (
|
|
426
|
+
<form {...formProps} autocomplete="off" id="foo" name="bar" noValidate>
|
|
427
|
+
<input />
|
|
428
|
+
</form>
|
|
429
|
+
)}
|
|
430
|
+
</Form>
|
|
431
|
+
</>
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
class FormComponent3 extends React.Component {
|
|
435
|
+
render() {
|
|
436
|
+
return (
|
|
437
|
+
<Form onSubmit={() => {}}>
|
|
438
|
+
{({ formProps }) => (
|
|
439
|
+
<form {...formProps} autocomplete="off" id="foo" name="bar" noValidate>
|
|
440
|
+
<input />
|
|
441
|
+
</form>
|
|
442
|
+
)}
|
|
443
|
+
</Form>
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const formElement = (
|
|
449
|
+
<Form onSubmit={() => {}}>
|
|
450
|
+
{({ formProps }) => (
|
|
451
|
+
<form {...formProps} autocomplete="off" id="foo" name="bar" noValidate>
|
|
452
|
+
<input />
|
|
453
|
+
</form>
|
|
454
|
+
)}
|
|
455
|
+
</Form>
|
|
456
|
+
);
|
|
457
|
+
`,
|
|
458
|
+
`
|
|
459
|
+
import React from 'react';
|
|
460
|
+
import Form from '@atlaskit/form';
|
|
461
|
+
|
|
462
|
+
const FormComponent1 = () => (
|
|
463
|
+
<Form onSubmit={() => {}} autocomplete="off" id="foo" name="bar" noValidate><input /></Form>
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
const FormComponent2 = () => (
|
|
467
|
+
<>
|
|
468
|
+
<Form onSubmit={() => {}} autocomplete="off" id="foo" name="bar" noValidate><input /></Form>
|
|
469
|
+
</>
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
class FormComponent3 extends React.Component {
|
|
473
|
+
render() {
|
|
474
|
+
return (<Form onSubmit={() => {}} autocomplete="off" id="foo" name="bar" noValidate><input /></Form>);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const formElement = (
|
|
479
|
+
<Form onSubmit={() => {}} autocomplete="off" id="foo" name="bar" noValidate><input /></Form>
|
|
480
|
+
);
|
|
481
|
+
`,
|
|
482
|
+
'should migrate existing props on `form` into their respective props on `Form`',
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
defineInlineTest(
|
|
486
|
+
{ default: transformer, parser: 'tsx' },
|
|
487
|
+
{},
|
|
488
|
+
`
|
|
489
|
+
import React from 'react';
|
|
490
|
+
import Form from '@atlaskit/form';
|
|
491
|
+
|
|
492
|
+
const FormComponent1 = () => (
|
|
493
|
+
<Form onSubmit={() => {}}>
|
|
494
|
+
{({ formProps }) => (
|
|
495
|
+
<form {...formProps} aria-label="foo" aria-labelledby="bar">
|
|
496
|
+
<input />
|
|
497
|
+
</form>
|
|
498
|
+
)}
|
|
499
|
+
</Form>
|
|
500
|
+
);
|
|
501
|
+
|
|
502
|
+
const FormComponent2 = () => (
|
|
503
|
+
<>
|
|
504
|
+
<Form onSubmit={() => {}}>
|
|
505
|
+
{({ formProps }) => (
|
|
506
|
+
<form {...formProps} aria-label="foo" aria-labelledby="bar">
|
|
507
|
+
<input />
|
|
508
|
+
</form>
|
|
509
|
+
)}
|
|
510
|
+
</Form>
|
|
511
|
+
</>
|
|
512
|
+
);
|
|
513
|
+
|
|
514
|
+
class FormComponent3 extends React.Component {
|
|
515
|
+
render() {
|
|
516
|
+
return (
|
|
517
|
+
<Form onSubmit={() => {}}>
|
|
518
|
+
{({ formProps }) => (
|
|
519
|
+
<form {...formProps} aria-label="foo" aria-labelledby="bar">
|
|
520
|
+
<input />
|
|
521
|
+
</form>
|
|
522
|
+
)}
|
|
523
|
+
</Form>
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const formElement = (
|
|
529
|
+
<Form onSubmit={() => {}}>
|
|
530
|
+
{({ formProps }) => (
|
|
531
|
+
<form {...formProps} aria-label="foo" aria-labelledby="bar">
|
|
532
|
+
<input />
|
|
533
|
+
</form>
|
|
534
|
+
)}
|
|
535
|
+
</Form>
|
|
536
|
+
);
|
|
537
|
+
`,
|
|
538
|
+
`
|
|
539
|
+
import React from 'react';
|
|
540
|
+
import Form from '@atlaskit/form';
|
|
541
|
+
|
|
542
|
+
const FormComponent1 = () => (
|
|
543
|
+
<Form onSubmit={() => {}} label="foo" labelId="bar"><input /></Form>
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
const FormComponent2 = () => (
|
|
547
|
+
<>
|
|
548
|
+
<Form onSubmit={() => {}} label="foo" labelId="bar"><input /></Form>
|
|
549
|
+
</>
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
class FormComponent3 extends React.Component {
|
|
553
|
+
render() {
|
|
554
|
+
return (<Form onSubmit={() => {}} label="foo" labelId="bar"><input /></Form>);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const formElement = (
|
|
559
|
+
<Form onSubmit={() => {}} label="foo" labelId="bar"><input /></Form>
|
|
560
|
+
);
|
|
561
|
+
`,
|
|
562
|
+
'should migrate existing props on `form` into different names',
|
|
563
|
+
);
|
|
564
|
+
|
|
565
|
+
defineInlineTest(
|
|
566
|
+
{ default: transformer, parser: 'tsx' },
|
|
567
|
+
{},
|
|
568
|
+
`
|
|
569
|
+
import React from 'react';
|
|
570
|
+
import Form from '@atlaskit/form';
|
|
571
|
+
|
|
572
|
+
const FormComponent1 = () => (
|
|
573
|
+
<Form onSubmit={() => {}}>
|
|
574
|
+
{({ formProps }) => (
|
|
575
|
+
<form {...formProps} autocomplete="off" id="foo" name="bar" noValidate quu="qux">
|
|
576
|
+
<input />
|
|
577
|
+
</form>
|
|
578
|
+
)}
|
|
579
|
+
</Form>
|
|
580
|
+
);
|
|
581
|
+
|
|
582
|
+
const FormComponent2 = () => (
|
|
583
|
+
<>
|
|
584
|
+
<Form onSubmit={() => {}}>
|
|
585
|
+
{({ formProps }) => (
|
|
586
|
+
<form {...formProps} autocomplete="off" id="foo" name="bar" noValidate quu="qux">
|
|
587
|
+
<input />
|
|
588
|
+
</form>
|
|
589
|
+
)}
|
|
590
|
+
</Form>
|
|
591
|
+
</>
|
|
592
|
+
);
|
|
593
|
+
|
|
594
|
+
class FormComponent3 extends React.Component {
|
|
595
|
+
render() {
|
|
596
|
+
return (
|
|
597
|
+
<Form onSubmit={() => {}}>
|
|
598
|
+
{({ formProps }) => (
|
|
599
|
+
<form {...formProps} autocomplete="off" id="foo" name="bar" noValidate quu="qux">
|
|
600
|
+
<input />
|
|
601
|
+
</form>
|
|
602
|
+
)}
|
|
603
|
+
</Form>
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
const formElement = (
|
|
609
|
+
<Form onSubmit={() => {}}>
|
|
610
|
+
{({ formProps }) => (
|
|
611
|
+
<form {...formProps} autocomplete="off" id="foo" name="bar" noValidate quu="qux">
|
|
612
|
+
<input />
|
|
613
|
+
</form>
|
|
614
|
+
)}
|
|
615
|
+
</Form>
|
|
616
|
+
);
|
|
617
|
+
`,
|
|
618
|
+
`
|
|
619
|
+
import React from 'react';
|
|
620
|
+
import Form from '@atlaskit/form';
|
|
621
|
+
|
|
622
|
+
const FormComponent1 = () => (
|
|
623
|
+
<Form
|
|
624
|
+
onSubmit={() => {}}
|
|
625
|
+
formProps={{
|
|
626
|
+
quu: "qux"
|
|
627
|
+
}}
|
|
628
|
+
autocomplete="off"
|
|
629
|
+
id="foo"
|
|
630
|
+
name="bar"
|
|
631
|
+
noValidate><input /></Form>
|
|
632
|
+
);
|
|
633
|
+
|
|
634
|
+
const FormComponent2 = () => (
|
|
635
|
+
<>
|
|
636
|
+
<Form
|
|
637
|
+
onSubmit={() => {}}
|
|
638
|
+
formProps={{
|
|
639
|
+
quu: "qux"
|
|
640
|
+
}}
|
|
641
|
+
autocomplete="off"
|
|
642
|
+
id="foo"
|
|
643
|
+
name="bar"
|
|
644
|
+
noValidate><input /></Form>
|
|
645
|
+
</>
|
|
646
|
+
);
|
|
647
|
+
|
|
648
|
+
class FormComponent3 extends React.Component {
|
|
649
|
+
render() {
|
|
650
|
+
return (
|
|
651
|
+
<Form
|
|
652
|
+
onSubmit={() => {}}
|
|
653
|
+
formProps={{
|
|
654
|
+
quu: "qux"
|
|
655
|
+
}}
|
|
656
|
+
autocomplete="off"
|
|
657
|
+
id="foo"
|
|
658
|
+
name="bar"
|
|
659
|
+
noValidate><input /></Form>
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
const formElement = (
|
|
665
|
+
<Form
|
|
666
|
+
onSubmit={() => {}}
|
|
667
|
+
formProps={{
|
|
668
|
+
quu: "qux"
|
|
669
|
+
}}
|
|
670
|
+
autocomplete="off"
|
|
671
|
+
id="foo"
|
|
672
|
+
name="bar"
|
|
673
|
+
noValidate><input /></Form>
|
|
674
|
+
);
|
|
675
|
+
`,
|
|
676
|
+
'should migrate existing props on `form` into their respective props on `Form` and also use `formProps` if needed',
|
|
677
|
+
);
|
|
678
|
+
});
|
|
679
|
+
|
|
404
680
|
defineInlineTest(
|
|
405
681
|
{ default: transformer, parser: 'tsx' },
|
|
406
682
|
{},
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
type API,
|
|
3
3
|
type FileInfo,
|
|
4
4
|
type JSCodeshift,
|
|
5
|
+
type JSXAttribute,
|
|
5
6
|
type JSXElement,
|
|
6
7
|
type Options,
|
|
7
8
|
} from 'jscodeshift';
|
|
@@ -16,6 +17,14 @@ import {
|
|
|
16
17
|
} from './utils/helpers';
|
|
17
18
|
|
|
18
19
|
const importPath = '@atlaskit/form';
|
|
20
|
+
const EXISTING_FORM_ATTRIBUTES: Record<string, any> = {
|
|
21
|
+
autocomplete: 'autocomplete',
|
|
22
|
+
id: 'id',
|
|
23
|
+
'aria-label': 'label',
|
|
24
|
+
'aria-labelledby': 'labelId',
|
|
25
|
+
name: 'name',
|
|
26
|
+
noValidate: 'noValidate',
|
|
27
|
+
};
|
|
19
28
|
|
|
20
29
|
const convertToSimpleForm = (j: JSCodeshift, collection: Collection<any>) => {
|
|
21
30
|
const importDeclarationCollection = getImportDeclarationCollection(j, collection, importPath);
|
|
@@ -98,6 +107,8 @@ const convertToSimpleForm = (j: JSCodeshift, collection: Collection<any>) => {
|
|
|
98
107
|
// We are required to do it this way instead of a map to make the types work correctly.
|
|
99
108
|
// We also have to use `any` here and below because typing in this SUCKS.
|
|
100
109
|
const nonFormPropsAttributes: any[] = [];
|
|
110
|
+
// These are the attributes that exist on `Form` that can migrate directly over.
|
|
111
|
+
const existingFormPropsAttributes: JSXAttribute[] = [];
|
|
101
112
|
htmlForm?.openingElement?.attributes?.forEach((attr) => {
|
|
102
113
|
if (otherSpreadPropsSeen) {
|
|
103
114
|
return;
|
|
@@ -112,7 +123,9 @@ const convertToSimpleForm = (j: JSCodeshift, collection: Collection<any>) => {
|
|
|
112
123
|
}
|
|
113
124
|
}
|
|
114
125
|
|
|
115
|
-
|
|
126
|
+
const attrName = attr.name;
|
|
127
|
+
|
|
128
|
+
if (attrName.type !== 'JSXIdentifier') {
|
|
116
129
|
return;
|
|
117
130
|
}
|
|
118
131
|
|
|
@@ -120,6 +133,11 @@ const convertToSimpleForm = (j: JSCodeshift, collection: Collection<any>) => {
|
|
|
120
133
|
return;
|
|
121
134
|
}
|
|
122
135
|
|
|
136
|
+
if (Object.keys(EXISTING_FORM_ATTRIBUTES).includes(attrName.name)) {
|
|
137
|
+
existingFormPropsAttributes.push(attr);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
123
141
|
let value: any;
|
|
124
142
|
if (attr.value === null) {
|
|
125
143
|
value = j.booleanLiteral(true) as any;
|
|
@@ -129,7 +147,7 @@ const convertToSimpleForm = (j: JSCodeshift, collection: Collection<any>) => {
|
|
|
129
147
|
value = attr.value as any;
|
|
130
148
|
}
|
|
131
149
|
|
|
132
|
-
nonFormPropsAttributes.push(j.property('init',
|
|
150
|
+
nonFormPropsAttributes.push(j.property('init', attrName, value));
|
|
133
151
|
});
|
|
134
152
|
|
|
135
153
|
// We don't know how to handle other spread props in the formProps object, so ignore it
|
|
@@ -145,6 +163,16 @@ const convertToSimpleForm = (j: JSCodeshift, collection: Collection<any>) => {
|
|
|
145
163
|
);
|
|
146
164
|
addJSXAttributeToJSXElement(j, jsxElementPath, formPropsAttr, 1);
|
|
147
165
|
}
|
|
166
|
+
existingFormPropsAttributes.forEach((attr) => {
|
|
167
|
+
// add existing props to new `Form`
|
|
168
|
+
const fromName = attr.name.name;
|
|
169
|
+
if (typeof fromName !== 'string') {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const toName = EXISTING_FORM_ATTRIBUTES[fromName];
|
|
173
|
+
attr.name.name = toName;
|
|
174
|
+
addJSXAttributeToJSXElement(j, jsxElementPath, attr, 1);
|
|
175
|
+
});
|
|
148
176
|
|
|
149
177
|
// replace functional child with inner (all children of HTML `form`)
|
|
150
178
|
const htmlFormChildren = htmlForm.children?.filter((child) => child.type !== 'JSXText');
|
package/dist/cjs/form.js
CHANGED
|
@@ -5,8 +5,7 @@ var _typeof = require("@babel/runtime/helpers/typeof");
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", {
|
|
6
6
|
value: true
|
|
7
7
|
});
|
|
8
|
-
exports.IsDisabledContext = exports.FormContext = void 0;
|
|
9
|
-
exports.default = Form;
|
|
8
|
+
exports.default = exports.IsDisabledContext = exports.FormContext = void 0;
|
|
10
9
|
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
11
10
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
12
11
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
@@ -14,6 +13,8 @@ var _react = _interopRequireWildcard(require("react"));
|
|
|
14
13
|
var _finalForm = require("final-form");
|
|
15
14
|
var _finalFormFocus = _interopRequireDefault(require("final-form-focus"));
|
|
16
15
|
var _set = _interopRequireDefault(require("lodash/set"));
|
|
16
|
+
var _forwardRefWithGeneric = _interopRequireDefault(require("@atlaskit/ds-lib/forward-ref-with-generic"));
|
|
17
|
+
var _mergeRefs = _interopRequireDefault(require("@atlaskit/ds-lib/merge-refs"));
|
|
17
18
|
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
18
19
|
var _utils = require("./utils");
|
|
19
20
|
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); }
|
|
@@ -42,10 +43,17 @@ var FormContext = exports.FormContext = /*#__PURE__*/(0, _react.createContext)({
|
|
|
42
43
|
* An is disabled context creates the context for when a value is disabled.
|
|
43
44
|
*/
|
|
44
45
|
var IsDisabledContext = exports.IsDisabledContext = /*#__PURE__*/(0, _react.createContext)(false);
|
|
45
|
-
function
|
|
46
|
-
var
|
|
46
|
+
var FormBase = function FormBase(props, ref) {
|
|
47
|
+
var autocomplete = props.autocomplete,
|
|
48
|
+
userProvidedFormProps = props.formProps,
|
|
49
|
+
id = props.id,
|
|
50
|
+
label = props.label,
|
|
51
|
+
labelId = props.labelId,
|
|
52
|
+
name = props.name,
|
|
53
|
+
noValidate = props.noValidate,
|
|
47
54
|
onSubmit = props.onSubmit,
|
|
48
|
-
testId = props.testId
|
|
55
|
+
testId = props.testId,
|
|
56
|
+
xcss = props.xcss;
|
|
49
57
|
var formRef = (0, _react.useRef)(null);
|
|
50
58
|
var onSubmitRef = (0, _react.useRef)(onSubmit);
|
|
51
59
|
onSubmitRef.current = onSubmit;
|
|
@@ -146,14 +154,29 @@ function Form(props) {
|
|
|
146
154
|
subscribe: form.subscribe
|
|
147
155
|
};
|
|
148
156
|
}, [registerField, getCurrentValue, form.subscribe]);
|
|
157
|
+
var conditionalFormProps = {
|
|
158
|
+
autocomplete: autocomplete,
|
|
159
|
+
className: xcss,
|
|
160
|
+
id: id,
|
|
161
|
+
'aria-label': label,
|
|
162
|
+
'aria-labelledby': labelId,
|
|
163
|
+
name: name,
|
|
164
|
+
noValidate: noValidate,
|
|
165
|
+
'data-testid': testId
|
|
166
|
+
};
|
|
149
167
|
|
|
150
168
|
// Abstracting so we can use the same for both rendering patterns
|
|
151
|
-
var formProps =
|
|
169
|
+
var formProps = {
|
|
152
170
|
onKeyDown: handleKeyDown,
|
|
153
171
|
onSubmit: handleSubmit,
|
|
154
|
-
ref: formRef
|
|
155
|
-
}
|
|
156
|
-
|
|
172
|
+
ref: ref ? (0, _mergeRefs.default)([ref, formRef]) : formRef
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// We don't want to add undefined values to the component
|
|
176
|
+
Object.keys(conditionalFormProps).forEach(function (attr) {
|
|
177
|
+
if (conditionalFormProps[attr] !== undefined) {
|
|
178
|
+
formProps[attr] = conditionalFormProps[attr];
|
|
179
|
+
}
|
|
157
180
|
});
|
|
158
181
|
var childrenContent = function () {
|
|
159
182
|
if (typeof children === 'function') {
|
|
@@ -183,4 +206,16 @@ function Form(props) {
|
|
|
183
206
|
}, /*#__PURE__*/_react.default.createElement(IsDisabledContext.Provider, {
|
|
184
207
|
value: isDisabled
|
|
185
208
|
}, childrenContent));
|
|
186
|
-
}
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* __Form__
|
|
213
|
+
*
|
|
214
|
+
* A form allows users to input information.
|
|
215
|
+
*
|
|
216
|
+
* - [Examples](https://atlassian.design/components/form/examples)
|
|
217
|
+
* - [Code](https://atlassian.design/components/form/code)
|
|
218
|
+
* - [Usage](https://atlassian.design/components/form/usage)
|
|
219
|
+
*/
|
|
220
|
+
var Form = (0, _forwardRefWithGeneric.default)(FormBase);
|
|
221
|
+
var _default = exports.default = Form;
|
package/dist/es2019/form.js
CHANGED
|
@@ -3,6 +3,8 @@ import React, { createContext, useCallback, useEffect, useMemo, useRef, useState
|
|
|
3
3
|
import { createForm } from 'final-form';
|
|
4
4
|
import createDecorator from 'final-form-focus';
|
|
5
5
|
import set from 'lodash/set';
|
|
6
|
+
import forwardRefWithGeneric from '@atlaskit/ds-lib/forward-ref-with-generic';
|
|
7
|
+
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
|
|
6
8
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
7
9
|
import { getFirstErrorField } from './utils';
|
|
8
10
|
/**
|
|
@@ -26,11 +28,18 @@ export const FormContext = /*#__PURE__*/createContext({
|
|
|
26
28
|
* An is disabled context creates the context for when a value is disabled.
|
|
27
29
|
*/
|
|
28
30
|
export const IsDisabledContext = /*#__PURE__*/createContext(false);
|
|
29
|
-
|
|
31
|
+
const FormBase = (props, ref) => {
|
|
30
32
|
const {
|
|
33
|
+
autocomplete,
|
|
31
34
|
formProps: userProvidedFormProps,
|
|
35
|
+
id,
|
|
36
|
+
label,
|
|
37
|
+
labelId,
|
|
38
|
+
name,
|
|
39
|
+
noValidate,
|
|
32
40
|
onSubmit,
|
|
33
|
-
testId
|
|
41
|
+
testId,
|
|
42
|
+
xcss
|
|
34
43
|
} = props;
|
|
35
44
|
const formRef = useRef(null);
|
|
36
45
|
const onSubmitRef = useRef(onSubmit);
|
|
@@ -124,16 +133,30 @@ export default function Form(props) {
|
|
|
124
133
|
subscribe: form.subscribe
|
|
125
134
|
};
|
|
126
135
|
}, [registerField, getCurrentValue, form.subscribe]);
|
|
136
|
+
const conditionalFormProps = {
|
|
137
|
+
autocomplete,
|
|
138
|
+
className: xcss,
|
|
139
|
+
id,
|
|
140
|
+
'aria-label': label,
|
|
141
|
+
'aria-labelledby': labelId,
|
|
142
|
+
name,
|
|
143
|
+
noValidate,
|
|
144
|
+
'data-testid': testId
|
|
145
|
+
};
|
|
127
146
|
|
|
128
147
|
// Abstracting so we can use the same for both rendering patterns
|
|
129
148
|
const formProps = {
|
|
130
149
|
onKeyDown: handleKeyDown,
|
|
131
150
|
onSubmit: handleSubmit,
|
|
132
|
-
ref: formRef
|
|
133
|
-
...(testId && {
|
|
134
|
-
'data-testid': testId
|
|
135
|
-
})
|
|
151
|
+
ref: ref ? mergeRefs([ref, formRef]) : formRef
|
|
136
152
|
};
|
|
153
|
+
|
|
154
|
+
// We don't want to add undefined values to the component
|
|
155
|
+
Object.keys(conditionalFormProps).forEach(attr => {
|
|
156
|
+
if (conditionalFormProps[attr] !== undefined) {
|
|
157
|
+
formProps[attr] = conditionalFormProps[attr];
|
|
158
|
+
}
|
|
159
|
+
});
|
|
137
160
|
const childrenContent = (() => {
|
|
138
161
|
if (typeof children === 'function') {
|
|
139
162
|
const result = children.length > 0 ? children({
|
|
@@ -159,4 +182,16 @@ export default function Form(props) {
|
|
|
159
182
|
}, /*#__PURE__*/React.createElement(IsDisabledContext.Provider, {
|
|
160
183
|
value: isDisabled
|
|
161
184
|
}, childrenContent));
|
|
162
|
-
}
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* __Form__
|
|
189
|
+
*
|
|
190
|
+
* A form allows users to input information.
|
|
191
|
+
*
|
|
192
|
+
* - [Examples](https://atlassian.design/components/form/examples)
|
|
193
|
+
* - [Code](https://atlassian.design/components/form/code)
|
|
194
|
+
* - [Usage](https://atlassian.design/components/form/usage)
|
|
195
|
+
*/
|
|
196
|
+
const Form = forwardRefWithGeneric(FormBase);
|
|
197
|
+
export default Form;
|
package/dist/esm/form.js
CHANGED
|
@@ -7,6 +7,8 @@ import React, { createContext, useCallback, useEffect, useMemo, useRef, useState
|
|
|
7
7
|
import { createForm } from 'final-form';
|
|
8
8
|
import createDecorator from 'final-form-focus';
|
|
9
9
|
import set from 'lodash/set';
|
|
10
|
+
import forwardRefWithGeneric from '@atlaskit/ds-lib/forward-ref-with-generic';
|
|
11
|
+
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
|
|
10
12
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
11
13
|
import { getFirstErrorField } from './utils';
|
|
12
14
|
/**
|
|
@@ -32,10 +34,17 @@ export var FormContext = /*#__PURE__*/createContext({
|
|
|
32
34
|
* An is disabled context creates the context for when a value is disabled.
|
|
33
35
|
*/
|
|
34
36
|
export var IsDisabledContext = /*#__PURE__*/createContext(false);
|
|
35
|
-
|
|
36
|
-
var
|
|
37
|
+
var FormBase = function FormBase(props, ref) {
|
|
38
|
+
var autocomplete = props.autocomplete,
|
|
39
|
+
userProvidedFormProps = props.formProps,
|
|
40
|
+
id = props.id,
|
|
41
|
+
label = props.label,
|
|
42
|
+
labelId = props.labelId,
|
|
43
|
+
name = props.name,
|
|
44
|
+
noValidate = props.noValidate,
|
|
37
45
|
onSubmit = props.onSubmit,
|
|
38
|
-
testId = props.testId
|
|
46
|
+
testId = props.testId,
|
|
47
|
+
xcss = props.xcss;
|
|
39
48
|
var formRef = useRef(null);
|
|
40
49
|
var onSubmitRef = useRef(onSubmit);
|
|
41
50
|
onSubmitRef.current = onSubmit;
|
|
@@ -136,14 +145,29 @@ export default function Form(props) {
|
|
|
136
145
|
subscribe: form.subscribe
|
|
137
146
|
};
|
|
138
147
|
}, [registerField, getCurrentValue, form.subscribe]);
|
|
148
|
+
var conditionalFormProps = {
|
|
149
|
+
autocomplete: autocomplete,
|
|
150
|
+
className: xcss,
|
|
151
|
+
id: id,
|
|
152
|
+
'aria-label': label,
|
|
153
|
+
'aria-labelledby': labelId,
|
|
154
|
+
name: name,
|
|
155
|
+
noValidate: noValidate,
|
|
156
|
+
'data-testid': testId
|
|
157
|
+
};
|
|
139
158
|
|
|
140
159
|
// Abstracting so we can use the same for both rendering patterns
|
|
141
|
-
var formProps =
|
|
160
|
+
var formProps = {
|
|
142
161
|
onKeyDown: handleKeyDown,
|
|
143
162
|
onSubmit: handleSubmit,
|
|
144
|
-
ref: formRef
|
|
145
|
-
}
|
|
146
|
-
|
|
163
|
+
ref: ref ? mergeRefs([ref, formRef]) : formRef
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// We don't want to add undefined values to the component
|
|
167
|
+
Object.keys(conditionalFormProps).forEach(function (attr) {
|
|
168
|
+
if (conditionalFormProps[attr] !== undefined) {
|
|
169
|
+
formProps[attr] = conditionalFormProps[attr];
|
|
170
|
+
}
|
|
147
171
|
});
|
|
148
172
|
var childrenContent = function () {
|
|
149
173
|
if (typeof children === 'function') {
|
|
@@ -173,4 +197,16 @@ export default function Form(props) {
|
|
|
173
197
|
}, /*#__PURE__*/React.createElement(IsDisabledContext.Provider, {
|
|
174
198
|
value: isDisabled
|
|
175
199
|
}, childrenContent));
|
|
176
|
-
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* __Form__
|
|
204
|
+
*
|
|
205
|
+
* A form allows users to input information.
|
|
206
|
+
*
|
|
207
|
+
* - [Examples](https://atlassian.design/components/form/examples)
|
|
208
|
+
* - [Code](https://atlassian.design/components/form/code)
|
|
209
|
+
* - [Usage](https://atlassian.design/components/form/usage)
|
|
210
|
+
*/
|
|
211
|
+
var Form = forwardRefWithGeneric(FormBase);
|
|
212
|
+
export default Form;
|
package/dist/types/form.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { type ReactNode } from 'react';
|
|
2
2
|
import { type FieldConfig, type FieldSubscriber, type FieldSubscription, type FormApi, type FormState, type Unsubscribe } from 'final-form';
|
|
3
|
+
import type { StrictXCSSProp, XCSSAllProperties, XCSSAllPseudos } from '@atlaskit/css';
|
|
3
4
|
import { type OnSubmitHandler } from './types';
|
|
4
5
|
type DefaultValue<FieldValue> = (value?: FieldValue) => FieldValue;
|
|
5
6
|
type RegisterField = <FieldValue>(name: string, defaultValue: FieldValue | DefaultValue<FieldValue>, subscriber: FieldSubscriber<FieldValue>, subscription: FieldSubscription, config: FieldConfig<FieldValue>) => Unsubscribe;
|
|
@@ -21,7 +22,7 @@ export declare const FormContext: React.Context<{
|
|
|
21
22
|
*/
|
|
22
23
|
export declare const IsDisabledContext: React.Context<boolean>;
|
|
23
24
|
interface FormChildrenProps {
|
|
24
|
-
ref: React.RefObject<HTMLFormElement
|
|
25
|
+
ref: React.RefObject<HTMLFormElement> | ((value: HTMLFormElement | null) => void);
|
|
25
26
|
onSubmit: (event?: React.FormEvent<HTMLFormElement> | React.SyntheticEvent<HTMLElement>) => void;
|
|
26
27
|
onKeyDown: (event: React.KeyboardEvent<HTMLElement>) => void;
|
|
27
28
|
}
|
|
@@ -37,11 +38,22 @@ type FormChildrenArgs<FormValues> = {
|
|
|
37
38
|
reset: (initialValues?: FormValues) => void;
|
|
38
39
|
};
|
|
39
40
|
type ExcludeReservedFormProps = {
|
|
41
|
+
autocomplete?: never;
|
|
42
|
+
id?: never;
|
|
43
|
+
label?: never;
|
|
44
|
+
labelId?: never;
|
|
40
45
|
onKeyDown?: never;
|
|
41
46
|
onSubmit?: never;
|
|
47
|
+
name?: never;
|
|
48
|
+
noValidate?: never;
|
|
42
49
|
ref?: never;
|
|
50
|
+
xcss?: never;
|
|
43
51
|
};
|
|
44
52
|
export interface FormProps<FormValues> {
|
|
53
|
+
/**
|
|
54
|
+
* Indicates whether the value of the form's controls can be automatically completed by the browser. It is `on` by default.
|
|
55
|
+
*/
|
|
56
|
+
autocomplete?: 'off' | 'on';
|
|
45
57
|
/**
|
|
46
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`.
|
|
47
59
|
* You can read more about these props in [react-final form documentation](https://final-form.org/docs/final-form/types/FormState).
|
|
@@ -56,17 +68,53 @@ export interface FormProps<FormValues> {
|
|
|
56
68
|
[x: string]: any;
|
|
57
69
|
} & ExcludeReservedFormProps;
|
|
58
70
|
/**
|
|
59
|
-
*
|
|
71
|
+
* `id` attribute applied to the `form` element.
|
|
72
|
+
*/
|
|
73
|
+
id?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Accessible name to be applied to the form element. Maps to the `aria-label` attribute.
|
|
76
|
+
*/
|
|
77
|
+
label?: string;
|
|
78
|
+
/**
|
|
79
|
+
* ID of the element that has the accessible name to be applied to the form element. Maps to the `aria-labelledby` attribute.
|
|
80
|
+
*/
|
|
81
|
+
labelId?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Event handler called when the form is submitted. Fields must be free of validation errors.
|
|
60
84
|
*/
|
|
61
85
|
onSubmit: OnSubmitHandler<FormValues>;
|
|
62
86
|
/**
|
|
63
|
-
*
|
|
87
|
+
* Sets the form and its fields as disabled. Users cannot edit or focus on the fields.
|
|
64
88
|
*/
|
|
65
89
|
isDisabled?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* `name` attribute applied to the `form` element.
|
|
92
|
+
*/
|
|
93
|
+
name?: string;
|
|
94
|
+
/**
|
|
95
|
+
* Indicates if the inputs within the form will bypass HTML5 constraint
|
|
96
|
+
* validation when submitted. This is not recommended to be used because it
|
|
97
|
+
* can cause experiences to be inaccessible. It is `false` by default but will
|
|
98
|
+
* be set to `true` in the future to increase accessibility, so it is **not recommended**.
|
|
99
|
+
*/
|
|
100
|
+
noValidate?: boolean;
|
|
66
101
|
/**
|
|
67
102
|
* A test identifier for the form element. This will be applied as `data-testid` attribute.
|
|
68
103
|
*/
|
|
69
104
|
testId?: string;
|
|
105
|
+
/**
|
|
106
|
+
* Apply a subset of permitted styles powered by Atlassian Design System design tokens.
|
|
107
|
+
*/
|
|
108
|
+
xcss?: StrictXCSSProp<XCSSAllProperties, XCSSAllPseudos>;
|
|
70
109
|
}
|
|
71
|
-
|
|
72
|
-
|
|
110
|
+
/**
|
|
111
|
+
* __Form__
|
|
112
|
+
*
|
|
113
|
+
* A form allows users to input information.
|
|
114
|
+
*
|
|
115
|
+
* - [Examples](https://atlassian.design/components/form/examples)
|
|
116
|
+
* - [Code](https://atlassian.design/components/form/code)
|
|
117
|
+
* - [Usage](https://atlassian.design/components/form/usage)
|
|
118
|
+
*/
|
|
119
|
+
declare const Form: <FormValues extends Record<string, any> = {}>(props: FormProps<FormValues> & React.RefAttributes<HTMLFormElement>) => React.ReactElement | null;
|
|
120
|
+
export default Form;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { type ReactNode } from 'react';
|
|
2
2
|
import { type FieldConfig, type FieldSubscriber, type FieldSubscription, type FormApi, type FormState, type Unsubscribe } from 'final-form';
|
|
3
|
+
import type { StrictXCSSProp, XCSSAllProperties, XCSSAllPseudos } from '@atlaskit/css';
|
|
3
4
|
import { type OnSubmitHandler } from './types';
|
|
4
5
|
type DefaultValue<FieldValue> = (value?: FieldValue) => FieldValue;
|
|
5
6
|
type RegisterField = <FieldValue>(name: string, defaultValue: FieldValue | DefaultValue<FieldValue>, subscriber: FieldSubscriber<FieldValue>, subscription: FieldSubscription, config: FieldConfig<FieldValue>) => Unsubscribe;
|
|
@@ -21,7 +22,7 @@ export declare const FormContext: React.Context<{
|
|
|
21
22
|
*/
|
|
22
23
|
export declare const IsDisabledContext: React.Context<boolean>;
|
|
23
24
|
interface FormChildrenProps {
|
|
24
|
-
ref: React.RefObject<HTMLFormElement
|
|
25
|
+
ref: React.RefObject<HTMLFormElement> | ((value: HTMLFormElement | null) => void);
|
|
25
26
|
onSubmit: (event?: React.FormEvent<HTMLFormElement> | React.SyntheticEvent<HTMLElement>) => void;
|
|
26
27
|
onKeyDown: (event: React.KeyboardEvent<HTMLElement>) => void;
|
|
27
28
|
}
|
|
@@ -37,11 +38,22 @@ type FormChildrenArgs<FormValues> = {
|
|
|
37
38
|
reset: (initialValues?: FormValues) => void;
|
|
38
39
|
};
|
|
39
40
|
type ExcludeReservedFormProps = {
|
|
41
|
+
autocomplete?: never;
|
|
42
|
+
id?: never;
|
|
43
|
+
label?: never;
|
|
44
|
+
labelId?: never;
|
|
40
45
|
onKeyDown?: never;
|
|
41
46
|
onSubmit?: never;
|
|
47
|
+
name?: never;
|
|
48
|
+
noValidate?: never;
|
|
42
49
|
ref?: never;
|
|
50
|
+
xcss?: never;
|
|
43
51
|
};
|
|
44
52
|
export interface FormProps<FormValues> {
|
|
53
|
+
/**
|
|
54
|
+
* Indicates whether the value of the form's controls can be automatically completed by the browser. It is `on` by default.
|
|
55
|
+
*/
|
|
56
|
+
autocomplete?: 'off' | 'on';
|
|
45
57
|
/**
|
|
46
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`.
|
|
47
59
|
* You can read more about these props in [react-final form documentation](https://final-form.org/docs/final-form/types/FormState).
|
|
@@ -56,17 +68,53 @@ export interface FormProps<FormValues> {
|
|
|
56
68
|
[x: string]: any;
|
|
57
69
|
} & ExcludeReservedFormProps;
|
|
58
70
|
/**
|
|
59
|
-
*
|
|
71
|
+
* `id` attribute applied to the `form` element.
|
|
72
|
+
*/
|
|
73
|
+
id?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Accessible name to be applied to the form element. Maps to the `aria-label` attribute.
|
|
76
|
+
*/
|
|
77
|
+
label?: string;
|
|
78
|
+
/**
|
|
79
|
+
* ID of the element that has the accessible name to be applied to the form element. Maps to the `aria-labelledby` attribute.
|
|
80
|
+
*/
|
|
81
|
+
labelId?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Event handler called when the form is submitted. Fields must be free of validation errors.
|
|
60
84
|
*/
|
|
61
85
|
onSubmit: OnSubmitHandler<FormValues>;
|
|
62
86
|
/**
|
|
63
|
-
*
|
|
87
|
+
* Sets the form and its fields as disabled. Users cannot edit or focus on the fields.
|
|
64
88
|
*/
|
|
65
89
|
isDisabled?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* `name` attribute applied to the `form` element.
|
|
92
|
+
*/
|
|
93
|
+
name?: string;
|
|
94
|
+
/**
|
|
95
|
+
* Indicates if the inputs within the form will bypass HTML5 constraint
|
|
96
|
+
* validation when submitted. This is not recommended to be used because it
|
|
97
|
+
* can cause experiences to be inaccessible. It is `false` by default but will
|
|
98
|
+
* be set to `true` in the future to increase accessibility, so it is **not recommended**.
|
|
99
|
+
*/
|
|
100
|
+
noValidate?: boolean;
|
|
66
101
|
/**
|
|
67
102
|
* A test identifier for the form element. This will be applied as `data-testid` attribute.
|
|
68
103
|
*/
|
|
69
104
|
testId?: string;
|
|
105
|
+
/**
|
|
106
|
+
* Apply a subset of permitted styles powered by Atlassian Design System design tokens.
|
|
107
|
+
*/
|
|
108
|
+
xcss?: StrictXCSSProp<XCSSAllProperties, XCSSAllPseudos>;
|
|
70
109
|
}
|
|
71
|
-
|
|
72
|
-
|
|
110
|
+
/**
|
|
111
|
+
* __Form__
|
|
112
|
+
*
|
|
113
|
+
* A form allows users to input information.
|
|
114
|
+
*
|
|
115
|
+
* - [Examples](https://atlassian.design/components/form/examples)
|
|
116
|
+
* - [Code](https://atlassian.design/components/form/code)
|
|
117
|
+
* - [Usage](https://atlassian.design/components/form/usage)
|
|
118
|
+
*/
|
|
119
|
+
declare const Form: <FormValues extends Record<string, any> = {}>(props: FormProps<FormValues> & React.RefAttributes<HTMLFormElement>) => React.ReactElement | null;
|
|
120
|
+
export default Form;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/form",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.2.0",
|
|
4
4
|
"description": "A form allows users to input information.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@atlaskit/docs": "^11.1.0",
|
|
53
53
|
"@atlaskit/link": "^3.2.0",
|
|
54
54
|
"@atlaskit/lozenge": "^13.0.0",
|
|
55
|
-
"@atlaskit/modal-dialog": "^14.
|
|
55
|
+
"@atlaskit/modal-dialog": "^14.4.0",
|
|
56
56
|
"@atlaskit/radio": "^8.3.0",
|
|
57
57
|
"@atlaskit/range": "^9.2.0",
|
|
58
58
|
"@atlaskit/section-message": "^8.7.0",
|