123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- /* eslint-disable no-param-reassign */
- import type {
- PartialTree,
- PartialTreeFile,
- PartialTreeFolder,
- PartialTreeFolderNode,
- PartialTreeId,
- } from '@uppy/core/lib/Uppy'
- import shallowClone from './shallowClone.ts'
- /*
- 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
|