Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
ee35f66
polish component states with hover, focus, and disabled styles
Omaima33 Feb 26, 2026
92d5393
add useForm hook and FormContext for form state management
Omaima33 Feb 27, 2026
0f17c77
add Form wrapper component with submit handling
Omaima33 Feb 27, 2026
7118c2c
export Form, useForm, and FormContext from package
Omaima33 Feb 27, 2026
cd3d0b4
increase timeout for autoDismiss test stability
Omaima33 Feb 27, 2026
e946f54
add PasswordInput component with visibility toggle and strength meter
Omaima33 Feb 27, 2026
7f1c2e8
add NumberInput component with increment buttons and formatting
Omaima33 Feb 27, 2026
a8b6ed9
add DatePicker component with calendar popup
Omaima33 Feb 27, 2026
f815264
add PhoneInput component with country code selection
Omaima33 Feb 27, 2026
f4524f1
feat: add FileInput component with drag-and-drop and preview
Omaima33 Feb 27, 2026
f59e2e6
feat: add ColorPicker component with swatches and RGB/HSL inputs
Omaima33 Feb 27, 2026
b565391
feat: add Switch component with toggle states and customization
Omaima33 Feb 27, 2026
86a2a05
Merge branch 'develop' of https://github.com/CISCODE-MA/FormKit-UI in…
Omaima33 Mar 3, 2026
5568524
refactor: restrict public API to DynamicForm export only
Omaima33 Mar 3, 2026
1d0f857
refactor: restructure codebase to CHM architecture with core/, models…
Omaima33 Mar 3, 2026
89d769b
chore: remove legacy code and consolidate to CHM architecture
Omaima33 Mar 3, 2026
a917861
feat(testing): add test suite achieving 80%+ coverage (192 tests)
Omaima33 Mar 4, 2026
f55c79b
docs: enhance JSDoc for FieldType and ConditionalOperator, add changeset
Omaima33 Mar 4, 2026
b50ff0e
refactor: fix layer import rules and component default exports
Omaima33 Mar 4, 2026
4ac5a4a
style: add field components with improved styling
Omaima33 Mar 6, 2026
c39dcd9
Merge branch 'feat/instructions-refactor' of https://github.com/CISCO…
Omaima33 Mar 6, 2026
e3c28a5
restore the checkbox field
Omaima33 Mar 6, 2026
73945c6
restore the password field
Omaima33 Mar 6, 2026
cb22946
feat: add PhoneField with country selector and countries.json data (2…
Omaima33 Mar 6, 2026
6178e0e
password field style adjustments
Omaima33 Mar 6, 2026
af3350d
feat(FileField): add accept, maxFileSize, and multiple config options…
Omaima33 Mar 6, 2026
3ce0f1d
adjust radio and checkbox fields styles
Omaima33 Mar 6, 2026
650d99b
adjust szitch field styles
Omaima33 Mar 9, 2026
8df9c5e
feat: add SliderField with range input, editable value sync, and min/…
Omaima33 Mar 9, 2026
5cf1c49
feat: add RangeSliderField with dual-thumb slider and editable from/t…
Omaima33 Mar 9, 2026
a714f34
feat: add OTPField with configurable length and Full paste support
Omaima33 Mar 9, 2026
76cad4c
feat: add TagsField with multi-tag input, paste support, and configur…
Omaima33 Mar 9, 2026
596f15c
feat: add RatingField with star rating, half-star support, and keyboa…
Omaima33 Mar 9, 2026
9e8d4e8
feat: add TimeField with step interval
Omaima33 Mar 9, 2026
1f4e2ba
feat: add DateTimeField with combined date and time input
Omaima33 Mar 9, 2026
c127a06
test: add comprehensive tests for new field components
Omaima33 Mar 9, 2026
445e57e
fix: unify checkbox styles across components
Omaima33 Mar 10, 2026
c842e31
feat: add MultiSelectField with search, tags, and keyboard navigation
Omaima33 Mar 10, 2026
30d8cb3
fix: remove focus styles from rating field
Omaima33 Mar 10, 2026
af05926
feat: update SelectField to use custom dropdown with search matching …
Omaima33 Mar 10, 2026
713f335
fix: update field and form tests
Omaima33 Mar 10, 2026
9e132c0
feat: update time, date and dateTime fields styles to have custom dro…
Omaima33 Mar 10, 2026
6dbbf5b
fix: adjust select and multi select fields styles
Omaima33 Mar 10, 2026
61a893a
fix: update dropdowns and pickers positioning and style across compon…
Omaima33 Mar 10, 2026
3476dae
feat: add responsive measures to form fields
Omaima33 Mar 10, 2026
c573c51
feat: update OTP field styles to support mobile layout
Omaima33 Mar 11, 2026
bb0d904
feat(i18n): add internationalization with English and French locale s…
Omaima33 Mar 11, 2026
94edf86
feat(form): automatically scroll to first invalid field and focus it …
Omaima33 Mar 11, 2026
60a4fff
feat(ArrayField): refactor to reuse Field components via scoped context
Omaima33 Mar 12, 2026
3db31b7
feat: add translation content for Array field and optional params
Omaima33 Mar 12, 2026
c5edb9c
refactor: remove unused config param
Omaima33 Mar 12, 2026
e0011bb
feat(layout): add grid-based layout system with sections and responsi…
Omaima33 Mar 13, 2026
c5d428a
fix(ArrayField): enable per-field Zod validation and error display fo…
Omaima33 Mar 13, 2026
6ae676e
refactore and remove duplicate logic
Omaima33 Mar 30, 2026
9b46dde
Merge branch 'develop' into refactore
Omaima33 Mar 30, 2026
b855342
address and fix the Sonar annotated findings
Omaima33 Mar 30, 2026
bd5f48c
Merge branch 'refactore' of https://github.com/CISCODE-MA/FormKit-UI …
Omaima33 Mar 30, 2026
d56a922
fix: formatting issues
Zaiidmo Apr 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .changeset/improved-field-styles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
'@ciscode/ui-form-kit': patch
---

Improved field component styles with transitions, hover states, and success states

- Added transition-all duration-150 for smooth animations
- Added hover:border-gray-400 for hover states on inputs
- Added green success state (border-green-500) when field is valid
- Improved responsive padding (px-3 py-2 sm:px-4 sm:py-2.5)
- Better disabled states with hover:border-gray-300
- Improved checkbox, radio, and switch sizing
- Better file input button styling with blue background
- Added aria-live=polite to error messages
33 changes: 33 additions & 0 deletions .changeset/instructions-refactor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
'@ciscode/ui-form-kit': minor
---

Refactor codebase to align with copilot-instructions.md guidelines

**Architecture Changes:**

- Restructured to Component-Hook-Model (CHM) architecture
- Created `src/core/` for framework-free pure functions (validator, conditional, schema-helpers)
- Created `src/models/` for TypeScript contracts with zero runtime logic
- Restricted public API exports in `src/index.ts`

**Accessibility Improvements:**

- Fixed RadioGroupField to use proper `role="radiogroup"` with `aria-labelledby`
- Fixed SwitchField to use proper `role="switch"` with keyboard support (Enter/Space)

**Bug Fixes:**

- Fixed `handleSubmit` to mark fields with errors as touched on validation failure
- Fixed `useAsyncValidation` to properly handle DOMException AbortError

**Testing:**

- Added comprehensive test suite with 192 tests
- Achieved 80%+ coverage: 94.64% statements, 83.77% branches, 83.33% functions
- Coverage tests for core/, hooks/, and components/

**Documentation:**

- Enhanced JSDoc for FieldType enum values
- Enhanced JSDoc for ConditionalOperator types
68 changes: 35 additions & 33 deletions .github/instructions/bugfix.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
describe('Bug: Button not disabled when loading', () => {
it('should disable button during loading', () => {
render(<Button isLoading>Click</Button>);

// This SHOULD pass but currently FAILS
expect(screen.getByRole('button')).toBeDisabled();
});
Expand Down Expand Up @@ -59,11 +59,11 @@ useEffect(() => {

### 1. State Management Issues

| Bug Type | Symptoms | Solution |
| --------------------- | ---------------------- | --------------------------- |
| **Stale closure** | Old values in callback | Update dependencies |
| **Infinite loop** | Component re-renders | Fix useEffect dependencies |
| **Lost state** | State resets unexpectedly| Check component key |
| Bug Type | Symptoms | Solution |
| ----------------- | ------------------------- | -------------------------- |
| **Stale closure** | Old values in callback | Update dependencies |
| **Infinite loop** | Component re-renders | Fix useEffect dependencies |
| **Lost state** | State resets unexpectedly | Check component key |

**Example fix:**

Expand All @@ -81,19 +81,19 @@ useEffect(() => {
// ✅ FIX - Functional update
useEffect(() => {
const timer = setInterval(() => {
setCount(prev => prev + 1); // ✅ Uses current count
setCount((prev) => prev + 1); // ✅ Uses current count
}, 1000);
return () => clearInterval(timer);
}, []);
```

### 2. useEffect Issues

| Bug Type | Symptoms | Solution |
| --------------------- | --------------------- | --------------------------- |
| **Memory leak** | Performance degrades | Add cleanup function |
| **Missing cleanup** | Side effects persist | Return cleanup |
| **Wrong dependencies**| Unexpected behavior | Fix dependency array |
| Bug Type | Symptoms | Solution |
| ---------------------- | -------------------- | -------------------- |
| **Memory leak** | Performance degrades | Add cleanup function |
| **Missing cleanup** | Side effects persist | Return cleanup |
| **Wrong dependencies** | Unexpected behavior | Fix dependency array |

**Example fix:**

Expand All @@ -112,11 +112,11 @@ useEffect(() => {

### 3. Event Handler Issues

| Bug Type | Symptoms | Solution |
| --------------------- | --------------------- | --------------------------- |
| **Handler not called**| Click doesn't work | Check event binding |
| **Multiple calls** | Handler fires twice | Remove duplicate listeners |
| **Wrong event** | Unexpected behavior | Use correct event type |
| Bug Type | Symptoms | Solution |
| ---------------------- | ------------------- | -------------------------- |
| **Handler not called** | Click doesn't work | Check event binding |
| **Multiple calls** | Handler fires twice | Remove duplicate listeners |
| **Wrong event** | Unexpected behavior | Use correct event type |

**Example fix:**

Expand All @@ -131,11 +131,11 @@ useEffect(() => {

### 4. Rendering Issues

| Bug Type | Symptoms | Solution |
| --------------------- | --------------------- | --------------------------- |
| **Conditional render**| Component disappears | Fix condition logic |
| **Key prop** | Wrong items update | Use stable unique keys |
| **Forced re-render** | Performance issues | Memoize expensive calcs |
| Bug Type | Symptoms | Solution |
| ---------------------- | -------------------- | ----------------------- |
| **Conditional render** | Component disappears | Fix condition logic |
| **Key prop** | Wrong items update | Use stable unique keys |
| **Forced re-render** | Performance issues | Memoize expensive calcs |

**Example fix:**

Expand All @@ -153,11 +153,11 @@ useEffect(() => {

### 5. Accessibility Bugs

| Bug Type | Symptoms | Solution |
| --------------------- | --------------------- | --------------------------- |
| **Missing ARIA** | Screen reader issues | Add ARIA attributes |
| **No keyboard nav** | Can't use keyboard | Add keyboard handlers |
| **Poor contrast** | Hard to read | Fix colors |
| Bug Type | Symptoms | Solution |
| ------------------- | -------------------- | --------------------- |
| **Missing ARIA** | Screen reader issues | Add ARIA attributes |
| **No keyboard nav** | Can't use keyboard | Add keyboard handlers |
| **Poor contrast** | Hard to read | Fix colors |

**Example fix:**

Expand All @@ -182,9 +182,9 @@ useEffect(() => {
```typescript
it('should fix the bug', async () => {
render(<Component />);

await userEvent.click(screen.getByRole('button'));

expect(screen.getByText(/expected/i)).toBeInTheDocument();
});
```
Expand Down Expand Up @@ -217,10 +217,10 @@ npm run dev
```typescript
/**
* Component that was buggy
*
*
* @fixed v1.2.3 - Fixed click handler issue
*/
export function Component(props: Props): JSX.Element
export function Component(props: Props): JSX.Element;
```

---
Expand All @@ -241,10 +241,12 @@ const sortedItems = [...props.items].sort();

```typescript
// ❌ Bug - Object comparison
if (user === prevUser) { } // Always false (different references)
if (user === prevUser) {
} // Always false (different references)

// ✅ Fix - Compare values
if (user.id === prevUser.id) { }
if (user.id === prevUser.id) {
}
```

### 3. Missing Null Checks
Expand Down
29 changes: 23 additions & 6 deletions .github/instructions/components.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
## 🎯 Component Architecture

### Component Structure

```
ComponentName/
├── ComponentName.tsx # Main component
Expand All @@ -17,6 +18,7 @@ ComponentName/
```

### Form Component Template

```typescript
import React, { forwardRef } from 'react';
import { FormFieldProps } from './FormField.types';
Expand Down Expand Up @@ -52,6 +54,7 @@ FormField.displayName = 'FormField';
## 📝 Props Standards

### Form Component Props

```typescript
export interface FormFieldProps extends React.InputHTMLAttributes<HTMLInputElement> {
/** Field label text */
Expand All @@ -66,6 +69,7 @@ export interface FormFieldProps extends React.InputHTMLAttributes<HTMLInputEleme
```

### Required Props Documentation

- ✅ JSDoc for all props
- ✅ Validation rules clearly stated
- ✅ onChange/onBlur signatures with examples
Expand All @@ -76,6 +80,7 @@ export interface FormFieldProps extends React.InputHTMLAttributes<HTMLInputEleme
## ♿ Accessibility (A11y)

### Form Accessibility

```typescript
// ✅ Good - Accessible form field
<div className="field">
Expand Down Expand Up @@ -105,6 +110,7 @@ export interface FormFieldProps extends React.InputHTMLAttributes<HTMLInputEleme
```

### Required Accessibility Features

- ✅ `<label>` with `htmlFor` attribute
- ✅ `aria-required` for required fields
- ✅ `aria-invalid` for fields with errors
Expand All @@ -117,12 +123,13 @@ export interface FormFieldProps extends React.InputHTMLAttributes<HTMLInputEleme
## 🎨 Theming & Styling

### Theme Support for Forms

```typescript
import { useTheme } from '../context/ThemeContext';

export const ThemedInput: React.FC = () => {
const { theme } = useTheme();

return (
<input
style={{
Expand All @@ -138,6 +145,7 @@ export const ThemedInput: React.FC = () => {
```

### Form Error States

```typescript
const errorStyles = {
borderColor: theme.colors.error,
Expand All @@ -154,6 +162,7 @@ const successStyles = {
## 🧪 Form Component Testing

### Test Coverage Requirements

```typescript
describe('FormField', () => {
it('renders label and input', () => {
Expand All @@ -174,7 +183,7 @@ describe('FormField', () => {
it('calls onChange when value changes', async () => {
const onChange = jest.fn();
render(<FormField label="Name" onChange={onChange} />);

await userEvent.type(screen.getByLabelText('Name'), 'John');
expect(onChange).toHaveBeenCalled();
});
Expand All @@ -188,20 +197,21 @@ describe('FormField', () => {
```

### Validation Testing

```typescript
it('validates email format', async () => {
const { rerender } = render(
<FormField label="Email" type="email" value="invalid" error={undefined} />
);

// Trigger validation
fireEvent.blur(screen.getByLabelText('Email'));

// Update with error
rerender(
<FormField label="Email" type="email" value="invalid" error="Invalid email format" />
);

expect(screen.getByRole('alert')).toHaveTextContent('Invalid email format');
});
```
Expand All @@ -211,6 +221,7 @@ it('validates email format', async () => {
## 🔄 Form State Management

### Controlled Components

```typescript
const [value, setValue] = useState('');

Expand All @@ -222,6 +233,7 @@ const [value, setValue] = useState('');
```

### React Hook Form Integration

```typescript
import { useForm, Controller } from 'react-hook-form';

Expand All @@ -242,14 +254,15 @@ const { control, handleSubmit } = useForm();
```

### Form Submission

```typescript
const handleSubmit = async (data: FormData) => {
try {
await submitForm(data);
} catch (error) {
setError('submission', {
type: 'manual',
message: 'Failed to submit form'
message: 'Failed to submit form',
});
}
};
Expand All @@ -260,6 +273,7 @@ const handleSubmit = async (data: FormData) => {
## 📦 Component Exports

### Public API (index.ts)

```typescript
// Export form components
export { FormField } from './FormField';
Expand All @@ -277,6 +291,7 @@ export type { FormSelectProps } from './FormSelect.types';
## 🚫 Anti-Patterns to Avoid

### ❌ Uncontrolled Forms

```typescript
// Bad - No state management
<input type="text" defaultValue="initial" />
Expand All @@ -287,6 +302,7 @@ const [value, setValue] = useState('initial');
```

### ❌ Missing Error Handling

```typescript
// Bad - Silent failures
<form onSubmit={handleSubmit}>
Expand All @@ -303,6 +319,7 @@ const [value, setValue] = useState('initial');
```

### ❌ Inline Validation on Every Keystroke

```typescript
// Bad - Validates on every keystroke (annoying UX)
<input onChange={(e) => validateEmail(e.target.value)} />
Expand Down
Loading
Loading