【问题标题】:Theme UI sx prop ignored when importing a storybook component导入故事书组件时忽略主题 UI sx 属性
【发布时间】:2020-10-14 12:36:15
【问题描述】:

我已使用包含组件的 ThemeUI 设置并发布到私人服务器的 StoryBook 设计系统。如下所示的按钮就是这样一个组件。

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 属性会按预期工作。

【问题讨论】:

    标签: reactjs theme-ui


    【解决方案1】:

    TL;DR sx 通过 theme-ui 转换为 className

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


    来自documentation

    在后台,主题 UI 使用 custom pragma comment 将 主题感知 sx 道具到样式对象并将其传递给 Emotion 的 jsx 职能。 sx 属性仅适用于定义了 文件顶部的自定义编译指示,它替换了默认的 React jsx 函数。这意味着你可以控制你的哪些模块 应用程序无需 Babel 插件即可选择此功能 或附加配置。这是一个完整的 替换 Emotion 自定义 JSX 杂注。

    在每个文件上使用编译指示

    所以首先需要在文件顶部有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 内容向下传递。我一直在专业从事一个使用主题 UI 的大型项目,除了将 className 向下传递以自动合并样式之外,我们从来不需要其他任何东西。

    【讨论】:

    • 我将在一个测试项目中试一试。如果可行,我认为这是一个更优雅的解决方案。
    • @alasdair009 我添加了一个工作演示来证明我的观点。
    • 新的 theme-ui 版本的编译指示是:/** @jsxImportSource theme-ui */,感谢 EmileBergeron 为我提供了关于 theme-ui 如何在后台工作的概念上的清晰 :)
    【解决方案2】:

    好吧,事实证明,如果您需要更改传递给组件的属性名称,或者 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。

    【讨论】:

      猜你喜欢
      • 2021-05-12
      • 2022-01-22
      • 2021-03-14
      • 2019-12-30
      • 2021-12-31
      • 1970-01-01
      • 2021-11-01
      • 2021-11-23
      • 2019-12-06
      相关资源
      最近更新 更多