Опора 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) и передавать ее дочернему элементу.

Другие вопросы по тегам