@uppy/provider-views
Version:
View library for Uppy remote provider plugins.
123 lines (108 loc) • 3.33 kB
text/typescript
/* eslint-disable no-param-reassign */
import type {
PartialTree,
PartialTreeFile,
PartialTreeFolder,
PartialTreeFolderNode,
PartialTreeId,
} from '@uppy/core'
import shallowClone from './shallowClone.js'
/*
FROM | TO
root | root
folder | folder
folder ✅︎ | folder ✅︎
file | file ✅︎
file | file ✅︎
folder | folder ✅︎
file | file ✅︎
file | file
file | file
*/
const percolateDown = (
tree: PartialTree,
id: PartialTreeId,
shouldMarkAsChecked: boolean,
) => {
const children = tree.filter(
(item) => item.type !== 'root' && item.parentId === id,
) as (PartialTreeFolderNode | PartialTreeFile)[]
children.forEach((item) => {
item.status =
shouldMarkAsChecked && !(item.type === 'file' && item.restrictionError) ?
'checked'
: 'unchecked'
percolateDown(tree, item.id, shouldMarkAsChecked)
})
}
/*
FROM | TO
root | root
folder | folder
folder | folder [▬] ('partial' status)
file | file
folder | folder ✅︎
file ✅︎ | file ✅︎
file | file
file | file
*/
const percolateUp = (tree: PartialTree, id: PartialTreeId) => {
const folder = tree.find((item) => item.id === id) as PartialTreeFolder
if (folder.type === 'root') return
const validChildren = tree.filter(
(item) =>
// is a child
item.type !== 'root' &&
item.parentId === folder.id &&
// does pass validations
!(item.type === 'file' && item.restrictionError),
) as (PartialTreeFile | PartialTreeFolderNode)[]
const areAllChildrenChecked = validChildren.every(
(item) => item.status === 'checked',
)
const areAllChildrenUnchecked = validChildren.every(
(item) => item.status === 'unchecked',
)
if (areAllChildrenChecked) {
folder.status = 'checked'
} else if (areAllChildrenUnchecked) {
folder.status = 'unchecked'
} else {
folder.status = 'partial'
}
percolateUp(tree, folder.parentId)
}
const afterToggleCheckbox = (
oldTree: PartialTree,
clickedRange: string[],
): PartialTree => {
const tree: PartialTree = shallowClone(oldTree)
if (clickedRange.length >= 2) {
// We checked two or more items
const newlyCheckedItems = tree.filter(
(item) => item.type !== 'root' && clickedRange.includes(item.id),
) as (PartialTreeFile | PartialTreeFolderNode)[]
newlyCheckedItems.forEach((item) => {
if (item.type === 'file') {
item.status = item.restrictionError ? 'unchecked' : 'checked'
} else {
item.status = 'checked'
}
})
newlyCheckedItems.forEach((item) => {
percolateDown(tree, item.id, true)
})
percolateUp(tree, newlyCheckedItems[0].parentId)
} else {
// We checked exactly one item
const clickedItem = tree.find((item) => item.id === clickedRange[0]) as
| PartialTreeFile
| PartialTreeFolderNode
clickedItem.status =
clickedItem.status === 'checked' ? 'unchecked' : 'checked'
percolateDown(tree, clickedItem.id, clickedItem.status === 'checked')
percolateUp(tree, clickedItem.parentId)
}
return tree
}
export default afterToggleCheckbox