Skip to content

Commit

Permalink
Feat/dropzone card dropzone (#38)
Browse files Browse the repository at this point in the history
* feat(redmine 1246935): add dropzone in dropzoneCard

* feat(redmine 1246935): taking into account Tony's feedback

* feat(redmine 1246935): add Dropzone component

* feat(redmine 1246935): add dropzone in dropzoneCard

feat(redmine 1246935): taking into account Tony's feedback

feat(redmine 1246935): add Dropzone component

* feat(redmine 1246935): fix install dependencies job

* feat(readmine 1246935): add children in dropzone component

* feat (redmine 1246935): add files cards

* feat (redmine 1246935): add files cards and fix errors

* feat(redmine 1244990): remove tooltip

* feat(redmine 1244990): add tooltip and removeCards props

* feat(redmine 1244990): add BitByteConverter component

* feat(redmine 1244990): add TruncateStringWithEllipsis component

* feat(redmine 1244990): add changset

* feat(redmine 1244990): fix pr review

* chore: connect dropzone with storybook

* fix: unit tests with pretty-bytes

* chore: move dropzone in its own package

* feat(redmine 1244990): remove TrucateString component

* feat(redmine 1244990): remove TrucateString component

---------

Co-authored-by: Tony CABAYE <tony.cabaye@smile.fr>
  • Loading branch information
vapersmile and tonai authored Oct 16, 2023
1 parent d644c7c commit 195cc64
Show file tree
Hide file tree
Showing 33 changed files with 22,881 additions and 21,306 deletions.
5 changes: 5 additions & 0 deletions .changeset/calm-starfishes-breathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@smile/react-front-kit': patch
---

Add BitConverter, TruncateString, Dropzone and DropzoneCard components
43,211 changes: 22,106 additions & 21,105 deletions package-lock.json

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions packages/react-front-kit-dropzone/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# React Front Kit dropzone

Dropzone component.

## Prerequisite

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

## Installation

Install `@smile/react-front-kit-dropzone` and peer dependencies with:

```bash
npm i @smile/react-front-kit-dropzone @emotion/react @mantine/core @mantine/hooks @mantine/styles @mantine/dropzone @phosphor-icons/react
```

## License

MIT
3 changes: 3 additions & 0 deletions packages/react-front-kit-dropzone/babel.config.js
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/react-front-kit-dropzone/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { jestConfig as default } from 'test';
73 changes: 73 additions & 0 deletions packages/react-front-kit-dropzone/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"name": "@smile/react-front-kit-dropzone",
"version": "0.2.0",
"description": "Dropzone React component library based on mantine",
"license": "MIT",
"homepage": "https://github.com/Smile-SA/react-front-kit",
"repository": {
"type": "git",
"url": "git@github.com:Smile-SA/react-front-kit.git"
},
"bugs": {
"url": "https://github.com/Smile-SA/react-front-kit/issues"
},
"keywords": [
"react",
"react-component",
"next",
"nextjs",
"ui",
"components",
"ui-kit",
"library",
"frontend",
"design",
"emotion",
"dropzone"
],
"author": {
"name": "Tony Cabaye",
"email": "tonai59+github@gmail.com",
"url": "https://github.com/tonai"
},
"main": "./dist/index.js",
"module": "./src/index.tsx",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsc --project tsconfig.build.json",
"test": "jest",
"prepublishOnly": "npm run build && node ./scripts/prepublish.mjs"
},
"dependencies": {
"@smile/react-front-kit": "*",
"@smile/react-front-kit-shared": "*"
},
"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",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"test": "*",
"tsconfig": "*",
"typescript": "^5.2.2"
},
"peerDependencies": {
"@emotion/react": ">=11",
"@mantine/core": "6",
"@mantine/dropzone": "6",
"@mantine/hooks": "6",
"@mantine/styles": "6",
"@phosphor-icons/react": ">=2",
"react": ">=18.0",
"react-dom": ">=18.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { Meta, StoryObj } from '@storybook/react';

import { useStorybookArgsConnect } from '@smile/react-front-kit-shared/src/storybook-utils';

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

const meta = {
argTypes: {
browseLabel: {
control: 'text',
},
dragLabel: {
control: 'text',
},
},
component: Cmp,
decorators: [
function Component(Story, ctx) {
const args = useStorybookArgsConnect(ctx.args, {
onDrop: 'files',
onRemoveFile: (file) => ({
files: ctx.args.files?.filter((f) => f !== file),
}),
});
return <Story args={{ ...args }} />;
},
],
tags: ['autodocs'],
title: '3-custom/Components/Dropzone',
} satisfies Meta<typeof Cmp>;

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

export const Dropzone: IStory = {
args: {
browseLabel: undefined,
children: undefined,
dragLabel: undefined,
files: [],
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { renderWithProviders } from '@smile/react-front-kit-shared/src/test-utils';

import { Dropzone } from './Dropzone';

describe('Dropzone', () => {
it('matches snapshot', () => {
const { container } = renderWithProviders(
<Dropzone
files={[
{
name: 'CERFA.postman_collection.json',
size: 1579,
},
{
name: 'CERFA.postman_collection.json',
size: 1579,
},
{
name: 'CERFA.postman_collection.json',
size: 1579,
},
{
name: 'CERFA.postman_collection.json',
size: 1579,
},
]}
// eslint-disable-next-line no-console
onDrop={(file) => console.log(file)}
/>,
);
expect(container).toMatchSnapshot();
});
});
176 changes: 176 additions & 0 deletions packages/react-front-kit-dropzone/src/Components/Dropzone/Dropzone.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
'use client';

import type {
FileWithPath,
DropzoneProps as IMantineDropzoneProps,
} from '@mantine/dropzone';
import type { MouseEvent, ReactElement } from 'react';

import { ActionIcon, Text, Tooltip } from '@mantine/core';
import { Dropzone as MantineDropzone } from '@mantine/dropzone';
import { createStyles } from '@mantine/styles';
import { Eye, Plus, X } from '@phosphor-icons/react';
import { BitConverter } from '@smile/react-front-kit';

export interface IFile extends Partial<FileWithPath> {
name: string;
}

export interface IDropzoneProps
extends Omit<IMantineDropzoneProps, 'children'> {
browseLabel?: string;
buttonPlusTitle?: string;
children?: ReactElement;
dragLabel?: string;
files?: IFile[];
onRemoveFile?: (file: IFile) => void;
}

const useStyles = createStyles((theme) => ({
buttonPlus: {
alignItems: 'center',
cursor: 'pointer',
display: 'flex',
justifyContent: 'center',
margin: 'auto',
},
cardFile: {
background:
theme.colorScheme === 'dark' ? theme.black : theme.colors.gray[2],
borderRadius: '10px',
display: 'flex',
flexDirection: 'column',
height: '70px',
margin: '10px',
padding: '10px',
position: 'relative',
width: '80px',
},
cardFileButtonClose: {
position: 'absolute',
right: '-7px',
top: '-7px',
},
cardFileText: {
'&:first-of-type': {
fontWeight: 600,
},
display: 'inline-block',
fontSize: '12px',
height: 'fit-content',
margin: 'auto',
width: '100%',
},
cardsFile: {
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'center',
},
dropzoneBrowse: {
alignItems: 'center',
display: 'flex',
fontWeight: 600,
justifyContent: 'center',
marginTop: '0px',
},
dropzoneInner: {
margin: 'auto',
p: {
margin: '10px',
},
pointerEvents: 'auto',
textAlign: 'center',
},
dropzoneRoot: {
display: 'flex',
minHeight: '100%',
minWidth: '100%',
},
eye: { marginRight: '8px' },
}));

export function Dropzone(props: IDropzoneProps): ReactElement {
const {
children,
dragLabel = 'Drag and drop your documents here',
buttonPlusTitle = 'Add button',
browseLabel = 'Browse your device',
files = [],
onRemoveFile,
...MantineDropzoneProps
} = props;
const { classes } = useStyles();

function handleFileClick(e: MouseEvent<HTMLDivElement>): void {
e.preventDefault();
e.stopPropagation();
}

return (
<MantineDropzone
{...MantineDropzoneProps}
classNames={{
inner: classes.dropzoneInner,
root: classes.dropzoneRoot,
}}
>
<ActionIcon
className={classes.buttonPlus}
radius="xl"
size="xl"
title={buttonPlusTitle}
variant="filled"
>
<Plus size={20} weight="bold" />
</ActionIcon>
<p>{dragLabel}</p>
<p className={classes.dropzoneBrowse}>
<Eye className={classes.eye} size={16} weight="bold" />
{browseLabel}
</p>
<div className={classes.cardsFile}>
{files.map((file, i) => {
const { name, size } = file;
return (
<Tooltip
key={`${i + i}`}
label={name}
position="bottom"
radius={6}
withArrow
>
<div
aria-hidden="true"
className={classes.cardFile}
onClick={(e) => {
handleFileClick(e);
}}
>
{Boolean(onRemoveFile) && (
<ActionIcon
className={classes.cardFileButtonClose}
onClick={() => onRemoveFile?.(file)}
radius="xl"
size="sm"
variant="filled"
>
<X size={8} weight="bold" />
</ActionIcon>
)}
<Text className={classes.cardFileText} span truncate>
{name}
</Text>
{size !== undefined && (
<span className={classes.cardFileText}>
<BitConverter options={{ locale: 'fr' }} value={size} />
</span>
)}
</div>
</Tooltip>
);
})}
</div>
{children}
</MantineDropzone>
);
}
Loading

0 comments on commit 195cc64

Please sign in to comment.