Skip to content

Commit dea2bc5

Browse files
sorinsarcaWestbrook
authored andcommitted
feat: reparentChildren - refactored arguments - breaking change
1 parent 07f966f commit dea2bc5

File tree

5 files changed

+83
-73
lines changed

5 files changed

+83
-73
lines changed

packages/menu/src/MenuItem.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -387,14 +387,17 @@ export class MenuItem extends LikeAnchor(Focusable) {
387387
);
388388
submenu.addEventListener('change', this.handleSubmenuChange);
389389
const popover = document.createElement('sp-popover');
390-
const returnSubmenu = reparentChildren([submenu], popover, (el) => {
391-
const slotName = el.slot;
392-
el.tabIndex = 0;
393-
el.removeAttribute('slot');
394-
return (el) => {
395-
el.tabIndex = -1;
396-
el.slot = slotName;
397-
};
390+
const returnSubmenu = reparentChildren([submenu], popover, {
391+
position: 'beforeend',
392+
prepareCallback: (el) => {
393+
const slotName = el.slot;
394+
el.tabIndex = 0;
395+
el.removeAttribute('slot');
396+
return (el) => {
397+
el.tabIndex = -1;
398+
el.slot = slotName;
399+
};
400+
},
398401
});
399402
const closeOverlay = openOverlay(this, 'click', popover, {
400403
placement: this.isLTR ? 'right-start' : 'left-start',

packages/overlay/src/ActiveOverlay.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -358,14 +358,17 @@ export class ActiveOverlay extends SpectrumElement {
358358
element: HTMLElement & { placement: Placement }
359359
): void {
360360
this.originalPlacement = element.getAttribute('placement') as Placement;
361-
this.restoreContent = reparentChildren([element], this, (el) => {
362-
const slotName = el.slot;
363-
const placement = el.placement;
364-
el.removeAttribute('slot');
365-
return (el) => {
366-
el.slot = slotName;
367-
el.placement = placement;
368-
};
361+
this.restoreContent = reparentChildren([element], this, {
362+
position: 'beforeend',
363+
prepareCallback: (el) => {
364+
const slotName = el.slot;
365+
const placement = el.placement;
366+
el.removeAttribute('slot');
367+
return (el) => {
368+
el.slot = slotName;
369+
el.placement = placement;
370+
};
371+
},
369372
});
370373
this.stealOverlayContentResolver();
371374
}

packages/picker/src/Picker.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -314,12 +314,15 @@ export class PickerBase extends SizedMixin(Focusable) {
314314

315315
this.restoreChildren = reparentChildren<
316316
Element & { focused?: boolean }
317-
>(reparentableChildren, this.optionsMenu, () => {
318-
return (el) => {
319-
if (typeof el.focused !== 'undefined') {
320-
el.focused = false;
321-
}
322-
};
317+
>(reparentableChildren, this.optionsMenu, {
318+
position: 'beforeend',
319+
prepareCallback: () => {
320+
return (el) => {
321+
if (typeof el.focused !== 'undefined') {
322+
el.focused = false;
323+
}
324+
};
325+
},
323326
});
324327

325328
this.sizePopover(this.popover);

packages/shared/src/reparent-children.ts

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,40 +32,54 @@ function restoreChildren<T extends Element>(
3232

3333
export const reparentChildren = <T extends Element>(
3434
srcElements: T[],
35-
newParent: Element,
36-
prepareCallback?: ((el: T) => ((el: T) => void) | void) | null,
37-
position?: InsertPosition
38-
): (() => Element[]) => {
39-
const placeholderItems: Comment[] = [];
40-
const cleanupCallbacks: ((el: T) => void)[] = [];
35+
destination: Element,
36+
{
37+
position,
38+
prepareCallback,
39+
}: {
40+
position: InsertPosition;
41+
prepareCallback?: (el: T) => ((el: T) => void) | void;
42+
} = { position: 'beforeend' }
43+
): (() => T[]) => {
44+
let length = srcElements.length;
45+
if (length === 0) {
46+
return () => srcElements;
47+
}
4148

42-
// default is to append
43-
position = position || 'beforeend';
49+
let step = 1;
50+
let index = 0;
4451

4552
if (position === 'afterbegin' || position === 'afterend') {
46-
srcElements.reverse();
53+
step = -1;
54+
index = length - 1;
4755
}
4856

49-
for (let index = 0; index < srcElements.length; ++index) {
57+
const placeholderItems = new Array<Comment>(length);
58+
const cleanupCallbacks = new Array<(el: T) => void>(length);
59+
const placeholderTemplate: Comment = document.createComment(
60+
'placeholder for reparented element'
61+
);
62+
63+
do {
5064
const srcElement = srcElements[index];
5165
if (prepareCallback) {
52-
cleanupCallbacks.push(
53-
prepareCallback(srcElement) as (el: T) => void
54-
);
66+
cleanupCallbacks[index] = prepareCallback(srcElement) as (
67+
el: T
68+
) => void;
5569
}
56-
const placeholderItem: Comment = document.createComment(
57-
'placeholder for reparented element'
58-
);
59-
placeholderItems.push(placeholderItem);
70+
placeholderItems[index] = placeholderTemplate.cloneNode() as Comment;
71+
6072
const parentElement =
6173
srcElement.parentElement || srcElement.getRootNode();
6274
if (parentElement && parentElement !== srcElement) {
63-
parentElement.replaceChild(placeholderItem, srcElement);
75+
parentElement.replaceChild(placeholderItems[index], srcElement);
6476
}
65-
newParent.insertAdjacentElement(position, srcElement);
66-
}
77+
destination.insertAdjacentElement(position, srcElement);
78+
79+
index += step;
80+
} while (--length > 0);
6781

68-
return function (): Element[] {
82+
return function (): T[] {
6983
return restoreChildren<T>(
7084
placeholderItems,
7185
srcElements,

packages/shared/test/reparent-children.test.ts

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -90,17 +90,16 @@ describe('Reparent Children', () => {
9090
) as HTMLDivElement;
9191

9292
expect(child.getAttribute('slot')).to.equal('slot');
93-
const restore = reparentChildren(
94-
[child],
95-
destination,
96-
(el: Element) => {
93+
const restore = reparentChildren([child], destination, {
94+
position: 'beforeend',
95+
prepareCallback: (el: Element) => {
9796
const slotName = el.slot;
9897
el.removeAttribute('slot');
9998
return (el: Element) => {
10099
el.slot = slotName;
101100
};
102-
}
103-
);
101+
},
102+
});
104103

105104
expect(child.hasAttribute('slot')).to.be.false;
106105

@@ -132,12 +131,9 @@ describe('Reparent Children', () => {
132131

133132
expect(source.children.length).to.equal(5);
134133
expect(destination.children.length).to.equal(1);
135-
const restore = reparentChildren(
136-
[...children],
137-
destination,
138-
null,
139-
'beforeend'
140-
);
134+
const restore = reparentChildren([...children], destination, {
135+
position: 'beforeend',
136+
});
141137

142138
expect(source.children.length).to.equal(0);
143139
expect(destination.children.length).to.equal(5 + 1);
@@ -179,12 +175,9 @@ describe('Reparent Children', () => {
179175

180176
expect(source.children.length).to.equal(5);
181177
expect(destination.children.length).to.equal(1);
182-
const restore = reparentChildren(
183-
[...children],
184-
destination,
185-
null,
186-
'afterbegin'
187-
);
178+
const restore = reparentChildren([...children], destination, {
179+
position: 'afterbegin',
180+
});
188181

189182
expect(source.children.length).to.equal(0);
190183
expect(destination.children.length).to.equal(5 + 1);
@@ -224,12 +217,9 @@ describe('Reparent Children', () => {
224217
) as HTMLDivElement;
225218

226219
expect(source.children.length).to.equal(5);
227-
const restore = reparentChildren(
228-
[...children],
229-
destination,
230-
null,
231-
'beforebegin'
232-
);
220+
const restore = reparentChildren([...children], destination, {
221+
position: 'beforebegin',
222+
});
233223

234224
expect(source.children.length).to.equal(0);
235225
expect(destination.children.length).to.equal(0);
@@ -274,12 +264,9 @@ describe('Reparent Children', () => {
274264
expect(marker.previousElementSibling).to.equal(destination);
275265
expect(marker.nextElementSibling).to.be.null;
276266

277-
const restore = reparentChildren(
278-
[...children],
279-
destination,
280-
null,
281-
'afterend'
282-
);
267+
const restore = reparentChildren([...children], destination, {
268+
position: 'afterend',
269+
});
283270

284271
expect(source.children.length).to.equal(0);
285272
expect(destination.children.length).to.equal(0);

0 commit comments

Comments
 (0)