From 97f24ab8ca0cac8b70a3a9834583b28d9f19be7e Mon Sep 17 00:00:00 2001 From: Daniel Naab Date: Mon, 15 Apr 2024 16:05:28 -0500 Subject: [PATCH] dnd wired up to blueprint state. Added a test, which unfortunately does not work with JSDOM, so it is commented out --- .../FormManager/FormEdit/DraggableList.tsx | 69 ++++++------------- .../FormManager/FormEdit/FormEdit.stories.tsx | 33 ++++++++- .../FormEdit/PreviewSequencePattern.tsx | 18 +++-- .../design/src/FormManager/FormEdit/store.tsx | 15 ++++ 4 files changed, 80 insertions(+), 55 deletions(-) diff --git a/packages/design/src/FormManager/FormEdit/DraggableList.tsx b/packages/design/src/FormManager/FormEdit/DraggableList.tsx index f7c6aebb..8aa15c63 100644 --- a/packages/design/src/FormManager/FormEdit/DraggableList.tsx +++ b/packages/design/src/FormManager/FormEdit/DraggableList.tsx @@ -1,4 +1,4 @@ -import React, { Children, useState } from 'react'; +import React, { Children } from 'react'; import { DndContext, closestCenter, @@ -6,6 +6,7 @@ import { PointerSensor, useSensor, useSensors, + UniqueIdentifier, } from '@dnd-kit/core'; import { arrayMove, @@ -16,32 +17,24 @@ import { } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; -import { - getPattern, - type Blueprint, - type Pattern, - type PatternId, -} from '@atj/forms'; - -import { type SequencePattern } from '@atj/forms/src/patterns/sequence'; - const SortableItem = ({ id, children, }: { - id: string; + id: UniqueIdentifier; children: React.ReactNode; }) => { const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id }); - const style = { - transform: CSS.Transform.toString(transform), - transition, - }; - return ( -
  • +
    {children}
    -
  • + ); }; type DraggableListProps = React.PropsWithChildren<{ - pattern: SequencePattern; - form: Blueprint; - setSelectedPattern: (pattern: Pattern) => void; + order: UniqueIdentifier[]; + updateOrder: (order: UniqueIdentifier[]) => void; }>; export const DraggableList: React.FC = ({ - pattern, - form, - setSelectedPattern, children, + order, + updateOrder, }) => { - const [patterns, setPatterns] = useState( - pattern.data.patterns.map((patternId: PatternId) => { - return getPattern(form, patternId); - }) - ); const sensors = useSensors( useSensor(PointerSensor), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }) @@ -91,29 +77,18 @@ export const DraggableList: React.FC = ({ return; } if (active.id !== over.id) { - const oldIndex = patterns.findIndex(pattern => { - return pattern.id === active.id; - }); - const newIndex = patterns.findIndex(pattern => { - return pattern.id === over.id; - }); - const newOrder = arrayMove(patterns, oldIndex, newIndex); - setPatterns(newOrder); - setSelectedPattern({ - id: pattern.id, - type: pattern.type, - data: { - patterns: newOrder.map(pattern => pattern.id), - }, - } satisfies SequencePattern); + const oldIndex = order.indexOf(active.id); + const newIndex = order.indexOf(over.id); + const newOrder = arrayMove(order, oldIndex, newIndex); + updateOrder(newOrder); } }} > - + {arrayChildren.map((child, index) => { - const patternId = child.props._patternId; + const patternId = order[index]; return ( - + {child} ); diff --git a/packages/design/src/FormManager/FormEdit/FormEdit.stories.tsx b/packages/design/src/FormManager/FormEdit/FormEdit.stories.tsx index 9af62aba..90a0020d 100644 --- a/packages/design/src/FormManager/FormEdit/FormEdit.stories.tsx +++ b/packages/design/src/FormManager/FormEdit/FormEdit.stories.tsx @@ -6,7 +6,7 @@ import { createTestFormService } from '@atj/form-service'; import FormEdit from '.'; import { createTestForm, createTestFormEditContext } from '../../test-form'; -import { expect, userEvent, waitFor, within } from '@storybook/test'; +import { expect, fireEvent, userEvent, waitFor, within } from '@storybook/test'; export default { title: 'FormManager/FormEdit', @@ -56,6 +56,37 @@ export const FormEditAddPattern: StoryObj = { }, }; +// This test only works in a real browser, not via JSDOM as we use it. +/* +export const FormEditReorderPattern: StoryObj = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + + const grabber = await canvas.getAllByText(':::')[0]; + await grabber.focus(); + + // Enter reordering mode with the spacebar + await userEvent.type(grabber, ' '); + await new Promise(r => setTimeout(r, 100)); + + // Press the arrow down, to move the first pattern to the second position + await userEvent.type(grabber, '[ArrowDown]'); + await new Promise(r => setTimeout(r, 100)); + + // Press the spacebar to exit reordering mode + await userEvent.type(grabber, ' '); + await new Promise(r => setTimeout(r, 100)); + + // Pattern 1 should be after pattern 2 in the document + const pattern1 = canvas.getByText('Pattern 1'); + const pattern2 = canvas.getByText('Pattern 2'); + expect(pattern2.compareDocumentPosition(pattern1)).toBe( + Node.DOCUMENT_POSITION_FOLLOWING + ); + }, +}; +*/ + const editFieldLabel = async ( element: HTMLElement, buttonIndex: number, diff --git a/packages/design/src/FormManager/FormEdit/PreviewSequencePattern.tsx b/packages/design/src/FormManager/FormEdit/PreviewSequencePattern.tsx index 6f8e427a..800957bd 100644 --- a/packages/design/src/FormManager/FormEdit/PreviewSequencePattern.tsx +++ b/packages/design/src/FormManager/FormEdit/PreviewSequencePattern.tsx @@ -13,10 +13,7 @@ export const PatternPreviewSequence: PatternComponent< PatternProps > = function PatternPreviewSequence(props) { const form = useFormEditStore(state => state.form); - const setSelectedPattern = useFormEditStore( - state => state.setSelectedPattern - ); - + const updatePattern = useFormEditStore(state => state.updatePattern); const pattern = getPattern(form, props._patternId); /** @@ -33,9 +30,16 @@ export const PatternPreviewSequence: PatternComponent< */ return ( { + updatePattern({ + id: pattern.id, + type: pattern.type, + data: { + patterns: order, + }, + }); + }} > {props.children} diff --git a/packages/design/src/FormManager/FormEdit/store.tsx b/packages/design/src/FormManager/FormEdit/store.tsx index d265f6d3..02d4ed65 100644 --- a/packages/design/src/FormManager/FormEdit/store.tsx +++ b/packages/design/src/FormManager/FormEdit/store.tsx @@ -40,6 +40,7 @@ type FormEditState = { addPattern: (patternType: string) => void; handleEditClick: (patternId: PatternId) => void; setSelectedPattern: (element?: Pattern) => void; + updatePattern: (data: Pattern) => void; updateSelectedPattern: (formData: PatternMap) => void; }; @@ -75,6 +76,20 @@ const createFormEditStore = ({ } }, setSelectedPattern: selectedPattern => set({ selectedPattern }), + updatePattern: (pattern: Pattern) => { + const state = get(); + const builder = new BlueprintBuilder(state.form); + const success = builder.updatePattern( + state.context.config, + state.form.patterns[pattern.id], + { + [pattern.id]: pattern, + } + ); + if (success) { + set({ form: builder.form, selectedPattern: undefined }); + } + }, updateSelectedPattern: (formData: PatternMap) => { const state = get(); if (state.selectedPattern === undefined) {