support css selectors on the client

portals
Simon Holthausen 11 months ago
parent 1d40d3f237
commit ae62c7c84b

@ -1,7 +1,7 @@
/** @import { TemplateNode } from '#client' */
import { HYDRATION_END, HYDRATION_START, HYDRATION_START_ELSE } from '../../../../constants.js';
import { block, remove_nodes, render_effect } from '../../reactivity/effects.js';
import { hydrate_node, hydrating, set_hydrate_node } from '../hydration.js';
import { hydrate_node, hydrating, set_hydrate_node, set_hydrating } from '../hydration.js';
import { get_next_sibling } from '../operations.js';
const portals = new Map();
@ -44,18 +44,29 @@ export function portal_outlet(node, id) {
* @returns {void}
*/
export function portal(target, content) {
const is_css_selector = typeof target === 'string';
const portal = portals.get(target);
if (!portal)
let previous_hydrating = false;
let previous_hydrate_node = null;
// TODO right now the portal is rendered before the given anchor. Is that confusing for people and they'd rather have it as
// the first child _inside_ the anchor if the anchor is an element?
var anchor = is_css_selector ? document.querySelector(target) : portal?.anchor;
if (!anchor)
throw new Error(
'TODO error code: No portal found for given target. Make sure portal target exists before referencing it'
);
let previous_hydrate_node = null;
var anchor = portal.anchor;
if (hydrating) {
previous_hydrate_node = hydrate_node;
set_hydrate_node((anchor = /** @type {TemplateNode} */ (get_next_sibling(portal.anchor))));
previous_hydrating = true;
if (is_css_selector) {
// These are not SSR'd, so temporarily disable hydration to properly insert them
set_hydrating(false);
} else {
previous_hydrate_node = hydrate_node;
set_hydrate_node((anchor = /** @type {TemplateNode} */ (get_next_sibling(portal.anchor))));
}
}
const effect = block(() => {
@ -69,8 +80,12 @@ export function portal(target, content) {
};
});
if (hydrating) {
portal.anchor = hydrate_node; // so that next head block starts from the correct node
set_hydrate_node(/** @type {TemplateNode} */ (previous_hydrate_node));
if (previous_hydrating) {
if (is_css_selector) {
set_hydrating(true);
} else {
portal.anchor = hydrate_node; // so that next head block starts from the correct node
set_hydrate_node(/** @type {TemplateNode} */ (previous_hydrate_node));
}
}
}

@ -180,6 +180,10 @@ export function portal_outlet(payload, id) {
* @returns {void}
*/
export function portal(payload, target, content) {
payload.out += EMPTY_COMMENT;
if (typeof target === 'string') return; // targets a CSS selector - not possible in SSR, ignore
const portal = payload.portals.get(target);
if (!portal)
throw new Error(
@ -191,7 +195,6 @@ export function portal(payload, target, content) {
content(tmp_payload);
tmp_payload.out += EMPTY_COMMENT;
portal.content.push(tmp_payload.out);
payload.out += EMPTY_COMMENT;
}
/**

Loading…
Cancel
Save