@availity/mui-textfield 1.1.0 → 1.1.2
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 +9 -0
- package/dist/index.d.mts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +63 -21
- package/dist/index.mjs +61 -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 +58 -16
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
## [1.1.2](https://github.com/Availity/element/compare/@availity/mui-textfield@1.1.1...@availity/mui-textfield@1.1.2) (2025-04-04)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **mui-textfield:** ensure helperText props are passed to helperText ([2d3de04](https://github.com/Availity/element/commit/2d3de04393bb0df18d5a8d73cad0ea688f90a0b2))
|
|
11
|
+
|
|
12
|
+
## [1.1.1](https://github.com/Availity/element/compare/@availity/mui-textfield@1.1.0...@availity/mui-textfield@1.1.1) (2025-03-27)
|
|
13
|
+
|
|
5
14
|
## [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
15
|
|
|
7
16
|
### 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
|
+
} & FormHelperTextProps;
|
|
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
|
+
} & FormHelperTextProps;
|
|
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,50 @@ 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 = (_a) => {
|
|
114
|
+
var _b = _a, {
|
|
115
|
+
charCount,
|
|
116
|
+
helperText,
|
|
117
|
+
maxLength,
|
|
118
|
+
showCharacterCount
|
|
119
|
+
} = _b, FormHelperTextProps2 = __objRest(_b, [
|
|
120
|
+
"charCount",
|
|
121
|
+
"helperText",
|
|
122
|
+
"maxLength",
|
|
123
|
+
"showCharacterCount"
|
|
124
|
+
]);
|
|
125
|
+
if (showCharacterCount) {
|
|
126
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Grid, { container: true, justifyContent: "space-between", flexWrap: "nowrap", children: [
|
|
127
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_mui_form_utils.FormHelperText, __spreadProps(__spreadValues({}, FormHelperTextProps2), { sx: { marginRight: "12px" }, children: helperText })),
|
|
128
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Typography, { variant: "caption", marginTop: "4px", lineHeight: "1.25rem", children: [
|
|
129
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Typography, { component: "span", variant: "inherit", color: charCount > maxLength ? "error" : "textPrimary", children: charCount || 0 }),
|
|
130
|
+
"/",
|
|
131
|
+
maxLength
|
|
132
|
+
] })
|
|
133
|
+
] });
|
|
134
|
+
}
|
|
135
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_mui_form_utils.FormHelperText, __spreadProps(__spreadValues({}, FormHelperTextProps2), { children: helperText }));
|
|
136
|
+
};
|
|
137
|
+
var TextField = (0, import_react3.forwardRef)((props, ref) => {
|
|
103
138
|
var _b, _c, _d, _e, _f, _g, _h;
|
|
104
139
|
const _a = props, {
|
|
105
140
|
InputProps: InputProps2,
|
|
@@ -110,7 +145,8 @@ var TextField = (0, import_react2.forwardRef)((props, ref) => {
|
|
|
110
145
|
SelectProps: SelectProps2,
|
|
111
146
|
inputProps,
|
|
112
147
|
helperText,
|
|
113
|
-
showCharacterCount = false
|
|
148
|
+
showCharacterCount = false,
|
|
149
|
+
displayOverflowMaxLength = false
|
|
114
150
|
} = _a, rest = __objRest(_a, [
|
|
115
151
|
"InputProps",
|
|
116
152
|
"helpTopicId",
|
|
@@ -120,34 +156,32 @@ var TextField = (0, import_react2.forwardRef)((props, ref) => {
|
|
|
120
156
|
"SelectProps",
|
|
121
157
|
"inputProps",
|
|
122
158
|
"helperText",
|
|
123
|
-
"showCharacterCount"
|
|
159
|
+
"showCharacterCount",
|
|
160
|
+
"displayOverflowMaxLength"
|
|
124
161
|
]);
|
|
125
|
-
const [openDetected, setOpenDetected] = (0,
|
|
126
|
-
const [charCount, setCharCount] = (0,
|
|
162
|
+
const [openDetected, setOpenDetected] = (0, import_react3.useState)(false);
|
|
163
|
+
const [charCount, setCharCount] = (0, import_react3.useState)(0);
|
|
164
|
+
const maxLength = (inputProps == null ? void 0 : inputProps.maxLength) || ((_c = (_b = rest.slotProps) == null ? void 0 : _b.htmlInput) == null ? void 0 : _c.maxLength);
|
|
127
165
|
const resolvedProps = (props2) => !props2 || Object.keys(props2).length === 0 ? void 0 : props2;
|
|
128
|
-
return /* @__PURE__ */ (0,
|
|
166
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
129
167
|
import_TextField.default,
|
|
130
168
|
__spreadProps(__spreadValues({}, rest), {
|
|
131
169
|
onChange: (event) => {
|
|
132
170
|
setCharCount(event.target.value.length);
|
|
133
171
|
if (rest.onChange) rest.onChange(event);
|
|
134
172
|
},
|
|
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 },
|
|
173
|
+
helperText: helperText || /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, {}),
|
|
174
|
+
slots: { formHelperText: TextFieldFormHelperText },
|
|
145
175
|
slotProps: {
|
|
146
176
|
input: resolvedProps(__spreadValues(__spreadValues(__spreadValues({}, InputProps2), import_mui_form_utils.InputPropOverrides), (_d = rest.slotProps) == null ? void 0 : _d.input)),
|
|
147
|
-
htmlInput: resolvedProps(__spreadValues(__spreadValues({
|
|
177
|
+
htmlInput: resolvedProps(__spreadProps(__spreadValues(__spreadValues({
|
|
178
|
+
"aria-required": required
|
|
179
|
+
}, inputProps), (_e = rest.slotProps) == null ? void 0 : _e.htmlInput), {
|
|
180
|
+
maxLength: !displayOverflowMaxLength ? maxLength : void 0
|
|
181
|
+
})),
|
|
148
182
|
select: resolvedProps(__spreadValues(__spreadValues(__spreadValues(__spreadValues({
|
|
149
183
|
displayEmpty: !!rest.placeholder,
|
|
150
|
-
renderValue: (value) => rest.placeholder && (!value || Array.isArray(value) && value.length === 0) ? /* @__PURE__ */ (0,
|
|
184
|
+
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
185
|
}, 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
186
|
inputLabel: resolvedProps(__spreadValues(__spreadValues({
|
|
153
187
|
component: import_mui_form_utils.FormLabel,
|
|
@@ -155,7 +189,15 @@ var TextField = (0, import_react2.forwardRef)((props, ref) => {
|
|
|
155
189
|
required,
|
|
156
190
|
shrink: true
|
|
157
191
|
}, InputLabelProps), (_g = rest.slotProps) == null ? void 0 : _g.inputLabel)),
|
|
158
|
-
formHelperText: resolvedProps(__spreadValues(__spreadValues({
|
|
192
|
+
formHelperText: resolvedProps(__spreadProps(__spreadValues(__spreadValues({
|
|
193
|
+
component: "div"
|
|
194
|
+
}, FormHelperTextProps2), (_h = rest.slotProps) == null ? void 0 : _h.formHelperText), {
|
|
195
|
+
charCount,
|
|
196
|
+
helperText,
|
|
197
|
+
maxLength,
|
|
198
|
+
displayOverflowMaxLength,
|
|
199
|
+
showCharacterCount
|
|
200
|
+
}))
|
|
159
201
|
},
|
|
160
202
|
ref
|
|
161
203
|
})
|
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,50 @@ 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 = (_a) => {
|
|
87
|
+
var _b = _a, {
|
|
88
|
+
charCount,
|
|
89
|
+
helperText,
|
|
90
|
+
maxLength,
|
|
91
|
+
showCharacterCount
|
|
92
|
+
} = _b, FormHelperTextProps2 = __objRest(_b, [
|
|
93
|
+
"charCount",
|
|
94
|
+
"helperText",
|
|
95
|
+
"maxLength",
|
|
96
|
+
"showCharacterCount"
|
|
97
|
+
]);
|
|
98
|
+
if (showCharacterCount) {
|
|
99
|
+
return /* @__PURE__ */ jsxs(Grid, { container: true, justifyContent: "space-between", flexWrap: "nowrap", children: [
|
|
100
|
+
/* @__PURE__ */ jsx6(FormHelperText, __spreadProps(__spreadValues({}, FormHelperTextProps2), { sx: { marginRight: "12px" }, children: helperText })),
|
|
101
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "caption", marginTop: "4px", lineHeight: "1.25rem", children: [
|
|
102
|
+
/* @__PURE__ */ jsx6(Typography, { component: "span", variant: "inherit", color: charCount > maxLength ? "error" : "textPrimary", children: charCount || 0 }),
|
|
103
|
+
"/",
|
|
104
|
+
maxLength
|
|
105
|
+
] })
|
|
106
|
+
] });
|
|
107
|
+
}
|
|
108
|
+
return /* @__PURE__ */ jsx6(FormHelperText, __spreadProps(__spreadValues({}, FormHelperTextProps2), { children: helperText }));
|
|
109
|
+
};
|
|
110
|
+
var TextField = forwardRef3((props, ref) => {
|
|
76
111
|
var _b, _c, _d, _e, _f, _g, _h;
|
|
77
112
|
const _a = props, {
|
|
78
113
|
InputProps: InputProps2,
|
|
@@ -83,7 +118,8 @@ var TextField = forwardRef2((props, ref) => {
|
|
|
83
118
|
SelectProps: SelectProps2,
|
|
84
119
|
inputProps,
|
|
85
120
|
helperText,
|
|
86
|
-
showCharacterCount = false
|
|
121
|
+
showCharacterCount = false,
|
|
122
|
+
displayOverflowMaxLength = false
|
|
87
123
|
} = _a, rest = __objRest(_a, [
|
|
88
124
|
"InputProps",
|
|
89
125
|
"helpTopicId",
|
|
@@ -93,34 +129,32 @@ var TextField = forwardRef2((props, ref) => {
|
|
|
93
129
|
"SelectProps",
|
|
94
130
|
"inputProps",
|
|
95
131
|
"helperText",
|
|
96
|
-
"showCharacterCount"
|
|
132
|
+
"showCharacterCount",
|
|
133
|
+
"displayOverflowMaxLength"
|
|
97
134
|
]);
|
|
98
135
|
const [openDetected, setOpenDetected] = useState(false);
|
|
99
136
|
const [charCount, setCharCount] = useState(0);
|
|
137
|
+
const maxLength = (inputProps == null ? void 0 : inputProps.maxLength) || ((_c = (_b = rest.slotProps) == null ? void 0 : _b.htmlInput) == null ? void 0 : _c.maxLength);
|
|
100
138
|
const resolvedProps = (props2) => !props2 || Object.keys(props2).length === 0 ? void 0 : props2;
|
|
101
|
-
return /* @__PURE__ */
|
|
139
|
+
return /* @__PURE__ */ jsx6(
|
|
102
140
|
MuiTextField,
|
|
103
141
|
__spreadProps(__spreadValues({}, rest), {
|
|
104
142
|
onChange: (event) => {
|
|
105
143
|
setCharCount(event.target.value.length);
|
|
106
144
|
if (rest.onChange) rest.onChange(event);
|
|
107
145
|
},
|
|
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 },
|
|
146
|
+
helperText: helperText || /* @__PURE__ */ jsx6(Fragment, {}),
|
|
147
|
+
slots: { formHelperText: TextFieldFormHelperText },
|
|
118
148
|
slotProps: {
|
|
119
149
|
input: resolvedProps(__spreadValues(__spreadValues(__spreadValues({}, InputProps2), InputPropOverrides), (_d = rest.slotProps) == null ? void 0 : _d.input)),
|
|
120
|
-
htmlInput: resolvedProps(__spreadValues(__spreadValues({
|
|
150
|
+
htmlInput: resolvedProps(__spreadProps(__spreadValues(__spreadValues({
|
|
151
|
+
"aria-required": required
|
|
152
|
+
}, inputProps), (_e = rest.slotProps) == null ? void 0 : _e.htmlInput), {
|
|
153
|
+
maxLength: !displayOverflowMaxLength ? maxLength : void 0
|
|
154
|
+
})),
|
|
121
155
|
select: resolvedProps(__spreadValues(__spreadValues(__spreadValues(__spreadValues({
|
|
122
156
|
displayEmpty: !!rest.placeholder,
|
|
123
|
-
renderValue: (value) => rest.placeholder && (!value || Array.isArray(value) && value.length === 0) ? /* @__PURE__ */
|
|
157
|
+
renderValue: (value) => rest.placeholder && (!value || Array.isArray(value) && value.length === 0) ? /* @__PURE__ */ jsx6(SelectPlaceholder, { className: "MuiSelect-placeholder", children: rest.placeholder }) : value
|
|
124
158
|
}, SelectProps2), SelectPropOverrides), SelectAccessibilityOverrides(openDetected, setOpenDetected, SelectProps2 == null ? void 0 : SelectProps2.open)), (_f = rest.slotProps) == null ? void 0 : _f.select)),
|
|
125
159
|
inputLabel: resolvedProps(__spreadValues(__spreadValues({
|
|
126
160
|
component: FormLabel,
|
|
@@ -128,7 +162,15 @@ var TextField = forwardRef2((props, ref) => {
|
|
|
128
162
|
required,
|
|
129
163
|
shrink: true
|
|
130
164
|
}, InputLabelProps), (_g = rest.slotProps) == null ? void 0 : _g.inputLabel)),
|
|
131
|
-
formHelperText: resolvedProps(__spreadValues(__spreadValues({
|
|
165
|
+
formHelperText: resolvedProps(__spreadProps(__spreadValues(__spreadValues({
|
|
166
|
+
component: "div"
|
|
167
|
+
}, FormHelperTextProps2), (_h = rest.slotProps) == null ? void 0 : _h.formHelperText), {
|
|
168
|
+
charCount,
|
|
169
|
+
helperText,
|
|
170
|
+
maxLength,
|
|
171
|
+
displayOverflowMaxLength,
|
|
172
|
+
showCharacterCount
|
|
173
|
+
}))
|
|
132
174
|
},
|
|
133
175
|
ref
|
|
134
176
|
})
|
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,39 @@ 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
|
+
} & FormHelperTextProps;
|
|
44
|
+
|
|
45
|
+
const TextFieldFormHelperText = ({
|
|
46
|
+
charCount,
|
|
47
|
+
helperText,
|
|
48
|
+
maxLength,
|
|
49
|
+
showCharacterCount,
|
|
50
|
+
...FormHelperTextProps
|
|
51
|
+
}: TextFieldFormHelperTextProps) => {
|
|
52
|
+
if (showCharacterCount) {
|
|
53
|
+
return (
|
|
54
|
+
<Grid container justifyContent="space-between" flexWrap="nowrap">
|
|
55
|
+
<FormHelperText {...FormHelperTextProps} sx={{ marginRight: '12px' }}>
|
|
56
|
+
{helperText}
|
|
57
|
+
</FormHelperText>
|
|
58
|
+
<Typography variant="caption" marginTop="4px" lineHeight="1.25rem">
|
|
59
|
+
<Typography component="span" variant="inherit" color={charCount > maxLength ? 'error' : 'textPrimary'}>
|
|
60
|
+
{charCount || 0}
|
|
61
|
+
</Typography>
|
|
62
|
+
/{maxLength}
|
|
63
|
+
</Typography>
|
|
64
|
+
</Grid>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return <FormHelperText {...FormHelperTextProps}>{helperText}</FormHelperText>;
|
|
69
|
+
};
|
|
70
|
+
|
|
35
71
|
export const TextField = forwardRef<HTMLDivElement | HTMLInputElement, TextFieldProps>((props, ref) => {
|
|
36
72
|
const {
|
|
37
73
|
InputProps,
|
|
@@ -43,11 +79,15 @@ export const TextField = forwardRef<HTMLDivElement | HTMLInputElement, TextField
|
|
|
43
79
|
inputProps,
|
|
44
80
|
helperText,
|
|
45
81
|
showCharacterCount = false,
|
|
82
|
+
displayOverflowMaxLength = false,
|
|
46
83
|
...rest
|
|
47
84
|
} = props;
|
|
48
85
|
const [openDetected, setOpenDetected] = useState(false);
|
|
49
86
|
const [charCount, setCharCount] = useState(0);
|
|
50
87
|
|
|
88
|
+
// @ts-expect-error I'm not sure why maxLength is undefined in htmlInput, but it works. There's something weird with the type.
|
|
89
|
+
const maxLength = inputProps?.maxLength || rest.slotProps?.htmlInput?.maxLength;
|
|
90
|
+
|
|
51
91
|
const resolvedProps = (props: Record<string, unknown>) =>
|
|
52
92
|
!props || Object.keys(props).length === 0 ? undefined : props;
|
|
53
93
|
|
|
@@ -58,23 +98,16 @@ export const TextField = forwardRef<HTMLDivElement | HTMLInputElement, TextField
|
|
|
58
98
|
setCharCount(event.target.value.length);
|
|
59
99
|
if (rest.onChange) rest.onChange(event);
|
|
60
100
|
}}
|
|
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 }}
|
|
101
|
+
helperText={helperText || <></>}
|
|
102
|
+
slots={{ formHelperText: TextFieldFormHelperText }}
|
|
75
103
|
slotProps={{
|
|
76
104
|
input: resolvedProps({ ...InputProps, ...InputPropOverrides, ...rest.slotProps?.input }),
|
|
77
|
-
htmlInput: resolvedProps({
|
|
105
|
+
htmlInput: resolvedProps({
|
|
106
|
+
'aria-required': required,
|
|
107
|
+
...inputProps,
|
|
108
|
+
...rest.slotProps?.htmlInput,
|
|
109
|
+
maxLength: !displayOverflowMaxLength ? maxLength : undefined,
|
|
110
|
+
}),
|
|
78
111
|
select: resolvedProps({
|
|
79
112
|
displayEmpty: !!rest.placeholder,
|
|
80
113
|
renderValue: (value: unknown) =>
|
|
@@ -96,7 +129,16 @@ export const TextField = forwardRef<HTMLDivElement | HTMLInputElement, TextField
|
|
|
96
129
|
...InputLabelProps,
|
|
97
130
|
...rest.slotProps?.inputLabel,
|
|
98
131
|
}),
|
|
99
|
-
formHelperText: resolvedProps({
|
|
132
|
+
formHelperText: resolvedProps({
|
|
133
|
+
component: 'div',
|
|
134
|
+
...FormHelperTextProps,
|
|
135
|
+
...rest.slotProps?.formHelperText,
|
|
136
|
+
charCount,
|
|
137
|
+
helperText,
|
|
138
|
+
maxLength,
|
|
139
|
+
displayOverflowMaxLength,
|
|
140
|
+
showCharacterCount,
|
|
141
|
+
}),
|
|
100
142
|
}}
|
|
101
143
|
ref={ref}
|
|
102
144
|
/>
|