Skip to content

Commit

Permalink
fix(core): add transition effect when sorting array of primitives
Browse files Browse the repository at this point in the history
  • Loading branch information
hermanwikner committed Jan 3, 2023
1 parent fe96da1 commit 71e3212
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 7 deletions.
Expand Up @@ -14,11 +14,25 @@ import {nearestIndexOf} from './utils/nearestIndex'
import {ItemRow} from './ItemRow'
import {ArrayOfPrimitivesFunctions} from './ArrayOfPrimitivesFunctions'

interface State {
disableTransition: boolean
}
// Note: this should be a class component until React provides support for a hook version of getSnapshotBeforeUpdate
/** @beta */
export class ArrayOfPrimitivesInput extends React.PureComponent<ArrayOfPrimitivesInputProps> {
export class ArrayOfPrimitivesInput extends React.PureComponent<
ArrayOfPrimitivesInputProps,
State
> {
_element: HTMLElement | null = null

constructor(props: ArrayOfPrimitivesInputProps) {
super(props)

this.state = {
disableTransition: false,
}
}

handleAppend = (itemValue: PrimitiveValue) => {
const {value = [], onIndexFocus, onItemAppend} = this.props
onItemAppend(itemValue)
Expand All @@ -30,12 +44,26 @@ export class ArrayOfPrimitivesInput extends React.PureComponent<ArrayOfPrimitive
onItemPrepend(itemValue)
onIndexFocus(value.length)
}

handleSortEnd = (event: {fromIndex: number; toIndex: number}) => {
const {onIndexFocus, onMoveItem, value} = this.props

if (value) onMoveItem(event)
onIndexFocus(event.toIndex)
}

// Enable transition when the user starts dragging an item
handleItemMoveStart = () => {
this.setState({disableTransition: false})
}

// Disable transition when the user stops dragging an item.
// Note: there's an issue with the transition of items when the sorting is completed, so we disable the
// transition effect when the user stops dragging.
handleItemMoveEnd = () => {
this.setState({disableTransition: true})
}

focus() {
if (this._element) {
this._element.focus()
Expand Down Expand Up @@ -154,13 +182,20 @@ export class ArrayOfPrimitivesInput extends React.PureComponent<ArrayOfPrimitive
<Card padding={1} border>
<List
onItemMove={this.handleSortEnd}
onItemMoveStart={this.handleItemMoveStart}
onItemMoveEnd={this.handleItemMoveEnd}
items={membersWithSortIds.map((m) => m.id)}
sortable={isSortable}
gap={1}
>
{membersWithSortIds.map(({member, id}, index) => {
return (
<Item key={member.key} id={id} sortable={isSortable} disableTransition>
<Item
key={member.key}
id={id}
sortable={isSortable}
disableTransition={this.state.disableTransition}
>
{member.kind === 'item' && (
<ArrayOfPrimitivesItem
member={member}
Expand Down
26 changes: 21 additions & 5 deletions packages/sanity/src/core/form/inputs/arrays/common/list.tsx
Expand Up @@ -61,7 +61,7 @@ function sortingStrategy(axis: Axis) {
}

function SortableList(props: ListProps) {
const {items, axis, onItemMove, children, ...rest} = props
const {items, axis, onItemMove, onItemMoveStart, onItemMoveEnd, children, ...rest} = props

const sensors = useSensors(useSensor(PointerSensor), useSensor(KeyboardSensor, SENSOR_OPTIONS))

Expand All @@ -75,8 +75,10 @@ function SortableList(props: ListProps) {
toIndex: items.indexOf(over?.id as string),
})
}

onItemMoveEnd?.()
},
[items, onItemMove]
[items, onItemMove, onItemMoveEnd]
)
const modifiers = useMemo(
() => [restrictToParentElementWithMargins({y: 4}), ...(axis ? [restrictToAxis(axis)] : [])],
Expand All @@ -90,6 +92,7 @@ function SortableList(props: ListProps) {
modifiers={modifiers}
collisionDetection={closestCenter}
onDragEnd={handleDragEnd}
onDragStart={onItemMoveStart}
>
<SortableContext items={items} strategy={axis ? sortingStrategy(axis) : undefined}>
<Grid {...rest}>{children}</Grid>
Expand Down Expand Up @@ -133,19 +136,32 @@ interface ListProps extends ComponentProps<typeof Grid> {
axis?: Axis
items: string[]
onItemMove?: (event: {fromIndex: number; toIndex: number}) => void
onItemMoveStart?: () => void
onItemMoveEnd?: () => void
children?: React.ReactNode
}

export function List(props: ListProps) {
const {onItemMove, sortable, ...rest} = props
const {onItemMove, onItemMoveEnd, onItemMoveStart, sortable, ...rest} = props

// Note: this is here to make SortableList API compatible with onItemMove
const handleSortEnd = useCallback(
(event: {fromIndex: number; toIndex: number}) => onItemMove?.(event),
(event: {fromIndex: number; toIndex: number}) => {
onItemMove?.(event)
},
[onItemMove]
)

return sortable ? <SortableList onItemMove={handleSortEnd} {...rest} /> : <Grid {...rest} />
return sortable ? (
<SortableList
onItemMove={handleSortEnd}
onItemMoveStart={onItemMoveStart}
onItemMoveEnd={onItemMoveEnd}
{...rest}
/>
) : (
<Grid {...rest} />
)
}

interface ItemProps {
Expand Down

1 comment on commit 71e3212

@vercel
Copy link

@vercel vercel bot commented on 71e3212 Jan 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

test-studio – ./

test-studio.sanity.build
test-studio-git-next.sanity.build

Please sign in to comment.