diff --git a/.changeset/first-release-v0-0-1.md b/.changeset/first-release-v0-0-1.md new file mode 100644 index 0000000..d39b67d --- /dev/null +++ b/.changeset/first-release-v0-0-1.md @@ -0,0 +1,19 @@ +--- +'@ciscode/ui-form-kit': patch +--- + +# First release v0.0.1 + +Prepare the first public release of `@ciscode/ui-form-kit` as `v0.0.1`. + +This release includes the full baseline of FormKit-UI capabilities and quality hardening for the initial public version. + +- Establish a component-first architecture with clear core utilities, models, hooks, and UI exports. +- Deliver production-ready form primitives with typed APIs and validation-aware behavior. +- Improve accessibility and keyboard interactions across key fields, including date, time, multi-select, switch, and radio patterns. +- Enhance field styling and state feedback (hover, disabled, and valid states) for consistent UX. +- Fix form behavior edge cases in submit and async validation flows. +- Strengthen test coverage with comprehensive component and interaction-path tests, including high-impact branch scenarios. +- Enforce release quality gates via lint, typecheck, coverage, and CI Sonar checks. +- Correct Sonar release-check test path detection and maintain release-safe CI configuration. +- Ship release-ready package documentation and usage guidance in README. diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..2279f0b --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @CISCODE-MA/devops diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..8d34dee --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,20 @@ +version: 2 +updates: + - package-ecosystem: npm + directory: '/' + schedule: + interval: monthly + open-pull-requests-limit: 1 + groups: + npm-dependencies: + patterns: + - '*' + assignees: + - CISCODE-MA/cloud-devops + labels: + - 'dependencies' + - 'npm' + commit-message: + prefix: 'chore(deps)' + include: 'scope' + rebase-strategy: auto diff --git a/.github/instructions/bugfix.instructions.md b/.github/instructions/bugfix.instructions.md new file mode 100644 index 0000000..9c7da05 --- /dev/null +++ b/.github/instructions/bugfix.instructions.md @@ -0,0 +1,275 @@ +# Bugfix Instructions - UI Kit Module + +> **Last Updated**: February 2026 + +--- + +## πŸ” Bug Investigation Process + +### Phase 1: Reproduce + +**Before writing any code:** + +1. **Understand the issue** - Read bug report carefully +2. **Reproduce locally** - Create minimal reproduction +3. **Verify it's a bug** - Not expected behavior +4. **Check browser compatibility** - Test across browsers + +**Create failing test FIRST:** + +```typescript +describe('Bug: Button not disabled when loading', () => { + it('should disable button during loading', () => { + render(); + + // This SHOULD pass but currently FAILS + expect(screen.getByRole('button')).toBeDisabled(); + }); +}); +``` + +### Phase 2: Identify Root Cause + +**Investigation tools:** + +- **React DevTools** - Inspect component tree +- **Console logs** - Debug state changes +- **Debugger** - Breakpoints in code +- **Browser DevTools** - Check DOM/styles + +```typescript +// Debug component props/state +useEffect(() => { + console.log('Props changed:', props); +}, [props]); +``` + +### Phase 3: Understand Impact + +**Critical questions:** + +- Which browsers affected? +- Does it break accessibility? +- Is there a workaround? +- Does it affect other components? + +--- + +## πŸ› Common Bug Categories + +### 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 | + +**Example fix:** + +```typescript +// ❌ BUG - Stale closure +const [count, setCount] = useState(0); + +useEffect(() => { + const timer = setInterval(() => { + setCount(count + 1); // ❌ Always uses initial count + }, 1000); + return () => clearInterval(timer); +}, []); // Missing count dependency + +// βœ… FIX - Functional update +useEffect(() => { + const timer = setInterval(() => { + 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 | + +**Example fix:** + +```typescript +// ❌ BUG - No cleanup +useEffect(() => { + const subscription = api.subscribe(handleData); +}, []); + +// βœ… FIX - Cleanup on unmount +useEffect(() => { + const subscription = api.subscribe(handleData); + return () => subscription.unsubscribe(); +}, []); +``` + +### 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 | + +**Example fix:** + +```typescript +// ❌ BUG - Handler called immediately + +``` + +--- + +## πŸ”§ Fix Implementation Process + +### 1. Write Failing Test + +```typescript +it('should fix the bug', async () => { + render(); + + await userEvent.click(screen.getByRole('button')); + + expect(screen.getByText(/expected/i)).toBeInTheDocument(); +}); +``` + +### 2. Implement Fix + +```typescript +// Fix the component +export function Component() { + // Corrected implementation + return
Fixed!
; +} +``` + +### 3. Verify Test Passes + +```bash +npm test -- Component.test.tsx +``` + +### 4. Test in Browser + +```bash +npm run dev +# Manually test the fix +``` + +### 5. Update Documentation + +```typescript +/** + * Component that was buggy + * + * @fixed v1.2.3 - Fixed click handler issue + */ +export function Component(props: Props): JSX.Element; +``` + +--- + +## ⚠️ Common Gotchas + +### 1. Prop Mutation + +```typescript +// ❌ Bug - Mutating props +const sortedItems = props.items.sort(); // Mutates! + +// βœ… Fix - Create copy +const sortedItems = [...props.items].sort(); +``` + +### 2. Incorrect Comparison + +```typescript +// ❌ Bug - Object comparison +if (user === prevUser) { +} // Always false (different references) + +// βœ… Fix - Compare values +if (user.id === prevUser.id) { +} +``` + +### 3. Missing Null Checks + +```typescript +// ❌ Bug - No null check +return user.profile.name; // Crashes if profile is null + +// βœ… Fix - Optional chaining +return user?.profile?.name ?? 'Unknown'; +``` + +--- + +## πŸ“‹ Bugfix Checklist + +- [ ] Bug reproduced in browser +- [ ] Failing test created +- [ ] Root cause identified +- [ ] Fix implemented +- [ ] All tests pass +- [ ] Manually tested in browser +- [ ] Accessibility verified +- [ ] Documentation updated +- [ ] CHANGELOG updated +- [ ] No regression diff --git a/.github/instructions/components.instructions.md b/.github/instructions/components.instructions.md new file mode 100644 index 0000000..97d0ea7 --- /dev/null +++ b/.github/instructions/components.instructions.md @@ -0,0 +1,353 @@ +# Component Development Instructions - FormKit-UI + +> **Purpose**: React component development standards for form UI components. + +--- + +## 🎯 Component Architecture + +### Component Structure + +``` +ComponentName/ + β”œβ”€β”€ ComponentName.tsx # Main component + β”œβ”€β”€ ComponentName.test.tsx # Tests + β”œβ”€β”€ ComponentName.types.ts # Props & types + β”œβ”€β”€ ComponentName.styles.ts # Styled components (if using) + └── index.ts # Exports +``` + +### Form Component Template + +```typescript +import React, { forwardRef } from 'react'; +import { FormFieldProps } from './FormField.types'; + +/** + * Reusable form field with validation and error display + * @param {FormFieldProps} props - Component props + * @returns {JSX.Element} Rendered form field + */ +export const FormField = forwardRef( + ({ label, error, required, ...inputProps }, ref) => { + return ( +
+ + {error && ( + + {error} + + )} +
+ ); + } +); + +FormField.displayName = 'FormField'; +``` + +--- + +## πŸ“ Props Standards + +### Form Component Props + +```typescript +export interface FormFieldProps extends React.InputHTMLAttributes { + /** Field label text */ + label: string; + /** Error message to display */ + error?: string; + /** Is this field required? */ + required?: boolean; + /** Field description/help text */ + description?: string; +} +``` + +### Required Props Documentation + +- βœ… JSDoc for all props +- βœ… Validation rules clearly stated +- βœ… onChange/onBlur signatures with examples +- βœ… Default values documented + +--- + +## β™Ώ Accessibility (A11y) + +### Form Accessibility + +```typescript +// βœ… Good - Accessible form field +
+ + + {errors.email && ( + + {errors.email} + + )} +
+ +// ❌ Bad - Inaccessible +
+
Email
+ +
{error}
+
+``` + +### Required Accessibility Features + +- βœ… `