En styled-components podemos agregar estilos contextuales usando el patrón selector de componentes . Pero, ¿cómo seleccionamos variantes de padres específicas para diseñar contextualmente el componente secundario? Por ejemplo, aquí tenemos tres componentes, Child , NoteWrapper y Note .
const Child = styled.div<{ editing?: boolean }>` ${props => props.editing && css`some styles`} ` const NoteWrapper = styled.div<{ compact?: boolean }>` ${props => props.compact && css`some styles`} ` const Note = styled.input` /* How do I style this when Child is editing and NoteWrapper is compact */ ` const App = () => { return ( <Child editing> <NoteWrapper compact> <Note/> </NoteWrapper> </Child> ) } `Con CSS simple podríamos hacer algo como esto
.child.editing .note-wrapper.compact .note { /* Contextual styles here */ } Sé que puedo usar fácilmente las variables de editing y compact y pasarlas al componente Note . Sin embargo, sería difícil hacerlo si los componentes están muy anidados.
Mi pregunta es ¿cómo puedo aplicar estilo a Note cuando Child está editing y NoteWrapper es compact en el patrón selector styled-components ?
No creo que podamos hacer algo como esto en styled-components alguna manera. ¿Podemos?
const Note = styled.input` ${Child.editingClass} ${NoteWrapper.compactClass} & { /* The contextual styles here*/ } `Hasta donde yo sé, no puede acceder a editing o compact , ya que son accesorios y no se "propagan" en CSS. Pero puede lograr el mismo resultado utilizando clases o atributos de datos.
Así es como lo haría:
const App = () => { return ( <Child data-editing={true}> <NoteWrapper data-compact={true}> <Note/> </NoteWrapper> </Child> ) } const Child = styled.div` ` const NoteWrapper = styled.div` ` const Note = styled.input` ${Child}[data-editing="true"] ${NoteWrapper}[data-compact="true"] & { /* Only applied when Child is editing and NoteWrapper is compact */ color: red; } ` Esencialmente, los componentes con estilo deben producir CSS válido al final del día. ${Child} será reemplazado por el nombre de clase generado de forma personalizada, como .sc-abc123 . Y así, el resultado final es .sc-abc123[data-editing="true"] , que es CSS totalmente válido.
También podría usar clases, que se ve un poco más ordenado:
const App = () => { return ( <Child className="editing"> <NoteWrapper className="compact"> <Note/> </NoteWrapper> </Child> ) } const Child = styled.div` ` const NoteWrapper = styled.div` ` const Note = styled.input` ${Child}.editing ${NoteWrapper}.compact & { /* Only applied when Child is editing and NoteWrapper is compact */ color: red; } ` Prefiero usar atributos de datos porque está claro que se usan con fines lógicos y no porque editing sea una clase CSS con muchos estilos. Pero esa es una preferencia subjetiva, ambos funcionan igual de bien en términos de funcionalidad objetiva :)
También puede pasar los accesorios al componente Note y hacer una verificación lógica similar.
<Note compactEdit={editing && compact} /> const Note = styled.div` ${props => props.compactEdit ? css`color: red;` : css`color: blue;` }; `;