Lo descubrí y publiqué la respuesta a continuación.
Estoy tratando de crear una aplicación web completamente compartimentada dentro de un shadow-dom y he estado usando componentes Antd y me encontré con el problema en el que Antd está agregando opciones desplegables en la etiqueta del cuerpo en lugar de como un elemento secundario de la elemento en el que se está renderizando React.
Para aislar este problema, eliminé todo fuera de React.render y un solo elemento Antd que aún hace lo mismo.
Luego usé un componente diferente, "react-date-picker", que funciona como esperaba que lo hiciera Antd, donde el componente se muestra como un elemento secundario del div especificado para reaccionar.
Desafortunadamente, la representación de Antd en el cuerpo del HTML en lugar de como un elemento secundario hace que el uso de shadow-root no tenga sentido.
Esencialmente, mi pregunta es:
¿Es esta la funcionalidad normal de Antd? Si no, ¿qué podría estar arruinando para que esto suceda? Si es así, ¿hay una opción integrada de Antd que me falta y que representará las opciones de Antd como elementos secundarios? Si esa opción no existe dentro de sus bibliotecas, ¿hay alguna forma de obligar a Antd a renderizarse como un elemento secundario de mi nodo shadow-root?
Esto es lo que estoy usando para representar el componente Antd DatePicker:
import ReactDOM from 'react-dom';
import React from 'react';
import DatePicker from 'antd/lib/date-picker';
ReactDOM.render(<DatePicker/>, document.getElementById('entry-fields'));
Antes de hacer clic en el selector de fecha Antd:
Después de hacer clic en él, las opciones desplegables se agregan a <body>
y no a <div id="entry-fields>
:
Esto es lo que estoy usando para representar el componente selector de fecha de reacción para demostrar la funcionalidad que esperaba/necesitaba:
import ReactDOM from 'react-dom';
import React from 'react';
import DatePicker from "react-datepicker";
class Example extends React.Component {
state = {
startDate: new Date()
};
handleChange = (date: any) => {
this.setState({
startDate: date
});
};
render() {
return (
<DatePicker
selected={this.state.startDate}
onChange={this.handleChange}
/>
);
}
}
ReactDOM.render(<Example/>, document.getElementById('entry-fields'));
Antes de hacer clic en el selector de fecha del selector de fecha de reacción:
Después de hacer clic en el selector de fecha del selector de fecha de reacción (las opciones desplegables se agregan a medida que se representan los elementos secundarios del elemento en el que reacciona):
Básicamente, esperaba que Antd presentara sus opciones encapsuladas dentro del React representado en <div></div>
pero, en cambio, está agregando elementos en <body></body>
.
Tengo relativamente poca experiencia en el dominio de desarrollo web y he recurrido a hacer una pregunta aquí después de demasiado tiempo tratando de encontrar la respuesta por mi cuenta. Me estoy sintiendo extremadamente frustrado en el desarrollo web en general, donde cualquier pregunta parece generar cientos de publicaciones de blog medianas e irrelevantes que no son útiles en ninguna capacidad... suponiendo que no sea solo que yo no sepa qué buscar para encontrar las respuestas. Necesito que muy bien podría ser el caso.
Realmente agradezco cualquier ayuda por adelantado.
- Charles
SourceNo estoy seguro de cómo me las arreglé para pasar por alto esto, pero Antd tiene un parámetro llamado "getCalendarContainer" que, si se deja en blanco, generará opciones en el cuerpo del documento, pero si se proporciona con los parámetros correctos, los elementos secundarios se mostrarán en el contenedor de su elegir.
Saliendo de este ejemplo: https://react-component.github. io/calendar/examples/getCalendarContainer.html
Lo hice funcionar agregando esta función a mi componente:
getCalendarContainer()
{
return this.d || document.getElementById('calendarContainer');
}
y agregando esto al componente en JSX:
<div id="calendarContainer" ref={n => (this.d = n as HTMLDivElement)} >
<DatePicker onChange={EntryFields.onDateChange} getCalendarContainer={this.getCalendarContainer}/>
</div>
e inicializando la etiqueta div para hacer referencia a ella en el constructor del componente de esta manera:
private d: HTMLDivElement;
constructor(props: any)
{
super(props);
this.d = document.createElement("div");
...
También vale la pena señalar que lo anterior no funcionará de inmediato al usar shadow-DOM, ya que necesita acceder al nodo del que shadow-DOM es un elemento secundario y luego usar getElementById().
Algo así (pero probablemente mejor escrito, espero lol)
getContainer() {
let elem = null;
let shadowContainer = document.getElementById('entryFieldsShadow') as HTMLInputElement;
if (shadowContainer != null) {
let shadowDom = shadowContainer.firstElementChild;
if (shadowDom != null) {
let shadowRoot = shadowDom.shadowRoot;
if (shadowRoot != null) {
elem = shadowRoot.getElementById("entryFieldsContainer")
}
}
}
return elem || this.d;
}
donde se incluye el JSX con shadow root de react-shadow se ve así:
return (
<div id="entryFieldsShadow">
<root.div>
<div>
<div id="entryFieldsContainer"/>
<style type="text/css"> @import "static/1.css"; </style>
<Layout>
<Content>
{this.RowCols()}
</Content>
</Layout>
</div>
</root.div>
</div>
)