Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V0.3.9 #15

Merged
merged 17 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion ACCESSIBILITY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Accessibility When Developing and Testing

![Author: Leon Slater](https://img.shields.io/badge/Author-Leon_Slater-blue)
![Last update: 2024/08/05](https://img.shields.io/badge/Last_updated-2024/08/25-blue)

Accessibility is a core part of this library and the components it contains. So, at a minimum, all components should be tested with the following document in mind.

## Automated testing
Expand Down Expand Up @@ -27,7 +30,7 @@ These considerations will cover most scenarios, particularly at a component leve
- does any essential complex functionality have keyboard-only alternatives? (e.g. drag and drop)
3. **Is it clear and functional for users without vision?**
- points (1) and (2) above will do most of this for you
- **test using at least NVDA** as it is one of the most widely used screen-readers (bonus points for also testing with other screen-readers, such as TalkBack, Windows Narrator, and VoiceOver)
- **test using at least NVDA** as it is one of the most widely used screen-readers (bonus points for also testing with other screen-readers, such as TalkBack, Windows Narrator, and VoiceOver). In particular, **test with a screen-reader using only your keyboard**: does everything you can tab to have an announcement that clearly indicates what it's for?
- Consider if there are elements that need additional text (e.g. icon buttons), or if there are elements that a screen-reader can ignore (e.g. purely presentation iconography that you could set `aria-hidden="true"` for)
4. **Does it work at a viewport width of 320px?**
- This is to account for the "reflow" criterion: no loss of content or functionality occurs, and horizontal scrolling is avoided
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

![License: MIT](https://img.shields.io/npm/l/rea11y-easy-form)
![NPM version](https://img.shields.io/npm/v/rea11y-easy-form.svg)
![Types](https://img.shields.io/npm/types/rea11y-easy-form)
![Tree Shaking](https://flat.badgen.net/bundlephobia/tree-shaking/rea11y-easy-form)
![Types: TypeScript](https://img.shields.io/npm/types/rea11y-easy-form)
![Tree Shaking: Supported](https://badgen.net/bundlephobia/tree-shaking/rea11y-easy-form)

![React](https://img.shields.io/badge/React-%2320232a.svg?logo=React&logoColor=%2361DAFB)
![React Final Form](https://img.shields.io/badge/React%20Final%20Form-%23333639.svg?logo=react&logoColor=white)
Expand Down
411 changes: 170 additions & 241 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"@babel/preset-env": "^7.25.4",
"@babel/preset-typescript": "^7.24.7",
"@chromatic-com/storybook": "^1.7.0",
"@rollup/plugin-commonjs": "^26.0.1",
Expand All @@ -83,7 +83,7 @@
"@storybook/react-webpack5": "^8.2.9",
"@storybook/test": "^8.2.9",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.4.8",
"@testing-library/jest-dom": "^6.5.0",
"@testing-library/react": "^16.0.0",
"@types/dompurify": "^3.0.5",
"@types/jest": "^29.5.12",
Expand Down Expand Up @@ -116,7 +116,7 @@
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-typescript2": "^0.36.0",
"storybook": "^8.2.9",
"ts-jest": "^29.2.4",
"ts-jest": "^29.2.5",
"typescript": "^5.5.4"
},
"dependencies": {
Expand Down
99 changes: 51 additions & 48 deletions src/Roadmap.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,80 +4,83 @@ import { Meta } from '@storybook/blocks';

# Roadmap

![Author: Leon Slater](https://img.shields.io/badge/Author-Leon_Slater-blue)

## For 1.0

### Core component exports

* `EasyForm` ✓
* `EasyField` ✓
- `EasyForm` ✓
- `EasyField` ✓

### Form field components

* `Input` ✓
* `Textarea` ✓
* `Checkbox` ✓
* `CheckboxList` ✓
* `ColorInput` ✓
* `Radio` ✓
* `RadioList` ✓
* `Select` ✓
* `Switch` ✓
* `SwitchList` ✓
* `AutoComplete` ✓ (supports multi-select)
- `Input` ✓
- `Textarea` ✓
- `Checkbox` ✓
- `CheckboxList` ✓
- `ColorInput` ✓
- `Radio` ✓
- `RadioList` ✓
- `Select` ✓
- `Switch` ✓
- `SwitchList` ✓
- `AutoComplete` ✓ (supports multi-select)

### Util components (used by form components, and exported)

* `Fieldset` ✓ (also a container)
* `ErrorMessage` ✓
* `Label` ✓
* `Notice` ✓ (looks like an alert, but not a `role='alert'` element by default)
* `Skeleton` ✓ (for loading states)
* `ValidationSummary` ✓
* `VisuallyHidden` ✓
- `Fieldset` ✓ (also a container)
- `ErrorMessage` ✓
- `Label` ✓
- `MutatedFormSpy` ✓
- `Notice` ✓ (looks like an alert, but not a `role='alert'` element by default)
- `Skeleton` ✓ (for loading states)
- `ValidationSummary` ✓
- `VisuallyHidden` ✓

### Container/unique components

* `AsHtml` ✓
* `Disclosure` ✓
* `Fieldset` ✓ (also a util)
* `FieldRepeater` ✓ (unit tests and thorough manual testing ongoing)
* `FieldConditional` ✓
- `AsHtml` ✓
- `Disclosure` ✓
- `Fieldset` ✓ (also a util)
- `FieldRepeater` ✓ (unit tests and thorough manual testing ongoing)
- `FieldConditional` ✓

### Utility/Form functionality hooks

* `useAnnounce` ✓ (for easy screen-reader announcements)
* `useFieldValue` ✓ (for easy form field value fetching)
* `useCheckFieldValue` ✓ (for confirming a field (or fields) has the desired value(s))
* `useMutatedField` ✓ (for correcting async validation state issues)
* `useMutatedFormState` ✓ (for correcting async validation state issues)
- `useAnnounce` ✓ (for easy screen-reader announcements)
- `useFieldValue` ✓ (for easy form field value fetching)
- `useCheckFieldValue` ✓ (for confirming a field (or fields) has the desired value(s))
- `useMutatedField` ✓ (for correcting async validation state issues)
- `useMutatedFormState` ✓ (for correcting async validation state issues)

### Built-in validation functions

Only the most basic built-in rules to be included. We do not want to bloat the package.

* `isAlpha` ✓
* `isAlphaNumeric` ✓
* `isDate` ✓
* `isEmail` ✓
* `isEmpty` ✓ (reversed for `required` rule)
* `isHexColor` ✓
* `isInteger` ✓
* `isLowerCase` ✓
* `isNumber` ✓
* `isUpperCase` ✓
* `isUrl` ✓
- `isAlpha` ✓
- `isAlphaNumeric` ✓
- `isDate` ✓
- `isEmail` ✓
- `isEmpty` ✓ (reversed for `required` rule)
- `isHexColor` ✓
- `isInteger` ✓
- `isLowerCase` ✓
- `isNumber` ✓
- `isUpperCase` ✓
- `isUrl` ✓

### Miscellaneous / Chore

* Wide-spread CSS variables for easier theming? (not strictly necessary)
* Proper Generics handling for components that take an `as` prop
- Wide-spread CSS variables for easier theming? (not strictly necessary)
- Proper Generics handling for components that take an `as` prop

## Beyond 1.0 ideas

### Form field components

* `StarRating` (how granular? E.g. can it display 3.5 out of 5, but only allow selecting full values?)
* `RichTextEditor` (do we want this as part of the core code? Will be big!)
* `Datepicker` (do we want this? Can use native, and custom can be added)
* `Timepicker` (do we want this? Can use native, and custom can be added)
* `Telephone` (do we want this? Is complex. Can use native, and custom can be added)
- `StarRating` (how granular? E.g. can it display 3.5 out of 5, but only allow selecting full values?)
- `RichTextEditor` (do we want this as part of the core code? Will be big!)
- `Datepicker` (do we want this? Can use native, and custom can be added)
- `Timepicker` (do we want this? Can use native, and custom can be added)
- `Telephone` (do we want this? Is complex. Can use native, and custom can be added)
4 changes: 2 additions & 2 deletions src/components/CheckboxList/CheckboxList.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import React from 'react';
import { render } from '@testing-library/react';
import CheckboxList from './CheckboxList';
import SwitchList, { SWITCH_LIST_TYPE } from '../SwitchList';
import { CheckboxListProps } from './CheckboxList.types';
import { fieldClassName } from '../../utils';
import type { SwitchListProps } from '../SwitchList/SwitchList.types';

jest.mock('../SwitchList', () => ({
__esModule: true,
Expand All @@ -12,7 +12,7 @@ jest.mock('../SwitchList', () => ({
}));

describe('<CheckboxList />', () => {
let props: CheckboxListProps;
let props: Omit<SwitchListProps, 'type'>;

beforeEach(() => {
props = {
Expand Down
33 changes: 16 additions & 17 deletions src/components/CheckboxList/CheckboxList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,25 @@ import clsx from 'clsx';
import { isEqual } from '@react-hookz/deep-equal';
import { useFieldClassName } from '../../utils';
import SwitchList, { SWITCH_LIST_TYPE } from '../SwitchList';
import { CheckboxListProps } from './CheckboxList.types';
import type { SwitchListProps } from '../SwitchList/SwitchList.types';

const CheckboxList = forwardRef<HTMLFieldSetElement, CheckboxListProps>(
({ className, ...other }, ref) => {
const classPrefix = useFieldClassName('checkbox-list');
return (
<SwitchList
{...other}
ref={ref}
type={SWITCH_LIST_TYPE.CHECKBOX}
className={clsx(className, classPrefix)}
/>
);
}
);
const CheckboxList = forwardRef<
HTMLFieldSetElement,
Omit<SwitchListProps, 'type'>
>(({ className, ...other }, ref) => {
const classPrefix = useFieldClassName('checkbox-list');
return (
<SwitchList
{...other}
ref={ref}
type={SWITCH_LIST_TYPE.CHECKBOX}
className={clsx(className, classPrefix)}
/>
);
});

// do a deep equal comparison in this case,
// to account for lazy use of the `options` prop
// @todo: confirm if there is any performance benefit by memoising here,
// as the base SwitchList already does a deepEqual props comparison
// to account for the `options` prop being an inline array
const MemoisedCheckboxList = memo(CheckboxList, isEqual);
MemoisedCheckboxList.displayName = 'CheckboxList';
export default MemoisedCheckboxList;
3 changes: 0 additions & 3 deletions src/components/CheckboxList/CheckboxList.types.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/EasyField/EasyFieldField/EasyFieldField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ const EasyFieldField = ({

// @todo: setting classes based on meta state could cause a lot of DOM updates
// e.g. from the `validating` state on each keypress;
// if `validateFields` is also used, then this could
// if `validateFields` is also used, then this could
// cause a lot of extra DOM updates on the page.
// So we should test the impact of this, and maybe put this behind a prop
const metaClassNames = useDeepCompareMemo(
Expand Down
99 changes: 0 additions & 99 deletions src/components/EasyField/useEasyFieldValidator.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { capitaliseFirstLetter } from '../../../utils';

const handleValidatorOutcome = (
result?: any,
key?: string,
val?: any
): string | undefined => {
if (result) {
return typeof result === 'string'
? result
: typeof val === 'string'
? val
: capitaliseFirstLetter(key);
}
};

export default handleValidatorOutcome;
Loading
Loading