导入故事书组件时忽略主题 UI sx 属性

Theme UI sx prop ignored when importing a storybook component

我已经使用包含组件的 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 prop 中的所有属性都被忽略...

/** @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 prop 会按预期工作。

好的,如果您需要更改传递到组件中的 属性 的名称,那么 themeui 似乎会变得混乱。所以我做了以下更改(将 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 sx 被主题-ui

转换为 className

查看 working CodeSandbox demo,然后继续阅读。


来自documentation:

Under the hood, Theme UI uses a custom pragma comment that converts a theme-aware sx prop into a style object and passes it to Emotion's jsx functions. The sx prop only works in modules that have defined a custom pragma at the top of the file, which replaces the default React jsx functions. This means you can control which modules in your application opt into this feature without the need for a Babel plugin or additional configuration. This is intended as a complete replacement for the Emotion custom JSX pragma.

对每个文件使用 pragma

所以首先需要在文件顶部有pragma注释,并导入正确的jsx函数:

/** @jsx jsx */
import { jsx, Button as ButtonUI, SxStyleProp } from 'theme-ui';

sx 属性没有传递给组件,它实际上被转换为 CSS 并且 className 被自动生成并应用到组件。

传下去className

因此,如果您希望父组件通过 sx 属性将自定义样式应用于 Button 组件,则需要传递 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, // or ...props
}) => (
  <ButtonUI
    className={className}
    // {...props} // if you want any other props
    sx={{ /* any other style can be applied here as well */ }}

    disabled={disabled || false}
    variant={variant || 'primary'}
    onClick={onClick}
    onMouseOver={onMouseOver || (() => {})}
    onMouseOut={onMouseOut || (() => {})}
  >
    {children}
  </ButtonUI>
);

个人建议不要使用某种骇客手段来传递sx内容。我一直在专业地从事一个使用 theme-ui 的大型项目,除了传递 className 以自动合并样式之外,我们从来不需要任何其他东西。