Skip to content

Commit

Permalink
feat: clone react element
Browse files Browse the repository at this point in the history
  • Loading branch information
Col0ring committed Oct 8, 2024
1 parent d874a4f commit 093404a
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 23 deletions.
2 changes: 1 addition & 1 deletion frontend/antd/float-button/group/float-button.group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ export const FloatButtonGroup = sveltify<
['icon', 'closeIcon', 'description', 'tooltip', 'badge.count']
>(({ children, slots, style, shape = 'circle', className, ...props }) => {
const { token } = theme.useToken();
const [slotsChildren, restChildren] = useSlotsChildren(children);

const [slotsChildren, restChildren] = useSlotsChildren(children);
return (
<>
<div style={{ display: 'none' }}>{slotsChildren}</div>
Expand Down
1 change: 0 additions & 1 deletion frontend/antd/icon/icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export const Icon = sveltify<
const icon = icons[name as keyof typeof icons] as React.ComponentType<
GetProps<typeof icons.default>
>;

return (
<>
{icon ? (
Expand Down
20 changes: 13 additions & 7 deletions frontend/antd/icon/iconfont-provider/Index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,19 @@
// gradio properties
export let visible = true;
const [mergedProps, update] = getSlotContext({
props: $updatedProps,
_internal,
visible,
as_item,
restProps: $$restProps,
});
const [mergedProps, update] = getSlotContext(
{
props: $updatedProps,
_internal,
visible,
as_item,
restProps: $$restProps,
},
undefined,
{
shouldRestSlotKey: false,
}
);
$: update({
props: $updatedProps,
_internal,
Expand Down
4 changes: 4 additions & 0 deletions frontend/fixtures.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ declare module '*?inline' {
interface Window {
__gradio_space__: any;
}

interface Element {
_reactElement: React.ReactElement;
}
11 changes: 7 additions & 4 deletions frontend/svelte-preprocess-react/internal/Bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const Bridge: React.FC<BridgeProps> = ({ createPortal, node }) => {
key: `bridge${subnode.key}`,
createPortal,
node: subnode,
// slotKey
nodeSlotKey: subSlotKeys[i],
})
);
Expand All @@ -81,12 +82,14 @@ const Bridge: React.FC<BridgeProps> = ({ createPortal, node }) => {
);
}
}

// render in different container
return createPortal(
const element =
children === undefined
? React.createElement(node.reactComponent, props)
: React.createElement(node.reactComponent, props, children),
target
);
: React.createElement(node.reactComponent, props, ...children);
target._reactElement = element;

return createPortal(element, target);
};
export default Bridge;
62 changes: 52 additions & 10 deletions frontend/svelte-preprocess-react/react-slot.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { forwardRef, useEffect, useRef } from 'react';
import React, { forwardRef, useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { styleObject2HtmlStyle } from '@utils/styleObject2String';

export interface ReactSlotProps {
Expand All @@ -9,7 +10,33 @@ export interface ReactSlotProps {
}

function cloneElementWithEvents(element: HTMLElement) {
const clonedElement = element.cloneNode(true) as HTMLElement;
const portals: React.ReactPortal[] = [];

const clonedElement = element.cloneNode(false) as HTMLElement;

if (element._reactElement) {
portals.push(
createPortal(
React.cloneElement(element._reactElement, {
...element._reactElement.props,
children: React.Children.toArray(
element._reactElement.props.children
).map((child) => {
// get svelte-slot
if (React.isValidElement(child) && child.props.__slot__) {
return child;
}
return null;
}),
}),
clonedElement
)
);
return {
clonedElement,
portals,
};
}
// clone eventListener
Object.keys(element.getEventListeners()).forEach((eventName) => {
const listeners = element.getEventListeners(
Expand All @@ -20,14 +47,21 @@ function cloneElementWithEvents(element: HTMLElement) {
});
});
const elementsChildrenArray = Array.from(element.children);

for (let i = 0; i < elementsChildrenArray.length; i++) {
const child = elementsChildrenArray[i];

const clonedChild = cloneElementWithEvents(child as HTMLElement);
clonedElement.replaceChild(clonedChild, clonedElement.children[i]);
const { clonedElement: clonedChild, portals: portalsChildren } =
cloneElementWithEvents(child as HTMLElement);
portals.push(...portalsChildren);
clonedElement.appendChild(clonedChild);
// clonedElement.replaceChild(clonedChild, clonedElement.children[i]);
}

return clonedElement;
return {
clonedElement,
portals,
};
}

function mountElRef(elRef: React.ForwardedRef<HTMLElement>, el: HTMLElement) {
Expand All @@ -44,6 +78,7 @@ function mountElRef(elRef: React.ForwardedRef<HTMLElement>, el: HTMLElement) {
export const ReactSlot = forwardRef<HTMLElement, ReactSlotProps>(
({ slot, clone, className, style }, elRef) => {
const ref = useRef<HTMLElement>();
const [children, setChildren] = useState<React.ReactElement[]>([]);
useEffect(() => {
if (!ref.current || !slot) {
return;
Expand Down Expand Up @@ -82,7 +117,9 @@ export const ReactSlot = forwardRef<HTMLElement, ReactSlotProps>(
let observer: MutationObserver | null = null;
if (clone && window.MutationObserver) {
function render() {
cloned = cloneElementWithEvents(slot);
const { portals, clonedElement } = cloneElementWithEvents(slot);
cloned = clonedElement;
setChildren(portals);
cloned.style.display = 'contents';
mountElementProps();
ref.current?.appendChild(cloned);
Expand Down Expand Up @@ -115,9 +152,14 @@ export const ReactSlot = forwardRef<HTMLElement, ReactSlotProps>(
observer?.disconnect();
};
}, [slot, clone, className, style, elRef]);
return React.createElement('react-child', {
ref,
style: { display: 'contents' },
});

return React.createElement(
'react-child',
{
ref,
style: { display: 'contents' },
},
...children
);
}
);

0 comments on commit 093404a

Please sign in to comment.