Skip to content

Commit

Permalink
add inline file input
Browse files Browse the repository at this point in the history
  • Loading branch information
vassbence committed Nov 13, 2024
1 parent 27ce470 commit c9e06fa
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 0 deletions.
51 changes: 51 additions & 0 deletions src/components/InlineFileInput/InlineFileInput.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react'
import { InlineFileInput } from './index.js'
import { useClient } from '@based/react'
import { useToast } from '../Toast/index.js'

export default {
title: 'InlineFileInput',
component: InlineFileInput,
}

export const Default = () => {
const client = useClient()
const toast = useToast()
return (
<>
<InlineFileInput
onChange={async (files) => {
await Promise.allSettled(
files.map(async (file) => {
const res = await client.stream('db:file-upload', {
contents: file,
fileName: file.name,
mimeType: file.type,
})
toast(`✅ uploaded file: ${JSON.stringify(res)}`)
}),
)
}}
>
Upload a file
</InlineFileInput>
<InlineFileInput
multiple
onChange={async (files) => {
await Promise.allSettled(
files.map(async (file) => {
const res = await client.stream('db:file-upload', {
contents: file,
fileName: file.name,
mimeType: file.type,
})
toast(`✅ uploaded file: ${JSON.stringify(res)}`)
}),
)
}}
>
Upload multiple files
</InlineFileInput>
</>
)
}
70 changes: 70 additions & 0 deletions src/components/InlineFileInput/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { useRef, useState } from 'react'
import { Button, ButtonProps } from '../Button/index.js'
import { useToast } from '../Toast/index.js'

type InlineFileInputProps = {
multiple?: boolean
onChange: (value: File[]) => void | Promise<void>
} & Omit<ButtonProps, 'onClick' | 'loading'>

function InlineFileInput({
multiple = false,
onChange,
...buttonProps
}: InlineFileInputProps) {
const [loading, setLoading] = useState(false)
const ref = useRef<HTMLInputElement>()
const toast = useToast()

console.log(loading)

return (
<>
<Button
{...buttonProps}
onClick={() => {
ref.current.click()
}}
loading={loading}
/>
<input
style={{
position: 'absolute',
width: 1,
height: 1,
padding: 0,
margin: -1,
overflow: 'hidden',
clip: 'rect(0, 0, 0, 0)',
whiteSpace: 'nowrap',
borderWidth: 0,
}}
ref={ref}
type="file"
multiple={multiple}
onChange={async (e) => {
if (!e.target.files.length) return
const files = [...e.target.files]

try {
const result = onChange(files)

if (result instanceof Promise) {
console.log('promiset ad az onchange')
setLoading(true)
await result
}
} catch {
toast(`Upload failed: ${e}`, { color: 'red' })
} finally {
setLoading(false)
e.target.value = ''
}
}}
/>
</>
)
}

export { InlineFileInput }
export type { InlineFileInputProps }
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export * from './components/Note/index.js'
export * from './components/Calendar/index.js'
export * from './components/List/index.js'
export * from './components/ReferencesInput/index.js'
export * from './components/InlineFileInput/index.js'
export * from './components/Tabs/index.js'
export * from './hooks/useTheme.js'
export * from './hooks/useRerender.js'
Expand Down

0 comments on commit c9e06fa

Please sign in to comment.