@availity/mui-textfield 1.1.0 → 1.1.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 +2 -0
- package/dist/index.d.mts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +57 -21
- package/dist/index.mjs +55 -19
- package/package.json +1 -1
- package/src/lib/TextField.stories.tsx +13 -1
- package/src/lib/TextField.test.tsx +8 -4
- package/src/lib/TextField.tsx +55 -16
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
## [1.1.1](https://github.com/Availity/element/compare/@availity/mui-textfield@1.1.0...@availity/mui-textfield@1.1.1) (2025-03-27)
|
|
6
|
+
|
|
5
7
|
## [1.1.0](https://github.com/Availity/element/compare/@availity/mui-textfield@1.0.1...@availity/mui-textfield@1.1.0) (2025-03-21)
|
|
6
8
|
|
|
7
9
|
### Dependency Updates
|
package/dist/index.d.mts
CHANGED
|
@@ -11,7 +11,15 @@ type TextFieldProps = {
|
|
|
11
11
|
fullWidth?: boolean;
|
|
12
12
|
/** if `true`, the character counter will display. The maxLength is taken from the `inputProps.maxLength` prop. @default false */
|
|
13
13
|
showCharacterCount?: boolean;
|
|
14
|
+
/** If `true`, the input maxLength can be exceeded. If validation is required, you'll have to do it manually. @default false */
|
|
15
|
+
displayOverflowMaxLength?: boolean;
|
|
14
16
|
} & Pick<FormLabelProps, 'helpTopicId'> & Omit<TextFieldProps$1, 'fullWidth' | 'variant'>;
|
|
17
|
+
type TextFieldFormHelperTextProps = {
|
|
18
|
+
charCount: string;
|
|
19
|
+
helperText: string;
|
|
20
|
+
maxLength: string;
|
|
21
|
+
showCharacterCount: boolean;
|
|
22
|
+
};
|
|
15
23
|
declare const TextField: react.ForwardRefExoticComponent<Omit<TextFieldProps, "ref"> & react.RefAttributes<HTMLDivElement | HTMLInputElement>>;
|
|
16
24
|
|
|
17
|
-
export { TextField, type TextFieldProps };
|
|
25
|
+
export { TextField, type TextFieldFormHelperTextProps, type TextFieldProps };
|
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,15 @@ type TextFieldProps = {
|
|
|
11
11
|
fullWidth?: boolean;
|
|
12
12
|
/** if `true`, the character counter will display. The maxLength is taken from the `inputProps.maxLength` prop. @default false */
|
|
13
13
|
showCharacterCount?: boolean;
|
|
14
|
+
/** If `true`, the input maxLength can be exceeded. If validation is required, you'll have to do it manually. @default false */
|
|
15
|
+
displayOverflowMaxLength?: boolean;
|
|
14
16
|
} & Pick<FormLabelProps, 'helpTopicId'> & Omit<TextFieldProps$1, 'fullWidth' | 'variant'>;
|
|
17
|
+
type TextFieldFormHelperTextProps = {
|
|
18
|
+
charCount: string;
|
|
19
|
+
helperText: string;
|
|
20
|
+
maxLength: string;
|
|
21
|
+
showCharacterCount: boolean;
|
|
22
|
+
};
|
|
15
23
|
declare const TextField: react.ForwardRefExoticComponent<Omit<TextFieldProps, "ref"> & react.RefAttributes<HTMLDivElement | HTMLInputElement>>;
|
|
16
24
|
|
|
17
|
-
export { TextField, type TextFieldProps };
|
|
25
|
+
export { TextField, type TextFieldFormHelperTextProps, type TextFieldProps };
|
package/dist/index.js
CHANGED
|
@@ -64,7 +64,7 @@ __export(index_exports, {
|
|
|
64
64
|
module.exports = __toCommonJS(index_exports);
|
|
65
65
|
|
|
66
66
|
// src/lib/TextField.tsx
|
|
67
|
-
var
|
|
67
|
+
var import_react3 = require("react");
|
|
68
68
|
var import_TextField = __toESM(require("@mui/material/TextField"));
|
|
69
69
|
var import_mui_form_utils = require("@availity/mui-form-utils");
|
|
70
70
|
|
|
@@ -91,15 +91,44 @@ var Grid = (args) => {
|
|
|
91
91
|
var import_Stack = __toESM(require("@mui/material/Stack"));
|
|
92
92
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
93
93
|
|
|
94
|
+
// ../typography/src/lib/Typography.tsx
|
|
95
|
+
var import_react2 = require("react");
|
|
96
|
+
var import_Typography = __toESM(require("@mui/material/Typography"));
|
|
97
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
98
|
+
var Typography = (0, import_react2.forwardRef)(
|
|
99
|
+
(_a, ref) => {
|
|
100
|
+
var _b = _a, { children } = _b, rest = __objRest(_b, ["children"]);
|
|
101
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_Typography.default, __spreadProps(__spreadValues({}, rest), { ref, children }));
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
|
|
94
105
|
// src/lib/TextField.tsx
|
|
95
106
|
var import_styles = require("@mui/material/styles");
|
|
96
|
-
var
|
|
107
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
97
108
|
var SelectPlaceholder = (0, import_styles.styled)("span", {
|
|
98
109
|
name: "MuiTextField",
|
|
99
110
|
slot: "SelectPlaceholder",
|
|
100
111
|
overridesResolver: (props, styles) => styles.avFilled
|
|
101
112
|
})(({ theme }) => ({ opacity: 1, color: theme.palette.grey[400] }));
|
|
102
|
-
var
|
|
113
|
+
var TextFieldFormHelperText = ({
|
|
114
|
+
charCount,
|
|
115
|
+
helperText,
|
|
116
|
+
maxLength,
|
|
117
|
+
showCharacterCount
|
|
118
|
+
}) => {
|
|
119
|
+
if (showCharacterCount) {
|
|
120
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Grid, { container: true, justifyContent: "space-between", flexWrap: "nowrap", children: [
|
|
121
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_mui_form_utils.FormHelperText, { sx: { marginRight: "12px" }, children: helperText }),
|
|
122
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Typography, { variant: "caption", marginTop: "4px", lineHeight: "1.25rem", children: [
|
|
123
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Typography, { component: "span", variant: "inherit", color: charCount > maxLength ? "error" : "textPrimary", children: charCount || 0 }),
|
|
124
|
+
"/",
|
|
125
|
+
maxLength
|
|
126
|
+
] })
|
|
127
|
+
] });
|
|
128
|
+
}
|
|
129
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_mui_form_utils.FormHelperText, { children: helperText });
|
|
130
|
+
};
|
|
131
|
+
var TextField = (0, import_react3.forwardRef)((props, ref) => {
|
|
103
132
|
var _b, _c, _d, _e, _f, _g, _h;
|
|
104
133
|
const _a = props, {
|
|
105
134
|
InputProps: InputProps2,
|
|
@@ -110,7 +139,8 @@ var TextField = (0, import_react2.forwardRef)((props, ref) => {
|
|
|
110
139
|
SelectProps: SelectProps2,
|
|
111
140
|
inputProps,
|
|
112
141
|
helperText,
|
|
113
|
-
showCharacterCount = false
|
|
142
|
+
showCharacterCount = false,
|
|
143
|
+
displayOverflowMaxLength = false
|
|
114
144
|
} = _a, rest = __objRest(_a, [
|
|
115
145
|
"InputProps",
|
|
116
146
|
"helpTopicId",
|
|
@@ -120,34 +150,32 @@ var TextField = (0, import_react2.forwardRef)((props, ref) => {
|
|
|
120
150
|
"SelectProps",
|
|
121
151
|
"inputProps",
|
|
122
152
|
"helperText",
|
|
123
|
-
"showCharacterCount"
|
|
153
|
+
"showCharacterCount",
|
|
154
|
+
"displayOverflowMaxLength"
|
|
124
155
|
]);
|
|
125
|
-
const [openDetected, setOpenDetected] = (0,
|
|
126
|
-
const [charCount, setCharCount] = (0,
|
|
156
|
+
const [openDetected, setOpenDetected] = (0, import_react3.useState)(false);
|
|
157
|
+
const [charCount, setCharCount] = (0, import_react3.useState)(0);
|
|
158
|
+
const maxLength = (inputProps == null ? void 0 : inputProps.maxLength) || ((_c = (_b = rest.slotProps) == null ? void 0 : _b.htmlInput) == null ? void 0 : _c.maxLength);
|
|
127
159
|
const resolvedProps = (props2) => !props2 || Object.keys(props2).length === 0 ? void 0 : props2;
|
|
128
|
-
return /* @__PURE__ */ (0,
|
|
160
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
129
161
|
import_TextField.default,
|
|
130
162
|
__spreadProps(__spreadValues({}, rest), {
|
|
131
163
|
onChange: (event) => {
|
|
132
164
|
setCharCount(event.target.value.length);
|
|
133
165
|
if (rest.onChange) rest.onChange(event);
|
|
134
166
|
},
|
|
135
|
-
helperText:
|
|
136
|
-
|
|
137
|
-
" ",
|
|
138
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { style: { marginLeft: 4 }, children: [
|
|
139
|
-
charCount || 0,
|
|
140
|
-
"/",
|
|
141
|
-
(inputProps == null ? void 0 : inputProps.maxLength) || ((_c = (_b = rest.slotProps) == null ? void 0 : _b.htmlInput) == null ? void 0 : _c.maxLength)
|
|
142
|
-
] })
|
|
143
|
-
] }) : helperText,
|
|
144
|
-
slots: { formHelperText: import_mui_form_utils.FormHelperText },
|
|
167
|
+
helperText: helperText || /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, {}),
|
|
168
|
+
slots: { formHelperText: TextFieldFormHelperText },
|
|
145
169
|
slotProps: {
|
|
146
170
|
input: resolvedProps(__spreadValues(__spreadValues(__spreadValues({}, InputProps2), import_mui_form_utils.InputPropOverrides), (_d = rest.slotProps) == null ? void 0 : _d.input)),
|
|
147
|
-
htmlInput: resolvedProps(__spreadValues(__spreadValues({
|
|
171
|
+
htmlInput: resolvedProps(__spreadProps(__spreadValues(__spreadValues({
|
|
172
|
+
"aria-required": required
|
|
173
|
+
}, inputProps), (_e = rest.slotProps) == null ? void 0 : _e.htmlInput), {
|
|
174
|
+
maxLength: !displayOverflowMaxLength ? maxLength : void 0
|
|
175
|
+
})),
|
|
148
176
|
select: resolvedProps(__spreadValues(__spreadValues(__spreadValues(__spreadValues({
|
|
149
177
|
displayEmpty: !!rest.placeholder,
|
|
150
|
-
renderValue: (value) => rest.placeholder && (!value || Array.isArray(value) && value.length === 0) ? /* @__PURE__ */ (0,
|
|
178
|
+
renderValue: (value) => rest.placeholder && (!value || Array.isArray(value) && value.length === 0) ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SelectPlaceholder, { className: "MuiSelect-placeholder", children: rest.placeholder }) : value
|
|
151
179
|
}, SelectProps2), import_mui_form_utils.SelectPropOverrides), (0, import_mui_form_utils.SelectAccessibilityOverrides)(openDetected, setOpenDetected, SelectProps2 == null ? void 0 : SelectProps2.open)), (_f = rest.slotProps) == null ? void 0 : _f.select)),
|
|
152
180
|
inputLabel: resolvedProps(__spreadValues(__spreadValues({
|
|
153
181
|
component: import_mui_form_utils.FormLabel,
|
|
@@ -155,7 +183,15 @@ var TextField = (0, import_react2.forwardRef)((props, ref) => {
|
|
|
155
183
|
required,
|
|
156
184
|
shrink: true
|
|
157
185
|
}, InputLabelProps), (_g = rest.slotProps) == null ? void 0 : _g.inputLabel)),
|
|
158
|
-
formHelperText: resolvedProps(__spreadValues(__spreadValues({
|
|
186
|
+
formHelperText: resolvedProps(__spreadProps(__spreadValues(__spreadValues({
|
|
187
|
+
component: "div"
|
|
188
|
+
}, FormHelperTextProps2), (_h = rest.slotProps) == null ? void 0 : _h.formHelperText), {
|
|
189
|
+
charCount,
|
|
190
|
+
helperText,
|
|
191
|
+
maxLength,
|
|
192
|
+
displayOverflowMaxLength,
|
|
193
|
+
showCharacterCount
|
|
194
|
+
}))
|
|
159
195
|
},
|
|
160
196
|
ref
|
|
161
197
|
})
|
package/dist/index.mjs
CHANGED
|
@@ -31,7 +31,7 @@ var __objRest = (source, exclude) => {
|
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
// src/lib/TextField.tsx
|
|
34
|
-
import { forwardRef as
|
|
34
|
+
import { forwardRef as forwardRef3, useState } from "react";
|
|
35
35
|
import MuiTextField from "@mui/material/TextField";
|
|
36
36
|
import {
|
|
37
37
|
FormHelperText,
|
|
@@ -64,15 +64,44 @@ var Grid = (args) => {
|
|
|
64
64
|
import MuiStack from "@mui/material/Stack";
|
|
65
65
|
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
66
66
|
|
|
67
|
+
// ../typography/src/lib/Typography.tsx
|
|
68
|
+
import { forwardRef as forwardRef2 } from "react";
|
|
69
|
+
import { default as MuiTypography } from "@mui/material/Typography";
|
|
70
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
71
|
+
var Typography = forwardRef2(
|
|
72
|
+
(_a, ref) => {
|
|
73
|
+
var _b = _a, { children } = _b, rest = __objRest(_b, ["children"]);
|
|
74
|
+
return /* @__PURE__ */ jsx5(MuiTypography, __spreadProps(__spreadValues({}, rest), { ref, children }));
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
|
|
67
78
|
// src/lib/TextField.tsx
|
|
68
79
|
import { styled } from "@mui/material/styles";
|
|
69
|
-
import { jsx as
|
|
80
|
+
import { Fragment, jsx as jsx6, jsxs } from "react/jsx-runtime";
|
|
70
81
|
var SelectPlaceholder = styled("span", {
|
|
71
82
|
name: "MuiTextField",
|
|
72
83
|
slot: "SelectPlaceholder",
|
|
73
84
|
overridesResolver: (props, styles) => styles.avFilled
|
|
74
85
|
})(({ theme }) => ({ opacity: 1, color: theme.palette.grey[400] }));
|
|
75
|
-
var
|
|
86
|
+
var TextFieldFormHelperText = ({
|
|
87
|
+
charCount,
|
|
88
|
+
helperText,
|
|
89
|
+
maxLength,
|
|
90
|
+
showCharacterCount
|
|
91
|
+
}) => {
|
|
92
|
+
if (showCharacterCount) {
|
|
93
|
+
return /* @__PURE__ */ jsxs(Grid, { container: true, justifyContent: "space-between", flexWrap: "nowrap", children: [
|
|
94
|
+
/* @__PURE__ */ jsx6(FormHelperText, { sx: { marginRight: "12px" }, children: helperText }),
|
|
95
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "caption", marginTop: "4px", lineHeight: "1.25rem", children: [
|
|
96
|
+
/* @__PURE__ */ jsx6(Typography, { component: "span", variant: "inherit", color: charCount > maxLength ? "error" : "textPrimary", children: charCount || 0 }),
|
|
97
|
+
"/",
|
|
98
|
+
maxLength
|
|
99
|
+
] })
|
|
100
|
+
] });
|
|
101
|
+
}
|
|
102
|
+
return /* @__PURE__ */ jsx6(FormHelperText, { children: helperText });
|
|
103
|
+
};
|
|
104
|
+
var TextField = forwardRef3((props, ref) => {
|
|
76
105
|
var _b, _c, _d, _e, _f, _g, _h;
|
|
77
106
|
const _a = props, {
|
|
78
107
|
InputProps: InputProps2,
|
|
@@ -83,7 +112,8 @@ var TextField = forwardRef2((props, ref) => {
|
|
|
83
112
|
SelectProps: SelectProps2,
|
|
84
113
|
inputProps,
|
|
85
114
|
helperText,
|
|
86
|
-
showCharacterCount = false
|
|
115
|
+
showCharacterCount = false,
|
|
116
|
+
displayOverflowMaxLength = false
|
|
87
117
|
} = _a, rest = __objRest(_a, [
|
|
88
118
|
"InputProps",
|
|
89
119
|
"helpTopicId",
|
|
@@ -93,34 +123,32 @@ var TextField = forwardRef2((props, ref) => {
|
|
|
93
123
|
"SelectProps",
|
|
94
124
|
"inputProps",
|
|
95
125
|
"helperText",
|
|
96
|
-
"showCharacterCount"
|
|
126
|
+
"showCharacterCount",
|
|
127
|
+
"displayOverflowMaxLength"
|
|
97
128
|
]);
|
|
98
129
|
const [openDetected, setOpenDetected] = useState(false);
|
|
99
130
|
const [charCount, setCharCount] = useState(0);
|
|
131
|
+
const maxLength = (inputProps == null ? void 0 : inputProps.maxLength) || ((_c = (_b = rest.slotProps) == null ? void 0 : _b.htmlInput) == null ? void 0 : _c.maxLength);
|
|
100
132
|
const resolvedProps = (props2) => !props2 || Object.keys(props2).length === 0 ? void 0 : props2;
|
|
101
|
-
return /* @__PURE__ */
|
|
133
|
+
return /* @__PURE__ */ jsx6(
|
|
102
134
|
MuiTextField,
|
|
103
135
|
__spreadProps(__spreadValues({}, rest), {
|
|
104
136
|
onChange: (event) => {
|
|
105
137
|
setCharCount(event.target.value.length);
|
|
106
138
|
if (rest.onChange) rest.onChange(event);
|
|
107
139
|
},
|
|
108
|
-
helperText:
|
|
109
|
-
|
|
110
|
-
" ",
|
|
111
|
-
/* @__PURE__ */ jsxs("span", { style: { marginLeft: 4 }, children: [
|
|
112
|
-
charCount || 0,
|
|
113
|
-
"/",
|
|
114
|
-
(inputProps == null ? void 0 : inputProps.maxLength) || ((_c = (_b = rest.slotProps) == null ? void 0 : _b.htmlInput) == null ? void 0 : _c.maxLength)
|
|
115
|
-
] })
|
|
116
|
-
] }) : helperText,
|
|
117
|
-
slots: { formHelperText: FormHelperText },
|
|
140
|
+
helperText: helperText || /* @__PURE__ */ jsx6(Fragment, {}),
|
|
141
|
+
slots: { formHelperText: TextFieldFormHelperText },
|
|
118
142
|
slotProps: {
|
|
119
143
|
input: resolvedProps(__spreadValues(__spreadValues(__spreadValues({}, InputProps2), InputPropOverrides), (_d = rest.slotProps) == null ? void 0 : _d.input)),
|
|
120
|
-
htmlInput: resolvedProps(__spreadValues(__spreadValues({
|
|
144
|
+
htmlInput: resolvedProps(__spreadProps(__spreadValues(__spreadValues({
|
|
145
|
+
"aria-required": required
|
|
146
|
+
}, inputProps), (_e = rest.slotProps) == null ? void 0 : _e.htmlInput), {
|
|
147
|
+
maxLength: !displayOverflowMaxLength ? maxLength : void 0
|
|
148
|
+
})),
|
|
121
149
|
select: resolvedProps(__spreadValues(__spreadValues(__spreadValues(__spreadValues({
|
|
122
150
|
displayEmpty: !!rest.placeholder,
|
|
123
|
-
renderValue: (value) => rest.placeholder && (!value || Array.isArray(value) && value.length === 0) ? /* @__PURE__ */
|
|
151
|
+
renderValue: (value) => rest.placeholder && (!value || Array.isArray(value) && value.length === 0) ? /* @__PURE__ */ jsx6(SelectPlaceholder, { className: "MuiSelect-placeholder", children: rest.placeholder }) : value
|
|
124
152
|
}, SelectProps2), SelectPropOverrides), SelectAccessibilityOverrides(openDetected, setOpenDetected, SelectProps2 == null ? void 0 : SelectProps2.open)), (_f = rest.slotProps) == null ? void 0 : _f.select)),
|
|
125
153
|
inputLabel: resolvedProps(__spreadValues(__spreadValues({
|
|
126
154
|
component: FormLabel,
|
|
@@ -128,7 +156,15 @@ var TextField = forwardRef2((props, ref) => {
|
|
|
128
156
|
required,
|
|
129
157
|
shrink: true
|
|
130
158
|
}, InputLabelProps), (_g = rest.slotProps) == null ? void 0 : _g.inputLabel)),
|
|
131
|
-
formHelperText: resolvedProps(__spreadValues(__spreadValues({
|
|
159
|
+
formHelperText: resolvedProps(__spreadProps(__spreadValues(__spreadValues({
|
|
160
|
+
component: "div"
|
|
161
|
+
}, FormHelperTextProps2), (_h = rest.slotProps) == null ? void 0 : _h.formHelperText), {
|
|
162
|
+
charCount,
|
|
163
|
+
helperText,
|
|
164
|
+
maxLength,
|
|
165
|
+
displayOverflowMaxLength,
|
|
166
|
+
showCharacterCount
|
|
167
|
+
}))
|
|
132
168
|
},
|
|
133
169
|
ref
|
|
134
170
|
})
|
package/package.json
CHANGED
|
@@ -29,12 +29,24 @@ export const _TextField: StoryObj<typeof TextField> = {
|
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
export const _TextFieldCharacterCount: StoryObj<typeof TextField> = {
|
|
32
|
-
render: (args: TextFieldProps) => <TextField {...args} />,
|
|
32
|
+
render: (args: TextFieldProps) => <TextField sx={{ width: 'min-content' }} {...args} />,
|
|
33
|
+
args: {
|
|
34
|
+
label: 'Field Label',
|
|
35
|
+
id: 'test',
|
|
36
|
+
helpTopicId: '123',
|
|
37
|
+
showCharacterCount: true,
|
|
38
|
+
slotProps: { htmlInput: { maxLength: 10 } },
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const _TextFieldCharacterCountOverflow: StoryObj<typeof TextField> = {
|
|
43
|
+
render: (args: TextFieldProps) => <TextField sx={{ width: 'min-content' }} {...args} />,
|
|
33
44
|
args: {
|
|
34
45
|
label: 'Field Label',
|
|
35
46
|
id: 'test',
|
|
36
47
|
helpTopicId: '123',
|
|
37
48
|
showCharacterCount: true,
|
|
49
|
+
displayOverflowMaxLength: true,
|
|
38
50
|
slotProps: { htmlInput: { maxLength: 10 } },
|
|
39
51
|
},
|
|
40
52
|
};
|
|
@@ -14,12 +14,14 @@ describe('TextField', () => {
|
|
|
14
14
|
<TextField label="Test" showCharacterCount inputProps={{ 'data-testid': 'testTextField', maxLength: 20 }} />
|
|
15
15
|
);
|
|
16
16
|
|
|
17
|
-
expect(getByText('0
|
|
17
|
+
expect(getByText('0')).toBeTruthy();
|
|
18
|
+
expect(getByText('/20')).toBeTruthy();
|
|
18
19
|
|
|
19
20
|
const input = getByTestId('testTextField');
|
|
20
21
|
fireEvent.change(input, { target: { value: 'Some Text' } });
|
|
21
22
|
|
|
22
|
-
expect(getByText('9
|
|
23
|
+
expect(getByText('9')).toBeTruthy();
|
|
24
|
+
expect(getByText('/20')).toBeTruthy();
|
|
23
25
|
|
|
24
26
|
fireEvent.change(input, { target: { value: "Some More Text that doesn't fit" } });
|
|
25
27
|
|
|
@@ -34,12 +36,14 @@ describe('TextField', () => {
|
|
|
34
36
|
slotProps={{ htmlInput: { 'data-testid': 'testTextField', maxLength: 20 } }}
|
|
35
37
|
/>
|
|
36
38
|
);
|
|
37
|
-
expect(getByText('0
|
|
39
|
+
expect(getByText('0')).toBeTruthy();
|
|
40
|
+
expect(getByText('/20')).toBeTruthy();
|
|
38
41
|
|
|
39
42
|
const input = getByTestId('testTextField');
|
|
40
43
|
fireEvent.change(input, { target: { value: 'Some Text' } });
|
|
41
44
|
|
|
42
|
-
expect(getByText('9
|
|
45
|
+
expect(getByText('9')).toBeTruthy();
|
|
46
|
+
expect(getByText('/20')).toBeTruthy();
|
|
43
47
|
|
|
44
48
|
fireEvent.change(input, { target: { value: "Some More Text that doesn't fit" } });
|
|
45
49
|
|
package/src/lib/TextField.tsx
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
SelectProps,
|
|
13
13
|
} from '@availity/mui-form-utils';
|
|
14
14
|
import { Grid } from '@availity/mui-layout';
|
|
15
|
+
import { Typography } from '@availity/mui-typography';
|
|
15
16
|
import { styled } from '@mui/material/styles';
|
|
16
17
|
|
|
17
18
|
export type TextFieldProps = {
|
|
@@ -23,6 +24,8 @@ export type TextFieldProps = {
|
|
|
23
24
|
fullWidth?: boolean;
|
|
24
25
|
/** if `true`, the character counter will display. The maxLength is taken from the `inputProps.maxLength` prop. @default false */
|
|
25
26
|
showCharacterCount?: boolean;
|
|
27
|
+
/** If `true`, the input maxLength can be exceeded. If validation is required, you'll have to do it manually. @default false */
|
|
28
|
+
displayOverflowMaxLength?: boolean;
|
|
26
29
|
} & Pick<FormLabelProps, 'helpTopicId'> &
|
|
27
30
|
Omit<MuiTextFieldProps, 'fullWidth' | 'variant'>;
|
|
28
31
|
|
|
@@ -32,6 +35,36 @@ const SelectPlaceholder = styled('span', {
|
|
|
32
35
|
overridesResolver: (props, styles) => styles.avFilled,
|
|
33
36
|
})(({ theme }) => ({ opacity: 1, color: theme.palette.grey[400] }));
|
|
34
37
|
|
|
38
|
+
export type TextFieldFormHelperTextProps = {
|
|
39
|
+
charCount: string;
|
|
40
|
+
helperText: string;
|
|
41
|
+
maxLength: string;
|
|
42
|
+
showCharacterCount: boolean;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const TextFieldFormHelperText = ({
|
|
46
|
+
charCount,
|
|
47
|
+
helperText,
|
|
48
|
+
maxLength,
|
|
49
|
+
showCharacterCount,
|
|
50
|
+
}: TextFieldFormHelperTextProps) => {
|
|
51
|
+
if (showCharacterCount) {
|
|
52
|
+
return (
|
|
53
|
+
<Grid container justifyContent="space-between" flexWrap="nowrap">
|
|
54
|
+
<FormHelperText sx={{ marginRight: '12px' }}>{helperText}</FormHelperText>
|
|
55
|
+
<Typography variant="caption" marginTop="4px" lineHeight="1.25rem">
|
|
56
|
+
<Typography component="span" variant="inherit" color={charCount > maxLength ? 'error' : 'textPrimary'}>
|
|
57
|
+
{charCount || 0}
|
|
58
|
+
</Typography>
|
|
59
|
+
/{maxLength}
|
|
60
|
+
</Typography>
|
|
61
|
+
</Grid>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return <FormHelperText>{helperText}</FormHelperText>;
|
|
66
|
+
};
|
|
67
|
+
|
|
35
68
|
export const TextField = forwardRef<HTMLDivElement | HTMLInputElement, TextFieldProps>((props, ref) => {
|
|
36
69
|
const {
|
|
37
70
|
InputProps,
|
|
@@ -43,11 +76,15 @@ export const TextField = forwardRef<HTMLDivElement | HTMLInputElement, TextField
|
|
|
43
76
|
inputProps,
|
|
44
77
|
helperText,
|
|
45
78
|
showCharacterCount = false,
|
|
79
|
+
displayOverflowMaxLength = false,
|
|
46
80
|
...rest
|
|
47
81
|
} = props;
|
|
48
82
|
const [openDetected, setOpenDetected] = useState(false);
|
|
49
83
|
const [charCount, setCharCount] = useState(0);
|
|
50
84
|
|
|
85
|
+
// @ts-expect-error I'm not sure why maxLength is undefined in htmlInput, but it works. There's something weird with the type.
|
|
86
|
+
const maxLength = inputProps?.maxLength || rest.slotProps?.htmlInput?.maxLength;
|
|
87
|
+
|
|
51
88
|
const resolvedProps = (props: Record<string, unknown>) =>
|
|
52
89
|
!props || Object.keys(props).length === 0 ? undefined : props;
|
|
53
90
|
|
|
@@ -58,23 +95,16 @@ export const TextField = forwardRef<HTMLDivElement | HTMLInputElement, TextField
|
|
|
58
95
|
setCharCount(event.target.value.length);
|
|
59
96
|
if (rest.onChange) rest.onChange(event);
|
|
60
97
|
}}
|
|
61
|
-
helperText={
|
|
62
|
-
|
|
63
|
-
<Grid container justifyContent="space-between">
|
|
64
|
-
{helperText}{' '}
|
|
65
|
-
<span style={{ marginLeft: 4 }}>
|
|
66
|
-
{/* @ts-expect-error I'm not sure why maxLength is undefined here, but it works. */}
|
|
67
|
-
{charCount || 0}/{inputProps?.maxLength || rest.slotProps?.htmlInput?.maxLength}
|
|
68
|
-
</span>
|
|
69
|
-
</Grid>
|
|
70
|
-
) : (
|
|
71
|
-
helperText
|
|
72
|
-
)
|
|
73
|
-
}
|
|
74
|
-
slots={{ formHelperText: FormHelperText }}
|
|
98
|
+
helperText={helperText || <></>}
|
|
99
|
+
slots={{ formHelperText: TextFieldFormHelperText }}
|
|
75
100
|
slotProps={{
|
|
76
101
|
input: resolvedProps({ ...InputProps, ...InputPropOverrides, ...rest.slotProps?.input }),
|
|
77
|
-
htmlInput: resolvedProps({
|
|
102
|
+
htmlInput: resolvedProps({
|
|
103
|
+
'aria-required': required,
|
|
104
|
+
...inputProps,
|
|
105
|
+
...rest.slotProps?.htmlInput,
|
|
106
|
+
maxLength: !displayOverflowMaxLength ? maxLength : undefined,
|
|
107
|
+
}),
|
|
78
108
|
select: resolvedProps({
|
|
79
109
|
displayEmpty: !!rest.placeholder,
|
|
80
110
|
renderValue: (value: unknown) =>
|
|
@@ -96,7 +126,16 @@ export const TextField = forwardRef<HTMLDivElement | HTMLInputElement, TextField
|
|
|
96
126
|
...InputLabelProps,
|
|
97
127
|
...rest.slotProps?.inputLabel,
|
|
98
128
|
}),
|
|
99
|
-
formHelperText: resolvedProps({
|
|
129
|
+
formHelperText: resolvedProps({
|
|
130
|
+
component: 'div',
|
|
131
|
+
...FormHelperTextProps,
|
|
132
|
+
...rest.slotProps?.formHelperText,
|
|
133
|
+
charCount,
|
|
134
|
+
helperText,
|
|
135
|
+
maxLength,
|
|
136
|
+
displayOverflowMaxLength,
|
|
137
|
+
showCharacterCount,
|
|
138
|
+
}),
|
|
100
139
|
}}
|
|
101
140
|
ref={ref}
|
|
102
141
|
/>
|