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

388 feature make fileuploader component #390

Merged
merged 10 commits into from
Aug 20, 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
9 changes: 7 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,16 @@ updates:
interval: weekly

- package-ecosystem: npm
directory: '/packages/panda-preset'
directory: '/packages/*'
schedule:
interval: weekly

- package-ecosystem: npm
directory: '/packages/react'
directory: '/docs'
schedule:
interval: weekly

- package-ecosystem: npm
directory: '/figma'
schedule:
interval: weekly
2 changes: 1 addition & 1 deletion docs/app/data/categories.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@
"inputs": {
"name": "Inputs",
"description": "Components that allow users to input data.",
"items": ["Input", "Textarea"]
"items": ["Input", "Textarea", "File Uploader"]
}
}
2 changes: 2 additions & 0 deletions docs/app/preset/conditions/doc.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ Cerberus extends the [built-in conditions](https://panda-css.com/docs/concepts/c
| _darkMode | `[data-color-mode=dark] &, &.dark, .dark &` |
| _modalOpen | `&:is([data-modal-open=true])` |
| _screenReaderOnly | `&:is([data-screen-reader-only=true])` |
| _isOver | `&:is([data-over=true])` |
| _isDropped | `&:is([data-dropped=true])` |
| _invalid | `&:is(:invalid, [data-invalid], [aria-invalid])` |
| _userInvalid | `&:is(:user-invalid, [aria-invalid])` |
| _groupInvalid | `.group:is([data-invalid] &, [aria-invalid]) &` |
Expand Down
61 changes: 61 additions & 0 deletions docs/app/react/drag-n-drop/components/dnd-preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use client'

import {
Button,
DndContext,
Droppable,
Show,
type DragEndEvent,
} from '@cerberus-design/react'
import { useCallback, useState } from 'react'
import { Draggable } from './draggable'
import { css } from '@cerberus/styled-system/css'

const draggableMarkup = <Draggable>Drag me</Draggable>

export default function DnDPreview() {
const [isDropped, setIsDropped] = useState<boolean>(false)

const handleDragEnd = useCallback((event: DragEndEvent) => {
if (event.over && event.over.id === 'droppable') {
setIsDropped(true)
}
}, [])

const handleReset = useCallback(() => {
setIsDropped(false)
}, [])

return (
<DndContext onDragEnd={handleDragEnd}>
<Show
when={!isDropped}
fallback={<Button onClick={handleReset}>Reset</Button>}
>
{draggableMarkup}
</Show>

<Droppable
className={css({
bgColor: 'page.surface.200',
border: '4px dashed',
borderColor: 'page.border.100',
h: '8rem',
p: '4',
rounded: 'lg',
transitionProperty: 'border-color',
transitionDuration: '150ms',
w: '1/2',
_isOver: {
borderColor: 'success.border.initial',
},
})}
id="droppable"
>
<Show when={isDropped} fallback={<>Drop here</>}>
{draggableMarkup}
</Show>
</Droppable>
</DndContext>
)
}
34 changes: 34 additions & 0 deletions docs/app/react/drag-n-drop/components/draggable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useDraggable } from '@cerberus-design/react'
import { css } from '@cerberus/styled-system/css'
import type { ButtonHTMLAttributes, PropsWithChildren } from 'react'

export function Draggable(
props: PropsWithChildren<ButtonHTMLAttributes<HTMLButtonElement>>,
) {
const { attributes, listeners, setNodeRef, transform } = useDraggable({
id: 'draggable',
})
const style = transform
? {
transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
}
: undefined

return (
<button
className={css({
bgColor: 'info.bg.initial',
cursor: 'grab',
p: '4',
rounded: 'lg',
userSelect: 'none',
})}
ref={setNodeRef}
style={style}
{...listeners}
{...attributes}
>
{props.children}
</button>
)
}
98 changes: 98 additions & 0 deletions docs/app/react/drag-n-drop/doc.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
---
heading: 'Drag and Drop'
description: 'Drag and drop allow users to drag and drop items in the UI.'
a11y: 'utilities'
npm: '@cerberus-design/react'
source: 'components/Draggable.tsx'
recipe: ''
---

import {
WhenToUseAdmonition,
WhenNotToUseAdmonition,
} from '@/app/components/Admonition'
import CodePreview from '@/app/components/CodePreview'
import DnDPreview from '@/app/react/drag-n-drop/components/dnd-preview'

```ts
import {
DndContext,
Droppable,
useDraggable,
useDroppable,
} from '@cerberus-design/react'
```

<WhenToUseAdmonition description="When you need add drag and drop functionality to the UI." />

## Usage

<CodePreview preview={<DnDPreview />}>
```tsx title="nav.tsx"
'use client'

import {
Button,
DndContext,
Droppable,
Show,
type DragEndEvent,
} from '@cerberus-design/react'
import { useCallback, useState } from 'react'
import { Draggable } from './draggable'
import { css } from '@cerberus/styled-system/css'

const draggableMarkup = <Draggable>Drag me</Draggable>

function DnDPreview() {
const [isDropped, setIsDropped] = useState<boolean>(false)

const handleDragEnd = useCallback((event: DragEndEvent) => {
if (event.over && event.over.id === 'droppable') {
setIsDropped(true)
}
}, [])

const handleReset = useCallback(() => {
setIsDropped(false)
}, [])

return (
<DndContext onDragEnd={handleDragEnd}>
<Show
when={!isDropped}
fallback={<Button onClick={handleReset}>Reset</Button>}
>
{draggableMarkup}
</Show>

<Droppable
className={css({
bgColor: 'page.surface.200',
border: '4px dashed',
borderColor: 'page.border.100',
h: '8rem',
p: '4',
rounded: 'lg',
transitionProperty: 'border-color',
transitionDuration: '150ms',
w: '1/2',
_isOver: {
borderColor: 'success.border.initial',
},
})}
id="droppable"
>
<Show when={isDropped} fallback={<>Drop here</>}>
{draggableMarkup}
</Show>
</Droppable>
</DndContext>
)
}
```
</CodePreview>

## API

This API is a direct export of the [dnd kit library](https://dndkit.com/)
28 changes: 28 additions & 0 deletions docs/app/react/drag-n-drop/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import ApiLinks from '@/app/components/ApiLinks'
import OnThisPage from '../../components/OnThisPage'
import { PageMainContent, PageSections } from '../../components/PageLayout'
import Doc, { frontmatter } from './doc.mdx'
import FeatureHeader from '@/app/components/FeatureHeader'
import type { MatchFeatureKind } from '@/app/components/MatchFeatureImg'

export default function DnDPage() {
return (
<>
<PageMainContent>
<FeatureHeader
heading={frontmatter.heading}
description={frontmatter.description}
a11y={frontmatter.a11y as MatchFeatureKind}
/>
<ApiLinks {...frontmatter} />
<main>
<Doc />
</main>
</PageMainContent>

<PageSections>
<OnThisPage />
</PageSections>
</>
)
}
33 changes: 33 additions & 0 deletions docs/app/react/file-uploader/a11y.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
---

import {
WhenToUseAdmonition
} from '@/app/components/Admonition'
import OverviewList from '@/app/components/OverviewList'

## Use Cases

<OverviewList intro="Users should be able to:" rules={[
'Navigate to and activate a file uploader with assistive technology',
'Select files to upload',
'Receive feedback on the status of the upload',
]} />

## Interaction &amp; Style

Changes to color and thickness of stroke help provide clear visual cues for interaction.

## Keyboard Navigation

| Keys | Actions |
| -------- | --------------------------------------------------------------- |
| Tab | Focus lands on (non-disabled) input |
| Enter | Opens the file dialog to select a file to upload |
| Space | Opens the file dialog to select a file to upload |

## Labeling Elements

If the UI text is correctly linked, assistive tech (such as a screenreader) will read the UI text followed by the component's role.

The accessibility label for a input is typically the same as the label for the input.
11 changes: 11 additions & 0 deletions docs/app/react/file-uploader/components/file-uploader-preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { FileUploader } from '@cerberus-design/react'

export function BasicFileUploader() {
return (
<FileUploader
accept=".csv,.docx"
heading="Upload Files"
name="basic-example"
/>
)
}
57 changes: 57 additions & 0 deletions docs/app/react/file-uploader/dev.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
npm: '@cerberus-design/react'
source: 'components/Label.tsx'
recipe: 'label.ts'
---

import CodePreview from '@/app/components/CodePreview'
import {
BasicFileUploader
} from '@/app/react/file-uploader/components/file-uploader-preview'

```ts
import { FileUploader } from '@cerberus-design/react'
```

## Usage

<CodePreview preview={<BasicFileUploader />}>
```tsx title="file-uploader.tsx" {5,6}
import { FileUploader } from '@cerberus-design/react'

function BasicFileUploader() {
return (
<FileUploader
accept=".csv,.docx"
heading="Upload Files"
name="basic-example"
/>
)
}
```
</CodePreview>

## Customizing

To customize the FileUploader, we recommend extending the `fileUploader` slot recipe in your panda config.

## API

```ts showLineNumbers=false
export interface FileUploaderProps
extends InputHTMLAttributes<HTMLInputElement> {
heading?: string
name: string
}

define function FileUploader(props: FileUploaderProps): ReactNode
```

### Props

The `FileUploader` component accepts the following props:

| Name | Default | Description |
| -------- | ------- | ------------------------------------------------------------- |
| heading | | The heading for the file uploader |
| name | | The unique name of the file uploader |
32 changes: 32 additions & 0 deletions docs/app/react/file-uploader/guidelines.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
---

import CodePreview from '@/app/components/CodePreview'
import OverviewList from '@/app/components/OverviewList'
import {
WhenToUseAdmonition
} from '@/app/components/Admonition'
import {
BasicFileUploader
} from '@/app/react/file-uploader/components/file-uploader-preview'

## Usage

<WhenToUseAdmonition description="When you need to provide a way for users to upload files to the server." />

## File Uploader

File Uploaders can be used for any type of file (i.e. text, images, video, etc.).

<CodePreview preview={<BasicFileUploader />} />

## Placement

File Uploaders should be placed in a location that is easy to find and use.

<OverviewList intro="They can be placed in:" rules={[
'Forms',
'Modals',
'Pages',
'Sidebars',
]} />
Loading