From 8321916dce896b7bd70b7b1326acd3de59d536a2 Mon Sep 17 00:00:00 2001 From: Svyatoslav Date: Mon, 15 Jul 2024 10:25:45 +0300 Subject: [PATCH] feat(react,DropzoneCompact): add new component --- .../DropzoneCompact/DropzoneCompact.api.mdx | 31 +++++++++ .../DropzoneCompact.stories.tsx | 51 +++++++++++++++ .../DropzoneCompact/DropzoneCompact.tsx | 64 +++++++++++++++++++ .../DropzoneCompact/DropzoneCompact.types.ts | 15 +++++ .../src/components/DropzoneCompact/index.ts | 2 + packages/react/src/components/index.ts | 1 + .../src/hooks/useDragOver/useDragOver.ts | 14 ++-- packages/react/src/overrides.d.ts | 5 ++ .../lib/components/_dropzone-compact.scss | 18 ++++++ packages/theme/lib/components/_index.scss | 2 + 10 files changed, 196 insertions(+), 7 deletions(-) create mode 100644 packages/react/src/components/DropzoneCompact/DropzoneCompact.api.mdx create mode 100644 packages/react/src/components/DropzoneCompact/DropzoneCompact.stories.tsx create mode 100644 packages/react/src/components/DropzoneCompact/DropzoneCompact.tsx create mode 100644 packages/react/src/components/DropzoneCompact/DropzoneCompact.types.ts create mode 100644 packages/react/src/components/DropzoneCompact/index.ts create mode 100644 packages/theme/lib/components/_dropzone-compact.scss diff --git a/packages/react/src/components/DropzoneCompact/DropzoneCompact.api.mdx b/packages/react/src/components/DropzoneCompact/DropzoneCompact.api.mdx new file mode 100644 index 000000000..c259f67cc --- /dev/null +++ b/packages/react/src/components/DropzoneCompact/DropzoneCompact.api.mdx @@ -0,0 +1,31 @@ +import { Meta } from '@storybook/blocks'; +import LinkTo from '@storybook/addon-links/react'; +import { TableInterface } from '~storybook/components/TableInterface'; + + + +# DropzoneCompact API + +```js +import { DropzoneCompact } from '@esfront/react'; +``` + +## Component name + +The name `ESDropzoneCompact` can be used when providing default props. + +## Props + + + +
+ +## Demos + + diff --git a/packages/react/src/components/DropzoneCompact/DropzoneCompact.stories.tsx b/packages/react/src/components/DropzoneCompact/DropzoneCompact.stories.tsx new file mode 100644 index 000000000..8c53bae3a --- /dev/null +++ b/packages/react/src/components/DropzoneCompact/DropzoneCompact.stories.tsx @@ -0,0 +1,51 @@ +import { Args, Meta, StoryContext, StoryObj } from '@storybook/react'; + +import { DropzoneCompact } from '.'; + +import { Button } from '../Button'; + +const getText = (args: Args, context: StoryContext) => { + return args.children || (context.globals.locale === 'en' ? 'Drag over this area' : 'Переместите в эту область'); +}; + +const getButtonText = (context: StoryContext) => { + return context.globals.locale === 'en' ? 'Drag this button' : 'Переместите кнопку'; +}; + +const meta: Meta = { + tags: ['autodocs'], + component: DropzoneCompact, + parameters: { + references: ['DropzoneCompact'], + }, + argTypes: { + children: { + control: { + type: 'text', + }, + }, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Demo: Story = { + render: (args, context) => { + const onDrop = () => { + console.info('DROP'); + }; + + return ( + <> + + + {getText(args, context)} + + + ); + }, +}; diff --git a/packages/react/src/components/DropzoneCompact/DropzoneCompact.tsx b/packages/react/src/components/DropzoneCompact/DropzoneCompact.tsx new file mode 100644 index 000000000..5c267ba36 --- /dev/null +++ b/packages/react/src/components/DropzoneCompact/DropzoneCompact.tsx @@ -0,0 +1,64 @@ +import { forwardRef } from 'react'; + +import { DropzoneCompactProps } from './DropzoneCompact.types'; + +import clsx from 'clsx'; + +import { useDefaultProps } from '@mui/system/DefaultPropsProvider'; + +import { useDragOver } from '../../hooks/useDragOver'; + +/** + * This component allows to create droppable area when using dnd. + */ +export const DropzoneCompact = forwardRef(function DropzoneCompact(inProps, ref) { + const { + className, + style, + children, + onDragEnter: onDragEnterProp, + onDragLeave: onDragLeaveProp, + onDragOver: onDragOverProp, + onDrop: onDropProp, + } = useDefaultProps({ + props: inProps, + name: 'ESDropzoneCompact', + }); + + const { isDragOver, onDragEnter, onDragLeave, onDrop } = useDragOver(); + + const onDropzoneDragEnter = (event: React.DragEvent) => { + onDragEnter(); + onDragEnterProp?.(event); + }; + + const onDropzoneDragLeave = (event: React.DragEvent) => { + onDragLeave(); + onDragLeaveProp?.(event); + }; + + const onDropzoneDragOver = (event: React.DragEvent) => { + event.preventDefault(); + onDragOverProp?.(event); + }; + + const onDropzoneDrop = (event: React.DragEvent) => { + event.preventDefault(); + onDrop(); + onDropProp?.(event); + }; + + return ( +
+ {children} +
+ ); +}); diff --git a/packages/react/src/components/DropzoneCompact/DropzoneCompact.types.ts b/packages/react/src/components/DropzoneCompact/DropzoneCompact.types.ts new file mode 100644 index 000000000..d57143f9b --- /dev/null +++ b/packages/react/src/components/DropzoneCompact/DropzoneCompact.types.ts @@ -0,0 +1,15 @@ +import { CSSProperties, ReactNode } from 'react'; + +export interface DropzoneCompactProps { + children?: ReactNode; + + /** Class applied to the root element. */ + className?: string; + /** Style applied to the root element. */ + style?: CSSProperties; + + onDragEnter?: (event: React.DragEvent) => void; + onDragLeave?: (event: React.DragEvent) => void; + onDragOver?: (event: React.DragEvent) => void; + onDrop?: (event: React.DragEvent) => void; +} diff --git a/packages/react/src/components/DropzoneCompact/index.ts b/packages/react/src/components/DropzoneCompact/index.ts new file mode 100644 index 000000000..4b3bff570 --- /dev/null +++ b/packages/react/src/components/DropzoneCompact/index.ts @@ -0,0 +1,2 @@ +export { DropzoneCompact } from './DropzoneCompact'; +export type { DropzoneCompactProps } from './DropzoneCompact.types'; diff --git a/packages/react/src/components/index.ts b/packages/react/src/components/index.ts index 2ea56d6ca..18d21fd09 100644 --- a/packages/react/src/components/index.ts +++ b/packages/react/src/components/index.ts @@ -23,6 +23,7 @@ export * from './Dialog'; export * from './DialogStack'; export * from './Divider'; export * from './Dropzone'; +export * from './DropzoneCompact'; export * from './EmptyState'; export * from './EmptyStateCompact'; export * from './ErrorPage'; diff --git a/packages/react/src/hooks/useDragOver/useDragOver.ts b/packages/react/src/hooks/useDragOver/useDragOver.ts index 88d7a2674..5cd09d3a7 100644 --- a/packages/react/src/hooks/useDragOver/useDragOver.ts +++ b/packages/react/src/hooks/useDragOver/useDragOver.ts @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useCallback, useState } from 'react'; /** * The hook that allows to watch over the drag over state. @@ -7,17 +7,17 @@ import { useState } from 'react'; export const useDragOver = () => { const [count, setCount] = useState(0); - const onDragEnter = () => { + const onDragEnter = useCallback(() => { setCount((c) => c + 1); - }; + }, []); - const onDragLeave = () => { + const onDragLeave = useCallback(() => { setCount((c) => c - 1); - }; + }, []); - const onDrop = () => { + const onDrop = useCallback(() => { setCount(0); - }; + }, []); return { onDragEnter, onDragLeave, onDrop, isDragOver: count > 0 }; }; diff --git a/packages/react/src/overrides.d.ts b/packages/react/src/overrides.d.ts index 0b12797a1..35debd86f 100644 --- a/packages/react/src/overrides.d.ts +++ b/packages/react/src/overrides.d.ts @@ -40,6 +40,7 @@ import { } from './components/Dialog'; import { DividerProps } from './components/Divider'; import { DropzoneProps } from './components/Dropzone'; +import { DropzoneCompactProps } from './components/DropzoneCompact'; import { EmptyStateProps } from './components/EmptyState'; import { EmptyStateCompactProps } from './components/EmptyStateCompact'; import { @@ -208,6 +209,7 @@ declare module '@mui/material/styles/props' { ESDialogTitle: DialogTitleProps; ESDivider: DividerProps; ESDropzone: DropzoneProps; + ESDropzoneCompact: DropzoneCompactProps; ESEmptyState: EmptyStateProps; ESEmptyStateCompact: EmptyStateCompactProps; ESErrorPage: ErrorPageProps; @@ -535,6 +537,9 @@ declare module '@mui/material/styles/components' { ESDropzone?: { defaultProps?: ComponentsProps['ESDropzone']; }; + ESDropzoneCompact?: { + defaultProps?: ComponentsProps['ESDropzoneCompact']; + }; ESFileIcon?: { defaultProps?: ComponentsProps['ESFileIcon']; }; diff --git a/packages/theme/lib/components/_dropzone-compact.scss b/packages/theme/lib/components/_dropzone-compact.scss new file mode 100644 index 000000000..e25b40aaa --- /dev/null +++ b/packages/theme/lib/components/_dropzone-compact.scss @@ -0,0 +1,18 @@ +@mixin include() { + .es-dropzone-compact { + align-items: center; + background-color: var(--es-mono-a-a25); + border-radius: 4px; + color: var(--es-mono-a-a550); + display: flex; + justify-content: center; + outline: 1px dashed var(--es-mono-a-a300); + outline-offset: -1px; + padding: 12px; + transition: background-color 200ms; + + &--drag-over { + background-color: var(--es-mono-a-a50); + } + } +} diff --git a/packages/theme/lib/components/_index.scss b/packages/theme/lib/components/_index.scss index 81b71047f..2c87158eb 100644 --- a/packages/theme/lib/components/_index.scss +++ b/packages/theme/lib/components/_index.scss @@ -20,6 +20,7 @@ @use './dialog'; @use './divider'; @use './dropzone'; +@use './dropzone-compact'; @use './empty-state-compact'; @use './empty-state'; @use './error-page'; @@ -89,6 +90,7 @@ @include dialog.include; @include divider.include; @include dropzone.include; + @include dropzone-compact.include; @include empty-state-compact.include; @include empty-state.include; @include error-page.include;