2

我已经使用包含组件的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 道具会按预期工作。

4

2 回答 2

2

TL;DR由 theme-uisx转换为className

查看工作中的 CodeSandbox 演示,然后继续阅读。


文档中:

在底层,Theme UI 使用自定义的 pragma 注释,将主题感知sx道具转换为样式对象并将其传递给 Emotion 的jsx 函数。sxprop 仅适用于在文件顶部定义了自定义 pragma 的模块,它替换了默认的 React 函数jsx。这意味着您可以控制应用程序中的哪些模块选择使用此功能,而无需 Babel 插件或其他配置。这旨在完全替代 Emotion 自定义 JSX 编译指示。

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

因此,首先需要在文件顶部添加 pragma 注释,并导入正确的jsx函数:

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

prop 没有传递给sx组件,它实际上被转换为 CSS,并且 aclassName是自动生成的并应用于组件。

传下去className

因此,如果您希望父组件Button通过sxprop 将自定义样式应用到组件,则需要将 prop 向下传递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内容。className我一直在专业地从事一个使用主题 UI 的大型项目,除了传递向下自动合并样式之外,我们从来不需要任何其他东西。

于 2021-05-07T01:15:17.480 回答
1

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

于 2020-06-24T10:12:57.200 回答