このコミットが含まれているのは:
@@ -1,8 +1,8 @@
|
||||
import { useId, useState } from 'react'
|
||||
import { useId, useLayoutEffect, useRef, useState } from 'react'
|
||||
|
||||
import AnimatedCollapse from '@/components/common/AnimatedCollapse'
|
||||
import SortableList from '@/components/common/SortableList'
|
||||
import { fieldsForCounts, orderedCountFields,
|
||||
import { countChildPaths, fieldsForCounts, normaliseCountsParams, orderedCountFields,
|
||||
selectedCountChildren, selectedCountColumns, selectedCountFields } from '@/lib/counts'
|
||||
import { useCountsDefinition } from '@/lib/countsDefinitions'
|
||||
import { useClientMotion } from '@/lib/useClientMotion'
|
||||
@@ -22,12 +22,20 @@ const FieldBranch = ({ field, path, enabled, selected, params, select, update }:
|
||||
const [open, setOpen] = useState (false)
|
||||
const id = useId ()
|
||||
const motion = useClientMotion ()
|
||||
const checked = selected.has (path)
|
||||
const input = useRef<HTMLInputElement> (null)
|
||||
const leaves = countChildPaths (field.children ?? [], path, true)
|
||||
const count = leaves.filter (key => selected.has (key)).length
|
||||
const checked = field.children == null ? selected.has (path)
|
||||
: count > 0 && count === leaves.length
|
||||
const partial = count > 0 && count < leaves.length
|
||||
useLayoutEffect (() => {
|
||||
if (input.current != null) input.current.indeterminate = partial
|
||||
}, [partial])
|
||||
return <>
|
||||
<div className="flex items-center gap-1">
|
||||
<label className="inline-flex items-center gap-1">
|
||||
<input type="checkbox" checked={checked} disabled={!enabled || (field.children != null
|
||||
&& !field.children.some (child => selected.has (`${path}.${child.key}`)))}
|
||||
<input ref={input} type="checkbox" checked={checked} disabled={!enabled}
|
||||
aria-checked={partial ? 'mixed' : checked}
|
||||
onChange={event => select (path, event.target.checked)}/>
|
||||
{label (field.label, field.labelValues)}
|
||||
</label>
|
||||
@@ -89,48 +97,36 @@ const CountsFieldTree = (
|
||||
update: (key: string, value: string) => void },
|
||||
) => {
|
||||
const definition = useCountsDefinition ()
|
||||
const resolved = normaliseCountsParams (resource, params, definition)
|
||||
const fields = suppliedFields ?? fieldsForCounts (resource, definition)
|
||||
const roots = suppliedFields == null ? selectedCountColumns (resource, params, definition)
|
||||
: selectedCountFields (fields, params, selectionKey, parent).map (field => field.key)
|
||||
const selected = selectedCountChildren (params)
|
||||
const roots = suppliedFields == null ? selectedCountColumns (resource, resolved, definition)
|
||||
: selectedCountFields (fields, resolved, selectionKey, parent).map (field => field.key)
|
||||
const selected = selectedCountChildren (resolved, fieldsForCounts (resource, definition))
|
||||
const rootPath = (key: string) => parent ? `${parent}.${key}` : key
|
||||
for (const root of roots) selected.add (rootPath (root))
|
||||
const select = (path: string, checked: boolean) => {
|
||||
const root = fields.find (field => rootPath (field.key) === path)
|
||||
if (root != null)
|
||||
const next = new Set (selected)
|
||||
const paths = countChildPaths (fields, parent)
|
||||
.filter (key => key === path || key.startsWith (`${path}.`))
|
||||
for (const key of paths)
|
||||
{
|
||||
const next = new Set<string> (roots)
|
||||
if (checked) next.add (root.key)
|
||||
else next.delete (root.key)
|
||||
update (selectionKey, fields.filter (field => next.has (field.key))
|
||||
.map (field => field.key).join (' '))
|
||||
return
|
||||
if (checked) next.add (key)
|
||||
else next.delete (key)
|
||||
}
|
||||
if (checked)
|
||||
{
|
||||
const parts = path.split ('.')
|
||||
for (let index = 1; index < parts.length; ++index)
|
||||
selected.add (parts.slice (0, index + 1).join ('.'))
|
||||
}
|
||||
else selected.delete (path)
|
||||
const nextParams = new URLSearchParams (params)
|
||||
nextParams.set ('children', [...selected].filter (key => key.includes ('.')).join (' '))
|
||||
const children = selectedCountChildren (nextParams)
|
||||
const nextParams = new URLSearchParams (resolved)
|
||||
nextParams.set ('children', [...next].filter (key => key.includes ('.')).join (' '))
|
||||
const children = selectedCountChildren (nextParams, fieldsForCounts (resource, definition))
|
||||
update ('children', [...children].join (' '))
|
||||
const nextRoots = new Set (roots)
|
||||
const ancestor = fields.find (field => path.startsWith (`${rootPath (field.key)}.`))
|
||||
if (checked && ancestor != null) nextRoots.add (ancestor.key)
|
||||
for (const field of fields)
|
||||
if (field.children != null && !field.children.some (child =>
|
||||
children.has (`${rootPath (field.key)}.${child.key}`))) nextRoots.delete (field.key)
|
||||
update (selectionKey, fields.filter (field => nextRoots.has (field.key))
|
||||
update (selectionKey, fields.filter (field => field.children == null
|
||||
? next.has (rootPath (field.key)) : field.children.some (child =>
|
||||
children.has (`${rootPath (field.key)}.${child.key}`)))
|
||||
.map (field => field.key).join (' '))
|
||||
}
|
||||
const visibleFields = parent === ''
|
||||
? fields.filter (field => field.key !== 'thumbnail') : fields
|
||||
return (
|
||||
<>
|
||||
<FieldGroup fields={visibleFields} path={parent} params={params} enabled selected={selected}
|
||||
<FieldGroup fields={visibleFields} path={parent} params={resolved} enabled selected={selected}
|
||||
select={select} update={update}/>
|
||||
</>)
|
||||
}
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする