@abstraks-dev/ui-library 1.0.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/LICENSE +21 -0
- package/README.md +708 -0
- package/dist/__tests__/Anchor.test.js +145 -0
- package/dist/__tests__/ArrowRight.test.js +91 -0
- package/dist/__tests__/Avatar.test.js +123 -0
- package/dist/__tests__/Button.test.js +82 -0
- package/dist/__tests__/Card.test.js +198 -0
- package/dist/__tests__/CheckCircle.test.js +98 -0
- package/dist/__tests__/Checkbox.test.js +161 -0
- package/dist/__tests__/ChevronDown.test.js +73 -0
- package/dist/__tests__/Close.test.js +98 -0
- package/dist/__tests__/EditSquare.test.js +99 -0
- package/dist/__tests__/Error.test.js +74 -0
- package/dist/__tests__/Footer.test.js +66 -0
- package/dist/__tests__/Heading.test.js +227 -0
- package/dist/__tests__/Hero.test.js +74 -0
- package/dist/__tests__/Label.test.js +123 -0
- package/dist/__tests__/Loader.test.js +115 -0
- package/dist/__tests__/MenuHover.test.js +137 -0
- package/dist/__tests__/Paragraph.test.js +93 -0
- package/dist/__tests__/PlusCircle.test.js +99 -0
- package/dist/__tests__/Radio.test.js +153 -0
- package/dist/__tests__/Select.test.js +187 -0
- package/dist/__tests__/Tabs.test.js +162 -0
- package/dist/__tests__/TextArea.test.js +127 -0
- package/dist/__tests__/TextInput.test.js +181 -0
- package/dist/__tests__/Toggle.test.js +120 -0
- package/dist/__tests__/TrashX.test.js +99 -0
- package/dist/__tests__/useHeadingAccessibility.test.js +144 -0
- package/dist/components/Anchor.js +131 -0
- package/dist/components/Animation.js +129 -0
- package/dist/components/AnimationGroup.js +207 -0
- package/dist/components/AnimationToggle.js +216 -0
- package/dist/components/Avatar.js +153 -0
- package/dist/components/Button.js +218 -0
- package/dist/components/Card.js +222 -0
- package/dist/components/Checkbox.js +305 -0
- package/dist/components/Crud.js +564 -0
- package/dist/components/DragAndDrop.js +337 -0
- package/dist/components/Error.js +206 -0
- package/dist/components/Footer.js +99 -0
- package/dist/components/Form.js +412 -0
- package/dist/components/Header.js +372 -0
- package/dist/components/Heading.js +134 -0
- package/dist/components/Hero.js +181 -0
- package/dist/components/Label.js +256 -0
- package/dist/components/Loader.js +302 -0
- package/dist/components/MenuHover.js +114 -0
- package/dist/components/Paragraph.js +128 -0
- package/dist/components/Prompt.js +61 -0
- package/dist/components/Radio.js +254 -0
- package/dist/components/Select.js +422 -0
- package/dist/components/SideMenu.js +313 -0
- package/dist/components/Tabs.js +297 -0
- package/dist/components/TextArea.js +370 -0
- package/dist/components/TextInput.js +286 -0
- package/dist/components/Toggle.js +186 -0
- package/dist/components/crudFiles/CrudEditBase.js +150 -0
- package/dist/components/crudFiles/CrudViewBase.js +39 -0
- package/dist/components/crudFiles/crudDevelopment.js +118 -0
- package/dist/components/crudFiles/crudEditHandlers.js +50 -0
- package/dist/constants/animation.js +30 -0
- package/dist/icons/ArrowIcon.js +32 -0
- package/dist/icons/ArrowRight.js +33 -0
- package/dist/icons/CheckCircle.js +33 -0
- package/dist/icons/ChevronDown.js +28 -0
- package/dist/icons/Close.js +33 -0
- package/dist/icons/EditSquare.js +33 -0
- package/dist/icons/Ellipses.js +34 -0
- package/dist/icons/Hamburger.js +39 -0
- package/dist/icons/LoadingSpinner.js +42 -0
- package/dist/icons/PlusCircle.js +33 -0
- package/dist/icons/SaveIcon.js +32 -0
- package/dist/icons/TrashX.js +33 -0
- package/dist/icons/__tests__/CheckCircle.test.js +9 -0
- package/dist/icons/__tests__/ChevronDown.test.js +9 -0
- package/dist/icons/__tests__/Close.test.js +9 -0
- package/dist/icons/__tests__/EditSquare.test.js +9 -0
- package/dist/icons/__tests__/PlusCircle.test.js +9 -0
- package/dist/icons/__tests__/TrashX.test.js +9 -0
- package/dist/icons/index.js +89 -0
- package/dist/index.js +332 -0
- package/dist/setupTests.js +3 -0
- package/dist/styles/_variables.scss +286 -0
- package/dist/styles/anchor.scss +40 -0
- package/dist/styles/animation-accessibility.scss +96 -0
- package/dist/styles/animation-toggle.scss +233 -0
- package/dist/styles/animation.scss +3781 -0
- package/dist/styles/avatar.scss +285 -0
- package/dist/styles/button.scss +430 -0
- package/dist/styles/card.scss +210 -0
- package/dist/styles/checkbox.scss +160 -0
- package/dist/styles/crud.scss +474 -0
- package/dist/styles/dragAndDrop.scss +312 -0
- package/dist/styles/error.scss +232 -0
- package/dist/styles/footer.scss +58 -0
- package/dist/styles/form.scss +420 -0
- package/dist/styles/grid.scss +29 -0
- package/dist/styles/header.scss +276 -0
- package/dist/styles/heading.scss +118 -0
- package/dist/styles/hero.scss +185 -0
- package/dist/styles/htmlElements.scss +20 -0
- package/dist/styles/image.scss +9 -0
- package/dist/styles/label.scss +340 -0
- package/dist/styles/list-item.scss +5 -0
- package/dist/styles/loader.scss +354 -0
- package/dist/styles/logo.scss +19 -0
- package/dist/styles/main.css +9056 -0
- package/dist/styles/main.css.map +1 -0
- package/dist/styles/main.scss +0 -0
- package/dist/styles/menu-hover.scss +30 -0
- package/dist/styles/paragraph.scss +88 -0
- package/dist/styles/prompt.scss +51 -0
- package/dist/styles/radio.scss +202 -0
- package/dist/styles/select.scss +363 -0
- package/dist/styles/side-menu.scss +334 -0
- package/dist/styles/tabs.scss +540 -0
- package/dist/styles/text-area.scss +388 -0
- package/dist/styles/text-input.scss +171 -0
- package/dist/styles/toggle.scss +0 -0
- package/dist/styles/unordered-list.scss +8 -0
- package/dist/utils/ScrollHandler.js +30 -0
- package/dist/utils/accessibility.js +128 -0
- package/dist/utils/heroUtils.js +316 -0
- package/dist/utils/index.js +104 -0
- package/dist/utils/inputValidation.js +29 -0
- package/dist/utils/keyboardNavigation.js +536 -0
- package/dist/utils/labelUtils.js +708 -0
- package/dist/utils/loaderUtils.js +387 -0
- package/dist/utils/menuUtils.js +575 -0
- package/dist/utils/useHeadingAccessibility.js +298 -0
- package/dist/utils/useRadioGroup.js +260 -0
- package/dist/utils/useSelectAccessibility.js +426 -0
- package/dist/utils/useTabsAccessibility.js +278 -0
- package/dist/utils/useTextAreaAccessibility.js +255 -0
- package/dist/utils/useTextInputAccessibility.js +295 -0
- package/dist/utils/useTypographyAccessibility.js +168 -0
- package/dist/utils/useWindowSize.js +32 -0
- package/dist/utils/utils/ScrollHandler.js +26 -0
- package/dist/utils/utils/accessibility.js +133 -0
- package/dist/utils/utils/heroUtils.js +348 -0
- package/dist/utils/utils/index.js +9 -0
- package/dist/utils/utils/inputValidation.js +22 -0
- package/dist/utils/utils/keyboardNavigation.js +664 -0
- package/dist/utils/utils/labelUtils.js +772 -0
- package/dist/utils/utils/loaderUtils.js +436 -0
- package/dist/utils/utils/menuUtils.js +651 -0
- package/dist/utils/utils/useHeadingAccessibility.js +334 -0
- package/dist/utils/utils/useRadioGroup.js +311 -0
- package/dist/utils/utils/useSelectAccessibility.js +498 -0
- package/dist/utils/utils/useTabsAccessibility.js +316 -0
- package/dist/utils/utils/useTextAreaAccessibility.js +303 -0
- package/dist/utils/utils/useTextInputAccessibility.js +338 -0
- package/dist/utils/utils/useTypographyAccessibility.js +180 -0
- package/dist/utils/utils/useWindowSize.js +26 -0
- package/dist/utils/utils/validation.js +131 -0
- package/dist/utils/validation.js +139 -0
- package/package.json +90 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.TextArea = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _propTypes = require("prop-types");
|
|
9
|
+
var _Label = require("./Label");
|
|
10
|
+
var _Error = require("./Error");
|
|
11
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (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 (const 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); }
|
|
12
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } /*eslint-disable no-unused-vars*/ // components
|
|
13
|
+
/**
|
|
14
|
+
* TextArea Component
|
|
15
|
+
*
|
|
16
|
+
* A fully accessible, modern textarea component following WCAG 2.1 AA guidelines.
|
|
17
|
+
* Features keyboard navigation, screen reader support, character counting, and validation.
|
|
18
|
+
*
|
|
19
|
+
* This is a stateless component - state management should be handled externally.
|
|
20
|
+
* Use with the useTextAreaAccessibility hook for complete functionality.
|
|
21
|
+
*
|
|
22
|
+
* @component
|
|
23
|
+
* @example
|
|
24
|
+
* <TextArea
|
|
25
|
+
* id="description"
|
|
26
|
+
* label="Description"
|
|
27
|
+
* value={description}
|
|
28
|
+
* onChange={handleChange}
|
|
29
|
+
* maxLength={500}
|
|
30
|
+
* required
|
|
31
|
+
* rows={4}
|
|
32
|
+
* />
|
|
33
|
+
*/
|
|
34
|
+
const TextArea = exports.TextArea = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
35
|
+
// Core props
|
|
36
|
+
id,
|
|
37
|
+
name,
|
|
38
|
+
label,
|
|
39
|
+
value = '',
|
|
40
|
+
onChange,
|
|
41
|
+
onFocus,
|
|
42
|
+
onBlur,
|
|
43
|
+
// Validation props
|
|
44
|
+
required = false,
|
|
45
|
+
error = false,
|
|
46
|
+
errorText = '',
|
|
47
|
+
maxLength,
|
|
48
|
+
minLength,
|
|
49
|
+
// Appearance props
|
|
50
|
+
rows = 4,
|
|
51
|
+
cols,
|
|
52
|
+
placeholder,
|
|
53
|
+
disabled = false,
|
|
54
|
+
readOnly = false,
|
|
55
|
+
resize = 'vertical',
|
|
56
|
+
// Layout props
|
|
57
|
+
className = '',
|
|
58
|
+
variant = 'default',
|
|
59
|
+
size = 'medium',
|
|
60
|
+
// Accessibility props
|
|
61
|
+
'aria-label': ariaLabel,
|
|
62
|
+
'aria-labelledby': ariaLabelledby,
|
|
63
|
+
'aria-describedby': ariaDescribedby,
|
|
64
|
+
'aria-invalid': ariaInvalid,
|
|
65
|
+
// Character count props
|
|
66
|
+
showCharacterCount = false,
|
|
67
|
+
characterCountThreshold = 0.8,
|
|
68
|
+
// Legacy props (for backward compatibility - internal use only)
|
|
69
|
+
componentName = 'text-area',
|
|
70
|
+
additionalClassName = '',
|
|
71
|
+
noLabel = false,
|
|
72
|
+
setName,
|
|
73
|
+
inputValue,
|
|
74
|
+
onChangeFunc,
|
|
75
|
+
focus,
|
|
76
|
+
blur,
|
|
77
|
+
placeHolder,
|
|
78
|
+
inputEl
|
|
79
|
+
}, ref) => {
|
|
80
|
+
// Handle legacy prop mapping
|
|
81
|
+
const finalId = id || setName;
|
|
82
|
+
const finalName = name || setName;
|
|
83
|
+
const finalLabel = label || setName;
|
|
84
|
+
const finalValue = value || inputValue || '';
|
|
85
|
+
const finalOnChange = onChange || onChangeFunc;
|
|
86
|
+
const finalOnFocus = onFocus || focus;
|
|
87
|
+
const finalOnBlur = onBlur || blur;
|
|
88
|
+
const finalPlaceholder = placeholder || placeHolder;
|
|
89
|
+
const finalClassName = className || additionalClassName;
|
|
90
|
+
const showLabel = !noLabel;
|
|
91
|
+
|
|
92
|
+
// Generate unique IDs for accessibility
|
|
93
|
+
const textareaId = finalId || `textarea-${Math.random().toString(36).substr(2, 9)}`;
|
|
94
|
+
const errorId = `${textareaId}-error`;
|
|
95
|
+
const charCountId = `${textareaId}-char-count`;
|
|
96
|
+
const helpTextId = `${textareaId}-help`;
|
|
97
|
+
|
|
98
|
+
// Calculate character count info
|
|
99
|
+
const charCount = finalValue.length;
|
|
100
|
+
const remainingChars = maxLength ? maxLength - charCount : null;
|
|
101
|
+
const isOverLimit = maxLength && charCount > maxLength;
|
|
102
|
+
const isNearLimit = maxLength && charCount >= maxLength * characterCountThreshold;
|
|
103
|
+
|
|
104
|
+
// Build aria-describedby
|
|
105
|
+
const describedByIds = [];
|
|
106
|
+
if (ariaDescribedby) describedByIds.push(ariaDescribedby);
|
|
107
|
+
if (error && errorText) describedByIds.push(errorId);
|
|
108
|
+
if (showCharacterCount && maxLength) describedByIds.push(charCountId);
|
|
109
|
+
const finalAriaDescribedby = describedByIds.length > 0 ? describedByIds.join(' ') : undefined;
|
|
110
|
+
|
|
111
|
+
// Determine aria-invalid
|
|
112
|
+
const finalAriaInvalid = ariaInvalid || (error ? 'true' : undefined);
|
|
113
|
+
|
|
114
|
+
// Build CSS classes
|
|
115
|
+
const wrapperClasses = [`${componentName}-wrapper`, finalClassName, `${componentName}-wrapper--${variant}`, `${componentName}-wrapper--${size}`, error && `${componentName}-wrapper--error`, disabled && `${componentName}-wrapper--disabled`, readOnly && `${componentName}-wrapper--readonly`].filter(Boolean).join(' ');
|
|
116
|
+
const textareaClasses = ['text-area', `text-area--${variant}`, `text-area--${size}`, `text-area--resize-${resize}`, error && 'text-area--error', disabled && 'text-area--disabled', readOnly && 'text-area--readonly'].filter(Boolean).join(' ');
|
|
117
|
+
return /*#__PURE__*/_react.default.createElement("div", {
|
|
118
|
+
className: wrapperClasses,
|
|
119
|
+
"data-testid": `${componentName}-wrapper`
|
|
120
|
+
}, showLabel && finalLabel && /*#__PURE__*/_react.default.createElement(_Label.Label, {
|
|
121
|
+
htmlFor: textareaId,
|
|
122
|
+
required: required,
|
|
123
|
+
labelText: finalLabel,
|
|
124
|
+
className: `${componentName}__label`
|
|
125
|
+
}), /*#__PURE__*/_react.default.createElement("textarea", _extends({
|
|
126
|
+
ref: ref,
|
|
127
|
+
id: textareaId,
|
|
128
|
+
name: finalName,
|
|
129
|
+
value: finalValue,
|
|
130
|
+
onChange: finalOnChange,
|
|
131
|
+
onFocus: finalOnFocus,
|
|
132
|
+
onBlur: finalOnBlur,
|
|
133
|
+
className: textareaClasses,
|
|
134
|
+
"data-testid": "text-area"
|
|
135
|
+
// Validation attributes
|
|
136
|
+
,
|
|
137
|
+
required: required,
|
|
138
|
+
maxLength: maxLength,
|
|
139
|
+
minLength: minLength
|
|
140
|
+
// Appearance attributes
|
|
141
|
+
,
|
|
142
|
+
rows: rows,
|
|
143
|
+
cols: cols,
|
|
144
|
+
placeholder: finalPlaceholder,
|
|
145
|
+
disabled: disabled,
|
|
146
|
+
readOnly: readOnly
|
|
147
|
+
// Accessibility attributes
|
|
148
|
+
,
|
|
149
|
+
"aria-label": ariaLabel
|
|
150
|
+
}, !showLabel && {
|
|
151
|
+
'aria-labelledby': ariaLabelledby
|
|
152
|
+
}, {
|
|
153
|
+
"aria-describedby": finalAriaDescribedby,
|
|
154
|
+
"aria-invalid": finalAriaInvalid,
|
|
155
|
+
"aria-required": required || undefined
|
|
156
|
+
})), showCharacterCount && maxLength && /*#__PURE__*/_react.default.createElement("div", {
|
|
157
|
+
id: charCountId,
|
|
158
|
+
className: `${componentName}__char-count ${isOverLimit ? `${componentName}__char-count--error` : isNearLimit ? `${componentName}__char-count--warning` : ''}`,
|
|
159
|
+
"aria-live": "polite",
|
|
160
|
+
"aria-atomic": "true"
|
|
161
|
+
}, /*#__PURE__*/_react.default.createElement("span", {
|
|
162
|
+
className: `${componentName}__char-count-text`
|
|
163
|
+
}, isOverLimit ? `${Math.abs(remainingChars)} characters over limit` : `${remainingChars} characters remaining`), /*#__PURE__*/_react.default.createElement("span", {
|
|
164
|
+
className: `${componentName}__char-count-numbers`
|
|
165
|
+
}, charCount, "/", maxLength)), error && errorText && /*#__PURE__*/_react.default.createElement(_Error.Error, {
|
|
166
|
+
id: errorId,
|
|
167
|
+
className: `${componentName}__error`,
|
|
168
|
+
role: "alert",
|
|
169
|
+
"aria-live": "polite"
|
|
170
|
+
}, errorText));
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Set display name for debugging
|
|
174
|
+
TextArea.displayName = 'TextArea';
|
|
175
|
+
TextArea.propTypes = {
|
|
176
|
+
// ====================
|
|
177
|
+
// Core Props
|
|
178
|
+
// ====================
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Unique identifier for the textarea
|
|
182
|
+
*/
|
|
183
|
+
id: _propTypes.string,
|
|
184
|
+
/**
|
|
185
|
+
* Additional CSS classes to apply to the component
|
|
186
|
+
*/
|
|
187
|
+
className: _propTypes.string,
|
|
188
|
+
/**
|
|
189
|
+
* Name attribute for the textarea (used for form submission)
|
|
190
|
+
*/
|
|
191
|
+
name: _propTypes.string,
|
|
192
|
+
// ====================
|
|
193
|
+
// Content Props
|
|
194
|
+
// ====================
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Label text for the textarea
|
|
198
|
+
*/
|
|
199
|
+
label: _propTypes.string,
|
|
200
|
+
/**
|
|
201
|
+
* Current value of the textarea
|
|
202
|
+
*/
|
|
203
|
+
value: _propTypes.string,
|
|
204
|
+
/**
|
|
205
|
+
* Placeholder text to display when empty
|
|
206
|
+
*/
|
|
207
|
+
placeholder: _propTypes.string,
|
|
208
|
+
// ====================
|
|
209
|
+
// Appearance Props
|
|
210
|
+
// ====================
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Visual style variant
|
|
214
|
+
* @default 'default'
|
|
215
|
+
*/
|
|
216
|
+
variant: (0, _propTypes.oneOf)(['default', 'outline', 'filled']),
|
|
217
|
+
/**
|
|
218
|
+
* Size of the textarea
|
|
219
|
+
* @default 'medium'
|
|
220
|
+
*/
|
|
221
|
+
size: (0, _propTypes.oneOf)(['small', 'medium', 'large']),
|
|
222
|
+
/**
|
|
223
|
+
* Number of visible text rows
|
|
224
|
+
* @default 4
|
|
225
|
+
*/
|
|
226
|
+
rows: _propTypes.number,
|
|
227
|
+
/**
|
|
228
|
+
* Number of visible text columns
|
|
229
|
+
*/
|
|
230
|
+
cols: _propTypes.number,
|
|
231
|
+
/**
|
|
232
|
+
* How the textarea can be resized
|
|
233
|
+
* @default 'vertical'
|
|
234
|
+
*/
|
|
235
|
+
resize: (0, _propTypes.oneOf)(['none', 'both', 'horizontal', 'vertical']),
|
|
236
|
+
// ====================
|
|
237
|
+
// Behavior Props
|
|
238
|
+
// ====================
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Whether the textarea is required
|
|
242
|
+
* @default false
|
|
243
|
+
*/
|
|
244
|
+
required: _propTypes.bool,
|
|
245
|
+
/**
|
|
246
|
+
* Whether the textarea is disabled
|
|
247
|
+
* @default false
|
|
248
|
+
*/
|
|
249
|
+
disabled: _propTypes.bool,
|
|
250
|
+
/**
|
|
251
|
+
* Whether the textarea is read-only
|
|
252
|
+
* @default false
|
|
253
|
+
*/
|
|
254
|
+
readOnly: _propTypes.bool,
|
|
255
|
+
/**
|
|
256
|
+
* Whether to show character count
|
|
257
|
+
* @default false
|
|
258
|
+
*/
|
|
259
|
+
showCharacterCount: _propTypes.bool,
|
|
260
|
+
// ====================
|
|
261
|
+
// Validation Props
|
|
262
|
+
// ====================
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Whether the field has an error
|
|
266
|
+
* @default false
|
|
267
|
+
*/
|
|
268
|
+
error: _propTypes.bool,
|
|
269
|
+
/**
|
|
270
|
+
* Error message to display when error is true
|
|
271
|
+
*/
|
|
272
|
+
errorText: _propTypes.string,
|
|
273
|
+
/**
|
|
274
|
+
* Maximum number of characters allowed
|
|
275
|
+
*/
|
|
276
|
+
maxLength: _propTypes.number,
|
|
277
|
+
/**
|
|
278
|
+
* Minimum number of characters required
|
|
279
|
+
*/
|
|
280
|
+
minLength: _propTypes.number,
|
|
281
|
+
/**
|
|
282
|
+
* Threshold (0-1) at which to show character count warning
|
|
283
|
+
* @default 0.8
|
|
284
|
+
*/
|
|
285
|
+
characterCountThreshold: _propTypes.number,
|
|
286
|
+
// ====================
|
|
287
|
+
// Event Props
|
|
288
|
+
// ====================
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Change handler function - called when textarea value changes
|
|
292
|
+
* @param {Event} event - The change event
|
|
293
|
+
*/
|
|
294
|
+
onChange: _propTypes.func,
|
|
295
|
+
/**
|
|
296
|
+
* Focus handler function
|
|
297
|
+
* @param {Event} event - The focus event
|
|
298
|
+
*/
|
|
299
|
+
onFocus: _propTypes.func,
|
|
300
|
+
/**
|
|
301
|
+
* Blur handler function
|
|
302
|
+
* @param {Event} event - The blur event
|
|
303
|
+
*/
|
|
304
|
+
onBlur: _propTypes.func,
|
|
305
|
+
// ====================
|
|
306
|
+
// Accessibility Props
|
|
307
|
+
// ====================
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Accessible label (alternative to label prop)
|
|
311
|
+
*/
|
|
312
|
+
'aria-label': _propTypes.string,
|
|
313
|
+
/**
|
|
314
|
+
* ID of element that labels this textarea
|
|
315
|
+
*/
|
|
316
|
+
'aria-labelledby': _propTypes.string,
|
|
317
|
+
/**
|
|
318
|
+
* ID(s) of elements that describe this textarea
|
|
319
|
+
*/
|
|
320
|
+
'aria-describedby': _propTypes.string,
|
|
321
|
+
/**
|
|
322
|
+
* Whether the textarea value is invalid
|
|
323
|
+
*/
|
|
324
|
+
'aria-invalid': (0, _propTypes.oneOf)(['true', 'false', 'grammar', 'spelling']),
|
|
325
|
+
/**
|
|
326
|
+
* Use `className` instead
|
|
327
|
+
* Additional CSS classes
|
|
328
|
+
*/
|
|
329
|
+
additionalClassName: _propTypes.string,
|
|
330
|
+
/**
|
|
331
|
+
* Use external label management instead
|
|
332
|
+
* Whether to hide the label
|
|
333
|
+
*/
|
|
334
|
+
noLabel: _propTypes.bool,
|
|
335
|
+
/**
|
|
336
|
+
* Use `id` and `name` instead
|
|
337
|
+
* Legacy name prop
|
|
338
|
+
*/
|
|
339
|
+
setName: _propTypes.string,
|
|
340
|
+
/**
|
|
341
|
+
* Use `value` instead
|
|
342
|
+
* Legacy input value prop
|
|
343
|
+
*/
|
|
344
|
+
inputValue: _propTypes.string,
|
|
345
|
+
/**
|
|
346
|
+
* Use `onChange` instead
|
|
347
|
+
* Legacy change handler
|
|
348
|
+
*/
|
|
349
|
+
onChangeFunc: _propTypes.func,
|
|
350
|
+
/**
|
|
351
|
+
* Use `onFocus` instead
|
|
352
|
+
* Legacy focus handler
|
|
353
|
+
*/
|
|
354
|
+
focus: _propTypes.func,
|
|
355
|
+
/**
|
|
356
|
+
* Use `onBlur` instead
|
|
357
|
+
* Legacy blur handler
|
|
358
|
+
*/
|
|
359
|
+
blur: _propTypes.func,
|
|
360
|
+
/**
|
|
361
|
+
* Use `placeholder` instead
|
|
362
|
+
* Legacy placeholder prop
|
|
363
|
+
*/
|
|
364
|
+
placeHolder: _propTypes.string,
|
|
365
|
+
/**
|
|
366
|
+
* Internal prop for CSS class generation
|
|
367
|
+
* Base component name for CSS classes
|
|
368
|
+
*/
|
|
369
|
+
componentName: _propTypes.string
|
|
370
|
+
};
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.TextInput = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _propTypes = require("prop-types");
|
|
9
|
+
var _Label = require("./Label");
|
|
10
|
+
var _Error = require("./Error");
|
|
11
|
+
var _Animation = require("./Animation");
|
|
12
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (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 (const 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); }
|
|
13
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } /*eslint-disable no-unused-vars*/ // components
|
|
14
|
+
/**
|
|
15
|
+
* TextInput Component
|
|
16
|
+
*
|
|
17
|
+
* A fully accessible, modern text input component following WCAG 2.1 AA guidelines.
|
|
18
|
+
* Features keyboard navigation, screen reader support, validation, and various input types.
|
|
19
|
+
*
|
|
20
|
+
* This is a stateless component - state management should be handled externally.
|
|
21
|
+
* Use with the useTextInputAccessibility hook for complete functionality.
|
|
22
|
+
*
|
|
23
|
+
* @component
|
|
24
|
+
* @example
|
|
25
|
+
* <TextInput
|
|
26
|
+
* id="email"
|
|
27
|
+
* label="Email Address"
|
|
28
|
+
* type="email"
|
|
29
|
+
* value={email}
|
|
30
|
+
* onChange={handleChange}
|
|
31
|
+
* required
|
|
32
|
+
* />
|
|
33
|
+
*/
|
|
34
|
+
const TextInput = exports.TextInput = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
35
|
+
// Core props
|
|
36
|
+
id,
|
|
37
|
+
name,
|
|
38
|
+
label,
|
|
39
|
+
type = 'text',
|
|
40
|
+
value = '',
|
|
41
|
+
onChange,
|
|
42
|
+
onFocus,
|
|
43
|
+
onBlur,
|
|
44
|
+
// Validation props
|
|
45
|
+
required = false,
|
|
46
|
+
error = false,
|
|
47
|
+
errorText = '',
|
|
48
|
+
maxLength,
|
|
49
|
+
minLength,
|
|
50
|
+
// Appearance props
|
|
51
|
+
placeholder,
|
|
52
|
+
disabled = false,
|
|
53
|
+
readOnly = false,
|
|
54
|
+
autoComplete,
|
|
55
|
+
autoFocus = false,
|
|
56
|
+
// Layout props
|
|
57
|
+
className = '',
|
|
58
|
+
variant = 'default',
|
|
59
|
+
size = 'medium',
|
|
60
|
+
// Accessibility props
|
|
61
|
+
'aria-label': ariaLabel,
|
|
62
|
+
'aria-labelledby': ariaLabelledby,
|
|
63
|
+
'aria-describedby': ariaDescribedby,
|
|
64
|
+
'aria-invalid': ariaInvalid,
|
|
65
|
+
// Legacy props (for backward compatibility - internal use only)
|
|
66
|
+
componentName = 'text-input',
|
|
67
|
+
additionalClassName = '',
|
|
68
|
+
noLabel = false,
|
|
69
|
+
setName,
|
|
70
|
+
inputValue,
|
|
71
|
+
onChangeFunc,
|
|
72
|
+
focus,
|
|
73
|
+
blur,
|
|
74
|
+
placeHolder,
|
|
75
|
+
inputEl,
|
|
76
|
+
inputType,
|
|
77
|
+
...restProps
|
|
78
|
+
}, ref) => {
|
|
79
|
+
// Handle legacy prop mapping
|
|
80
|
+
const finalId = id || setName;
|
|
81
|
+
const finalName = name || setName;
|
|
82
|
+
const finalLabel = label || setName;
|
|
83
|
+
const finalType = type || inputType || 'text';
|
|
84
|
+
// Fix: Only use inputValue if value is strictly undefined (not empty string)
|
|
85
|
+
const finalValue = value !== undefined ? value : inputValue !== undefined ? inputValue : '';
|
|
86
|
+
// Always use onChange if provided, fallback to onChangeFunc
|
|
87
|
+
const finalOnChange = onChange ? onChange : onChangeFunc;
|
|
88
|
+
const finalOnFocus = onFocus || focus;
|
|
89
|
+
const finalOnBlur = onBlur || blur;
|
|
90
|
+
const finalPlaceholder = placeholder || placeHolder;
|
|
91
|
+
const finalClassName = className || additionalClassName;
|
|
92
|
+
const showLabel = !noLabel;
|
|
93
|
+
|
|
94
|
+
// Generate unique IDs for accessibility
|
|
95
|
+
const inputId = finalId || `input-${Math.random().toString(36).substr(2, 9)}`;
|
|
96
|
+
const errorId = `${inputId}-error`;
|
|
97
|
+
const helpTextId = `${inputId}-help`;
|
|
98
|
+
|
|
99
|
+
// Build aria-describedby
|
|
100
|
+
const describedByIds = [];
|
|
101
|
+
if (ariaDescribedby) describedByIds.push(ariaDescribedby);
|
|
102
|
+
if (error && errorText) describedByIds.push(errorId);
|
|
103
|
+
const finalAriaDescribedby = describedByIds.length > 0 ? describedByIds.join(' ') : undefined;
|
|
104
|
+
|
|
105
|
+
// Determine aria-invalid
|
|
106
|
+
const finalAriaInvalid = ariaInvalid || (error ? 'true' : undefined);
|
|
107
|
+
|
|
108
|
+
// Build CSS classes
|
|
109
|
+
const wrapperClasses = [`${componentName}-wrapper`, finalClassName, `${componentName}-wrapper--${variant}`, `${componentName}-wrapper--${size}`, error && `${componentName}-wrapper--error`, disabled && `${componentName}-wrapper--disabled`, readOnly && `${componentName}-wrapper--readonly`].filter(Boolean).join(' ');
|
|
110
|
+
const inputClasses = ['input', 'text-input', `text-input--${variant}`, `text-input--${size}`, `text-input--type-${finalType}`, error && 'text-input--error', disabled && 'text-input--disabled', readOnly && 'text-input--readonly'].filter(Boolean).join(' ');
|
|
111
|
+
return /*#__PURE__*/_react.default.createElement(_Animation.AnimatedDiv, {
|
|
112
|
+
fadingEntrances: "fadeIn",
|
|
113
|
+
duration: "faster"
|
|
114
|
+
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
115
|
+
className: wrapperClasses,
|
|
116
|
+
"data-testid": `${componentName}-wrapper`
|
|
117
|
+
}, showLabel && finalLabel && /*#__PURE__*/_react.default.createElement(_Label.Label, {
|
|
118
|
+
htmlFor: inputId,
|
|
119
|
+
required: required,
|
|
120
|
+
labelText: finalLabel,
|
|
121
|
+
className: `${componentName}__label`
|
|
122
|
+
}), /*#__PURE__*/_react.default.createElement("input", _extends({
|
|
123
|
+
ref: ref,
|
|
124
|
+
id: inputId,
|
|
125
|
+
name: finalName,
|
|
126
|
+
type: finalType,
|
|
127
|
+
value: finalValue,
|
|
128
|
+
onChange: finalOnChange,
|
|
129
|
+
onFocus: finalOnFocus,
|
|
130
|
+
onBlur: finalOnBlur,
|
|
131
|
+
className: inputClasses,
|
|
132
|
+
"data-testid": "input"
|
|
133
|
+
// Validation attributes
|
|
134
|
+
,
|
|
135
|
+
required: required,
|
|
136
|
+
maxLength: maxLength,
|
|
137
|
+
minLength: minLength
|
|
138
|
+
// Appearance attributes
|
|
139
|
+
,
|
|
140
|
+
placeholder: finalPlaceholder,
|
|
141
|
+
disabled: disabled,
|
|
142
|
+
readOnly: readOnly,
|
|
143
|
+
autoComplete: autoComplete,
|
|
144
|
+
autoFocus: autoFocus
|
|
145
|
+
// Accessibility attributes
|
|
146
|
+
,
|
|
147
|
+
"aria-label": ariaLabel
|
|
148
|
+
}, !showLabel && {
|
|
149
|
+
'aria-labelledby': ariaLabelledby
|
|
150
|
+
}, {
|
|
151
|
+
"aria-describedby": finalAriaDescribedby,
|
|
152
|
+
"aria-invalid": finalAriaInvalid,
|
|
153
|
+
"aria-required": required || undefined
|
|
154
|
+
}, restProps)), error && errorText && /*#__PURE__*/_react.default.createElement(_Error.Error, {
|
|
155
|
+
id: errorId,
|
|
156
|
+
className: `${componentName}__error`,
|
|
157
|
+
role: "alert",
|
|
158
|
+
"aria-live": "polite"
|
|
159
|
+
}, errorText)));
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Set display name for debugging
|
|
163
|
+
TextInput.displayName = 'TextInput';
|
|
164
|
+
TextInput.propTypes = {
|
|
165
|
+
// ===========================================
|
|
166
|
+
// Core Props
|
|
167
|
+
// ===========================================
|
|
168
|
+
/**
|
|
169
|
+
* Unique identifier for the input
|
|
170
|
+
*/
|
|
171
|
+
id: _propTypes.string,
|
|
172
|
+
/**
|
|
173
|
+
* Name attribute for the input (used for form submission)
|
|
174
|
+
*/
|
|
175
|
+
name: _propTypes.string,
|
|
176
|
+
// ===========================================
|
|
177
|
+
// Content Props
|
|
178
|
+
// ===========================================
|
|
179
|
+
/**
|
|
180
|
+
* Label text for the input
|
|
181
|
+
*/
|
|
182
|
+
label: _propTypes.string,
|
|
183
|
+
/**
|
|
184
|
+
* Placeholder text shown when input is empty
|
|
185
|
+
*/
|
|
186
|
+
placeholder: _propTypes.string,
|
|
187
|
+
// ===========================================
|
|
188
|
+
// Appearance Props
|
|
189
|
+
// ===========================================
|
|
190
|
+
/**
|
|
191
|
+
* Additional CSS classes
|
|
192
|
+
*/
|
|
193
|
+
className: _propTypes.string,
|
|
194
|
+
/**
|
|
195
|
+
* Visual style variant
|
|
196
|
+
*/
|
|
197
|
+
variant: (0, _propTypes.oneOf)(['default', 'outline', 'filled']),
|
|
198
|
+
/**
|
|
199
|
+
* Size of the input
|
|
200
|
+
*/
|
|
201
|
+
size: (0, _propTypes.oneOf)(['small', 'medium', 'large']),
|
|
202
|
+
// ===========================================
|
|
203
|
+
// Behavior Props
|
|
204
|
+
// ===========================================
|
|
205
|
+
/**
|
|
206
|
+
* Input type (text, email, password, etc.)
|
|
207
|
+
*/
|
|
208
|
+
type: (0, _propTypes.oneOf)(['text', 'email', 'password', 'tel', 'url', 'search', 'number', 'date', 'time', 'datetime-local', 'month', 'week']),
|
|
209
|
+
/**
|
|
210
|
+
* Current value of the input
|
|
211
|
+
*/
|
|
212
|
+
value: _propTypes.string,
|
|
213
|
+
/**
|
|
214
|
+
* Whether the field is required
|
|
215
|
+
*/
|
|
216
|
+
required: _propTypes.bool,
|
|
217
|
+
/**
|
|
218
|
+
* Whether the field has an error
|
|
219
|
+
*/
|
|
220
|
+
error: _propTypes.bool,
|
|
221
|
+
/**
|
|
222
|
+
* Error message to display when error is true
|
|
223
|
+
*/
|
|
224
|
+
errorText: _propTypes.string,
|
|
225
|
+
/**
|
|
226
|
+
* Maximum number of characters allowed
|
|
227
|
+
*/
|
|
228
|
+
maxLength: _propTypes.number,
|
|
229
|
+
/**
|
|
230
|
+
* Minimum number of characters required
|
|
231
|
+
*/
|
|
232
|
+
minLength: _propTypes.number,
|
|
233
|
+
/**
|
|
234
|
+
* Whether the input is disabled
|
|
235
|
+
*/
|
|
236
|
+
disabled: _propTypes.bool,
|
|
237
|
+
/**
|
|
238
|
+
* Whether the input is read-only
|
|
239
|
+
*/
|
|
240
|
+
readOnly: _propTypes.bool,
|
|
241
|
+
/**
|
|
242
|
+
* Autocomplete attribute for browser assistance
|
|
243
|
+
*/
|
|
244
|
+
autoComplete: _propTypes.string,
|
|
245
|
+
/**
|
|
246
|
+
* Whether the input should be focused on mount
|
|
247
|
+
*/
|
|
248
|
+
autoFocus: _propTypes.bool,
|
|
249
|
+
// ===========================================
|
|
250
|
+
// Event Props
|
|
251
|
+
// ===========================================
|
|
252
|
+
/**
|
|
253
|
+
* Change handler function - called when user types
|
|
254
|
+
* @param {Event} event - The change event
|
|
255
|
+
*/
|
|
256
|
+
onChange: _propTypes.func.isRequired,
|
|
257
|
+
/**
|
|
258
|
+
* Focus handler function
|
|
259
|
+
* @param {Event} event - The focus event
|
|
260
|
+
*/
|
|
261
|
+
onFocus: _propTypes.func,
|
|
262
|
+
/**
|
|
263
|
+
* Blur handler function
|
|
264
|
+
* @param {Event} event - The blur event
|
|
265
|
+
*/
|
|
266
|
+
onBlur: _propTypes.func,
|
|
267
|
+
// ===========================================
|
|
268
|
+
// Accessibility Props
|
|
269
|
+
// ===========================================
|
|
270
|
+
/**
|
|
271
|
+
* Accessible label (alternative to label prop)
|
|
272
|
+
*/
|
|
273
|
+
'aria-label': _propTypes.string,
|
|
274
|
+
/**
|
|
275
|
+
* ID of element that labels this input
|
|
276
|
+
*/
|
|
277
|
+
'aria-labelledby': _propTypes.string,
|
|
278
|
+
/**
|
|
279
|
+
* ID(s) of elements that describe this input
|
|
280
|
+
*/
|
|
281
|
+
'aria-describedby': _propTypes.string,
|
|
282
|
+
/**
|
|
283
|
+
* Whether the input value is invalid
|
|
284
|
+
*/
|
|
285
|
+
'aria-invalid': (0, _propTypes.oneOf)(['true', 'false', 'grammar', 'spelling'])
|
|
286
|
+
};
|