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 (
-
+
);
};
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) {