@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,412 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.Form = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _propTypes = require("prop-types");
|
|
9
|
+
var _accessibility = require("../utils/accessibility.js");
|
|
10
|
+
require("../styles/form.scss");
|
|
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); }
|
|
13
|
+
/**
|
|
14
|
+
* Form - A stateless, accessible form component with validation and error handling
|
|
15
|
+
*
|
|
16
|
+
return (
|
|
17
|
+
<Animation fadingEntrances="fadeIn" duration="faster">
|
|
18
|
+
<form
|
|
19
|
+
ref={ref}
|
|
20
|
+
className={`${componentName}-wrapper ${additionalClassName}`.trim()}
|
|
21
|
+
aria-label={ariaLabel}
|
|
22
|
+
aria-labelledby={ariaLabelledBy}
|
|
23
|
+
aria-describedby={ariaDescribedBy}
|
|
24
|
+
noValidate={noValidate}
|
|
25
|
+
autoComplete={autoComplete}
|
|
26
|
+
method={method}
|
|
27
|
+
action={action}
|
|
28
|
+
encType={encType}
|
|
29
|
+
target={target}
|
|
30
|
+
acceptCharset={acceptCharset}
|
|
31
|
+
role={role}
|
|
32
|
+
id={id}
|
|
33
|
+
onSubmit={handleSubmit}
|
|
34
|
+
{...props}
|
|
35
|
+
>
|
|
36
|
+
{children}
|
|
37
|
+
</form>
|
|
38
|
+
</Animation>
|
|
39
|
+
);
|
|
40
|
+
* }
|
|
41
|
+
* }}
|
|
42
|
+
* validationMode="onBlur"
|
|
43
|
+
* ariaLabel="User registration form"
|
|
44
|
+
* >
|
|
45
|
+
* <FormField name="email" required>
|
|
46
|
+
* <TextInput />
|
|
47
|
+
* </FormField>
|
|
48
|
+
* <Button type="submit">Submit</Button>
|
|
49
|
+
* </Form>
|
|
50
|
+
*/
|
|
51
|
+
const Form = exports.Form = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
52
|
+
componentName = 'form',
|
|
53
|
+
additionalClassName = '',
|
|
54
|
+
children = null,
|
|
55
|
+
onSubmit,
|
|
56
|
+
onChange,
|
|
57
|
+
onValidate,
|
|
58
|
+
validationMode = 'onSubmit',
|
|
59
|
+
noValidate = true,
|
|
60
|
+
autoComplete = 'on',
|
|
61
|
+
method = 'post',
|
|
62
|
+
action = '',
|
|
63
|
+
encType = 'application/x-www-form-urlencoded',
|
|
64
|
+
target = '_self',
|
|
65
|
+
acceptCharset = 'UTF-8',
|
|
66
|
+
ariaLabel = '',
|
|
67
|
+
ariaDescribedBy = '',
|
|
68
|
+
ariaLabelledBy = '',
|
|
69
|
+
disabled = false,
|
|
70
|
+
isSubmitting = false,
|
|
71
|
+
errors = {},
|
|
72
|
+
resetOnSubmit = false,
|
|
73
|
+
announceErrors = true,
|
|
74
|
+
announceSuccess = true,
|
|
75
|
+
id = '',
|
|
76
|
+
role = 'form',
|
|
77
|
+
...props
|
|
78
|
+
}, ref) => {
|
|
79
|
+
const [formData, setFormData] = (0, _react.useState)({});
|
|
80
|
+
const [touched, setTouched] = (0, _react.useState)({});
|
|
81
|
+
const [localErrors, setLocalErrors] = (0, _react.useState)({});
|
|
82
|
+
const [submissionCount, setSubmissionCount] = (0, _react.useState)(0);
|
|
83
|
+
|
|
84
|
+
// Merge external errors with local errors
|
|
85
|
+
const allErrors = {
|
|
86
|
+
...localErrors,
|
|
87
|
+
...errors
|
|
88
|
+
};
|
|
89
|
+
const hasErrors = Object.keys(allErrors).length > 0;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Validates a single field
|
|
93
|
+
* @param {string} fieldName - Name of the field to validate
|
|
94
|
+
* @param {*} value - Value to validate
|
|
95
|
+
* @returns {string|null} Error message or null if valid
|
|
96
|
+
*/
|
|
97
|
+
const validateField = (0, _react.useCallback)((fieldName, value) => {
|
|
98
|
+
if (!onValidate) return null;
|
|
99
|
+
return onValidate(fieldName, value, formData);
|
|
100
|
+
}, [onValidate, formData]);
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Updates form data and handles validation based on mode
|
|
104
|
+
*/
|
|
105
|
+
const updateFormData = (0, _react.useCallback)((fieldName, value) => {
|
|
106
|
+
const newFormData = {
|
|
107
|
+
...formData,
|
|
108
|
+
[fieldName]: value
|
|
109
|
+
};
|
|
110
|
+
setFormData(newFormData);
|
|
111
|
+
|
|
112
|
+
// Real-time validation for onChange mode
|
|
113
|
+
if (validationMode === 'onChange' || touched[fieldName]) {
|
|
114
|
+
const error = validateField(fieldName, value);
|
|
115
|
+
setLocalErrors(prev => ({
|
|
116
|
+
...prev,
|
|
117
|
+
[fieldName]: error
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
onChange?.(newFormData, fieldName, value);
|
|
121
|
+
}, [formData, validationMode, touched, validateField, onChange]);
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Handles field blur events for onBlur validation
|
|
125
|
+
*/
|
|
126
|
+
const handleFieldBlur = (0, _react.useCallback)((fieldName, value) => {
|
|
127
|
+
setTouched(prev => ({
|
|
128
|
+
...prev,
|
|
129
|
+
[fieldName]: true
|
|
130
|
+
}));
|
|
131
|
+
if (validationMode === 'onBlur' || validationMode === 'onChange') {
|
|
132
|
+
const error = validateField(fieldName, value);
|
|
133
|
+
setLocalErrors(prev => ({
|
|
134
|
+
...prev,
|
|
135
|
+
[fieldName]: error
|
|
136
|
+
}));
|
|
137
|
+
|
|
138
|
+
// Announce validation errors
|
|
139
|
+
if (error && announceErrors) {
|
|
140
|
+
(0, _accessibility.announceToScreenReader)(`${fieldName}: ${error}`, 'assertive');
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}, [validationMode, validateField, announceErrors]);
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Validates all form fields
|
|
147
|
+
* @returns {Object} Object containing all field errors
|
|
148
|
+
*/
|
|
149
|
+
const validateAllFields = (0, _react.useCallback)(() => {
|
|
150
|
+
if (!onValidate) return {};
|
|
151
|
+
const newErrors = {};
|
|
152
|
+
Object.keys(formData).forEach(fieldName => {
|
|
153
|
+
const error = validateField(fieldName, formData[fieldName]);
|
|
154
|
+
if (error) {
|
|
155
|
+
newErrors[fieldName] = error;
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
return newErrors;
|
|
159
|
+
}, [formData, validateField, onValidate]);
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Handles form submission
|
|
163
|
+
*/
|
|
164
|
+
const handleSubmit = (0, _react.useCallback)(async event => {
|
|
165
|
+
event.preventDefault();
|
|
166
|
+
if (disabled || isSubmitting) return;
|
|
167
|
+
setSubmissionCount(prev => prev + 1);
|
|
168
|
+
|
|
169
|
+
// Validate all fields on submit
|
|
170
|
+
const validationErrors = validateAllFields();
|
|
171
|
+
setLocalErrors(validationErrors);
|
|
172
|
+
const hasValidationErrors = Object.keys(validationErrors).length > 0;
|
|
173
|
+
if (hasValidationErrors) {
|
|
174
|
+
// Focus first error field
|
|
175
|
+
const firstErrorField = Object.keys(validationErrors)[0];
|
|
176
|
+
const errorElement = document.querySelector(`[name="${firstErrorField}"]`);
|
|
177
|
+
if (errorElement) {
|
|
178
|
+
(0, _accessibility.safeFocus)(errorElement);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Announce validation failure
|
|
182
|
+
if (announceErrors) {
|
|
183
|
+
const errorCount = Object.keys(validationErrors).length;
|
|
184
|
+
(0, _accessibility.announceToScreenReader)(`Form submission failed. ${errorCount} field${errorCount !== 1 ? 's' : ''} ${errorCount !== 1 ? 'have' : 'has'} validation errors.`, 'assertive');
|
|
185
|
+
}
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
// Provide form utilities to onSubmit callback
|
|
190
|
+
const formUtils = {
|
|
191
|
+
setErrors: setLocalErrors,
|
|
192
|
+
setFormData,
|
|
193
|
+
resetForm: () => {
|
|
194
|
+
setFormData({});
|
|
195
|
+
setLocalErrors({});
|
|
196
|
+
setTouched({});
|
|
197
|
+
},
|
|
198
|
+
updateField: updateFormData
|
|
199
|
+
};
|
|
200
|
+
await onSubmit?.(formData, formUtils, event);
|
|
201
|
+
|
|
202
|
+
// Reset form if requested
|
|
203
|
+
if (resetOnSubmit) {
|
|
204
|
+
formUtils.resetForm();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Announce success
|
|
208
|
+
if (announceSuccess) {
|
|
209
|
+
(0, _accessibility.announceToScreenReader)('Form submitted successfully', 'polite');
|
|
210
|
+
}
|
|
211
|
+
} catch (error) {
|
|
212
|
+
// Let the onSubmit handler manage errors, but provide fallback
|
|
213
|
+
logError('Form submission error:', error);
|
|
214
|
+
if (announceErrors) {
|
|
215
|
+
(0, _accessibility.announceToScreenReader)('Form submission failed', 'assertive');
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}, [disabled, isSubmitting, validateAllFields, onSubmit, formData, resetOnSubmit, announceSuccess, announceErrors, updateFormData]);
|
|
219
|
+
|
|
220
|
+
// Generate comprehensive class names
|
|
221
|
+
const classNames = [componentName, additionalClassName, disabled && `${componentName}--disabled`, isSubmitting && `${componentName}--submitting`, hasErrors && `${componentName}--has-errors`].filter(Boolean).join(' ');
|
|
222
|
+
|
|
223
|
+
// Enhanced children with form context
|
|
224
|
+
const enhancedChildren = _react.default.Children.map(children, child => {
|
|
225
|
+
if (/*#__PURE__*/_react.default.isValidElement(child)) {
|
|
226
|
+
// Check if this is a form field that needs form context
|
|
227
|
+
const fieldName = child.props?.name || child.props?.setName;
|
|
228
|
+
if (fieldName) {
|
|
229
|
+
return /*#__PURE__*/_react.default.cloneElement(child, {
|
|
230
|
+
error: allErrors[fieldName],
|
|
231
|
+
errorText: allErrors[fieldName],
|
|
232
|
+
value: formData[fieldName] || child.props.value || '',
|
|
233
|
+
inputValue: formData[fieldName] || child.props.inputValue || '',
|
|
234
|
+
onChangeFunc: event => {
|
|
235
|
+
const value = event.target?.value !== undefined ? event.target.value : event;
|
|
236
|
+
updateFormData(fieldName, value);
|
|
237
|
+
child.props?.onChangeFunc?.(event);
|
|
238
|
+
},
|
|
239
|
+
onChange: event => {
|
|
240
|
+
const value = event.target?.value !== undefined ? event.target.value : event;
|
|
241
|
+
updateFormData(fieldName, value);
|
|
242
|
+
child.props?.onChange?.(event);
|
|
243
|
+
},
|
|
244
|
+
onBlur: event => {
|
|
245
|
+
const value = event.target?.value !== undefined ? event.target.value : formData[fieldName];
|
|
246
|
+
handleFieldBlur(fieldName, value);
|
|
247
|
+
child.props?.onBlur?.(event);
|
|
248
|
+
},
|
|
249
|
+
blur: event => {
|
|
250
|
+
const value = event.target?.value !== undefined ? event.target.value : formData[fieldName];
|
|
251
|
+
handleFieldBlur(fieldName, value);
|
|
252
|
+
child.props?.blur?.(event);
|
|
253
|
+
},
|
|
254
|
+
disabled: disabled || child.props?.disabled,
|
|
255
|
+
'aria-invalid': !!allErrors[fieldName],
|
|
256
|
+
'aria-describedby': allErrors[fieldName] ? `${fieldName}-error` : child.props?.['aria-describedby'],
|
|
257
|
+
...child.props
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return child;
|
|
262
|
+
});
|
|
263
|
+
return /*#__PURE__*/_react.default.createElement("form", _extends({
|
|
264
|
+
ref: ref,
|
|
265
|
+
className: classNames,
|
|
266
|
+
"data-testid": componentName,
|
|
267
|
+
onSubmit: handleSubmit,
|
|
268
|
+
noValidate: noValidate,
|
|
269
|
+
autoComplete: autoComplete,
|
|
270
|
+
method: method,
|
|
271
|
+
action: action,
|
|
272
|
+
encType: encType,
|
|
273
|
+
target: target,
|
|
274
|
+
acceptCharset: acceptCharset,
|
|
275
|
+
"aria-label": ariaLabel || undefined,
|
|
276
|
+
"aria-labelledby": ariaLabelledBy || undefined,
|
|
277
|
+
"aria-describedby": ariaDescribedBy || undefined,
|
|
278
|
+
role: role,
|
|
279
|
+
"aria-invalid": hasErrors,
|
|
280
|
+
id: id || undefined
|
|
281
|
+
}, props), /*#__PURE__*/_react.default.createElement("div", {
|
|
282
|
+
className: "sr-only",
|
|
283
|
+
"aria-live": "polite",
|
|
284
|
+
"aria-atomic": "true"
|
|
285
|
+
}), enhancedChildren, isSubmitting && /*#__PURE__*/_react.default.createElement("div", {
|
|
286
|
+
className: "sr-only",
|
|
287
|
+
"aria-live": "polite"
|
|
288
|
+
}, "Form is being submitted, please wait..."), hasErrors && /*#__PURE__*/_react.default.createElement("div", {
|
|
289
|
+
className: `${componentName}__errors-summary`,
|
|
290
|
+
role: "alert"
|
|
291
|
+
}, /*#__PURE__*/_react.default.createElement("p", {
|
|
292
|
+
className: `${componentName}__errors-title`
|
|
293
|
+
}, "Please correct the following errors:"), /*#__PURE__*/_react.default.createElement("ul", {
|
|
294
|
+
className: `${componentName}__errors-list`
|
|
295
|
+
}, Object.entries(allErrors).map(([fieldName, error]) => /*#__PURE__*/_react.default.createElement("li", {
|
|
296
|
+
key: fieldName,
|
|
297
|
+
className: `${componentName}__error-item`
|
|
298
|
+
}, /*#__PURE__*/_react.default.createElement("strong", null, fieldName, ":"), " ", error)))));
|
|
299
|
+
});
|
|
300
|
+
Form.propTypes = {
|
|
301
|
+
/**
|
|
302
|
+
* Base CSS class name for the component
|
|
303
|
+
*/
|
|
304
|
+
componentName: _propTypes.string,
|
|
305
|
+
/**
|
|
306
|
+
* Additional CSS class names to apply to the form
|
|
307
|
+
*/
|
|
308
|
+
additionalClassName: _propTypes.string,
|
|
309
|
+
/**
|
|
310
|
+
* Form content and fields
|
|
311
|
+
*/
|
|
312
|
+
children: _propTypes.node.isRequired,
|
|
313
|
+
/**
|
|
314
|
+
* Form submission handler
|
|
315
|
+
* @param {Object} formData - Current form data
|
|
316
|
+
* @param {Object} formUtils - Utilities for form management
|
|
317
|
+
* @param {Event} event - Submit event
|
|
318
|
+
*/
|
|
319
|
+
onSubmit: _propTypes.func,
|
|
320
|
+
/**
|
|
321
|
+
* Form change handler called when any field changes
|
|
322
|
+
* @param {Object} formData - Current form data
|
|
323
|
+
* @param {string} fieldName - Name of changed field
|
|
324
|
+
* @param {*} value - New field value
|
|
325
|
+
*/
|
|
326
|
+
onChange: _propTypes.func,
|
|
327
|
+
/**
|
|
328
|
+
* Field validation function
|
|
329
|
+
* @param {string} fieldName - Name of field to validate
|
|
330
|
+
* @param {*} value - Field value
|
|
331
|
+
* @param {Object} formData - Complete form data
|
|
332
|
+
* @returns {string|null} Error message or null if valid
|
|
333
|
+
*/
|
|
334
|
+
onValidate: _propTypes.func,
|
|
335
|
+
/**
|
|
336
|
+
* When to perform validation
|
|
337
|
+
*/
|
|
338
|
+
validationMode: (0, _propTypes.oneOf)(['onSubmit', 'onBlur', 'onChange']),
|
|
339
|
+
/**
|
|
340
|
+
* HTML form noValidate attribute
|
|
341
|
+
*/
|
|
342
|
+
noValidate: _propTypes.bool,
|
|
343
|
+
/**
|
|
344
|
+
* HTML form autoComplete attribute
|
|
345
|
+
*/
|
|
346
|
+
autoComplete: _propTypes.string,
|
|
347
|
+
/**
|
|
348
|
+
* HTML form method attribute
|
|
349
|
+
*/
|
|
350
|
+
method: (0, _propTypes.oneOf)(['get', 'post', 'dialog']),
|
|
351
|
+
/**
|
|
352
|
+
* HTML form action attribute
|
|
353
|
+
*/
|
|
354
|
+
action: _propTypes.string,
|
|
355
|
+
/**
|
|
356
|
+
* HTML form encType attribute
|
|
357
|
+
*/
|
|
358
|
+
encType: (0, _propTypes.oneOf)(['application/x-www-form-urlencoded', 'multipart/form-data', 'text/plain']),
|
|
359
|
+
/**
|
|
360
|
+
* HTML form target attribute
|
|
361
|
+
*/
|
|
362
|
+
target: (0, _propTypes.oneOf)(['_self', '_blank', '_parent', '_top']),
|
|
363
|
+
/**
|
|
364
|
+
* HTML form acceptCharset attribute
|
|
365
|
+
*/
|
|
366
|
+
acceptCharset: _propTypes.string,
|
|
367
|
+
/**
|
|
368
|
+
* Accessible label for the form
|
|
369
|
+
*/
|
|
370
|
+
ariaLabel: _propTypes.string,
|
|
371
|
+
/**
|
|
372
|
+
* ID of element that describes the form
|
|
373
|
+
*/
|
|
374
|
+
ariaDescribedBy: _propTypes.string,
|
|
375
|
+
/**
|
|
376
|
+
* ID of element that labels the form
|
|
377
|
+
*/
|
|
378
|
+
ariaLabelledBy: _propTypes.string,
|
|
379
|
+
/**
|
|
380
|
+
* Whether the entire form is disabled
|
|
381
|
+
*/
|
|
382
|
+
disabled: _propTypes.bool,
|
|
383
|
+
/**
|
|
384
|
+
* Whether the form is currently being submitted
|
|
385
|
+
*/
|
|
386
|
+
isSubmitting: _propTypes.bool,
|
|
387
|
+
/**
|
|
388
|
+
* External errors object (field name: error message)
|
|
389
|
+
*/
|
|
390
|
+
errors: _propTypes.object,
|
|
391
|
+
/**
|
|
392
|
+
* Whether to reset form data after successful submission
|
|
393
|
+
*/
|
|
394
|
+
resetOnSubmit: _propTypes.bool,
|
|
395
|
+
/**
|
|
396
|
+
* Whether to announce errors to screen readers
|
|
397
|
+
*/
|
|
398
|
+
announceErrors: _propTypes.bool,
|
|
399
|
+
/**
|
|
400
|
+
* Whether to announce successful submissions to screen readers
|
|
401
|
+
*/
|
|
402
|
+
announceSuccess: _propTypes.bool,
|
|
403
|
+
/**
|
|
404
|
+
* HTML id attribute for the form
|
|
405
|
+
*/
|
|
406
|
+
id: _propTypes.string,
|
|
407
|
+
/**
|
|
408
|
+
* ARIA role for the form
|
|
409
|
+
*/
|
|
410
|
+
role: _propTypes.string
|
|
411
|
+
};
|
|
412
|
+
var _default = exports.default = Form;
|