Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 6 additions & 40 deletions packages/@react-aria/collections/src/Hidden.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
*/

import {forwardRefType} from '@react-types/shared';
import React, {Context, createContext, forwardRef, JSX, ReactElement, ReactNode, useContext, useRef} from 'react';
import {useLayoutEffect} from '@react-aria/utils';
import React, {Context, createContext, forwardRef, JSX, ReactElement, ReactNode, useContext} from 'react';

// React doesn't understand the <template> element, which doesn't have children like a normal element.
// It will throw an error during hydration when it expects the firstChild to contain content rendered
Expand All @@ -21,56 +20,35 @@ import {useLayoutEffect} from '@react-aria/utils';
// does the same for appendChild/removeChild/insertBefore as per the issue below
// See https://github.com/facebook/react/issues/19932
if (typeof HTMLTemplateElement !== 'undefined') {
const getFirstChild = Object.getOwnPropertyDescriptor(Node.prototype, 'firstChild')!.get!;
const originalAppendChild = Object.getOwnPropertyDescriptor(Node.prototype, 'appendChild')!.value!;
const originalRemoveChild = Object.getOwnPropertyDescriptor(Node.prototype, 'removeChild')!.value!;
const originalInsertBefore = Object.getOwnPropertyDescriptor(Node.prototype, 'insertBefore')!.value!;

Object.defineProperty(HTMLTemplateElement.prototype, 'firstChild', {
configurable: true,
enumerable: true,
get: function () {
if (this.dataset.reactAriaHidden) {
return this.content.firstChild;
} else {
return getFirstChild.call(this);
}
return this.content.firstChild;
}
});

Object.defineProperty(HTMLTemplateElement.prototype, 'appendChild', {
configurable: true,
enumerable: true,
value: function (node) {
if (this.dataset.reactAriaHidden) {
return this.content.appendChild(node);
} else {
return originalAppendChild.call(this, node);
}
return this.content.appendChild(node);
}
});

Object.defineProperty(HTMLTemplateElement.prototype, 'removeChild', {
configurable: true,
enumerable: true,
value: function (node) {
if (this.dataset.reactAriaHidden) {
return this.content.removeChild(node);
} else {
return originalRemoveChild.call(this, node);
}
return this.content.removeChild(node);
}
});

Object.defineProperty(HTMLTemplateElement.prototype, 'insertBefore', {
configurable: true,
enumerable: true,
value: function (node, child) {
if (this.dataset.reactAriaHidden) {
return this.content.insertBefore(node, child);
} else {
return originalInsertBefore.call(this, node, child);
}
return this.content.insertBefore(node, child);
}
});
}
Expand All @@ -79,18 +57,6 @@ export const HiddenContext: Context<boolean> = createContext<boolean>(false);

export function Hidden(props: {children: ReactNode}): JSX.Element {
let isHidden = useContext(HiddenContext);
let templateRef = useRef<HTMLTemplateElement>(null);
// somehow React might add children to the template and we never hit the reactAriaHidden parts of the above overrides
// so we need to move those children into the content of the template since templates can't have direct children
useLayoutEffect(() => {
let el = templateRef.current;
if (!el?.dataset.reactAriaHidden) {
return;
}
while (el.childNodes.length > 0) {
el.content.appendChild(el.childNodes[0]);
}
}, []);

if (isHidden) {
// Don't hide again if we are already hidden.
Expand All @@ -106,7 +72,7 @@ export function Hidden(props: {children: ReactNode}): JSX.Element {
// In SSR, portals are not supported by React. Instead, always render into a <template>
// element, which the browser will never display to the user. In addition, the
// content is not part of the accessible DOM tree, so it won't affect ids or other accessibility attributes.
return <template ref={templateRef} data-react-aria-hidden>{children}</template>;
return <template>{children}</template>;
}

/** Creates a component that forwards its ref and returns null if it is in a hidden subtree. */
Expand Down