Skip to content

Develop#8

Merged
Zaiidmo merged 121 commits intomasterfrom
develop
Apr 6, 2026
Merged

Develop#8
Zaiidmo merged 121 commits intomasterfrom
develop

Conversation

@Zaiidmo
Copy link
Copy Markdown
Contributor

@Zaiidmo Zaiidmo commented Apr 6, 2026

Summary

  • What does this PR change?

Why

  • Why is this change needed?

Checklist

  • Added/updated tests (if behavior changed)
  • npm run lint passes
  • npm run typecheck passes
  • npm test passes
  • npm run build passes
  • Added a changeset (npx changeset) if this affects consumers

Notes

  • Anything reviewers should pay attention to?

Omaima33 and others added 30 commits February 12, 2026 15:16
Zaiidmo and others added 24 commits April 6, 2026 09:05
* polish component states with hover, focus, and disabled styles

* add useForm hook and FormContext for form state management

* add Form wrapper component with submit handling

* export Form, useForm, and FormContext from package

* increase timeout for autoDismiss test stability

* add PasswordInput component with visibility toggle and strength meter

* add NumberInput component with increment buttons and formatting

* add DatePicker component with calendar popup

* add PhoneInput component with country code selection

* feat: add FileInput component with drag-and-drop and preview

* feat: add ColorPicker component with swatches and RGB/HSL inputs

* feat: add Switch component with toggle states and customization

* refactor: restrict public API to DynamicForm export only

* refactor: restructure codebase to CHM architecture with core/, models/, fields/, and layout/ folders

* chore: remove legacy code and consolidate to CHM architecture

* feat(testing): add test suite achieving 80%+ coverage (192 tests)

* docs: enhance JSDoc for FieldType and ConditionalOperator, add changeset

* refactor: fix layer import rules and component default exports

* style: add field components with improved styling

* restore the checkbox field

* restore the password field

* feat: add PhoneField with country selector and countries.json data (240+ countries, flagcdn.com flags)

* password field style adjustments

* feat(FileField): add accept, maxFileSize, and multiple config options with client-side validation

* adjust radio and checkbox fields styles

* adjust szitch field styles

* feat: add SliderField with range input, editable value sync, and min/max/step config options

* feat: add RangeSliderField with dual-thumb slider and editable from/to inputs

* feat: add OTPField with configurable length and Full paste support

* feat: add TagsField with multi-tag input, paste support, and configurable limits

* feat: add RatingField with star rating, half-star support, and keyboard navigation

* feat: add TimeField with step interval

* feat: add DateTimeField with combined date and time input

* test: add comprehensive tests for new field components

* fix: unify checkbox styles across components

* feat: add MultiSelectField with search, tags, and keyboard navigation

* fix: remove focus styles from rating field

* feat: update SelectField to use custom dropdown with search matching MultiSelectField style

* fix: update field and form tests

* feat: update time, date and dateTime fields styles to have custom dropdowns and pickers

* fix: adjust select and multi select fields styles

* fix: update dropdowns and pickers positioning and style across components

* feat: add responsive measures to form fields

* feat: update OTP field styles to support mobile layout

* feat(i18n): add internationalization with English and French locale support

* feat(form): automatically scroll to first invalid field and focus it on submit

* feat(ArrayField): refactor to reuse Field components via scoped context

* feat: add translation content for Array field and optional params

* refactor: remove unused config param

* feat(layout): add grid-based layout system with sections and responsive columns

* fix(ArrayField): enable per-field Zod validation and error display for nested fields

* refactore and remove duplicate logic

* address and fix the Sonar annotated findings

* fix: formatting issues

---------

Co-authored-by: Zaiidmo <zaiidmoumnii@gmail.com>
@Zaiidmo Zaiidmo requested review from a team and Copilot April 6, 2026 14:54
@Zaiidmo Zaiidmo merged commit dc6e40e into master Apr 6, 2026
18 checks passed
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 6, 2026

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR evolves the repository from a template into the initial release of @ciscode/ui-form-kit, adding a full React form component system (fields, layout, wizard mode), a core utilities layer (validation, conditional logic, i18n, grid helpers), and updated build/test/CI tooling to support publishing.

Changes:

  • Introduces core modules (src/core, src/models, src/locales) and new public exports in src/index.ts.
  • Adds many form UI components + hooks (field implementations, layout primitives, context/i18n, wizard navigation, async validation, field arrays).
  • Updates toolchain for testing (Vitest + RTL + coverage), styling (Tailwind build + distributed CSS), linting/formatting, and CI/release workflows.

Reviewed changes

Copilot reviewed 114 out of 118 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
vitest.setup.ts Adds RTL cleanup + jest-dom setup for Vitest.
vitest.config.ts Switches to jsdom + setupFiles + coverage config/thresholds.
tsup.config.ts Standardizes config formatting; exports config constant.
tsconfig.json Adds global test types to main TS config.
tailwind.config.js Adds Tailwind content configuration.
src/vitest.d.ts Adds Vitest/jest-dom global type references under src/.
src/utils/noop.ts Removes placeholder util.
src/utils/index.ts Removes placeholder util index exports.
src/styles.css Adds Tailwind import + library utility/responsiveness CSS.
src/models/ValidationRule.ts Adds sync/async validation rule type contracts.
src/models/StepConfig.ts Adds wizard step configuration contract.
src/models/SectionConfig.ts Adds section/layout contracts + type guards.
src/models/index.ts Adds model type re-exports.
src/models/FormState.ts Defines form state/context shape contracts.
src/models/FieldConfig.ts Defines field configuration contract (including advanced field options).
src/locales/index.ts Exports locale dictionaries.
src/locales/fr.ts Adds French translation dictionary.
src/locales/en.ts Adds English translation dictionary.
src/index.ts Replaces wildcard exports with curated public API surface.
src/hooks/useNoop.ts Removes placeholder hook.
src/hooks/useI18n.ts Adds hook to access i18n context.
src/hooks/useFormStep.ts Adds wizard step navigation + per-step validation.
src/hooks/useFormContext.ts Adds public wrapper hook over internal context hook.
src/hooks/useFieldArray.ts Adds hook for array/repeatable field management.
src/hooks/useAsyncValidation.ts Adds debounced async validation with AbortController cancellation.
src/hooks/index.ts Replaces placeholder with curated hook exports.
src/hooks/FormKitContext.ts Adds internal FormKit context + access hook with error message.
src/hooks/tests/useFormContext.test.tsx Adds tests for context access hooks.
src/core/validator.ts Adds Zod error mapping + sync/field validation helpers.
src/core/types.ts Adds core form types + FieldType enum + constants.
src/core/schema-helpers.ts Adds helpers to build/merge Zod schemas.
src/core/index.ts Adds core barrel exports.
src/core/i18n.ts Adds translation key types + nested lookup + interpolation.
src/core/grid.ts Adds grid class helpers for sections/col spans.
src/core/errors.ts Adds custom error class hierarchy.
src/core/conditional.ts Adds conditional visibility evaluation utilities.
src/core/tests/validator.test.ts Adds tests for validator utilities.
src/core/tests/grid.test.ts Adds tests for grid helpers.
src/core/tests/conditional.test.ts Adds tests for conditional logic.
src/components/NoopButton.tsx Removes placeholder component.
src/components/layout/index.ts Adds layout barrel exports.
src/components/layout/FormSection.tsx Adds section rendering with per-section grid + border behavior.
src/components/layout/FormActions.tsx Adds submit/reset/prev controls with loading state.
src/components/layout/FieldLabel.tsx Adds standardized label/legend with required indicator.
src/components/layout/FieldGroup.tsx Adds field grouping wrapper with fieldset/legend.
src/components/layout/FieldError.tsx Adds standardized error message component.
src/components/layout/tests/FormSection.test.tsx Adds tests for FormSection behavior/layout.
src/components/layout/tests/FormActions.test.tsx Adds tests for action buttons + submitting state.
src/components/index.ts Replaces placeholder exports with real module exports + provider export.
src/components/form/index.ts Adds form module barrel exports.
src/components/form/FormStepper.tsx Adds wizard stepper UI with aria labels and navigation.
src/components/form/DynamicFormStep.tsx Adds per-step rendering wrapper for wizard mode.
src/components/fields/TextField.tsx Adds text/email/password/number input field implementation.
src/components/fields/TextareaField.tsx Adds textarea field implementation.
src/components/fields/SwitchField.tsx Adds accessible switch/toggle field implementation.
src/components/fields/SliderField.tsx Adds slider field with optional numeric input + track fill styling.
src/components/fields/RadioGroupField.tsx Adds radio group field implementation.
src/components/fields/PasswordField.tsx Adds password field with show/hide toggle.
src/components/fields/OTPField.tsx Adds OTP input with focus management + paste support.
src/components/fields/index.ts Adds fields barrel exports.
src/components/fields/FileField.tsx Adds file input with type/size validation + hints.
src/components/fields/Field.tsx Adds field router + conditional visibility handling.
src/components/fields/CheckboxField.tsx Adds checkbox field with custom visuals + a11y.
src/components/fields/tests/TimeField.test.tsx Adds interaction/a11y tests for time field.
src/components/fields/tests/TagsField.test.tsx Adds interaction tests for tags field.
src/components/fields/tests/SliderField.test.tsx Adds tests for slider behavior and constraints.
src/components/fields/tests/RatingField.test.tsx Adds tests for rating field interaction and a11y.
src/components/fields/tests/RangeSliderField.test.tsx Adds tests for range slider behavior/clamping.
src/components/fields/tests/PhoneField.test.tsx Adds tests for phone field dropdown + value preservation.
src/components/fields/tests/PasswordField.test.tsx Adds tests for password toggle + a11y.
src/components/fields/tests/OTPField.test.tsx Adds tests for OTP input behavior.
src/components/fields/tests/DateTimeField.test.tsx Adds tests for datetime picker interactions.
src/components/fields/tests/DateField.test.tsx Adds tests for date picker interactions.
src/components/context/index.ts Adds context barrel exports.
src/components/context/I18nContext.tsx Adds i18n provider/context with deep-merge for overrides.
src/components/context/FormKitContext.tsx Adds provider component wrapping hooks-layer context.
src/components/context/tests/I18nContext.test.tsx Adds i18n provider/hook tests + getTranslation tests.
README.md Replaces template README with package documentation + quality/release info.
postcss.config.cjs Adds PostCSS plugin config (tailwindcss + autoprefixer).
package.json Sets version to 0.0.1; adds Tailwind build step; adds coverage scripts; exports styles.css.
eslint.config.js Expands ignore list; tweaks TS/React rules.
.prettierrc.json Adds additional Prettier formatting options.
.github/workflows/release-check.yml Adds master PR release-check pipeline (quality/test/build/sonar).
.github/workflows/publish.yml Adds publish pipeline for npm on master push.
.github/workflows/pr-validation.yml Updates PR validation workflow (node 22) and removes develop push trigger.
.github/workflows/ci-release-check.yml Removes old release-check workflow.
.github/workflows/cd-release.yml Removes old publish workflow.
.github/instructions/sonarqube_mcp.instructions.md Adds repository instructions for Sonar MCP usage.
.github/instructions/bugfix.instructions.md Adds bugfix process guidelines doc.
.github/dependabot.yml Adds dependabot configuration.
.github/CODEOWNERS Adds code ownership rules.
.changeset/first-release-v0-0-1.md Adds changeset for v0.0.1 release.

Comment on lines +46 to +51
const { getValues } = useFormKitContext();

// Check conditional visibility
const values = getValues();
const visible = isFieldVisible(config.showWhen, config.hideWhen, values);

Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getValues() is typed to return Partial<TValues> (see FormContextValue), but isFieldVisible expects a full FormValues. This is a TypeScript type mismatch and will fail tsc. Consider updating evaluateRule/isFieldVisible to accept Partial<FormValues> (or Record<string, FieldValue | undefined>) since missing keys are valid in this logic, and keep the call site type-safe.

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +58
// Column span class
const colSpanClass = config.colSpan ? `col-span-${config.colSpan}` : '';
const wrapperClass = `formkit-field ${colSpanClass} ${config.className ?? ''}`.trim();
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

config.colSpan can be a responsive object (see ColSpanValue), so interpolating it directly into col-span-${config.colSpan} will produce col-span-[object Object] at runtime. Use the same helper used elsewhere (getColSpanClass) or otherwise normalize responsive values before constructing class names.

Copilot uses AI. Check for mistakes.
Comment on lines +74 to +79
// Get current array value
const fields = useMemo(() => {
const value = getValue(name);
return (Array.isArray(value) ? value : []) as TRow[];
}, [getValue, name]);

Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fields is memoized only on [getValue, name], so it will not update when the underlying array value changes (context updates will re-render but this useMemo will keep returning the old array). This will make append/remove/... operate on stale data. Prefer computing fields directly on each render, or include a dependency that actually changes with the form state (e.g., getValues() or a value snapshot from context).

Copilot uses AI. Check for mistakes.
'node_modules/**',
'coverage/**',
'.vitest/**',
'postcss.config.js',
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ignore list includes postcss.config.js, but the repo adds postcss.config.cjs. With eslint ., the .cjs file will still be linted and may error due to CommonJS globals. Either ignore postcss.config.cjs (and/or *.cjs configs) or add an override with sourceType: 'commonjs' for that file.

Suggested change
'postcss.config.js',
'postcss.config.js',
'postcss.config.cjs',

Copilot uses AI. Check for mistakes.
"scripts": {
"clean": "rimraf dist *.tsbuildinfo",
"build": "tsup",
"clean": "rimraf dist *.tsbuildinfo && rm -rf coverage",
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clean uses rm -rf coverage, which is not cross-platform (Windows shells will fail). Since the script already uses rimraf, consider replacing rm -rf coverage with rimraf coverage (or include coverage in the existing rimraf call).

Suggested change
"clean": "rimraf dist *.tsbuildinfo && rm -rf coverage",
"clean": "rimraf dist *.tsbuildinfo coverage",

Copilot uses AI. Check for mistakes.
Comment on lines +118 to +120
// Store single file or array based on multiple
setValue(config.key, fileList.length === 1 ? fileList[0] : fileList);
};
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When config.multiple is true, selecting a single file will still store a File (because the decision is based on fileList.length). This makes the stored value type inconsistent for consumers/config-driven validation. Consider using config.multiple to decide the value shape (always File[] when multiple is true, otherwise a single File or null).

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +76
{config.options?.map((option) => {
const optionId = `${fieldId}-${option.value}`;
const isChecked = value === option.value;

return (
<div key={String(option.value)} className="flex items-center gap-2">
<input
id={optionId}
name={config.key}
type="radio"
value={String(option.value)}
checked={isChecked}
disabled={isDisabled || option.disabled}
onChange={(e) => setValue(config.key, e.target.value)}
onBlur={() => setTouched(config.key, true)}
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FieldOption.value supports string | number, but the radio input stores String(option.value) and then writes back e.target.value (always a string). This breaks numeric options (checked comparison value === option.value will fail and the stored type changes). Consider setting the value from option.value directly (e.g. via an onChange={() => setValue(config.key, option.value)}) or parsing based on the original option type.

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +78
export function getGridColumnsClass(columns: ColumnCount = 1): string {
if (!isResponsiveColumns(columns)) {
return `grid-cols-${columns}`;
}

return buildResponsiveClasses(columns, 'grid-cols');
}
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getGridColumnsClass({ md: 2 }) currently returns only md:grid-cols-2 (no base grid-cols-*). With CSS grid, having display: grid but no grid-template-columns can lead to unexpected implicit columns on small screens, and SectionConfig docs state a default of 1 column. Consider passing a fallback (e.g. buildResponsiveClasses(columns, 'grid-cols', 1)) so responsive configs without default still render as single-column on mobile.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants