@@ -23,7 +23,7 @@ | |||
"@vitest/coverage-v8": "^0.33.0", | |||
"eslint": "^8.46.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"jsdom": "^22.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -23,7 +23,7 @@ | |||
"@vitest/coverage-v8": "^0.33.0", | |||
"eslint": "^8.46.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"jsdom": "^22.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -3,6 +3,7 @@ import { | |||
render, | |||
screen, | |||
cleanup, | |||
fireEvent, | |||
} from '@testing-library/react'; | |||
import userEvent from '@testing-library/user-event'; | |||
import { | |||
@@ -16,10 +17,48 @@ import matchers from '@testing-library/jest-dom/matchers'; | |||
import { | |||
FileSelectBox, | |||
FileSelectBoxDerivedElement, | |||
DELETE_KEYS, SELECT_KEYS, | |||
} from '.'; | |||
expect.extend(matchers); | |||
const userEventDrop = async ( | |||
dropZoneElement: HTMLElement, | |||
fileOrFiles: File | File[], | |||
targetInputElement: HTMLInputElement, | |||
) => { | |||
const dummyInput = window.document.createElement('input'); | |||
dummyInput.type = 'file'; | |||
await userEvent.upload(dummyInput, fileOrFiles); | |||
// targeting change event on the input element | |||
await userEvent.upload(targetInputElement, fileOrFiles); | |||
fireEvent.drop(dropZoneElement, { | |||
dataTransfer: { | |||
files: dummyInput.files, | |||
}, | |||
}); | |||
}; | |||
const userEventPaste = async ( | |||
dropZoneElement: HTMLElement, | |||
fileOrFiles: File | File[], | |||
) => { | |||
const dummyInput = window.document.createElement('input'); | |||
dummyInput.type = 'file'; | |||
await userEvent.upload(dummyInput, fileOrFiles); | |||
// targeting change event on the input element | |||
await userEvent.upload(dropZoneElement, fileOrFiles); | |||
fireEvent.paste(dropZoneElement, { | |||
clipboardData: { | |||
files: dummyInput.files, | |||
}, | |||
}); | |||
}; | |||
describe('FileSelectBox', () => { | |||
afterEach(() => { | |||
cleanup(); | |||
@@ -35,42 +74,82 @@ describe('FileSelectBox', () => { | |||
}); | |||
it('renders a border', () => { | |||
render( | |||
<FileSelectBox | |||
border | |||
/>, | |||
); | |||
const border = screen.getByTestId('border'); | |||
expect(border).toBeInTheDocument(); | |||
}); | |||
it('renders a label', () => { | |||
render( | |||
<FileSelectBox | |||
label="foo" | |||
/>, | |||
); | |||
const textbox = screen.getByLabelText('foo'); | |||
expect(textbox).toBeInTheDocument(); | |||
const label = screen.getByTestId('label'); | |||
expect(label).toHaveTextContent('foo'); | |||
}); | |||
it('renders a hidden label', () => { | |||
render( | |||
<FileSelectBox | |||
label="foo" | |||
hiddenLabel | |||
/>, | |||
); | |||
const textbox = screen.getByLabelText('foo'); | |||
expect(textbox).toBeInTheDocument(); | |||
const label = screen.queryByTestId('label'); | |||
expect(label).toBeInTheDocument(); | |||
expect(label).toHaveClass('sr-only'); | |||
}); | |||
describe('enhanced', () => { | |||
render( | |||
<FileSelectBox | |||
border | |||
/>, | |||
); | |||
const border = screen.getByTestId('border'); | |||
expect(border).toBeInTheDocument(); | |||
}); | |||
it('renders a block component', () => { | |||
render( | |||
<FileSelectBox | |||
block | |||
/>, | |||
); | |||
const root = screen.getByTestId('root'); | |||
expect(root).toHaveClass('flex w-full'); | |||
}); | |||
it('renders a label', () => { | |||
render( | |||
<FileSelectBox | |||
label="foo" | |||
/>, | |||
); | |||
const textbox = screen.getByLabelText('foo'); | |||
expect(textbox).toBeInTheDocument(); | |||
const label = screen.getByTestId('label'); | |||
expect(label).toHaveTextContent('foo'); | |||
}); | |||
it('renders a hidden label', () => { | |||
render( | |||
<FileSelectBox | |||
label="foo" | |||
hiddenLabel | |||
/>, | |||
); | |||
const textbox = screen.getByLabelText('foo'); | |||
expect(textbox).toBeInTheDocument(); | |||
const label = screen.queryByTestId('label'); | |||
expect(label).toBeInTheDocument(); | |||
expect(label).toHaveClass('sr-only'); | |||
}); | |||
it('handles a change event', async () => { | |||
const onChange = vi.fn(); | |||
render( | |||
<FileSelectBox | |||
onChange={onChange} | |||
/>, | |||
); | |||
const input = screen.getByTestId('input') as FileSelectBoxDerivedElement; | |||
const file = new File(['foo'], 'foo.txt', {type: 'text/plain'}); | |||
await userEvent.upload(input, file); | |||
expect(onChange).toBeCalledTimes(1); | |||
}); | |||
it('handles a blur event', async () => { | |||
const onBlur = vi.fn(); | |||
render( | |||
<FileSelectBox | |||
onBlur={onBlur} | |||
/>, | |||
); | |||
const input = screen.getByTestId('input') as FileSelectBoxDerivedElement; | |||
input.focus(); | |||
input.blur(); | |||
expect(onBlur).toBeCalledTimes(1); | |||
}); | |||
describe('when enhanced', () => { | |||
it('renders a hint', () => { | |||
render( | |||
<FileSelectBox | |||
@@ -78,8 +157,244 @@ describe('FileSelectBox', () => { | |||
hint="foo" | |||
/>, | |||
); | |||
const hint = screen.getByTestId('hint'); | |||
expect(hint).toBeInTheDocument(); | |||
}); | |||
it('renders a preview for a single file', async () => { | |||
render( | |||
<FileSelectBox | |||
enhanced | |||
/>, | |||
); | |||
const input = screen.getByTestId('input') as FileSelectBoxDerivedElement; | |||
const file = new File(['foo'], 'foo.txt', {type: 'text/plain'}); | |||
await userEvent.upload(input, file); | |||
expect(input.files).toHaveLength(1); | |||
const preview = screen.getByTestId('preview'); | |||
expect(preview).toBeInTheDocument(); | |||
}); | |||
it('renders a preview for a single file without name', async () => { | |||
render( | |||
<FileSelectBox | |||
enhanced | |||
/>, | |||
); | |||
const input = screen.getByTestId('input') as FileSelectBoxDerivedElement; | |||
const file = new Blob(['foo'], {type: 'text/plain'}); | |||
await userEvent.upload(input, file as unknown as File); | |||
expect(input.files).toHaveLength(1); | |||
const preview = screen.getByTestId('preview'); | |||
expect(preview).toBeInTheDocument(); | |||
}); | |||
it('renders a preview for a single file without name', async () => { | |||
render( | |||
<FileSelectBox | |||
enhanced | |||
/>, | |||
); | |||
const input = screen.getByTestId('input') as FileSelectBoxDerivedElement; | |||
const { size: _size, ...partialFile } = new File(['foo'], 'foo.txt', {type: 'text/plain'}); | |||
await userEvent.upload(input, partialFile as unknown as File); | |||
expect(input.files).toHaveLength(1); | |||
const preview = screen.getByTestId('preview'); | |||
expect(preview).toBeInTheDocument(); | |||
}); | |||
it('renders a preview for multiple files', async () => { | |||
render( | |||
<FileSelectBox | |||
enhanced | |||
multiple | |||
/>, | |||
); | |||
const input = screen.getByTestId('input') as FileSelectBoxDerivedElement; | |||
const files = [ | |||
new File(['foo'], 'foo.txt', {type: 'text/plain'}), | |||
new File(['bar'], 'bar.txt', {type: 'text/plain'}), | |||
]; | |||
await userEvent.upload(input, files); | |||
expect(input.files).toHaveLength(files.length); | |||
const preview = screen.getByTestId('preview'); | |||
expect(preview).toBeInTheDocument(); | |||
}); | |||
it('renders a preview for multiple files without names', async () => { | |||
render( | |||
<FileSelectBox | |||
enhanced | |||
multiple | |||
/>, | |||
); | |||
const input = screen.getByTestId('input') as FileSelectBoxDerivedElement; | |||
const files = [ | |||
new Blob(['foo'], {type: 'text/plain'}), | |||
new Blob(['bar'], {type: 'text/plain'}), | |||
]; | |||
await userEvent.upload(input, files as unknown as File[]); | |||
expect(input.files).toHaveLength(files.length); | |||
const preview = screen.getByTestId('preview'); | |||
expect(preview).toBeInTheDocument(); | |||
}); | |||
it('renders actions when at least one file is selected', async () => { | |||
render( | |||
<FileSelectBox | |||
enhanced | |||
multiple | |||
/>, | |||
); | |||
const input = screen.getByTestId('input'); | |||
const files = [ | |||
new File(['foo'], 'foo.txt', {type: 'text/plain'}), | |||
new File(['bar'], 'bar.txt', {type: 'text/plain'}), | |||
]; | |||
await userEvent.upload(input, files); | |||
const actions = screen.getByTestId('actions'); | |||
expect(actions).toBeInTheDocument(); | |||
}); | |||
it('clears selected files through the clear button', async () => { | |||
render( | |||
<FileSelectBox | |||
enhanced | |||
/>, | |||
); | |||
const input = screen.getByTestId('input') as FileSelectBoxDerivedElement; | |||
const file = new File(['foo'], 'foo.txt', {type: 'text/plain'}); | |||
await userEvent.upload(input, file); | |||
const clearButton = screen.getByTestId('clear'); | |||
await userEvent.click(clearButton); | |||
expect(input.files).toHaveLength(0); | |||
}); | |||
it.each(DELETE_KEYS)('clears selected files through pressing %s key', async (key) => { | |||
render( | |||
<FileSelectBox | |||
enhanced | |||
/>, | |||
); | |||
const input = screen.getByTestId('input') as FileSelectBoxDerivedElement; | |||
const file = new File(['foo'], 'foo.txt', {type: 'text/plain'}); | |||
await userEvent.upload(input, file); | |||
input.focus(); | |||
await userEvent.keyboard(`{${key}}`); | |||
expect(input.files).toHaveLength(0); | |||
}); | |||
it('ignores other key presses when input is focused', async () => { | |||
render( | |||
<FileSelectBox | |||
enhanced | |||
/>, | |||
); | |||
const input = screen.getByTestId('input') as FileSelectBoxDerivedElement; | |||
const file = new File(['foo'], 'foo.txt', {type: 'text/plain'}); | |||
await userEvent.upload(input, file); | |||
input.focus(); | |||
await userEvent.keyboard('a'); | |||
expect(input.files).toHaveLength(1); | |||
}); | |||
it.each(SELECT_KEYS)('opens picker on pressing %s when input is in focus', async (key) => { | |||
render( | |||
<FileSelectBox | |||
enhanced | |||
/>, | |||
); | |||
const input = screen.getByTestId('input') as FileSelectBoxDerivedElement; | |||
const file = new File(['foo'], 'foo.txt', {type: 'text/plain'}); | |||
await userEvent.upload(input, file); | |||
input.focus(); | |||
await userEvent.keyboard(`{${key}}`); | |||
// how to assert? | |||
}); | |||
it('opens picker when files are previously selected (showPicker)', async () => { | |||
render( | |||
<FileSelectBox | |||
enhanced | |||
/>, | |||
); | |||
const input = screen.getByTestId('input') as FileSelectBoxDerivedElement; | |||
const showPicker = vi.fn(); | |||
input.showPicker = showPicker; | |||
const file = new File(['foo'], 'foo.txt', {type: 'text/plain'}); | |||
await userEvent.upload(input, file); | |||
const clearButton = screen.getByTestId('reselect'); | |||
await userEvent.click(clearButton); | |||
expect(showPicker).toBeCalledTimes(1); | |||
}); | |||
it('opens picker when files are previously selected (no showPicker)', async () => { | |||
render( | |||
<FileSelectBox | |||
enhanced | |||
/>, | |||
); | |||
const input = screen.getByTestId('input') as FileSelectBoxDerivedElement; | |||
const showPicker = vi.spyOn(input, 'click'); | |||
const file = new File(['foo'], 'foo.txt', {type: 'text/plain'}); | |||
await userEvent.upload(input, file); | |||
const clearButton = screen.getByTestId('reselect'); | |||
await userEvent.click(clearButton); | |||
expect(showPicker).toBeCalledTimes(1); | |||
}); | |||
it('accepts drop files', async () => { | |||
const onChange = vi.fn(); | |||
render( | |||
<FileSelectBox | |||
enhanced | |||
onChange={onChange} | |||
/>, | |||
); | |||
const root = screen.getByTestId('root'); | |||
const file = new File(['foo'], 'foo.txt', { type: 'text/plain' }); | |||
const input = screen.getByTestId('input') as FileSelectBoxDerivedElement; | |||
await userEventDrop(root, file, input); | |||
expect(onChange).toBeCalledTimes(1); | |||
}); | |||
it('accepts pasted files', async () => { | |||
const onChange = vi.fn(); | |||
render( | |||
<FileSelectBox | |||
enhanced | |||
onChange={onChange} | |||
/>, | |||
); | |||
const input = screen.getByTestId('input') as FileSelectBoxDerivedElement; | |||
const file = new File(['foo'], 'foo.txt', { type: 'text/plain' }); | |||
await userEventPaste(input, file); | |||
expect(onChange).toBeCalledTimes(1); | |||
}); | |||
}); | |||
}); |
@@ -79,12 +79,14 @@ export interface FileSelectBoxProps< | |||
clearLabel?: string, | |||
} | |||
export type FileSelectBoxDefaultPreviewComponentDerivedElement = HTMLDivElement; | |||
/** | |||
* Default component for the {@link FileSelectBoxProps.previewComponent|previewComponent prop} | |||
* of the {@link FileSelectBox} component. | |||
*/ | |||
export const FileSelectBoxDefaultPreviewComponent = React.forwardRef< | |||
HTMLDivElement, | |||
FileSelectBoxDefaultPreviewComponentDerivedElement, | |||
CommonPreviewComponentProps | |||
>(({ | |||
file, | |||
@@ -101,40 +103,40 @@ export const FileSelectBoxDefaultPreviewComponent = React.forwardRef< | |||
> | |||
<div className="w-full whitespace-nowrap overflow-hidden text-ellipsis"> | |||
{file?.name ?? ( | |||
<span className="opacity-50"> | |||
File | |||
</span> | |||
<span className="opacity-50"> | |||
File | |||
</span> | |||
)} | |||
</div> | |||
{!mini && ( | |||
<> | |||
{typeof file?.type === 'string' && ( | |||
<div className="w-full whitespace-nowrap overflow-hidden text-ellipsis">{file?.type}</div> | |||
)} | |||
{typeof file?.size === 'number' && ( | |||
<div | |||
title={new Intl.NumberFormat(undefined, { | |||
style: 'unit', | |||
unit: 'byte', | |||
unitDisplay: 'long', | |||
}).format(file.size ?? 0)} | |||
className="w-full whitespace-nowrap overflow-hidden text-ellipsis tabular-nums" | |||
> | |||
{new Intl.NumberFormat(undefined, { | |||
style: 'unit', | |||
unit: 'kilobyte', | |||
unitDisplay: 'long', | |||
}).format(file.size ?? 0)} | |||
</div> | |||
)} | |||
{typeof file?.lastModified === 'number' && ( | |||
<div className="w-full whitespace-nowrap overflow-hidden text-ellipsis"> | |||
<time dateTime={new Date(file.lastModified).toISOString()}> | |||
{new Date(file.lastModified).toDateString()} | |||
</time> | |||
</div> | |||
)} | |||
</> | |||
<> | |||
{typeof file?.type === 'string' && ( | |||
<div className="w-full whitespace-nowrap overflow-hidden text-ellipsis">{file?.type}</div> | |||
)} | |||
{typeof file?.size === 'number' && ( | |||
<div | |||
title={new Intl.NumberFormat(undefined, { | |||
style: 'unit', | |||
unit: 'byte', | |||
unitDisplay: 'long', | |||
}).format(file.size)} | |||
className="w-full whitespace-nowrap overflow-hidden text-ellipsis tabular-nums" | |||
> | |||
{new Intl.NumberFormat(undefined, { | |||
style: 'unit', | |||
unit: 'kilobyte', | |||
unitDisplay: 'long', | |||
}).format(file.size)} | |||
</div> | |||
)} | |||
{typeof file?.lastModified === 'number' && ( | |||
<div className="w-full whitespace-nowrap overflow-hidden text-ellipsis"> | |||
<time dateTime={new Date(file.lastModified).toISOString()}> | |||
{new Date(file.lastModified).toDateString()} | |||
</time> | |||
</div> | |||
)} | |||
</> | |||
)} | |||
</div> | |||
)); | |||
@@ -149,6 +151,16 @@ const isMouseUpEvent = (e: React.SyntheticEvent): e is React.MouseEvent => e.typ | |||
const isDropEvent = (e: React.SyntheticEvent): e is React.DragEvent => e.type === 'drop'; | |||
const isPasteEvent = (e: React.SyntheticEvent): e is React.ClipboardEvent => e.type === 'paste'; | |||
export const DELETE_KEYS = ['Backspace', 'Delete'] as const; | |||
type DeleteKey = typeof DELETE_KEYS[number]; | |||
export const SELECT_KEYS = ['Enter', 'Space', 'Return'] as const; | |||
type SelectKey = typeof SELECT_KEYS[number]; | |||
/** | |||
* Component for selecting files. | |||
*/ | |||
@@ -171,6 +183,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||
onBlur, | |||
reselectLabel = 'Reselect', | |||
clearLabel = 'Clear', | |||
onPaste, | |||
...etcProps | |||
}, | |||
forwardedRef, | |||
@@ -179,17 +192,17 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||
const [fileList, setFileList] = React.useState<FileList>(); | |||
const [lastUpdated, setLastUpdated] = React.useState<number>(); | |||
const clearFileListRef = React.useRef(false); | |||
const [deleteKeyPressed, setDeleteKeyPressed] = React.useState(false); | |||
const [aboutToClear, setAboutToClear] = React.useState(false); | |||
const [aboutToSelect, setAboutToSelect] = React.useState(false); | |||
const clearFiles = ( | |||
fileInput: FileSelectBoxDerivedElement, | |||
clearRef: React.MutableRefObject<boolean>, | |||
) => { | |||
const clearRefMut = clearRef; | |||
const clearRefMut = clearRef as unknown as Record<string, boolean>; | |||
clearRefMut.current = true; | |||
const fileInputMut = fileInput; | |||
const fileInputMut = fileInput as unknown as Record<string, string>; | |||
fileInputMut.value = ''; | |||
setFileList(undefined); | |||
@@ -200,28 +213,26 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||
React.ChangeEvent<FileSelectBoxDerivedElement> | |||
| React.MouseEvent<HTMLButtonElement> | |||
| React.DragEvent<HTMLDivElement> | |||
| React.KeyboardEvent<FileSelectBoxDerivedElement>, | |||
| React.KeyboardEvent<FileSelectBoxDerivedElement> | |||
| React.ClipboardEvent<FileSelectBoxDerivedElement>, | |||
FileSelectBoxDerivedElement | |||
>({ | |||
forwardedRef, | |||
valueSetterFn: (e) => { | |||
const fileInput = defaultRef.current; | |||
if (!fileInput) { | |||
return; | |||
} | |||
if (isButtonElement(e.currentTarget) && isMouseUpEvent(e)) { | |||
const fileInput = defaultRef.current as FileSelectBoxDerivedElement; | |||
if (isMouseUpEvent(e) && isButtonElement(e.currentTarget)) { | |||
clearFiles(fileInput, clearFileListRef); | |||
return; | |||
} | |||
if (isInputElement(e.currentTarget) && isKeyUpEvent(e)) { | |||
if (isKeyUpEvent(e) && isInputElement(e.currentTarget) && e.currentTarget === fileInput) { | |||
// delete via keyboard | |||
const { code } = e; | |||
if (!(code === 'Backspace' || code === 'Delete')) { | |||
return; | |||
if (DELETE_KEYS.includes(code as DeleteKey)) { | |||
clearFiles(fileInput, clearFileListRef); | |||
setAboutToClear(false); | |||
} | |||
clearFiles(e.currentTarget, clearFileListRef); | |||
return; | |||
} | |||
if (isDropEvent(e)) { | |||
@@ -229,12 +240,31 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||
const { dataTransfer } = e; | |||
const { files } = dataTransfer; | |||
if (files && files.length > 0) { | |||
setFileList(fileInput.files = files); | |||
try { | |||
fileInput.files = files; | |||
} catch { | |||
// noop, the assignment throws for test environments | |||
} | |||
setFileList(files); | |||
setLastUpdated(Date.now()); | |||
} | |||
return; | |||
} | |||
console.warn('Unhandled event', e); | |||
if (isPasteEvent(e)) { | |||
const { clipboardData } = e; | |||
const { files } = clipboardData; | |||
if (files && files.length > 0) { | |||
try { | |||
fileInput.files = files; | |||
} catch { | |||
// noop, the assignment throws for test environments | |||
} | |||
setFileList(files); | |||
setLastUpdated(Date.now()); | |||
} | |||
return; | |||
} | |||
// Unhandled event | |||
}, | |||
}); | |||
const labelId = React.useId(); | |||
@@ -254,45 +284,32 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||
FileSelectBoxDerivedElement | |||
> = React.useCallback((e) => { | |||
const { currentTarget } = e; | |||
if (clientSide && currentTarget.files && currentTarget.files.length > 0) { | |||
if (currentTarget.files && currentTarget.files.length > 0) { | |||
setFileList(currentTarget.files); | |||
setLastUpdated(Date.now()); | |||
setAboutToSelect(false); | |||
onChange?.(e); | |||
return; | |||
} | |||
if (clientSide && clearFileListRef.current) { | |||
} else if (clearFileListRef.current) { | |||
clearFileListRef.current = false; | |||
setFileList(undefined); | |||
setLastUpdated(Date.now()); | |||
onChange?.(e); | |||
return; | |||
} | |||
e.preventDefault(); | |||
e.currentTarget.files = fileList ?? null; | |||
setAboutToSelect(false); | |||
}, [clientSide, fileList, onChange]); | |||
onChange?.(e); | |||
}, [clearFileListRef, onChange]); | |||
const handleKeyDown: React.KeyboardEventHandler< | |||
FileSelectBoxDerivedElement | |||
> = React.useCallback((e) => { | |||
const { code } = e; | |||
if (code === 'Backspace' || code === 'Delete') { | |||
setDeleteKeyPressed(true); | |||
} else if (code === 'Enter' || code === 'Space' || code === 'Return') { | |||
setAboutToSelect(true); | |||
if (DELETE_KEYS.includes(code as DeleteKey)) { | |||
setAboutToClear(true); | |||
return; | |||
} | |||
}, []); | |||
const handleKeyUp: React.KeyboardEventHandler< | |||
FileSelectBoxDerivedElement | |||
> = React.useCallback((e) => { | |||
const { code } = e; | |||
if (code === 'Backspace' || code === 'Delete') { | |||
doSetFileList(e); | |||
setDeleteKeyPressed(false); | |||
if (SELECT_KEYS.includes(code as SelectKey)) { | |||
setAboutToSelect(true); | |||
} | |||
}, [doSetFileList]); | |||
// ignore other keys | |||
}, []); | |||
const handleReselectMouseDown: React.MouseEventHandler< | |||
HTMLButtonElement | |||
@@ -308,13 +325,17 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||
HTMLButtonElement | |||
> = React.useCallback(() => { | |||
const fileInput = defaultRef.current as FileSelectBoxDerivedElement; | |||
if (typeof fileInput.showPicker !== 'function') { | |||
fileInput.click(); | |||
return; | |||
} | |||
fileInput.showPicker(); | |||
}, [defaultRef]); | |||
const handleDeleteMouseDown: React.MouseEventHandler< | |||
HTMLButtonElement | |||
> = React.useCallback(() => { | |||
setDeleteKeyPressed(true); | |||
setAboutToClear(true); | |||
setTimeout(() => { | |||
const fileInput = defaultRef.current as FileSelectBoxDerivedElement; | |||
fileInput.focus(); | |||
@@ -325,14 +346,14 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||
FileSelectBoxDerivedElement | |||
> = React.useCallback((e) => { | |||
setAboutToSelect(false); | |||
setDeleteKeyPressed(false); | |||
setAboutToClear(false); | |||
onBlur?.(e); | |||
}, [onBlur]); | |||
React.useEffect(() => { | |||
const handleLabelMouseUp = () => { | |||
setAboutToSelect(false); | |||
setDeleteKeyPressed(false); | |||
setAboutToClear(false); | |||
}; | |||
window.addEventListener('mouseup', handleLabelMouseUp, { capture: true }); | |||
@@ -342,6 +363,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||
}, [defaultRef, aboutToSelect]); | |||
const filesCount = fileList?.length ?? 0; | |||
const fileListArray = Array.from(fileList ?? []); | |||
return ( | |||
<div | |||
@@ -402,7 +424,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||
type="file" | |||
onBlur={handleBlur} | |||
onKeyDown={clientSide ? handleKeyDown : undefined} | |||
onKeyUp={clientSide ? handleKeyUp : undefined} | |||
onKeyUp={clientSide ? doSetFileList : undefined} | |||
className={clsx( | |||
'peer box-border focus:outline-0 px-4 pt-2 block resize-y min-h-16 cursor-pointer disabled:cursor-not-allowed file:bg-transparent file:text-primary file:block file:font-bold file:font-semi-expanded file:uppercase file:p-0 file:border-0 group-focus-within:file:text-secondary', | |||
{ | |||
@@ -411,6 +433,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||
}, | |||
)} | |||
onChange={clientSide ? handleFileChange : onChange} | |||
onPaste={clientSide ? doSetFileList : onPaste} | |||
multiple={multiple} | |||
data-testid="input" | |||
aria-labelledby={label ? `${labelId}` : undefined} | |||
@@ -434,15 +457,20 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||
{filesCount > 0 | |||
&& clientSide | |||
&& ( | |||
<React.Fragment key={lastUpdated}> | |||
<div className="sm:absolute top-0 left-0 w-full h-full pointer-events-none pb-12 box-border overflow-hidden pt-8"> | |||
<React.Fragment | |||
key={lastUpdated} | |||
> | |||
<div | |||
className="sm:absolute top-0 left-0 w-full h-full pointer-events-none pb-12 box-border overflow-hidden pt-8" | |||
data-testid="preview" | |||
> | |||
{multiple | |||
&& ( | |||
<div className="pointer-events-auto w-full h-full overflow-auto px-4 box-border"> | |||
<div className="w-full grid gap-2 grid-cols-3"> | |||
{Array.from(fileList ?? []).map((file) => ( | |||
{fileListArray.map((file, i) => ( | |||
<div | |||
key={file.name} | |||
key={file.name ?? i} | |||
data-testid="selectedFileItem" | |||
className="w-full p-2 aspect-square rounded overflow-hidden relative before:absolute before:content-[''] before:bg-current before:top-0 before:left-0 before:w-full before:h-full before:opacity-10" | |||
> | |||
@@ -458,9 +486,9 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||
</div> | |||
)} | |||
{!multiple | |||
&& Array.from(fileList ?? []).map((file) => ( | |||
&& fileListArray.map((file, i) => ( | |||
<div | |||
key={file.name} | |||
key={file.name ?? i} | |||
className="pointer-events-auto w-full h-full px-4 box-border" | |||
> | |||
<div | |||
@@ -480,7 +508,10 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||
</div> | |||
))} | |||
</div> | |||
<div className="absolute bottom-0 left-0 w-full text-center h-12 box-border flex"> | |||
<div | |||
data-testid="actions" | |||
className="absolute bottom-0 left-0 w-full text-center h-12 box-border flex" | |||
> | |||
<div className="w-0 flex-auto flex flex-col items-center justify-center h-full"> | |||
<button | |||
type="button" | |||
@@ -517,8 +548,8 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||
className={clsx( | |||
'flex w-full h-full bg-negative text-primary disabled:text-primary items-center justify-center leading-none gap-4 select-none focus:outline-0', | |||
{ | |||
'group-focus-within:text-secondary group-focus-within:active:text-tertiary': !deleteKeyPressed, | |||
'text-tertiary': deleteKeyPressed, | |||
'group-focus-within:text-secondary group-focus-within:active:text-tertiary': !aboutToClear, | |||
'text-tertiary': aboutToClear, | |||
}, | |||
)} | |||
> | |||
@@ -23,7 +23,7 @@ | |||
"@vitest/coverage-v8": "^0.33.0", | |||
"eslint": "^8.46.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"jsdom": "^22.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -25,7 +25,7 @@ | |||
"@vitest/coverage-v8": "^0.33.0", | |||
"eslint": "^8.46.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"jsdom": "^22.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -23,7 +23,7 @@ | |||
"@vitest/coverage-v8": "^0.33.0", | |||
"eslint": "^8.46.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"jsdom": "^22.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -23,7 +23,7 @@ | |||
"@vitest/coverage-v8": "^0.33.0", | |||
"eslint": "^8.46.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"jsdom": "^22.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -23,7 +23,7 @@ | |||
"@vitest/coverage-v8": "^0.33.0", | |||
"eslint": "^8.46.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"jsdom": "^22.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -23,7 +23,7 @@ | |||
"@vitest/coverage-v8": "^0.33.0", | |||
"eslint": "^8.46.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"jsdom": "^22.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -23,7 +23,7 @@ | |||
"@vitest/coverage-v8": "^0.33.0", | |||
"eslint": "^8.46.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"jsdom": "^22.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -23,7 +23,7 @@ | |||
"@vitest/coverage-v8": "^0.33.0", | |||
"eslint": "^8.46.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"jsdom": "^22.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -23,7 +23,7 @@ | |||
"@vitest/coverage-v8": "^0.33.0", | |||
"eslint": "^8.46.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"jsdom": "^22.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -20,7 +20,6 @@ | |||
"@types/react": "^18.2.18", | |||
"eslint": "^8.35.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -20,7 +20,6 @@ | |||
"@types/react": "^18.2.18", | |||
"eslint": "^8.35.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -20,7 +20,6 @@ | |||
"@types/react": "^18.2.18", | |||
"eslint": "^8.35.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -20,7 +20,6 @@ | |||
"@types/react": "^18.2.18", | |||
"eslint": "^8.35.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -20,7 +20,6 @@ | |||
"@types/react": "^18.2.18", | |||
"eslint": "^8.35.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
@@ -31,7 +31,7 @@ importers: | |||
version: 4.9.5 | |||
vitest: | |||
specifier: ^0.28.1 | |||
version: 0.28.1(jsdom@21.1.0) | |||
version: 0.28.1 | |||
categories/web/action/react: | |||
dependencies: | |||
@@ -73,8 +73,8 @@ importers: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.46.0)(typescript@5.2.2) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
specifier: ^22.1.0 | |||
version: 22.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.46.0)(tslib@2.6.0)(typescript@5.2.2) | |||
@@ -95,7 +95,7 @@ importers: | |||
version: 5.2.2 | |||
vitest: | |||
specifier: ^0.34.1 | |||
version: 0.34.1(jsdom@21.1.0) | |||
version: 0.34.1(jsdom@22.1.0) | |||
categories/web/blob/react: | |||
dependencies: | |||
@@ -137,8 +137,8 @@ importers: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.46.0)(typescript@5.2.2) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
specifier: ^22.1.0 | |||
version: 22.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.46.0)(tslib@2.6.0)(typescript@5.2.2) | |||
@@ -159,7 +159,7 @@ importers: | |||
version: 5.2.2 | |||
vitest: | |||
specifier: ^0.34.1 | |||
version: 0.34.1(jsdom@21.1.0) | |||
version: 0.34.1(jsdom@22.1.0) | |||
categories/web/choice/react: | |||
dependencies: | |||
@@ -207,8 +207,8 @@ importers: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.46.0)(typescript@5.2.2) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
specifier: ^22.1.0 | |||
version: 22.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.46.0)(tslib@2.6.0)(typescript@5.2.2) | |||
@@ -229,7 +229,7 @@ importers: | |||
version: 5.2.2 | |||
vitest: | |||
specifier: ^0.34.1 | |||
version: 0.34.1(jsdom@21.1.0) | |||
version: 0.34.1(jsdom@22.1.0) | |||
categories/web/color/react: | |||
dependencies: | |||
@@ -283,8 +283,8 @@ importers: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.46.0)(typescript@5.2.2) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
specifier: ^22.1.0 | |||
version: 22.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.46.0)(tslib@2.6.0)(typescript@5.2.2) | |||
@@ -305,7 +305,7 @@ importers: | |||
version: 5.2.2 | |||
vitest: | |||
specifier: ^0.34.1 | |||
version: 0.34.1(jsdom@21.1.0) | |||
version: 0.34.1(jsdom@22.1.0) | |||
categories/web/formatted/react: | |||
dependencies: | |||
@@ -353,8 +353,8 @@ importers: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.46.0)(typescript@5.2.2) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
specifier: ^22.1.0 | |||
version: 22.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.46.0)(tslib@2.6.0)(typescript@5.2.2) | |||
@@ -375,7 +375,7 @@ importers: | |||
version: 5.2.2 | |||
vitest: | |||
specifier: ^0.34.1 | |||
version: 0.34.1(jsdom@21.1.0) | |||
version: 0.34.1(jsdom@22.1.0) | |||
categories/web/freeform/react: | |||
dependencies: | |||
@@ -420,8 +420,8 @@ importers: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.46.0)(typescript@5.2.2) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
specifier: ^22.1.0 | |||
version: 22.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.46.0)(tslib@2.6.0)(typescript@5.2.2) | |||
@@ -442,7 +442,7 @@ importers: | |||
version: 5.2.2 | |||
vitest: | |||
specifier: ^0.34.1 | |||
version: 0.34.1(jsdom@21.1.0) | |||
version: 0.34.1(jsdom@22.1.0) | |||
categories/web/information/react: | |||
dependencies: | |||
@@ -481,8 +481,8 @@ importers: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.46.0)(typescript@5.2.2) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
specifier: ^22.1.0 | |||
version: 22.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.46.0)(tslib@2.6.0)(typescript@5.2.2) | |||
@@ -503,7 +503,7 @@ importers: | |||
version: 5.2.2 | |||
vitest: | |||
specifier: ^0.34.1 | |||
version: 0.34.1(jsdom@21.1.0) | |||
version: 0.34.1(jsdom@22.1.0) | |||
categories/web/multichoice/react: | |||
dependencies: | |||
@@ -551,8 +551,8 @@ importers: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.46.0)(typescript@5.2.2) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
specifier: ^22.1.0 | |||
version: 22.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.46.0)(tslib@2.6.0)(typescript@5.2.2) | |||
@@ -573,7 +573,7 @@ importers: | |||
version: 5.2.2 | |||
vitest: | |||
specifier: ^0.34.1 | |||
version: 0.34.1(jsdom@21.1.0) | |||
version: 0.34.1(jsdom@22.1.0) | |||
categories/web/navigation/react: | |||
dependencies: | |||
@@ -615,8 +615,8 @@ importers: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.46.0)(typescript@5.2.2) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
specifier: ^22.1.0 | |||
version: 22.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.46.0)(tslib@2.6.0)(typescript@5.2.2) | |||
@@ -637,7 +637,7 @@ importers: | |||
version: 5.2.2 | |||
vitest: | |||
specifier: ^0.34.1 | |||
version: 0.34.1(jsdom@21.1.0) | |||
version: 0.34.1(jsdom@22.1.0) | |||
categories/web/number/react: | |||
dependencies: | |||
@@ -685,8 +685,8 @@ importers: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.46.0)(typescript@5.2.2) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
specifier: ^22.1.0 | |||
version: 22.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.46.0)(tslib@2.6.0)(typescript@5.2.2) | |||
@@ -707,7 +707,7 @@ importers: | |||
version: 5.2.2 | |||
vitest: | |||
specifier: ^0.34.1 | |||
version: 0.34.1(jsdom@21.1.0) | |||
version: 0.34.1(jsdom@22.1.0) | |||
categories/web/temporal/react: | |||
dependencies: | |||
@@ -755,8 +755,8 @@ importers: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.46.0)(typescript@5.2.2) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
specifier: ^22.1.0 | |||
version: 22.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.46.0)(tslib@2.6.0)(typescript@5.2.2) | |||
@@ -777,7 +777,7 @@ importers: | |||
version: 5.2.2 | |||
vitest: | |||
specifier: ^0.34.1 | |||
version: 0.34.1(jsdom@21.1.0) | |||
version: 0.34.1(jsdom@22.1.0) | |||
packages/amanuensis: | |||
dependencies: | |||
@@ -829,7 +829,7 @@ importers: | |||
version: 4.9.5 | |||
vitest: | |||
specifier: ^0.28.1 | |||
version: 0.28.1(jsdom@21.1.0) | |||
version: 0.28.1 | |||
packages/audio-utils: | |||
dependencies: | |||
@@ -860,7 +860,7 @@ importers: | |||
version: 4.9.5 | |||
vitest: | |||
specifier: ^0.28.1 | |||
version: 0.28.1(jsdom@21.1.0) | |||
version: 0.28.1 | |||
packages/blob-utils: | |||
dependencies: | |||
@@ -894,7 +894,7 @@ importers: | |||
version: 4.9.5 | |||
vitest: | |||
specifier: ^0.28.1 | |||
version: 0.28.1(jsdom@21.1.0) | |||
version: 0.28.1 | |||
packages/image-utils: | |||
dependencies: | |||
@@ -934,7 +934,7 @@ importers: | |||
version: 4.9.5 | |||
vitest: | |||
specifier: ^0.28.1 | |||
version: 0.28.1(jsdom@21.1.0) | |||
version: 0.28.1 | |||
packages/react-binary-data-canvas: | |||
devDependencies: | |||
@@ -959,9 +959,6 @@ importers: | |||
eslint-config-lxsmnsyc: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.43.0)(typescript@4.9.5) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.43.0)(tslib@2.6.0)(typescript@4.9.5) | |||
@@ -982,7 +979,7 @@ importers: | |||
version: 4.9.5 | |||
vitest: | |||
specifier: ^0.28.1 | |||
version: 0.28.1(jsdom@21.1.0) | |||
version: 0.28.1 | |||
packages/react-blob-previews: | |||
devDependencies: | |||
@@ -1007,9 +1004,6 @@ importers: | |||
eslint-config-lxsmnsyc: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.43.0)(typescript@4.9.5) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.43.0)(tslib@2.6.0)(typescript@4.9.5) | |||
@@ -1030,7 +1024,7 @@ importers: | |||
version: 4.9.5 | |||
vitest: | |||
specifier: ^0.28.1 | |||
version: 0.28.1(jsdom@21.1.0) | |||
version: 0.28.1 | |||
packages/react-refractor: | |||
dependencies: | |||
@@ -1068,9 +1062,6 @@ importers: | |||
eslint-config-lxsmnsyc: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.43.0)(typescript@4.9.5) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.43.0)(tslib@2.6.0)(typescript@4.9.5) | |||
@@ -1094,7 +1085,7 @@ importers: | |||
version: 4.9.5 | |||
vitest: | |||
specifier: ^0.28.1 | |||
version: 0.28.1(jsdom@21.1.0) | |||
version: 0.28.1 | |||
packages/react-utils: | |||
devDependencies: | |||
@@ -1119,9 +1110,6 @@ importers: | |||
eslint-config-lxsmnsyc: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.43.0)(typescript@4.9.5) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.43.0)(tslib@2.6.0)(typescript@4.9.5) | |||
@@ -1142,7 +1130,7 @@ importers: | |||
version: 4.9.5 | |||
vitest: | |||
specifier: ^0.28.1 | |||
version: 0.28.1(jsdom@21.1.0) | |||
version: 0.28.1 | |||
packages/react-wavesurfer: | |||
dependencies: | |||
@@ -1186,9 +1174,6 @@ importers: | |||
eslint-config-lxsmnsyc: | |||
specifier: ^0.5.0 | |||
version: 0.5.0(eslint@8.43.0)(typescript@4.9.5) | |||
jsdom: | |||
specifier: ^21.1.0 | |||
version: 21.1.0 | |||
pridepack: | |||
specifier: 2.4.4 | |||
version: 2.4.4(eslint@8.43.0)(tslib@2.6.0)(typescript@4.9.5) | |||
@@ -1209,7 +1194,7 @@ importers: | |||
version: 4.9.5 | |||
vitest: | |||
specifier: ^0.28.1 | |||
version: 0.28.1(jsdom@21.1.0) | |||
version: 0.28.1 | |||
packages/text-utils: | |||
dependencies: | |||
@@ -1246,7 +1231,7 @@ importers: | |||
version: 4.9.5 | |||
vitest: | |||
specifier: ^0.28.1 | |||
version: 0.28.1(jsdom@21.1.0) | |||
version: 0.28.1 | |||
packages/video-utils: | |||
devDependencies: | |||
@@ -1273,7 +1258,7 @@ importers: | |||
version: 4.9.5 | |||
vitest: | |||
specifier: ^0.28.1 | |||
version: 0.28.1(jsdom@21.1.0) | |||
version: 0.28.1 | |||
packages: | |||
@@ -3260,7 +3245,7 @@ packages: | |||
std-env: 3.3.3 | |||
test-exclude: 6.0.0 | |||
v8-to-istanbul: 9.1.0 | |||
vitest: 0.34.1(jsdom@21.1.0) | |||
vitest: 0.34.1(jsdom@22.1.0) | |||
transitivePeerDependencies: | |||
- supports-color | |||
dev: true | |||
@@ -3339,13 +3324,6 @@ packages: | |||
resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} | |||
dev: true | |||
/acorn-globals@7.0.1: | |||
resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} | |||
dependencies: | |||
acorn: 8.9.0 | |||
acorn-walk: 8.2.0 | |||
dev: true | |||
/acorn-jsx@5.3.2(acorn@7.4.1): | |||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} | |||
peerDependencies: | |||
@@ -4014,19 +3992,11 @@ packages: | |||
engines: {node: '>=4'} | |||
hasBin: true | |||
/cssom@0.3.8: | |||
resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} | |||
dev: true | |||
/cssom@0.5.0: | |||
resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} | |||
dev: true | |||
/cssstyle@2.3.0: | |||
resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} | |||
engines: {node: '>=8'} | |||
/cssstyle@3.0.0: | |||
resolution: {integrity: sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==} | |||
engines: {node: '>=14'} | |||
dependencies: | |||
cssom: 0.3.8 | |||
rrweb-cssom: 0.6.0 | |||
dev: true | |||
/csstype@3.1.2: | |||
@@ -4053,13 +4023,13 @@ packages: | |||
resolution: {integrity: sha512-Cp+jOa8QJef5nXS5hU7M1DWzXPEIoVR3kbV0dQuVGwROZg8bGf1DcCnkmajBTnvghTtSNMUdRrPjgaT6ZQucbw==} | |||
dev: false | |||
/data-urls@3.0.2: | |||
resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} | |||
engines: {node: '>=12'} | |||
/data-urls@4.0.0: | |||
resolution: {integrity: sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==} | |||
engines: {node: '>=14'} | |||
dependencies: | |||
abab: 2.0.6 | |||
whatwg-mimetype: 3.0.0 | |||
whatwg-url: 11.0.0 | |||
whatwg-url: 12.0.1 | |||
dev: true | |||
/debug@3.2.7: | |||
@@ -6368,9 +6338,9 @@ packages: | |||
resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} | |||
dev: false | |||
/jsdom@21.1.0: | |||
resolution: {integrity: sha512-m0lzlP7qOtthD918nenK3hdItSd2I+V3W9IrBcB36sqDwG+KnUs66IF5GY7laGWUnlM9vTsD0W1QwSEBYWWcJg==} | |||
engines: {node: '>=14'} | |||
/jsdom@22.1.0: | |||
resolution: {integrity: sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==} | |||
engines: {node: '>=16'} | |||
peerDependencies: | |||
canvas: ^2.5.0 | |||
peerDependenciesMeta: | |||
@@ -6378,21 +6348,18 @@ packages: | |||
optional: true | |||
dependencies: | |||
abab: 2.0.6 | |||
acorn: 8.9.0 | |||
acorn-globals: 7.0.1 | |||
cssom: 0.5.0 | |||
cssstyle: 2.3.0 | |||
data-urls: 3.0.2 | |||
cssstyle: 3.0.0 | |||
data-urls: 4.0.0 | |||
decimal.js: 10.4.3 | |||
domexception: 4.0.0 | |||
escodegen: 2.1.0 | |||
form-data: 4.0.0 | |||
html-encoding-sniffer: 3.0.0 | |||
http-proxy-agent: 5.0.0 | |||
https-proxy-agent: 5.0.1 | |||
is-potential-custom-element-name: 1.0.1 | |||
nwsapi: 2.2.6 | |||
nwsapi: 2.2.7 | |||
parse5: 7.1.2 | |||
rrweb-cssom: 0.6.0 | |||
saxes: 6.0.0 | |||
symbol-tree: 3.2.4 | |||
tough-cookie: 4.1.3 | |||
@@ -6400,7 +6367,7 @@ packages: | |||
webidl-conversions: 7.0.0 | |||
whatwg-encoding: 2.0.0 | |||
whatwg-mimetype: 3.0.0 | |||
whatwg-url: 11.0.0 | |||
whatwg-url: 12.0.1 | |||
ws: 8.13.0 | |||
xml-name-validator: 4.0.0 | |||
transitivePeerDependencies: | |||
@@ -7101,8 +7068,8 @@ packages: | |||
boolbase: 1.0.0 | |||
dev: true | |||
/nwsapi@2.2.6: | |||
resolution: {integrity: sha512-vSZ4miHQ4FojLjmz2+ux4B0/XA16jfwt/LBzIUftDpRd8tujHFkXjMyLwjS08fIZCzesj2z7gJukOKJwqebJAQ==} | |||
/nwsapi@2.2.7: | |||
resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} | |||
dev: true | |||
/oauth-sign@0.9.0: | |||
@@ -8007,6 +7974,10 @@ packages: | |||
fsevents: 2.3.3 | |||
dev: true | |||
/rrweb-cssom@0.6.0: | |||
resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} | |||
dev: true | |||
/run-applescript@5.0.0: | |||
resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==} | |||
engines: {node: '>=12'} | |||
@@ -8548,9 +8519,9 @@ packages: | |||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} | |||
dev: true | |||
/tr46@3.0.0: | |||
resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} | |||
engines: {node: '>=12'} | |||
/tr46@4.1.1: | |||
resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==} | |||
engines: {node: '>=14'} | |||
dependencies: | |||
punycode: 2.3.0 | |||
dev: true | |||
@@ -9002,7 +8973,7 @@ packages: | |||
fsevents: 2.3.3 | |||
dev: true | |||
/vitest@0.28.1(jsdom@21.1.0): | |||
/vitest@0.28.1: | |||
resolution: {integrity: sha512-F6wAO3K5+UqJCCGt0YAl3Ila2f+fpBrJhl9n7qWEhREwfzQeXlMkkCqGqGtzBxCSa8kv5QHrkshX8AaPTXYACQ==} | |||
engines: {node: '>=v14.16.0'} | |||
hasBin: true | |||
@@ -9036,7 +9007,6 @@ packages: | |||
cac: 6.7.14 | |||
chai: 4.3.7 | |||
debug: 4.3.4 | |||
jsdom: 21.1.0 | |||
local-pkg: 0.4.3 | |||
pathe: 1.1.1 | |||
picocolors: 1.0.0 | |||
@@ -9058,7 +9028,7 @@ packages: | |||
- terser | |||
dev: true | |||
/vitest@0.34.1(jsdom@21.1.0): | |||
/vitest@0.34.1(jsdom@22.1.0): | |||
resolution: {integrity: sha512-G1PzuBEq9A75XSU88yO5G4vPT20UovbC/2osB2KEuV/FisSIIsw7m5y2xMdB7RsAGHAfg2lPmp2qKr3KWliVlQ==} | |||
engines: {node: '>=v14.18.0'} | |||
hasBin: true | |||
@@ -9102,7 +9072,7 @@ packages: | |||
cac: 6.7.14 | |||
chai: 4.3.7 | |||
debug: 4.3.4 | |||
jsdom: 21.1.0 | |||
jsdom: 22.1.0 | |||
local-pkg: 0.4.3 | |||
magic-string: 0.30.1 | |||
pathe: 1.1.1 | |||
@@ -9209,11 +9179,11 @@ packages: | |||
engines: {node: '>=12'} | |||
dev: true | |||
/whatwg-url@11.0.0: | |||
resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} | |||
engines: {node: '>=12'} | |||
/whatwg-url@12.0.1: | |||
resolution: {integrity: sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==} | |||
engines: {node: '>=14'} | |||
dependencies: | |||
tr46: 3.0.0 | |||
tr46: 4.1.1 | |||
webidl-conversions: 7.0.0 | |||
dev: true | |||