|
1 | | -import React from 'react'; |
| 1 | +import React, { PropsWithChildren } from 'react'; |
2 | 2 | import { |
3 | 3 | attr, |
4 | 4 | children, |
@@ -59,7 +59,7 @@ function create_fragment(ctx) { |
59 | 59 | function instance($$self, $$props, $$invalidate) { |
60 | 60 | let { id } = $$props; |
61 | 61 |
|
62 | | - $$self.$$set = $$props => { |
| 62 | + $$self.$$set = ($$props) => { |
63 | 63 | if ('id' in $$props) $$invalidate(0, (id = $$props.id)); |
64 | 64 | }; |
65 | 65 |
|
@@ -114,55 +114,73 @@ function createSlot(id) { |
114 | 114 | } |
115 | 115 |
|
116 | 116 | export function createReactComponent(name: string, SvelteComponent$$: any) { |
117 | | - let ReactComponent$$ = function ReactComponent(props) { |
118 | | - const rootRef = React.useRef<HTMLDivElement>(null); |
| 117 | + let ReactComponent$$ = function ReactComponent( |
| 118 | + props: PropsWithChildren<unknown>, |
| 119 | + ) { |
119 | 120 | const svelteComponentRef = React.useRef<any>(); |
| 121 | + const [svelteMountTarget, setSvelteMountTarget] = |
| 122 | + React.useState<HTMLElement | null>(null); |
| 123 | + const onRefChange = React.useCallback(setSvelteMountTarget, [ |
| 124 | + setSvelteMountTarget, |
| 125 | + ]); |
120 | 126 | const [mounted, setMounted] = React.useState(false); |
121 | 127 | const id = React.useId(); |
| 128 | + const slotId = `${id}-slot`; |
122 | 129 | const events = getEvents(props); |
123 | 130 | const { children, ...svelteProps } = props; |
124 | 131 |
|
125 | 132 | React.useEffect(() => { |
126 | | - const defaultSlot = createSlot(id); |
127 | | - let component = new SvelteComponent$$({ |
128 | | - target: rootRef.current, |
129 | | - props: { |
130 | | - ...svelteProps, |
131 | | - $$slots: { |
132 | | - default: [defaultSlot], |
| 133 | + if (svelteMountTarget) { |
| 134 | + const defaultSlot = createSlot(id); |
| 135 | + |
| 136 | + svelteComponentRef.current = new SvelteComponent$$({ |
| 137 | + target: svelteMountTarget, |
| 138 | + props: { |
| 139 | + ...svelteProps, |
| 140 | + $$slots: { |
| 141 | + default: [defaultSlot], |
| 142 | + }, |
| 143 | + $$scope: {}, |
133 | 144 | }, |
134 | | - $$scope: {}, |
135 | | - }, |
136 | | - hydrate: true, |
137 | | - }); |
138 | | - setMounted(true); |
139 | | - svelteComponentRef.current = component; |
| 145 | + hydrate: true, |
| 146 | + }); |
140 | 147 |
|
141 | | - for (const [event, handler] of events) { |
142 | | - component.$on(event, handler); |
143 | | - } |
| 148 | + setMounted(true); |
144 | 149 |
|
145 | | - return () => { |
146 | | - component.$destroy(); |
147 | | - }; |
148 | | - }, []); |
| 150 | + for (const [event, handler] of events) { |
| 151 | + svelteComponentRef.current.$on(event, handler); |
| 152 | + } |
| 153 | + |
| 154 | + return () => { |
| 155 | + svelteComponentRef.current.$destroy(); |
| 156 | + setMounted(false); |
| 157 | + }; |
| 158 | + } |
| 159 | + }, [svelteMountTarget]); |
149 | 160 |
|
150 | 161 | React.useEffect(() => { |
151 | 162 | React.startTransition(() => { |
152 | | - svelteComponentRef.current!.$set(props); |
| 163 | + svelteComponentRef.current?.$set(svelteProps); |
153 | 164 | }); |
154 | | - }, [props]); |
| 165 | + }, [svelteProps]); |
155 | 166 |
|
156 | 167 | return ( |
157 | 168 | <> |
158 | 169 | <div |
159 | | - ref={rootRef} |
| 170 | + key={id} |
| 171 | + ref={onRefChange} |
160 | 172 | style={{ display: 'contents' }} |
161 | 173 | dangerouslySetInnerHTML={{ __html: '' }} |
162 | 174 | /> |
163 | 175 | {mounted && |
164 | 176 | children && |
165 | | - ReactDOM.createPortal(children, document.getElementById(id))} |
| 177 | + ReactDOM.createPortal( |
| 178 | + children, |
| 179 | + svelteComponentRef.current.$$.root.querySelector( |
| 180 | + `[id='${slotId}']`, |
| 181 | + ), |
| 182 | + slotId, |
| 183 | + )} |
166 | 184 | </> |
167 | 185 | ); |
168 | 186 | }; |
|
0 commit comments