Conversation
…to feat/components
…/, fields/, and layout/ folders
…DE-MA/FormKit-UI into feat/components
…40+ countries, flagcdn.com flags)
… with client-side validation
…max/step config options
…MultiSelectField style
…pdowns and pickers
|
There was a problem hiding this comment.
Pull request overview
This PR refactors the library toward a Component–Hook–Model (CHM) architecture, introduces a framework-free core/ layer, and adds a broad set of new field/layout components with corresponding tests and coverage tooling.
Changes:
- Added new framework-free utilities under
src/core/(validation, conditional visibility, grid helpers, i18n) and custom error classes. - Introduced new component modules (
components/form,components/layout,components/fields,components/context) and removed legacy components/adapters/errors modules. - Added extensive Vitest test suites and coverage support (
@vitest/coverage-v8,test:cov).
Reviewed changes
Copilot reviewed 92 out of 128 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| src/hooks/tests/useAsyncValidation.test.ts | Adds tests for async validation hook behavior (debounce, abort, manual trigger, error handling). |
| src/hooks/FormKitContext.ts | Introduces hook-level FormKit context to support CHM layer separation. |
| src/errors/types.ts | Removes legacy error type definitions. |
| src/errors/index.ts | Removes legacy errors barrel export. |
| src/errors/errorFormatters.ts | Removes legacy error formatting utilities. |
| src/core/validator.ts | Adds framework-free Zod validation helpers and error mapping. |
| src/core/types.ts | Adds core type system/constants (FieldType, values, defaults). |
| src/core/schema-helpers.ts | Adds schema construction helpers for field configs. |
| src/core/index.ts | Adds core public exports surface for the new core/ module. |
| src/core/i18n.ts | Adds framework-free i18n types and translation getter utility. |
| src/core/grid.ts | Adds pure grid class generators and normalization utilities. |
| src/core/errors.ts | Adds core error classes (FormKitError, FieldValidationError, etc.). |
| src/core/conditional.ts | Adds framework-free conditional visibility evaluation. |
| src/core/tests/validator.test.ts | Adds tests for validator utilities. |
| src/core/tests/schema-helpers.test.ts | Adds tests for schema helper utilities. |
| src/core/tests/grid.test.ts | Adds tests for grid class utilities. |
| src/core/tests/conditional.test.ts | Adds tests for conditional visibility logic. |
| src/components/layout/index.ts | Adds layout module barrel exports. |
| src/components/layout/tests/FormSection.test.tsx | Adds tests for FormSection layout behavior and accessibility (fieldset/legend). |
| src/components/layout/FormSection.tsx | Adds FormSection component with grid layout and per-field colSpan wrappers. |
| src/components/layout/FormActions.tsx | Adds FormActions buttons with i18n and loading state. |
| src/components/layout/FieldLabel.tsx | Adds shared accessible label/legend component with required indicator. |
| src/components/layout/FieldGroup.tsx | Adds field grouping wrapper using fieldset/legend. |
| src/components/layout/FieldError.tsx | Adds standardized error message component using role="alert". |
| src/components/index.ts | Replaces legacy exports with CHM module exports and internal context exports. |
| src/components/form/index.ts | Adds form module barrel exports. |
| src/components/form/FormStepper.tsx | Adds wizard stepper component with accessible navigation semantics. |
| src/components/form/DynamicFormStep.tsx | Adds per-step renderer for wizard mode. |
| src/components/fields/index.ts | Adds fields module barrel exports for new field components. |
| src/components/fields/tests/TimeField.test.tsx | Adds tests for TimeField behavior and a11y. |
| src/components/fields/tests/TagsField.test.tsx | Adds tests for TagsField interactions (add/remove/paste/limits). |
| src/components/fields/tests/SliderField.test.tsx | Adds tests for SliderField rendering and value syncing. |
| src/components/fields/tests/RatingField.test.tsx | Adds tests for RatingField interactions and aria attributes. |
| src/components/fields/tests/RangeSliderField.test.tsx | Adds tests for RangeSliderField constraints and disabling. |
| src/components/fields/tests/PhoneField.test.tsx | Adds tests for PhoneField country selection and submission shape. |
| src/components/fields/tests/PasswordField.test.tsx | Adds tests for PasswordField toggle behavior and a11y flags. |
| src/components/fields/tests/OTPField.test.tsx | Adds tests for OTP input behavior (paste, navigation, length). |
| src/components/fields/tests/MultiSelectField.test.tsx | Adds tests for MultiSelect dropdown interactions and aria attributes. |
| src/components/fields/tests/DateTimeField.test.tsx | Adds tests for DateTime picker behavior and a11y flags. |
| src/components/fields/TextareaField.tsx | Adds new context-driven textarea field implementation. |
| src/components/fields/TextField.tsx | Adds new context-driven text/email/number field implementation. |
| src/components/fields/TagsField.tsx | Adds tags input field with keyboard/paste support and limits. |
| src/components/fields/SwitchField.tsx | Adds switch field with role="switch" and label interactions. |
| src/components/fields/SliderField.tsx | Adds slider field with optional numeric input and track styling. |
| src/components/fields/RatingField.tsx | Adds star rating component with half-star support and slider semantics. |
| src/components/fields/RadioGroupField.tsx | Adds radio group field using fieldset/legend and error display. |
| src/components/fields/PasswordField.tsx | Adds password field with show/hide toggle and i18n labels. |
| src/components/fields/OTPField.tsx | Adds OTP field with focus management and paste support. |
| src/components/fields/FileField.tsx | Adds file upload field with type/size validation and i18n messages. |
| src/components/fields/Field.tsx | Adds universal field router with conditional visibility handling. |
| src/components/fields/CheckboxField.tsx | Adds checkbox field with custom visuals and hidden native input. |
| src/components/context/index.ts | Adds context module barrel exports. |
| src/components/context/I18nContext.tsx | Adds I18nProvider + deep merge for custom translations. |
| src/components/context/FormKitContext.tsx | Adds provider component wiring hook-level context into components. |
| src/components/tests/ErrorMessage.test.tsx | Removes tests for legacy ErrorMessage component. |
| src/components/Textarea.tsx | Removes legacy Textarea component. |
| src/components/Select.tsx | Removes legacy Select component. |
| src/components/RadioGroup.tsx | Removes legacy RadioGroup component. |
| src/components/Input.tsx | Removes legacy Input component. |
| src/components/FormField.tsx | Removes legacy FormField wrapper component. |
| src/components/ErrorMessage.tsx | Removes legacy ErrorMessage component. |
| src/components/Checkbox.tsx | Removes legacy Checkbox component. |
| src/adapters/zod.ts | Removes legacy Zod adapter. |
| src/adapters/react-hook-form.ts | Removes legacy React Hook Form adapter. |
| src/adapters/index.ts | Removes legacy adapters barrel export. |
| src/adapters/tests/zod.test.ts | Removes tests for legacy Zod adapter. |
| package.json | Adds Vitest coverage dependency and test:cov script. |
| .changeset/instructions-refactor.md | Adds changeset documenting architecture refactor + testing/coverage outcomes. |
| .changeset/improved-field-styles.md | Adds changeset documenting styling improvements for new field components. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| <div | ||
| className={`flex items-start gap-3 ${isDisabled ? 'cursor-not-allowed' : 'cursor-pointer'}`} | ||
| onClick={() => !isDisabled && setValue(config.key, !isChecked)} | ||
| > | ||
| {/* Hidden native checkbox for form submission and a11y */} | ||
| <input | ||
| id={fieldId} | ||
| name={config.key} | ||
| type="checkbox" | ||
| checked={isChecked} | ||
| disabled={isDisabled} | ||
| aria-invalid={showError} | ||
| aria-required={config.required} | ||
| aria-describedby={describedBy} | ||
| onChange={(e) => setValue(config.key, e.target.checked)} |
| // Column span class | ||
| const colSpanClass = config.colSpan ? `col-span-${config.colSpan}` : ''; | ||
| const wrapperClass = `formkit-field ${colSpanClass} ${config.className ?? ''}`.trim(); | ||
|
|
||
| // Route to appropriate field component based on type | ||
| const renderField = (): JSX.Element => { |
| <svg className="w-6 h-6 sm:w-8 sm:h-8" viewBox="0 0 24 24" fill="none"> | ||
| <defs> | ||
| <linearGradient id="halfFill"> | ||
| <stop offset="50%" stopColor="currentColor" /> | ||
| <stop offset="50%" stopColor="transparent" /> | ||
| </linearGradient> | ||
| </defs> |
| <div | ||
| className="flex gap-1.5 sm:gap-2 w-full" | ||
| role="group" | ||
| aria-label={`${config.label} - ${length} digit code`} | ||
| > |
| disabled={isDisabled} | ||
| aria-label={`Digit ${index + 1} of ${length}`} | ||
| aria-invalid={showError} | ||
| aria-describedby={index === 0 ? describedBy : undefined} |
| role="listbox" | ||
| aria-label={`${config.label} ${t('tags.addTag')}`} | ||
| aria-describedby={describedBy} | ||
| > |
|
|
||
| {canAddMore && !isDisabled && ( | ||
| <input | ||
| ref={inputRef} | ||
| id={inputId} | ||
| type="text" | ||
| value={inputValue} | ||
| onChange={(e) => setInputValue(e.target.value)} | ||
| onKeyDown={handleKeyDown} | ||
| onPaste={handlePaste} | ||
| onBlur={() => { | ||
| // Add tag on blur if there's input | ||
| if (inputValue.trim()) { | ||
| addTag(inputValue); | ||
| } | ||
| setTouched(config.key, true); | ||
| }} | ||
| placeholder={tags.length === 0 ? (config.placeholder ?? t('field.typeAndEnter')) : ''} | ||
| disabled={isDisabled} | ||
| aria-invalid={showError} | ||
| className=" | ||
| formkit-tags-input | ||
| flex-1 min-w-[120px] | ||
| border-none outline-none | ||
| bg-transparent | ||
| text-sm | ||
| placeholder:text-gray-400 | ||
| " | ||
| /> | ||
| )} | ||
| </div> | ||
|
|
| renderTagsField({ minTags: 1 }, ['required']); | ||
|
|
||
| // Remove button should not be visible when at minimum | ||
| expect(screen.queryByRole('button', { name: 'Remove required' })).not.toBeInTheDocument(); |
| @@ -0,0 +1,14 @@ | |||
| --- | |||
| /** | ||
| * TextField - Handles text, email, password, and number inputs | ||
| */ |




No description provided.