@instructure/ui-form-field 9.11.0 → 9.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/es/FormField/index.js +5 -1
- package/es/FormFieldGroup/__new-tests__/FormFieldGroup.test.js +4 -4
- package/es/FormFieldGroup/index.js +18 -4
- package/es/FormFieldLabel/index.js +6 -6
- package/es/FormFieldLayout/__new-tests__/FormFieldLayout.test.js +10 -8
- package/es/FormFieldLayout/index.js +79 -58
- package/es/FormFieldLayout/props.js +1 -6
- package/es/FormFieldLayout/styles.js +105 -9
- package/es/FormFieldLayout/theme.js +56 -0
- package/es/FormFieldMessages/props.js +3 -2
- package/es/FormFieldMessages/styles.js +5 -3
- package/es/FormPropTypes.js +6 -0
- package/lib/FormField/index.js +5 -1
- package/lib/FormFieldGroup/__new-tests__/FormFieldGroup.test.js +4 -4
- package/lib/FormFieldGroup/index.js +18 -4
- package/lib/FormFieldLabel/index.js +6 -5
- package/lib/FormFieldLayout/__new-tests__/FormFieldLayout.test.js +9 -7
- package/lib/FormFieldLayout/index.js +77 -58
- package/lib/FormFieldLayout/props.js +1 -6
- package/lib/FormFieldLayout/styles.js +105 -9
- package/lib/FormFieldLayout/theme.js +62 -0
- package/lib/FormFieldMessages/props.js +3 -2
- package/lib/FormFieldMessages/styles.js +5 -3
- package/lib/FormPropTypes.js +6 -0
- package/package.json +15 -15
- package/src/FormField/README.md +31 -3
- package/src/FormField/index.tsx +3 -0
- package/src/FormFieldGroup/__new-tests__/FormFieldGroup.test.tsx +4 -6
- package/src/FormFieldGroup/index.tsx +41 -6
- package/src/FormFieldLabel/index.tsx +8 -3
- package/src/FormFieldLayout/__new-tests__/FormFieldLayout.test.tsx +6 -8
- package/src/FormFieldLayout/index.tsx +83 -100
- package/src/FormFieldLayout/props.ts +30 -7
- package/src/FormFieldLayout/styles.ts +124 -12
- package/src/FormFieldLayout/theme.ts +59 -0
- package/src/FormFieldMessages/props.ts +8 -2
- package/src/FormFieldMessages/styles.ts +5 -4
- package/src/FormPropTypes.ts +4 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/FormField/index.d.ts.map +1 -1
- package/types/FormFieldGroup/index.d.ts +1 -0
- package/types/FormFieldGroup/index.d.ts.map +1 -1
- package/types/FormFieldLabel/index.d.ts +2 -2
- package/types/FormFieldLabel/index.d.ts.map +1 -1
- package/types/FormFieldLayout/index.d.ts +8 -7
- package/types/FormFieldLayout/index.d.ts.map +1 -1
- package/types/FormFieldLayout/props.d.ts +27 -3
- package/types/FormFieldLayout/props.d.ts.map +1 -1
- package/types/FormFieldLayout/styles.d.ts +4 -3
- package/types/FormFieldLayout/styles.d.ts.map +1 -1
- package/types/FormFieldLayout/theme.d.ts +10 -0
- package/types/FormFieldLayout/theme.d.ts.map +1 -0
- package/types/FormFieldMessages/index.d.ts +8 -2
- package/types/FormFieldMessages/index.d.ts.map +1 -1
- package/types/FormFieldMessages/props.d.ts +5 -0
- package/types/FormFieldMessages/props.d.ts.map +1 -1
- package/types/FormFieldMessages/styles.d.ts +2 -3
- package/types/FormFieldMessages/styles.d.ts.map +1 -1
- package/types/FormPropTypes.d.ts +3 -0
- package/types/FormPropTypes.d.ts.map +1 -1
package/es/FormPropTypes.js
CHANGED
|
@@ -25,6 +25,12 @@
|
|
|
25
25
|
import PropTypes from 'prop-types';
|
|
26
26
|
const formMessageTypePropType = PropTypes.oneOf(['error', 'newError', 'hint', 'success', 'screenreader-only']);
|
|
27
27
|
const formMessageChildPropType = PropTypes.node;
|
|
28
|
+
|
|
29
|
+
// TODO it will be easier if this would be just a string
|
|
30
|
+
/**
|
|
31
|
+
* The text to display in the form message
|
|
32
|
+
*/
|
|
33
|
+
|
|
28
34
|
/**
|
|
29
35
|
* ---
|
|
30
36
|
* category: utilities/form
|
package/lib/FormField/index.js
CHANGED
|
@@ -55,7 +55,11 @@ class FormField extends _react.Component {
|
|
|
55
55
|
return /*#__PURE__*/_react.default.createElement(_FormFieldLayout.FormFieldLayout, Object.assign({}, (0, _omitProps.omitProps)(this.props, FormField.allowedProps), (0, _pickProps.pickProps)(this.props, _FormFieldLayout.FormFieldLayout.allowedProps), {
|
|
56
56
|
label: this.props.label,
|
|
57
57
|
vAlign: this.props.vAlign,
|
|
58
|
-
as: "label"
|
|
58
|
+
as: "label"
|
|
59
|
+
// This makes the control in focus when the label is clicked
|
|
60
|
+
// This is needed to prevent the wrong element to be focused, e.g.
|
|
61
|
+
// multi selects Tag-s
|
|
62
|
+
,
|
|
59
63
|
htmlFor: this.props.id,
|
|
60
64
|
elementRef: this.handleRef
|
|
61
65
|
}));
|
|
@@ -48,7 +48,7 @@ describe('<FormFieldGroup />', () => {
|
|
|
48
48
|
description: "Please enter your full name"
|
|
49
49
|
}, /*#__PURE__*/_react.default.createElement("label", null, "First: ", /*#__PURE__*/_react.default.createElement("input", null)), /*#__PURE__*/_react.default.createElement("label", null, "Middle: ", /*#__PURE__*/_react.default.createElement("input", null)), /*#__PURE__*/_react.default.createElement("label", null, "Last: ", /*#__PURE__*/_react.default.createElement("input", null))))),
|
|
50
50
|
container = _render.container;
|
|
51
|
-
const formFieldGroup = container.querySelector("
|
|
51
|
+
const formFieldGroup = container.querySelector("span[class$='-formFieldLayout__label']");
|
|
52
52
|
const firstNameInput = _react2.screen.getByLabelText('First:');
|
|
53
53
|
const middleNameInput = _react2.screen.getByLabelText('Middle:');
|
|
54
54
|
const lastNameInput = _react2.screen.getByLabelText('Last:');
|
|
@@ -66,7 +66,7 @@ describe('<FormFieldGroup />', () => {
|
|
|
66
66
|
description: "Please enter your full name"
|
|
67
67
|
}, children)),
|
|
68
68
|
container = _render2.container;
|
|
69
|
-
const formFieldGroup = container.querySelector(
|
|
69
|
+
const formFieldGroup = container.querySelector('label');
|
|
70
70
|
expect(formFieldGroup).toBeInTheDocument();
|
|
71
71
|
});
|
|
72
72
|
it('links the messages to the fieldset via aria-describedby', () => {
|
|
@@ -88,13 +88,13 @@ describe('<FormFieldGroup />', () => {
|
|
|
88
88
|
expect(message).toHaveTextContent('Invalid name');
|
|
89
89
|
expect(message).toHaveAttribute('id', messagesId);
|
|
90
90
|
});
|
|
91
|
-
it('displays description message inside the
|
|
91
|
+
it('displays description message inside the label', () => {
|
|
92
92
|
const description = 'Please enter your full name';
|
|
93
93
|
const _render4 = (0, _react2.render)( /*#__PURE__*/_react.default.createElement(_index.FormFieldGroup, {
|
|
94
94
|
description: description
|
|
95
95
|
}, _label5 || (_label5 = /*#__PURE__*/_react.default.createElement("label", null, "First: ", /*#__PURE__*/_react.default.createElement("input", null))), _label6 || (_label6 = /*#__PURE__*/_react.default.createElement("label", null, "Middle: ", /*#__PURE__*/_react.default.createElement("input", null))), _label7 || (_label7 = /*#__PURE__*/_react.default.createElement("label", null, "Last: ", /*#__PURE__*/_react.default.createElement("input", null))))),
|
|
96
96
|
container = _render4.container;
|
|
97
|
-
const legend = container.querySelector("
|
|
97
|
+
const legend = container.querySelector("span[class$='-formFieldLayout__label']");
|
|
98
98
|
expect(legend).toBeInTheDocument();
|
|
99
99
|
expect(legend).toHaveTextContent(description);
|
|
100
100
|
});
|
|
@@ -67,13 +67,17 @@ let FormFieldGroup = exports.FormFieldGroup = (_dec = (0, _emotion.withStyle)(_s
|
|
|
67
67
|
(_this$props$makeStyle2 = (_this$props2 = this.props).makeStyles) === null || _this$props$makeStyle2 === void 0 ? void 0 : _this$props$makeStyle2.call(_this$props2, this.makeStylesVariables);
|
|
68
68
|
}
|
|
69
69
|
get makeStylesVariables() {
|
|
70
|
+
// new form errors dont need borders
|
|
71
|
+
const oldInvalid = !!this.props.messages && this.props.messages.findIndex(message => {
|
|
72
|
+
return message.type === 'error';
|
|
73
|
+
}) >= 0;
|
|
70
74
|
return {
|
|
71
|
-
invalid:
|
|
75
|
+
invalid: oldInvalid
|
|
72
76
|
};
|
|
73
77
|
}
|
|
74
78
|
get invalid() {
|
|
75
79
|
return !!this.props.messages && this.props.messages.findIndex(message => {
|
|
76
|
-
return message.type === 'error';
|
|
80
|
+
return message.type === 'error' || message.type === 'newError';
|
|
77
81
|
}) >= 0;
|
|
78
82
|
}
|
|
79
83
|
renderColumns() {
|
|
@@ -105,12 +109,21 @@ let FormFieldGroup = exports.FormFieldGroup = (_dec = (0, _emotion.withStyle)(_s
|
|
|
105
109
|
makeStyles = _this$props3.makeStyles,
|
|
106
110
|
isGroup = _this$props3.isGroup,
|
|
107
111
|
props = (0, _objectWithoutProperties2.default)(_this$props3, _excluded);
|
|
112
|
+
// This is quite ugly, but according to ARIA spec the `aria-invalid` prop
|
|
113
|
+
// can only be used with certain roles see
|
|
114
|
+
// https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-invalid#associated_roles
|
|
115
|
+
// `aria-invalid` is put on in FormFieldLayout because the error message
|
|
116
|
+
// DOM part gets there its ID.
|
|
117
|
+
let ariaInvalid = void 0;
|
|
118
|
+
if (this.props.role && this.invalid && ['application', 'checkbox', 'combobox', 'gridcell', 'listbox', 'radiogroup', 'slider', 'spinbutton', 'textbox', 'tree', 'columnheader', 'rowheader', 'searchbox', 'switch', 'treegrid'].includes(this.props.role)) {
|
|
119
|
+
ariaInvalid = 'true';
|
|
120
|
+
}
|
|
108
121
|
return (0, _emotion.jsx)(_FormFieldLayout.FormFieldLayout, Object.assign({}, (0, _omitProps.omitProps)(props, FormFieldGroup.allowedProps), (0, _pickProps.pickProps)(props, _FormFieldLayout.FormFieldLayout.allowedProps), {
|
|
109
122
|
vAlign: props.vAlign,
|
|
110
123
|
layout: props.layout === 'inline' ? 'inline' : 'stacked',
|
|
111
124
|
label: props.description,
|
|
112
125
|
"aria-disabled": props.disabled ? 'true' : void 0,
|
|
113
|
-
"aria-invalid":
|
|
126
|
+
"aria-invalid": ariaInvalid,
|
|
114
127
|
elementRef: this.handleRef,
|
|
115
128
|
isGroup: isGroup
|
|
116
129
|
}), this.renderFields());
|
|
@@ -120,6 +133,7 @@ let FormFieldGroup = exports.FormFieldGroup = (_dec = (0, _emotion.withStyle)(_s
|
|
|
120
133
|
disabled: false,
|
|
121
134
|
rowSpacing: 'medium',
|
|
122
135
|
colSpacing: 'small',
|
|
123
|
-
vAlign: 'middle'
|
|
136
|
+
vAlign: 'middle',
|
|
137
|
+
isGroup: true
|
|
124
138
|
}, _FormFieldGroup)) || _class);
|
|
125
139
|
var _default = exports.default = FormFieldGroup;
|
|
@@ -8,11 +8,12 @@ exports.default = exports.FormFieldLabel = void 0;
|
|
|
8
8
|
var _react = require("react");
|
|
9
9
|
var _omitProps = require("@instructure/ui-react-utils/lib/omitProps.js");
|
|
10
10
|
var _getElementType = require("@instructure/ui-react-utils/lib/getElementType.js");
|
|
11
|
+
var _deprecated = require("@instructure/ui-react-utils/lib/deprecated.js");
|
|
11
12
|
var _emotion = require("@instructure/emotion");
|
|
12
13
|
var _styles = _interopRequireDefault(require("./styles"));
|
|
13
14
|
var _theme = _interopRequireDefault(require("./theme"));
|
|
14
15
|
var _props = require("./props");
|
|
15
|
-
var _dec, _class, _FormFieldLabel;
|
|
16
|
+
var _dec, _dec2, _class, _FormFieldLabel;
|
|
16
17
|
/*
|
|
17
18
|
* The MIT License (MIT)
|
|
18
19
|
*
|
|
@@ -42,8 +43,7 @@ var _dec, _class, _FormFieldLabel;
|
|
|
42
43
|
parent: FormField
|
|
43
44
|
---
|
|
44
45
|
|
|
45
|
-
This is a helper component that is used by most of the custom form
|
|
46
|
-
components. In most cases it shouldn't be used directly.
|
|
46
|
+
This is a helper component that is used by most of the custom form components. In most cases it shouldn't be used directly.
|
|
47
47
|
|
|
48
48
|
```js
|
|
49
49
|
---
|
|
@@ -52,8 +52,9 @@ type: example
|
|
|
52
52
|
<FormFieldLabel>Hello</FormFieldLabel>
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
@deprecated This is an internal component that will be removed in the future
|
|
55
56
|
**/
|
|
56
|
-
let FormFieldLabel = exports.FormFieldLabel = (_dec = (0, _emotion.withStyle)(_styles.default, _theme.default), _dec(_class = (_FormFieldLabel = class FormFieldLabel extends _react.Component {
|
|
57
|
+
let FormFieldLabel = exports.FormFieldLabel = (_dec = (0, _emotion.withStyle)(_styles.default, _theme.default), _dec2 = (0, _deprecated.deprecated)('10', null, 'This component will be removed in a future version'), _dec(_class = _dec2(_class = (_FormFieldLabel = class FormFieldLabel extends _react.Component {
|
|
57
58
|
constructor(...args) {
|
|
58
59
|
super(...args);
|
|
59
60
|
this.ref = null;
|
|
@@ -81,5 +82,5 @@ let FormFieldLabel = exports.FormFieldLabel = (_dec = (0, _emotion.withStyle)(_s
|
|
|
81
82
|
}
|
|
82
83
|
}, _FormFieldLabel.displayName = "FormFieldLabel", _FormFieldLabel.componentId = 'FormFieldLabel', _FormFieldLabel.propTypes = _props.propTypes, _FormFieldLabel.allowedProps = _props.allowedProps, _FormFieldLabel.defaultProps = {
|
|
83
84
|
as: 'span'
|
|
84
|
-
}, _FormFieldLabel)) || _class);
|
|
85
|
+
}, _FormFieldLabel)) || _class) || _class);
|
|
85
86
|
var _default = exports.default = FormFieldLabel;
|
|
@@ -7,7 +7,7 @@ var _vitest = require("vitest");
|
|
|
7
7
|
var _runAxeCheck = require("@instructure/ui-axe-check/lib/runAxeCheck.js");
|
|
8
8
|
require("@testing-library/jest-dom");
|
|
9
9
|
var _index = require("../index");
|
|
10
|
-
var _FormFieldLayout, _FormFieldLayout2
|
|
10
|
+
var _FormFieldLayout, _FormFieldLayout2;
|
|
11
11
|
/*
|
|
12
12
|
* The MIT License (MIT)
|
|
13
13
|
*
|
|
@@ -49,7 +49,7 @@ describe('<FormFieldLayout />', () => {
|
|
|
49
49
|
}))),
|
|
50
50
|
container = _render.container;
|
|
51
51
|
const formFieldLayout = container.querySelector("label[class$='-formFieldLayout']");
|
|
52
|
-
const formFieldLabel = container.querySelector("span[class$='-
|
|
52
|
+
const formFieldLabel = container.querySelector("span[class$='-formFieldLayout__label']");
|
|
53
53
|
expect(formFieldLayout).toBeInTheDocument();
|
|
54
54
|
expect(formFieldLabel).toBeInTheDocument();
|
|
55
55
|
expect(formFieldLabel).toHaveTextContent('Username');
|
|
@@ -64,13 +64,15 @@ describe('<FormFieldLayout />', () => {
|
|
|
64
64
|
});
|
|
65
65
|
it('should provide a ref to the input container', () => {
|
|
66
66
|
const inputContainerRef = _vitest.vi.fn();
|
|
67
|
+
const ref = /*#__PURE__*/_react.default.createRef();
|
|
67
68
|
(0, _react2.render)( /*#__PURE__*/_react.default.createElement(_index.FormFieldLayout, {
|
|
68
69
|
label: "Username",
|
|
69
70
|
inputContainerRef: inputContainerRef
|
|
70
|
-
},
|
|
71
|
-
type: "text"
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
expect(
|
|
71
|
+
}, /*#__PURE__*/_react.default.createElement("input", {
|
|
72
|
+
type: "text",
|
|
73
|
+
ref: ref
|
|
74
|
+
})));
|
|
75
|
+
expect(ref.current).toBeInstanceOf(HTMLInputElement);
|
|
76
|
+
expect(inputContainerRef).toHaveBeenCalledWith(ref.current.parentElement);
|
|
75
77
|
});
|
|
76
78
|
});
|
|
@@ -8,18 +8,14 @@ exports.default = exports.FormFieldLayout = void 0;
|
|
|
8
8
|
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
|
|
9
9
|
var _react = require("react");
|
|
10
10
|
var _hasVisibleChildren = require("@instructure/ui-a11y-utils/lib/hasVisibleChildren.js");
|
|
11
|
-
var _ScreenReaderContent = require("@instructure/ui-a11y-content/lib/ScreenReaderContent");
|
|
12
|
-
var _Grid = require("@instructure/ui-grid/lib/Grid");
|
|
13
|
-
var _console = require("@instructure/console");
|
|
14
11
|
var _omitProps = require("@instructure/ui-react-utils/lib/omitProps.js");
|
|
15
|
-
var _pickProps = require("@instructure/ui-react-utils/lib/pickProps.js");
|
|
16
12
|
var _getElementType = require("@instructure/ui-react-utils/lib/getElementType.js");
|
|
17
13
|
var _withDeterministicId = require("@instructure/ui-react-utils/lib/DeterministicIdContext/withDeterministicId.js");
|
|
18
14
|
var _emotion = require("@instructure/emotion");
|
|
19
|
-
var _FormFieldLabel = require("../FormFieldLabel");
|
|
20
15
|
var _FormFieldMessages = require("../FormFieldMessages");
|
|
21
16
|
var _styles = _interopRequireDefault(require("./styles"));
|
|
22
17
|
var _props = require("./props");
|
|
18
|
+
var _theme = _interopRequireDefault(require("./theme"));
|
|
23
19
|
const _excluded = ["makeStyles", "styles", "messages", "isGroup"];
|
|
24
20
|
var _dec, _dec2, _class, _FormFieldLayout;
|
|
25
21
|
/*
|
|
@@ -51,10 +47,11 @@ var _dec, _dec2, _class, _FormFieldLayout;
|
|
|
51
47
|
parent: FormField
|
|
52
48
|
---
|
|
53
49
|
**/
|
|
54
|
-
let FormFieldLayout = exports.FormFieldLayout = (_dec = (0, _withDeterministicId.withDeterministicId)(), _dec2 = (0, _emotion.withStyle)(_styles.default,
|
|
50
|
+
let FormFieldLayout = exports.FormFieldLayout = (_dec = (0, _withDeterministicId.withDeterministicId)(), _dec2 = (0, _emotion.withStyle)(_styles.default, _theme.default), _dec(_class = _dec2(_class = (_FormFieldLayout = class FormFieldLayout extends _react.Component {
|
|
55
51
|
constructor(props) {
|
|
56
52
|
super(props);
|
|
57
53
|
this._messagesId = void 0;
|
|
54
|
+
this._labelId = void 0;
|
|
58
55
|
this.ref = null;
|
|
59
56
|
this.handleRef = el => {
|
|
60
57
|
const elementRef = this.props.elementRef;
|
|
@@ -63,71 +60,99 @@ let FormFieldLayout = exports.FormFieldLayout = (_dec = (0, _withDeterministicId
|
|
|
63
60
|
elementRef(el);
|
|
64
61
|
}
|
|
65
62
|
};
|
|
63
|
+
this.makeStyleProps = () => {
|
|
64
|
+
var _this$props$messages;
|
|
65
|
+
const hasNewErrorMsgAndIsGroup = !!((_this$props$messages = this.props.messages) !== null && _this$props$messages !== void 0 && _this$props$messages.find(m => m.type === 'newError')) && !!this.props.isGroup;
|
|
66
|
+
return {
|
|
67
|
+
hasMessages: this.hasMessages,
|
|
68
|
+
hasVisibleLabel: this.hasVisibleLabel,
|
|
69
|
+
// if true render error message above the controls (and below the label)
|
|
70
|
+
hasNewErrorMsgAndIsGroup: hasNewErrorMsgAndIsGroup
|
|
71
|
+
};
|
|
72
|
+
};
|
|
66
73
|
this.handleInputContainerRef = node => {
|
|
67
74
|
if (typeof this.props.inputContainerRef === 'function') {
|
|
68
75
|
this.props.inputContainerRef(node);
|
|
69
76
|
}
|
|
70
77
|
};
|
|
71
78
|
this._messagesId = props.messagesId || props.deterministicId();
|
|
72
|
-
|
|
73
|
-
This will cause a layout issue in Internet Explorer 11 unless you also add a value for the 'width' prop.`);
|
|
79
|
+
this._labelId = props.deterministicId('FormField-Label');
|
|
74
80
|
}
|
|
75
81
|
componentDidMount() {
|
|
76
82
|
var _this$props$makeStyle, _this$props;
|
|
77
|
-
(_this$props$makeStyle = (_this$props = this.props).makeStyles) === null || _this$props$makeStyle === void 0 ? void 0 : _this$props$makeStyle.call(_this$props);
|
|
83
|
+
(_this$props$makeStyle = (_this$props = this.props).makeStyles) === null || _this$props$makeStyle === void 0 ? void 0 : _this$props$makeStyle.call(_this$props, this.makeStyleProps());
|
|
78
84
|
}
|
|
79
85
|
componentDidUpdate() {
|
|
80
86
|
var _this$props$makeStyle2, _this$props2;
|
|
81
|
-
(_this$props$makeStyle2 = (_this$props2 = this.props).makeStyles) === null || _this$props$makeStyle2 === void 0 ? void 0 : _this$props$makeStyle2.call(_this$props2);
|
|
87
|
+
(_this$props$makeStyle2 = (_this$props2 = this.props).makeStyles) === null || _this$props$makeStyle2 === void 0 ? void 0 : _this$props$makeStyle2.call(_this$props2, this.makeStyleProps());
|
|
82
88
|
}
|
|
83
89
|
get hasVisibleLabel() {
|
|
84
|
-
return this.props.label
|
|
90
|
+
return this.props.label ? (0, _hasVisibleChildren.hasVisibleChildren)(this.props.label) : false;
|
|
85
91
|
}
|
|
86
92
|
get hasMessages() {
|
|
87
|
-
|
|
93
|
+
if (!this.props.messages || this.props.messages.length == 0) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
for (const msg of this.props.messages) {
|
|
97
|
+
if (msg.text) {
|
|
98
|
+
if (typeof msg.text === 'string') {
|
|
99
|
+
return msg.text.length > 0;
|
|
100
|
+
}
|
|
101
|
+
// this is more complicated (e.g. an array, a React component,...)
|
|
102
|
+
// but we don't try to optimize here for these cases
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
88
107
|
}
|
|
89
108
|
get elementType() {
|
|
90
109
|
return (0, _getElementType.getElementType)(FormFieldLayout, this.props);
|
|
91
110
|
}
|
|
92
|
-
get inlineContainerAndLabel() {
|
|
93
|
-
// Return if both the component container and label will display inline
|
|
94
|
-
return this.props.inline && this.props.layout === 'inline';
|
|
95
|
-
}
|
|
96
111
|
renderLabel() {
|
|
97
112
|
if (this.hasVisibleLabel) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
113
|
+
var _this$props$styles2;
|
|
114
|
+
if (this.elementType == 'fieldset') {
|
|
115
|
+
var _this$props$styles;
|
|
116
|
+
// `legend` has some special built in CSS, this can only be reset
|
|
117
|
+
// this way https://stackoverflow.com/a/65866981/319473
|
|
118
|
+
return (0, _emotion.jsx)("legend", {
|
|
119
|
+
style: {
|
|
120
|
+
display: 'contents'
|
|
121
|
+
}
|
|
122
|
+
}, (0, _emotion.jsx)("span", {
|
|
123
|
+
css: (_this$props$styles = this.props.styles) === null || _this$props$styles === void 0 ? void 0 : _this$props$styles.formFieldLabel
|
|
124
|
+
}, this.props.label));
|
|
125
|
+
}
|
|
126
|
+
return (0, _emotion.jsx)("span", {
|
|
127
|
+
css: (_this$props$styles2 = this.props.styles) === null || _this$props$styles2 === void 0 ? void 0 : _this$props$styles2.formFieldLabel
|
|
128
|
+
}, this.props.label);
|
|
129
|
+
} else if (this.props.label) {
|
|
130
|
+
if (this.elementType == 'fieldset') {
|
|
131
|
+
return (0, _emotion.jsx)("legend", {
|
|
132
|
+
id: this._labelId,
|
|
133
|
+
style: {
|
|
134
|
+
display: 'contents'
|
|
135
|
+
}
|
|
136
|
+
}, this.props.label);
|
|
137
|
+
}
|
|
138
|
+
// needs to be wrapped because it needs an `id`
|
|
139
|
+
return (0, _emotion.jsx)("div", {
|
|
140
|
+
id: this._labelId,
|
|
141
|
+
style: {
|
|
142
|
+
display: 'contents'
|
|
143
|
+
}
|
|
144
|
+
}, this.props.label);
|
|
145
|
+
} else return null;
|
|
119
146
|
}
|
|
120
147
|
renderVisibleMessages() {
|
|
121
|
-
return this.hasMessages ? (0, _emotion.jsx)(
|
|
122
|
-
offset: this.inlineContainerAndLabel ? void 0 : 3,
|
|
123
|
-
textAlign: this.inlineContainerAndLabel ? 'end' : void 0
|
|
124
|
-
}, (0, _emotion.jsx)(_FormFieldMessages.FormFieldMessages, {
|
|
148
|
+
return this.hasMessages ? (0, _emotion.jsx)(_FormFieldMessages.FormFieldMessages, {
|
|
125
149
|
id: this._messagesId,
|
|
126
|
-
messages: this.props.messages
|
|
127
|
-
|
|
150
|
+
messages: this.props.messages,
|
|
151
|
+
gridArea: "messages"
|
|
152
|
+
}) : null;
|
|
128
153
|
}
|
|
129
154
|
render() {
|
|
130
|
-
//
|
|
155
|
+
// Should be `<label>` if it's a FormField, fieldset if it's a group
|
|
131
156
|
const ElementType = this.elementType;
|
|
132
157
|
const _this$props3 = this.props,
|
|
133
158
|
makeStyles = _this$props3.makeStyles,
|
|
@@ -136,26 +161,20 @@ let FormFieldLayout = exports.FormFieldLayout = (_dec = (0, _withDeterministicId
|
|
|
136
161
|
isGroup = _this$props3.isGroup,
|
|
137
162
|
props = (0, _objectWithoutProperties2.default)(_this$props3, _excluded);
|
|
138
163
|
const width = props.width,
|
|
139
|
-
layout = props.layout,
|
|
140
164
|
children = props.children;
|
|
141
|
-
const
|
|
142
|
-
return (0, _emotion.jsx)(ElementType, Object.assign({}, (0, _omitProps.omitProps)(props, [...FormFieldLayout.allowedProps
|
|
165
|
+
const hasNewErrorMsgAndIsGroup = !!(messages !== null && messages !== void 0 && messages.find(m => m.type === 'newError')) && isGroup;
|
|
166
|
+
return (0, _emotion.jsx)(ElementType, Object.assign({}, (0, _omitProps.omitProps)(props, [...FormFieldLayout.allowedProps]), {
|
|
143
167
|
css: styles === null || styles === void 0 ? void 0 : styles.formFieldLayout,
|
|
168
|
+
"aria-describedby": this.hasMessages ? this._messagesId : void 0,
|
|
169
|
+
"aria-errormessage": this.props['aria-invalid'] ? this._messagesId : void 0,
|
|
144
170
|
style: {
|
|
145
171
|
width
|
|
146
172
|
},
|
|
147
|
-
"aria-describedby": this.hasMessages ? this._messagesId : void 0,
|
|
148
173
|
ref: this.handleRef
|
|
149
|
-
}), this.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}, (0, _pickProps.pickProps)(props, _Grid.Grid.allowedProps)), (0, _emotion.jsx)(_Grid.Grid.Row, null, this.renderLabel(), (0, _emotion.jsx)(_Grid.Grid.Col, {
|
|
154
|
-
width: this.inlineContainerAndLabel ? 'auto' : void 0,
|
|
155
|
-
elementRef: this.handleInputContainerRef
|
|
156
|
-
}, hasNewErrorMsg && (0, _emotion.jsx)("div", {
|
|
157
|
-
css: styles === null || styles === void 0 ? void 0 : styles.groupErrorMessage
|
|
158
|
-
}, this.renderVisibleMessages()), children)), !hasNewErrorMsg && this.renderVisibleMessages()));
|
|
174
|
+
}), this.renderLabel(), hasNewErrorMsgAndIsGroup && this.renderVisibleMessages(), (0, _emotion.jsx)("span", {
|
|
175
|
+
css: styles === null || styles === void 0 ? void 0 : styles.formFieldChildren,
|
|
176
|
+
ref: this.handleInputContainerRef
|
|
177
|
+
}, children), !hasNewErrorMsgAndIsGroup && this.renderVisibleMessages());
|
|
159
178
|
}
|
|
160
179
|
}, _FormFieldLayout.displayName = "FormFieldLayout", _FormFieldLayout.componentId = 'FormFieldLayout', _FormFieldLayout.propTypes = _props.propTypes, _FormFieldLayout.allowedProps = _props.allowedProps, _FormFieldLayout.defaultProps = {
|
|
161
180
|
inline: false,
|
|
@@ -47,9 +47,4 @@ const propTypes = exports.propTypes = {
|
|
|
47
47
|
elementRef: _propTypes.default.func,
|
|
48
48
|
isGroup: _propTypes.default.bool
|
|
49
49
|
};
|
|
50
|
-
const allowedProps = exports.allowedProps = ['label', 'id', 'as', 'messages', 'messagesId', 'children', 'inline', 'layout', 'labelAlign', 'width', 'inputContainerRef', 'elementRef'
|
|
51
|
-
|
|
52
|
-
// added vAlign because FormField and FormFieldGroup passes it, but not adding
|
|
53
|
-
// it to allowedProps to prevent it from getting passed through accidentally
|
|
54
|
-
//'vAlign'
|
|
55
|
-
];
|
|
50
|
+
const allowedProps = exports.allowedProps = ['label', 'id', 'as', 'messages', 'messagesId', 'children', 'inline', 'layout', 'labelAlign', 'width', 'inputContainerRef', 'elementRef', 'vAlign'];
|
|
@@ -28,6 +28,31 @@ exports.default = void 0;
|
|
|
28
28
|
* SOFTWARE.
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
+
const generateGridLayout = (isInlineLayout, hasNewErrorMsgAndIsGroup, hasVisibleLabel, hasMessages) => {
|
|
32
|
+
if (isInlineLayout) {
|
|
33
|
+
if (hasNewErrorMsgAndIsGroup) {
|
|
34
|
+
if (hasMessages) {
|
|
35
|
+
return `${hasVisibleLabel ? ' "label messages"' : '. messages'}
|
|
36
|
+
". controls"`;
|
|
37
|
+
} else {
|
|
38
|
+
return `${hasVisibleLabel ? ' "label controls"' : '. controls'}`;
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
return `${hasVisibleLabel ? ' "label controls"' : '. controls'}
|
|
42
|
+
${hasMessages ? ' ". messages"' : ''}`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// stacked layout -- in this case we could use a simple `Flex`
|
|
46
|
+
if (hasNewErrorMsgAndIsGroup) {
|
|
47
|
+
return `${hasVisibleLabel ? ' "label"' : ''}
|
|
48
|
+
${hasMessages ? ' "messages"' : ''}
|
|
49
|
+
"controls"`;
|
|
50
|
+
} else {
|
|
51
|
+
return `${hasVisibleLabel ? ' "label"' : ''}
|
|
52
|
+
"controls"
|
|
53
|
+
${hasMessages ? ' "messages"' : ''}`;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
31
56
|
/**
|
|
32
57
|
* ---
|
|
33
58
|
* private: true
|
|
@@ -35,15 +60,55 @@ exports.default = void 0;
|
|
|
35
60
|
* Generates the style object from the theme and provided additional information
|
|
36
61
|
* @param {Object} componentTheme The theme variable object.
|
|
37
62
|
* @param {Object} props the props of the component, the style is applied to
|
|
38
|
-
* @param {Object}
|
|
63
|
+
* @param {Object} styleProps
|
|
39
64
|
* @return {Object} The final style object, which will be used in the component
|
|
40
65
|
*/
|
|
41
|
-
const generateStyle = (
|
|
42
|
-
const inline = props.inline
|
|
66
|
+
const generateStyle = (componentTheme, props, styleProps) => {
|
|
67
|
+
const inline = props.inline,
|
|
68
|
+
layout = props.layout,
|
|
69
|
+
vAlign = props.vAlign,
|
|
70
|
+
labelAlign = props.labelAlign;
|
|
71
|
+
const hasMessages = styleProps.hasMessages,
|
|
72
|
+
hasVisibleLabel = styleProps.hasVisibleLabel,
|
|
73
|
+
hasNewErrorMsgAndIsGroup = styleProps.hasNewErrorMsgAndIsGroup;
|
|
74
|
+
const isInlineLayout = layout === 'inline';
|
|
75
|
+
// This is quite ugly, we should simplify it
|
|
76
|
+
const gridTemplateAreas = generateGridLayout(isInlineLayout, hasNewErrorMsgAndIsGroup, hasVisibleLabel, hasMessages);
|
|
77
|
+
let gridTemplateColumns = '100%'; // stacked layout
|
|
78
|
+
if (isInlineLayout) {
|
|
79
|
+
gridTemplateColumns = '1fr 3fr';
|
|
80
|
+
if (inline) {
|
|
81
|
+
gridTemplateColumns = 'auto 3fr';
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const labelStyles = {
|
|
85
|
+
all: 'initial',
|
|
86
|
+
display: 'block',
|
|
87
|
+
gridArea: 'label',
|
|
88
|
+
color: componentTheme.color,
|
|
89
|
+
fontFamily: componentTheme.fontFamily,
|
|
90
|
+
fontWeight: componentTheme.fontWeight,
|
|
91
|
+
fontSize: componentTheme.fontSize,
|
|
92
|
+
lineHeight: componentTheme.lineHeight,
|
|
93
|
+
...(isInlineLayout && {
|
|
94
|
+
margin: '0',
|
|
95
|
+
// when inline add a small padding between the label and the control
|
|
96
|
+
paddingRight: componentTheme.inlinePadding,
|
|
97
|
+
// and use the horizontal alignment prop
|
|
98
|
+
[`@media screen and (width >= ${componentTheme.stackedOrInlineBreakpoint})`]: {
|
|
99
|
+
textAlign: labelAlign
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
};
|
|
103
|
+
let alignItems = 'start';
|
|
104
|
+
if (vAlign == 'top') {
|
|
105
|
+
alignItems = 'start';
|
|
106
|
+
} else if (vAlign == 'middle') {
|
|
107
|
+
alignItems = 'center';
|
|
108
|
+
} else if (vAlign == 'bottom') {
|
|
109
|
+
alignItems = 'end';
|
|
110
|
+
}
|
|
43
111
|
return {
|
|
44
|
-
groupErrorMessage: {
|
|
45
|
-
margin: '0.5rem 0'
|
|
46
|
-
},
|
|
47
112
|
formFieldLayout: {
|
|
48
113
|
label: 'formFieldLayout',
|
|
49
114
|
all: 'initial',
|
|
@@ -54,13 +119,44 @@ const generateStyle = (_componentTheme, props) => {
|
|
|
54
119
|
direction: 'inherit',
|
|
55
120
|
textAlign: 'start',
|
|
56
121
|
opacity: 'inherit',
|
|
57
|
-
display: '
|
|
122
|
+
display: 'grid',
|
|
123
|
+
alignItems: alignItems,
|
|
124
|
+
verticalAlign: 'middle',
|
|
125
|
+
// removes margin in inline layouts
|
|
126
|
+
gridTemplateColumns: gridTemplateColumns,
|
|
127
|
+
gridTemplateAreas: gridTemplateAreas,
|
|
128
|
+
[`@media screen and (width < ${componentTheme.stackedOrInlineBreakpoint})`]: {
|
|
129
|
+
// for small screens use the stacked layout
|
|
130
|
+
gridTemplateColumns: '100%',
|
|
131
|
+
gridTemplateAreas: generateGridLayout(false, hasNewErrorMsgAndIsGroup, hasVisibleLabel, hasMessages)
|
|
132
|
+
},
|
|
133
|
+
columnGap: '0.375rem',
|
|
134
|
+
rowGap: '0.75rem',
|
|
58
135
|
width: '100%',
|
|
59
136
|
...(inline && {
|
|
60
|
-
display: 'inline-
|
|
61
|
-
verticalAlign: 'middle',
|
|
137
|
+
display: 'inline-grid',
|
|
62
138
|
width: 'auto'
|
|
63
139
|
})
|
|
140
|
+
},
|
|
141
|
+
formFieldLabel: {
|
|
142
|
+
label: 'formFieldLayout__label',
|
|
143
|
+
...labelStyles,
|
|
144
|
+
// NOTE: needs separate groups for `:is()` and `:-webkit-any()` because of css selector group validation (see https://www.w3.org/TR/selectors-3/#grouping)
|
|
145
|
+
'&:is(label)': labelStyles,
|
|
146
|
+
'&:-webkit-any(label)': labelStyles
|
|
147
|
+
},
|
|
148
|
+
formFieldChildren: {
|
|
149
|
+
label: 'formFieldLayout__children',
|
|
150
|
+
gridArea: 'controls',
|
|
151
|
+
// add a small margin between the message and the controls
|
|
152
|
+
...(hasMessages && hasNewErrorMsgAndIsGroup && {
|
|
153
|
+
marginTop: '0.375rem'
|
|
154
|
+
}),
|
|
155
|
+
...(isInlineLayout && inline && {
|
|
156
|
+
[`@media screen and (width >= ${componentTheme.stackedOrInlineBreakpoint})`]: {
|
|
157
|
+
justifySelf: 'start'
|
|
158
|
+
}
|
|
159
|
+
})
|
|
64
160
|
}
|
|
65
161
|
};
|
|
66
162
|
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
/*
|
|
8
|
+
* The MIT License (MIT)
|
|
9
|
+
*
|
|
10
|
+
* Copyright (c) 2015 - present Instructure, Inc.
|
|
11
|
+
*
|
|
12
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
* in the Software without restriction, including without limitation the rights
|
|
15
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
* furnished to do so, subject to the following conditions:
|
|
18
|
+
*
|
|
19
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
* copies or substantial portions of the Software.
|
|
21
|
+
*
|
|
22
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
* SOFTWARE.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Generates the theme object for the component from the theme and provided additional information
|
|
33
|
+
* @param {Object} theme The actual theme object.
|
|
34
|
+
* @return {Object} The final theme object with the overrides and component variables
|
|
35
|
+
*/
|
|
36
|
+
const generateComponentTheme = theme => {
|
|
37
|
+
const colors = theme.colors,
|
|
38
|
+
typography = theme.typography,
|
|
39
|
+
spacing = theme.spacing,
|
|
40
|
+
breakpoints = theme.breakpoints,
|
|
41
|
+
themeName = theme.key;
|
|
42
|
+
const themeSpecificStyle = {
|
|
43
|
+
canvas: {
|
|
44
|
+
color: theme['ic-brand-font-color-dark']
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const componentVariables = {
|
|
48
|
+
color: colors === null || colors === void 0 ? void 0 : colors.licorice,
|
|
49
|
+
fontFamily: typography === null || typography === void 0 ? void 0 : typography.fontFamily,
|
|
50
|
+
fontWeight: typography === null || typography === void 0 ? void 0 : typography.fontWeightBold,
|
|
51
|
+
fontSize: typography === null || typography === void 0 ? void 0 : typography.fontSizeMedium,
|
|
52
|
+
lineHeight: typography === null || typography === void 0 ? void 0 : typography.lineHeightFit,
|
|
53
|
+
inlinePadding: spacing === null || spacing === void 0 ? void 0 : spacing.xxSmall,
|
|
54
|
+
stackedOrInlineBreakpoint: breakpoints === null || breakpoints === void 0 ? void 0 : breakpoints.medium,
|
|
55
|
+
spacing: theme.spacing
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
...componentVariables,
|
|
59
|
+
...themeSpecificStyle[themeName]
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
var _default = exports.default = generateComponentTheme;
|
|
@@ -32,6 +32,7 @@ var _FormPropTypes = require("../FormPropTypes");
|
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
34
|
const propTypes = exports.propTypes = {
|
|
35
|
-
messages: _propTypes.default.arrayOf(_FormPropTypes.FormPropTypes.message)
|
|
35
|
+
messages: _propTypes.default.arrayOf(_FormPropTypes.FormPropTypes.message),
|
|
36
|
+
gridArea: _propTypes.default.string
|
|
36
37
|
};
|
|
37
|
-
const allowedProps = exports.allowedProps = ['messages'];
|
|
38
|
+
const allowedProps = exports.allowedProps = ['messages', 'gridArea'];
|
|
@@ -35,16 +35,18 @@ exports.default = void 0;
|
|
|
35
35
|
* Generates the style object from the theme and provided additional information
|
|
36
36
|
* @param {Object} componentTheme The theme variable object.
|
|
37
37
|
* @param {Object} props the props of the component, the style is applied to
|
|
38
|
-
* @param {Object} state the state of the component, the style is applied to
|
|
39
38
|
* @return {Object} The final style object, which will be used in the component
|
|
40
39
|
*/
|
|
41
|
-
const generateStyle = componentTheme => {
|
|
40
|
+
const generateStyle = (componentTheme, props) => {
|
|
42
41
|
return {
|
|
43
42
|
formFieldMessages: {
|
|
44
43
|
label: 'formFieldMessages',
|
|
45
44
|
padding: 0,
|
|
46
45
|
display: 'block',
|
|
47
|
-
margin: `calc(
|
|
46
|
+
margin: `calc(-${componentTheme.topMargin}) 0 0 0`,
|
|
47
|
+
...(props.gridArea && {
|
|
48
|
+
gridArea: props.gridArea
|
|
49
|
+
})
|
|
48
50
|
},
|
|
49
51
|
message: {
|
|
50
52
|
label: 'formFieldMessages__message',
|