Skip to content

Commit

Permalink
feat: created haring-react-hook-form package
Browse files Browse the repository at this point in the history
feat: created FormDynamicZone and DynamicZone, started dealing with typescript hell
  • Loading branch information
Quentin LE CAIGNEC committed Aug 19, 2024
1 parent 69a0aba commit 8bfefc0
Show file tree
Hide file tree
Showing 15 changed files with 1,933 additions and 1,079 deletions.
2,656 changes: 1,577 additions & 1,079 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/haring-react-hook-form/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# @smile/haring-react-hook-form
32 changes: 32 additions & 0 deletions packages/haring-react-hook-form/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# @smile/haring-react-hook-form

React Hook Form related components.

## Documentation

You can access the documentation here: https://smile-sa.github.io/haring-doc

## Prerequisite

You must have React 18 or later installed on your project.

## Installation

You must install `@smile/haring-react` first and then install
`react-hook-form` peer dependencies with:

```bash
npm i @smile/haring-react react-hook-form
```

## Styles

Import the styles in your app with:

```js
import '@smile/haring-react-hook-form/style.css';
```

## License

LGPL-3.0
3 changes: 3 additions & 0 deletions packages/haring-react-hook-form/babel.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const { babelConfig } = require('test');

module.exports = babelConfig;
1 change: 1 addition & 0 deletions packages/haring-react-hook-form/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { jestConfig as default } from 'test';
107 changes: 107 additions & 0 deletions packages/haring-react-hook-form/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
{
"name": "@smile/haring-react-hook-form",
"version": "0.15.0",
"description": "React Hook Form component library based on mantine",
"license": "LGPL-3.0",
"homepage": "https://github.com/Smile-SA/haring",
"repository": {
"type": "git",
"url": "[email protected]:Smile-SA/haring.git"
},
"bugs": {
"url": "https://github.com/Smile-SA/haring/issues"
},
"keywords": [
"react",
"react-component",
"next",
"nextjs",
"ui",
"components",
"ui-kit",
"library",
"frontend",
"design",
"form",
"react-hook-form"
],
"author": {
"name": "Tony Cabaye",
"email": "[email protected]",
"url": "https://github.com/tonai"
},
"type": "module",
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
},
"./server": {
"import": "./dist/server.js",
"require": "./dist/server.cjs",
"types": "./dist/server.d.ts"
},
"./style.css": "./dist/style.css"
},
"types": "./dist/index.d.ts",
"typesVersions": {
"*": {
"server": [
"./dist/server.d.ts"
],
"mock": [
"./dist/mock.d.ts"
]
}
},
"files": [
"CHANGELOG.md",
"LICENSE",
"package.json",
"README.md",
"dist",
"src"
],
"scripts": {
"build": "vite build",
"test": "jest",
"prepublishOnly": "npm run build && node ../../scripts/prepublish.mjs"
},
"dependencies": {
"@smile/haring-react": "0.15.0",
"@smile/haring-react-shared": "0.15.0"
},
"devDependencies": {
"@babel/preset-env": "^7.22.20",
"@babel/preset-react": "^7.22.15",
"@babel/preset-typescript": "^7.23.0",
"@storybook/addon-actions": "^7.4.1",
"@storybook/jest": "^0.2.2",
"@storybook/preview-api": "^7.4.1",
"@storybook/testing-library": "^0.2.0",
"@testing-library/jest-dom": "^6.1.3",
"@testing-library/react": "^14.0.0",
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"@vitejs/plugin-react-swc": "^3.5.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"test": "*",
"tsconfig": "*",
"typescript": "~5.2.0",
"vite": "^5.0.12",
"vite-plugin-dts": "^3.7.2"
},
"peerDependencies": {
"@mantine/core": ">=7.11.0",
"@mantine/hooks": ">=7.11.0",
"react-hook-form": "^7.52.2",
"@phosphor-icons/react": ">=2",
"react": ">=18.0",
"react-dom": ">=18.0"
},
"engines": {
"node": ">=16"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { IFormDynamicZoneProps } from './FormDynamicZone';
import type { Meta, StoryObj } from '@storybook/react';
import type { ReactElement } from 'react';

import { FormProvider, useForm } from 'react-hook-form';

import { FormDynamicZone as Cmp } from './FormDynamicZone';

const meta = {
component: Cmp,
tags: ['autodocs'],
title: '3-custom/Form/FormDynamicZone',
} satisfies Meta<typeof Cmp>;

export default meta;
type IStory = StoryObj<typeof meta>;

function render() {
return function Render(props: IFormDynamicZoneProps): ReactElement {
const methods = useForm();
return (
<FormProvider {...methods}>
<Cmp {...props} />
</FormProvider>
);
};
}

export const FormDynamicZone: IStory = {
args: { dynamicZoneName: 'dynTest' },
render: render(),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import type { ReactElement } from 'react';

import { Flex } from '@mantine/core';
import { DynamicZone } from '@smile/haring-react';
import { useFieldArray, useFormContext, useWatch } from 'react-hook-form';

export interface IFormDynamicZoneProps {
dynamicZoneName: string;
}

interface IBaseField extends Record<string, unknown> {
readonly id: string;
}

export function FormDynamicZone(props: IFormDynamicZoneProps): ReactElement {
const { dynamicZoneName } = props;

const { control, register, handleSubmit } = useFormContext();
const { fields, append, remove, swap } = useFieldArray({
control,
name: dynamicZoneName,
});
const watched = useWatch({ control, name: dynamicZoneName });

function newBlock(field: IBaseField, index: number): ReactElement {
return (
<input
key={field.id}
{...register(`${dynamicZoneName}.${index}.value` as const)}
/>
);
}

function onAppend(): void {
append({
fieldName: `appended-${fields.length}`,
value: null,
});
}

function onSubmit(data: unknown): void {
console.log(data);

Check warning on line 42 in packages/haring-react-hook-form/src/Components/FormDynamicZone/FormDynamicZone.tsx

View workflow job for this annotation

GitHub Actions / test

Unexpected console statement
}

return (
<div>
<Flex>
<button onClick={onAppend} type="button">
add
</button>
<button onClick={() => remove(0)} type="button">
remove first
</button>
<button
onClick={() => swap(fields.length - 1, fields.length - 2)}
type="button"
>
swap last
</button>
</Flex>
{/* eslint-disable-next-line @typescript-eslint/no-misused-promises */}
<form onSubmit={handleSubmit(onSubmit)}>
form container, {dynamicZoneName}: {JSON.stringify(watched)}
<DynamicZone<IBaseField> fields={fields} onCreatingField={newBlock} />
<input type="submit" />
</form>
</div>
);
}
6 changes: 6 additions & 0 deletions packages/haring-react-hook-form/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* eslint-disable react-refresh/only-export-components */
'use client';

// component exports
export { FormDynamicZone } from './Components/FormDynamicZone/FormDynamicZone';
export type { IFormDynamicZoneProps } from './Components/FormDynamicZone/FormDynamicZone';
13 changes: 13 additions & 0 deletions packages/haring-react-hook-form/tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"extends": "tsconfig/react-library.json",
"compilerOptions": {
"outDir": "dist"
},
"exclude": [
"__snapshots__",
"src/**/*.test.tsx",
"src/**/*.stories.tsx",
"src/**/*.mock.tsx"
],
"include": ["src", "../../global.d.ts"]
}
7 changes: 7 additions & 0 deletions packages/haring-react-hook-form/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "tsconfig/react-library.json",
"compilerOptions": {
"plugins": [{ "name": "typescript-plugin-css-modules" }]
},
"include": [".", "../../global.d.ts"]
}
53 changes: 53 additions & 0 deletions packages/haring-react-hook-form/vite.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { resolve } from 'path';

import react from '@vitejs/plugin-react-swc';
import { defineConfig } from 'vite';
import dts from 'vite-plugin-dts';

export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.tsx'),
fileName: '[name]',
formats: ['cjs', 'es'],
},
rollupOptions: {
external: [
'@mantine/core',
'@mantine/hooks',
'@phosphor-icons/react',
'@smile/haring-react',
'@smile/haring-react-shared',
'@storybook/addon-actions',
'@storybook/preview-api',
'@tabler/icons-react',
'@testing-library/react',
'react',
'react/jsx-runtime',
],
input: {
index: resolve(__dirname, 'src/index.tsx'),
},
output: {
banner: (chunkInfo) => {
if (
['src/index.tsx'].find((modulePath) =>
chunkInfo.facadeModuleId?.endsWith(modulePath),
)
) {
return `"use client"`;
}
return '';
},
preserveModules: false,
},
},
},
plugins: [
react(),
dts({
insertTypesEntry: true,
tsconfigPath: './tsconfig.build.json',
}),
],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.container {
display: flex;
gap: 10px;
margin-top: 20px;
flex-wrap: wrap;
}
24 changes: 24 additions & 0 deletions packages/haring-react/src/Form/DynamicZone/DynamicZone.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { ReactElement } from 'react';

import { Stack } from '@mantine/core';

import classes from './DynamicZone.module.css';

export interface IDynamicZoneProps<Field> {
fields: Field[];
onCreatingField: (field: Field, index: number) => ReactElement;
}

export function DynamicZone<Field>(
props: IDynamicZoneProps<Field>,
): ReactElement {
const { fields, onCreatingField } = props;
return (
<div className={classes.container}>
wip
<Stack>
{fields.map((field, index) => onCreatingField(field, index))}
</Stack>
</div>
);
}
2 changes: 2 additions & 0 deletions packages/haring-react/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export type { IFetchAutocompleteFieldProps } from './Form/FetchAutocompleteField
export { FetchAutocompleteField } from './Form/FetchAutocompleteField/FetchAutocompleteField';
export type { IAddressAutocompleteFieldProps } from './Form/AddressGouvAutocompleteField/AddressGouvAutocompleteField';
export { AddressGouvAutocompleteField } from './Form/AddressGouvAutocompleteField/AddressGouvAutocompleteField';
// export type { IDynamicZoneProps } from './Form/DynamicZone/DynamicZone';
export { DynamicZone } from './Form/DynamicZone/DynamicZone';
export type { IAddressFieldsProps } from './Form/AddressFields/AddressFields';
export { AddressFields } from './Form/AddressFields/AddressFields';
export type { IIconCardProps } from './Components/IconCard/IconCard';
Expand Down

0 comments on commit 8bfefc0

Please sign in to comment.