このコミットが含まれているのは:
2026-10-28 21:13:08 +09:00
コミット 49721e6915
17個のファイルの変更、170行の追加、48行の削除
+9 -3
ファイルの表示
@@ -4,6 +4,7 @@ import { SortableContext, arrayMove, horizontalListSortingStrategy,
sortableKeyboardCoordinates } from '@dnd-kit/sortable'
import { useRef, useState } from 'react'
import { createPortal } from 'react-dom'
import { CSS } from '@dnd-kit/utilities'
import { useClientMotion } from '@/lib/useClientMotion'
@@ -55,11 +56,16 @@ const SortableColumns = ({ ids, fixed = [], name, onChange, children }: {
<SortableContext items={ids} strategy={horizontalListSortingStrategy}>
{children (ids)}
</SortableContext>
{typeof document !== 'undefined' && createPortal (<DragOverlay
{typeof document !== 'undefined' && createPortal (<DragOverlay adjustScale={false}
style={{ width: 'max-content', height: 'auto', maxWidth: 'calc(100vw - 2rem)' }}
dropAnimation={motion.reduced ? null : {
duration: motion.duration ('drop'), easing: motion.easing }}>
duration: motion.duration ('drop'), easing: motion.easing,
keyframes: ({ transform }) => [
{ transform: CSS.Translate.toString (transform.initial) },
{ transform: CSS.Translate.toString (transform.final) }] }}>
{active != null && <div lang={name (active).language}
className="rounded border border-blue-500 bg-white p-2 text-slate-900 shadow-lg
className="w-max max-w-[min(20rem,calc(100vw_-_2rem))] truncate rounded
border border-blue-500 bg-white px-2 py-1 text-sm text-slate-900 shadow-lg
dark:border-blue-400 dark:bg-slate-800 dark:text-slate-100">{name (active).text}</div>}
</DragOverlay>, document.body)}
</DndContext>
+1 -1
ファイルの表示
@@ -40,7 +40,7 @@ const SortableItem = ({ id, name, fixed, children, moveGroup, handleId, renderSh
}
else item.listeners?.onKeyDown?.(event)
}}><span aria-hidden>⠿</span></button>
const style = { transform: CSS.Transform.toString (item.transform), transition: item.transition }
const style = { transform: CSS.Translate.toString (item.transform), transition: item.transition }
if (renderShell != null)
return renderShell ({ ref: item.setNodeRef, style, handle, dragging: item.isDragging })
return <div ref={item.setNodeRef} style={style}
+19 -8
ファイルの表示
@@ -4,6 +4,7 @@ import { SortableContext, arrayMove, rectSortingStrategy,
sortableKeyboardCoordinates } from '@dnd-kit/sortable'
import { useId, useRef, useState } from 'react'
import { createPortal } from 'react-dom'
import { CSS } from '@dnd-kit/utilities'
import SortableItem from '@/components/common/SortableItem'
import { useClientMotion } from '@/lib/useClientMotion'
@@ -29,8 +30,10 @@ const Group = ({ id, children }: { id: string; children: ReactNode }) => {
}
const SortableList = ({ groups, name, renderItem, renderGroup, onChange, fixed = [] }: {
const SortableList = (
{ groups, name, handleName, renderItem, renderGroup, onChange, fixed = [] }: {
groups: Groups; name: (id: string) => Name
handleName?: (id: string) => Name
renderItem: (id: string, group: string) => ReactNode
renderGroup: (id: string, content: ReactNode) => ReactNode
onChange: (groups: Groups) => void; fixed?: string[] },
@@ -39,6 +42,7 @@ const SortableList = ({ groups, name, renderItem, renderGroup, onChange, fixed =
const scope = useId ()
const [active, setActive] = useState<string | null> (null)
const motion = useClientMotion ()
const accessibleName = handleName ?? name
const sensors = useSensors (
useSensor (MouseSensor, { activationConstraint: { distance: 4 } }),
useSensor (TouchSensor, { activationConstraint: { delay: 350, tolerance: 8 } }),
@@ -84,13 +88,14 @@ const SortableList = ({ groups, name, renderItem, renderGroup, onChange, fixed =
}
return <DndContext sensors={sensors} collisionDetection={closestCenter}
accessibility={{ announcements: {
onDragStart: event => name (String (event.active.id)).text,
onDragStart: event => accessibleName (String (event.active.id)).text,
onDragOver: event => event.over == null ? undefined : (
event.over.id.toString ().startsWith ('group:') ? undefined
: name (String (event.over.id)).text),
: accessibleName (String (event.over.id)).text),
onDragMove: () => undefined, onDragEnd: () => undefined,
onDragCancel: () => undefined },
screenReaderInstructions: { draggable: active == null ? '' : name (active).text } }}
screenReaderInstructions: {
draggable: active == null ? '' : accessibleName (active).text } }}
onDragStart={event => {
const id = String (event.active.id)
drag.current = { id, groups }
@@ -108,17 +113,23 @@ const SortableList = ({ groups, name, renderItem, renderGroup, onChange, fixed =
{Object.entries (groups).map (([group, ids]) => <div key={group}>
{renderGroup (group, <SortableContext items={ids} strategy={rectSortingStrategy}>
<Group id={group}>{ids.map (id => <SortableItem key={id} id={id}
name={name (id)} fixed={fixed.includes (id)} handleId={`${scope}-${id}`}
name={accessibleName (id)} fixed={fixed.includes (id)} handleId={`${scope}-${id}`}
moveGroup={direction => moveGroup (id, direction)}>
{renderItem (id, group)}
</SortableItem>)}</Group>
</SortableContext>)}
</div>)}
{typeof document !== 'undefined' && createPortal (
<DragOverlay dropAnimation={motion.reduced ? null : {
duration: motion.duration ('drop'), easing: motion.easing }}>
<DragOverlay adjustScale={false}
style={{ width: 'max-content', height: 'auto', maxWidth: 'calc(100vw - 2rem)' }}
dropAnimation={motion.reduced ? null : {
duration: motion.duration ('drop'), easing: motion.easing,
keyframes: ({ transform }) => [
{ transform: CSS.Translate.toString (transform.initial) },
{ transform: CSS.Translate.toString (transform.final) }] }}>
{active == null ? null : <div lang={name (active).language}
className="rounded border border-blue-500 bg-white px-3 py-2 text-sm
className="w-max max-w-[min(20rem,calc(100vw_-_2rem))] truncate rounded
border border-blue-500 bg-white px-2 py-1 text-sm
text-slate-900 shadow-lg dark:border-blue-400 dark:bg-slate-800 dark:text-slate-100">
{name (active).text}</div>}
</DragOverlay>, document.body)}
+3 -2
ファイルの表示
@@ -48,7 +48,8 @@ const ConditionEditor = (
const operator = fields.find (item => item.key === field)?.operators[0]
if (operator != null) setCondition ({ field, operator })
}}>
{fields.filter (field => field.operators.length > 0).map (field => (
{fields.filter (item => item.operators.length > 0
&& (!item.legacy || item.key === field)).map (field => (
<option key={field.key} value={field.key}>{fieldName (field.key)}</option>))}
</select>
<select value={operator} aria-label={message ('operator').text}
@@ -98,7 +99,7 @@ const CountsAdditionalConditions = ({ params, update }: {
const dialogue = useDialogue ()
const conditions = readCountState<CountsCondition[]> (params, 'conditions', [])
const metadata = definition.filterFields ?? definition.fields
const fields = metadata.filter (field => field.operators.length > 0)
const fields = metadata.filter (field => field.operators.length > 0 && !field.legacy)
const fieldName = (key: string) => (metadata.find (item => item.key === key)?.labels
?? [countsFieldLabel (key)]).map (label => message (
label, metadata.find (item => item.key === key)?.labelValues).text).join (' › ')
+3 -1
ファイルの表示
@@ -69,7 +69,9 @@ const FieldGroup = ({ fields, path, params, enabled, selected, select, update }:
const prefix = path ? `${path}.` : ''
return <SortableList groups={{ items: ordered.map (field => field.key) }}
fixed={path === '' ? ['thumbnail'] : []}
name={key => message ('reorder', {
name={key => message (fields.find (field => field.key === key)!.label,
fields.find (field => field.key === key)!.labelValues)}
handleName={key => message ('reorder', {
column: message (fields.find (field => field.key === key)!.label,
fields.find (field => field.key === key)!.labelValues).text })}
renderGroup={(_, content) => content}