Skip to content

Commit 5d2635e

Browse files
rfdingsteelsojka
andauthored
feat: drag and drop from palette @W-19284238 (#226)
* feature(design): add drag and drop support for regions * rework drag and drop * add local dragging logic * add drop target styles * fix styles * fix decorator render order * feat: add unit test + build fixes * fix: styling * fix: nodeToTargetMap being empty + update tests * fix: add back region green border * fix: test + bad css merge * fix: region decorator tests --------- Co-authored-by: Steven Sojka <[email protected]>
1 parent 7deb3bd commit 5d2635e

25 files changed

+1219
-225
lines changed

src/design/messaging-api/domain-types.ts

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ interface WithComponentId {
1919
componentId: string;
2020
}
2121

22+
interface WithComponentType {
23+
/**
24+
* The component type that the event is related to.
25+
*/
26+
componentType: string;
27+
}
28+
2229
/**
2330
* @inline
2431
* @hidden
@@ -196,8 +203,7 @@ export interface ClientAcknowledgedEvent extends WithBaseEvent {
196203
*/
197204
export interface ClientWindowDragEnteredEvent
198205
extends WithBaseEvent,
199-
WithClientVector,
200-
WithComponentId {
206+
WithComponentType {
201207
eventType: 'ClientWindowDragEntered';
202208
}
203209
/**
@@ -208,7 +214,7 @@ export interface ClientWindowDragEnteredEvent
208214
export interface ClientWindowDragMovedEvent
209215
extends WithBaseEvent,
210216
WithClientVector,
211-
WithComponentId {
217+
WithComponentType {
212218
eventType: 'ClientWindowDragMoved';
213219
}
214220
/**
@@ -218,8 +224,7 @@ export interface ClientWindowDragMovedEvent
218224
*/
219225
export interface ClientWindowDragExitedEvent
220226
extends WithBaseEvent,
221-
WithClientVector,
222-
WithComponentId {
227+
WithComponentType {
223228
eventType: 'ClientWindowDragExited';
224229
}
225230
/**
@@ -229,8 +234,7 @@ export interface ClientWindowDragExitedEvent
229234
*/
230235
export interface ClientWindowDragDroppedEvent
231236
extends WithBaseEvent,
232-
WithClientVector,
233-
WithComponentId {
237+
WithComponentType {
234238
eventType: 'ClientWindowDragDropped';
235239
}
236240
/**
@@ -354,10 +358,6 @@ export interface ComponentMovedToRegionEvent
354358
* The region that the component is being moved from.
355359
*/
356360
sourceRegionId: string;
357-
/**
358-
* The id of the component that the component was moved from.
359-
*/
360-
sourceComponentId: string;
361361
}
362362
/**
363363
* Emits when a component is hovered over.
@@ -421,14 +421,13 @@ export interface ComponentDeletedEvent extends WithBaseEvent, WithComponentId {
421421
*/
422422
export interface ComponentAddedToRegionEvent<
423423
TProps extends Record<string, unknown> = Record<string, unknown>
424-
> extends WithBaseEvent,
425-
WithComponentId {
424+
> extends WithBaseEvent {
426425
eventType: 'ComponentAddedToRegion';
427426
/**
428427
* The specifier of the component to add.
429428
* This will be used to lookup the component in the registry.
430429
*/
431-
componentSpecifier: string;
430+
componentType: string;
432431
/**
433432
* The properties of the component to add.
434433
* These will be used to initialize the component.
@@ -442,17 +441,27 @@ export interface ComponentAddedToRegionEvent<
442441
* The id of the region that the component is being added to.
443442
*/
444443
targetRegionId: string;
444+
/**
445+
* When an insertComponentId is provided, this will insert the new component before or after the component with that component id.
446+
*/
447+
insertType?: 'before' | 'after';
448+
/**
449+
* The id of the component this component should be inserted before or after.
450+
* If not provided, then it is up to the host to determine where in the target region this is inserted.
451+
*/
452+
insertComponentId?: string;
445453
}
446454
/**
447455
* Emits when a component drag starts from the host or client.
448456
* @target isomorphic
449457
* @group Events
450458
*/
451-
export interface ComponentDragStartedEvent
452-
extends WithBaseEvent,
453-
WithComponentId,
454-
Partial<WithClientVector> {
459+
export interface ComponentDragStartedEvent extends WithBaseEvent {
455460
eventType: 'ComponentDragStarted';
461+
/**
462+
* The type of the component that is being dragged.
463+
*/
464+
componentType: string;
456465
}
457466
/**
458467
* Emits when an error occurs.

src/design/messaging-api/messenging-api.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ describe('Messaging API', () => {
356356

357357
describe.each`
358358
method | eventName | payload
359-
${'addComponentToRegion'} | ${'ComponentAddedToRegion'} | ${{componentId: 'test-component', componentSpecifier: 'test-specifier', componentProperties: {test: 'value'}, targetComponentId: 'target-component', targetRegionId: 'test-region'}}
359+
${'addComponentToRegion'} | ${'ComponentAddedToRegion'} | ${{componentId: 'test-component', componentType: 'test-specifier', componentProperties: {test: 'value'}, targetComponentId: 'target-component', targetRegionId: 'test-region'}}
360360
${'moveComponentToRegion'} | ${'ComponentMovedToRegion'} | ${{componentId: 'test-component', targetComponentId: 'target-component', targetRegionId: 'target-region', sourceRegionId: 'source-region', sourceComponentId: 'source-component'}}
361361
${'notifyClientReady'} | ${'ClientReady'} | ${{clientId: 'test-client'}}
362362
${'startComponentDrag'} | ${'ComponentDragStarted'} | ${{componentId: 'test-component', x: 100, y: 200}}
@@ -400,7 +400,7 @@ describe('Messaging API', () => {
400400

401401
describe.each`
402402
method | eventName | payload
403-
${'addComponentToRegion'} | ${'ComponentAddedToRegion'} | ${{componentId: 'test-component', componentSpecifier: 'test-specifier', componentProperties: {test: 'value'}, targetComponentId: 'target-component', targetRegionId: 'test-region'}}
403+
${'addComponentToRegion'} | ${'ComponentAddedToRegion'} | ${{componentId: 'test-component', componentType: 'test-specifier', componentProperties: {test: 'value'}, targetComponentId: 'target-component', targetRegionId: 'test-region'}}
404404
${'moveComponentToRegion'} | ${'ComponentMovedToRegion'} | ${{componentId: 'test-component', targetComponentId: 'target-component', targetRegionId: 'target-region', sourceRegionId: 'source-region', sourceComponentId: 'source-component'}}
405405
${'startComponentDrag'} | ${'ComponentDragStarted'} | ${{componentId: 'test-component', x: 100, y: 200}}
406406
${'hoverInToComponent'} | ${'ComponentHoveredIn'} | ${{componentId: 'test-component'}}

src/design/react/components/ComponentDecorator.test.tsx

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ describe('design/react/ComponentDecorator', () => {
9090

9191
const finalResult = Object.assign(result, {
9292
host,
93-
element: result.container.querySelector('.pd-design--decorator'),
93+
element: result.container.querySelector('.pd-design__decorator'),
9494
}) as Result;
9595

9696
return finalResult;
@@ -150,22 +150,32 @@ describe('design/react/ComponentDecorator', () => {
150150
describe('when the component is a fragment', () => {
151151
it('should include the corresponding fragment class', async () => {
152152
const {element} = await testBed.render(TestComponent, {
153-
designMetadata: {id: 'test-1', isFragment: true},
153+
designMetadata: {
154+
id: 'test-1',
155+
isFragment: true,
156+
regionDirection: 'row',
157+
regionId: 'test-region',
158+
},
154159
});
155160

156-
expect(element.classList.contains('pd-design--fragment')).toBe(true);
157-
expect(element.classList.contains('pd-design--component')).toBe(false);
161+
expect(element.classList.contains('pd-design__fragment')).toBe(true);
162+
expect(element.classList.contains('pd-design__component')).toBe(false);
158163
});
159164
});
160165

161166
describe('when the component is a component', () => {
162167
it('should include the corresponding component class', async () => {
163168
const {element} = await testBed.render(TestComponent, {
164-
designMetadata: {id: 'test-1', isFragment: false},
169+
designMetadata: {
170+
id: 'test-1',
171+
isFragment: false,
172+
regionDirection: 'row',
173+
regionId: 'test-region',
174+
},
165175
});
166176

167-
expect(element.classList.contains('pd-design--fragment')).toBe(false);
168-
expect(element.classList.contains('pd-design--component')).toBe(true);
177+
expect(element.classList.contains('pd-design__fragment')).toBe(false);
178+
expect(element.classList.contains('pd-design__component')).toBe(true);
169179
});
170180
});
171181

@@ -182,8 +192,12 @@ describe('design/react/ComponentDecorator', () => {
182192
it('should show the frame', async () => {
183193
const {element} = await testBed.render(TestComponent);
184194

185-
expect(element.classList.contains('pd-design--show-frame')).toBe(true);
186-
expect(element.classList.contains('pd-design--hovered')).toBe(true);
195+
expect(element.classList.contains('pd-design__frame--visible')).toBe(
196+
true
197+
);
198+
expect(
199+
element.classList.contains('pd-design__decorator--hovered')
200+
).toBe(true);
187201
});
188202

189203
it('should notify the host of the hover', async () => {
@@ -203,9 +217,9 @@ describe('design/react/ComponentDecorator', () => {
203217
hoverOutSpy = jest.fn();
204218
testBed.afterRender(async ({host, element}) => {
205219
await waitFor(() => {
206-
expect(element.classList.contains('pd-design--hovered')).toBe(
207-
true
208-
);
220+
expect(
221+
element.classList.contains('pd-design__decorator--hovered')
222+
).toBe(true);
209223
});
210224

211225
host.on('ComponentHoveredOut', hoverOutSpy);
@@ -226,10 +240,12 @@ describe('design/react/ComponentDecorator', () => {
226240
it('should not show the frame', async () => {
227241
const {element} = await testBed.render(TestComponent);
228242

229-
expect(element.classList.contains('pd-design--show-frame')).toBe(
243+
expect(element.classList.contains('pd-design__frame--visible')).toBe(
230244
false
231245
);
232-
expect(element.classList.contains('pd-design--hovered')).toBe(false);
246+
expect(
247+
element.classList.contains('pd-design__decorator--hovered')
248+
).toBe(false);
233249
});
234250
});
235251
});
@@ -240,8 +256,12 @@ describe('design/react/ComponentDecorator', () => {
240256

241257
element.click();
242258

243-
expect(element.classList.contains('pd-design--show-frame')).toBe(true);
244-
expect(element.classList.contains('pd-design--selected')).toBe(true);
259+
expect(element.classList.contains('pd-design__frame--visible')).toBe(
260+
true
261+
);
262+
expect(
263+
element.classList.contains('pd-design__decorator--selected')
264+
).toBe(true);
245265
});
246266

247267
it('should notify the host of the selection', async () => {
@@ -272,15 +292,15 @@ describe('design/react/ComponentDecorator', () => {
272292
fireEvent.click(element);
273293

274294
await waitFor(() => {
275-
expect(element.classList.contains('pd-design--show-frame')).toBe(
276-
true
277-
);
295+
expect(
296+
element.classList.contains('pd-design__frame--visible')
297+
).toBe(true);
278298
});
279299

280300
host.on('ComponentDeleted', hostSpy);
281301
const deleteButton = await testBed.findBySelector(
282302
element,
283-
'.pd-design__toolbox-button'
303+
'.pd-design__frame__delete-icon'
284304
);
285305
fireEvent.click(deleteButton);
286306
});
@@ -292,6 +312,8 @@ describe('design/react/ComponentDecorator', () => {
292312
id: 'test-1',
293313
parentId: 'test-parent',
294314
regionId: 'test-region',
315+
regionDirection: 'row',
316+
isFragment: false,
295317
},
296318
});
297319

0 commit comments

Comments
 (0)