Опора sx UI темы игнорируется при импорте компонента сборника рассказов
Я установил и опубликовал на частном сервере систему дизайна StoryBook с использованием ThemeUI, которая содержит компоненты. Одним из таких компонентов является кнопка, показанная ниже.
import React, { FC } from "react";
import { Button as ButtonUI, SxStyleProp } from "theme-ui";
export const Button: FC<ButtonProps> = ({ onClick, children, variant, sx, disabled, onMouseOver, onMouseOut }) => {
return (
<ButtonUI
disabled={disabled || false}
variant={variant || "primary"}
onClick={onClick}
sx={{...sx}}
onMouseOver={onMouseOver || (() => {})}
onMouseOut={onMouseOut || (() => {})}
>
{children}
</ButtonUI>
);
};
export type ButtonProps = {
/**
* The action to perform when the button is clicked
*/
onClick: () => void;
/**
* The contents of the button
*/
children?: any;
/**
* The type of button
*/
variant?: string;
/**
* custom styles for the button
*/
sx?: SxStyleProp;
/**
* If the button is disabled
*/
disabled?: boolean;
/**
* The action to perform if the mouse moves over the button
*/
onMouseOver?: () => void;
/**
* The action to perform if the mouse moves off the button
*/
onMouseOut?: () => void;
};
Button.defaultProps = {
variant: "primary",
disabled: false
};
Когда я импортирую этот компонент в свое приложение React в отдельном проекте, компонент отображается, но все свойства в опоре sx игнорируются...
/** @jsx jsx */
import { Flex, jsx } from "theme-ui";
import Modal from "../Modal";
import { Button } from "<<<PRIVATE SERVER>>>";
/**
* Renders a popup the gives the player the option to logout
* @param title the heading of the modal
* @param confirmString the text for the confirm button
* @param cancelString the text for the cancel button
* @param confirmAction the action to perform when the user confirms
* @param cancelAction the action to perform when the user cancels
*/
export default function LogoutModal({ title, confirmString, cancelString, confirmAction, cancelAction }: Props) {
return (
<Modal
title={title}
closeAction={cancelAction}
children={
<Flex>
<Button
onClick={confirmAction}
sx={{
mr: 1
}}
variant="negative">{confirmString}</Button>
<Button
onClick={cancelAction}
sx={{
ml: 1
}}
variant="secondary">{cancelString}</Button>
</Flex>
}
/>
);
}
interface Props {
title: string;
confirmString: string;
cancelString: string;
confirmAction: () => void;
cancelAction: () => void;
}
Итак, кнопка отображается, но без применимого поля (или любых других стилей, которые я добавляю в опоре sx. Кто-нибудь знает, почему это так?
Интересно, что если я вызываю компонент где-то еще в Storybook (а не при импорте в отдельный проект), опора sx работает должным образом.
3 ответа
Хорошо, получается, если вам нужно изменить имя свойства, переданного в компонент, или тема ui выглядит запутанной. Итак, я сделал следующее изменение (изменил sx на csx):
export const Button: FC<ButtonProps> = ({ onClick, children, variant, csx, disabled, onMouseOver, onMouseOut }) => {
return (
<ButtonUI
disabled={disabled || false}
variant={variant || "primary"}
onClick={onClick}
sx={{...csx}}
onMouseOver={onMouseOver || (() => {})}
onMouseOut={onMouseOut || (() => {})}
>
{children}
</ButtonUI>
);
};
Затем, когда компонент вызывается, вы используете csx вместо sx.
TL;DR преобразуется в theme-ui
Из документации :
Под капотом Theme UI используется настраиваемый комментарий прагмы, который преобразует поддерживающую тему опору в объект стиля и передает его функциям Emotion. Опора работает только в модулях, которые определили специальную директиву в верхней части файла, которая заменяет функции React по умолчанию. Это означает, что вы можете контролировать, какие модули в вашем приложении выбирают эту функцию, без необходимости использования плагина Babel или дополнительной настройки. Это задумано как полная замена пользовательской прагмы JSX Emotion.
Итак, сначала нужно разместить комментарий прагмы вверху файла и импортировать правый
jsx
функция:
/** @jsx jsx */
import { jsx, Button as ButtonUI, SxStyleProp } from 'theme-ui';
Свойство не передается компоненту, оно фактически преобразуется в CSS, а имя класса автоматически создается и применяется к компоненту.
Итак, если вы хотите, чтобы родительский компонент применял собственный стиль к
Button
компонент через
sx
опора, вам нужно передать
className
опора
export const Button: FC<ButtonProps> = ({
onClick,
children,
variant,
// This does nothing...
// sx,
disabled,
onMouseOver,
onMouseOut,
// Make sure to pass the className down to the button.
className,
}) => (
<ButtonUI
className={className}
disabled={disabled || false}
variant={variant || 'primary'}
onClick={onClick}
onMouseOver={onMouseOver || (() => {})}
onMouseOut={onMouseOut || (() => {})}
>
{children}
</ButtonUI>
);
Общепринятый ответ работает должным образом , и это путь для решения этой проблемы.
Я пишу это, чтобы пролить свет на то, почему передача свойства className вашему дочернему компоненту не сработает.
const Parent = ({...props}) => <div {...props} sx={{
//some styles
}} > </div>
<Parent
sx={{
//some customer style
}} />
Вышеупомянутая опора sx не будет передана, так как она будет преобразована в className с помощью theme-ui.
Передача свойства className дочернему компоненту не будет иметь никакого эффекта, поскольку он также имеет свойство sx, которое будет преобразовано в другое имя класса.
Итак, лучший подход - иметь настраиваемую опору (например, csx) и передавать ее дочернему элементу.