其他

全局配置

为组件提供统一的全局化配置。

使用场景

覆盖配置分为两种场景

  • 需要覆盖多个组件公有 Props 配置(例如 timezone、rtl),使用 ConfigProvider
  • 当 ConfigProvider 暴露参数未能满足,希望修改全局修改某个组件的 某类 Props(例如期望将所有Button的 theme 都配置为 solid 或所有 Popover的 position),使用 semiGlobal

ConfigProvider

ConfigProvider 借助 context 机制实现,因此它能影响 JSX 树中的子组件。ConfigProvider 与 ConfigConsumer 不渲染自己的元素(方向切换时才会多包一层带 dir 属性的 div),未声明的属性(class、style、ref 和原生属性)会被丢弃,不会落到 DOM 上。

代码演示

如何引入

import { ConfigProvider, ConfigConsumer, useConfig } from '@fibrous/semi-ui-solid';

基本用法

通过传入 timeZone 参数,用户可以为时间类组件配置时区:

Select Time Zone:




代码
import { For, createSignal } from 'solid-js';
import { ConfigProvider, Select, DatePicker, TimePicker } from '@fibrous/semi-ui-solid';

const defaultTimestamp = 1581599305265;

// Fractional offsets are written as fixed GMT strings; an IANA name is kept because it follows daylight saving time
const gmtList = [
    ...Array.from({ length: 26 }, (_, index) => {
        const hourOffset = index - 11;
        const prefix = hourOffset >= 0 ? '+' : '-';
        return `GMT${prefix}${String(Math.abs(hourOffset)).padStart(2, '0')}:00`;
    }),
    'GMT-03:30',
    'GMT+05:45',
    'GMT+13:45',
    'America/New_York',
];

export default function ConfigProviderDemo() {
    const [timeZone, setTimeZone] = createSignal('GMT+08:00');

    return (
        <ConfigProvider timeZone={timeZone()}>
            <div style={{ width: '300px' }}>
                <h5 style={{ margin: '10px' }}>Select Time Zone:</h5>
                <Select aria-label="时区" placeholder="请选择时区" style={{ width: '300px' }} value={timeZone()} showClear onSelect={(value) => setTimeZone(String(value))}>
                    <For each={gmtList}>{(gmt) => <Select.Option value={gmt}>{gmt}</Select.Option>}</For>
                </Select>
                <br />
                <br />
                <DatePicker type="dateTime" defaultValue={defaultTimestamp} onChange={(date, dateString) => console.log('DatePicker changed: ', date, dateString)} />
                <br />
                <br />
                <TimePicker defaultValue={defaultTimestamp} onChange={(date, dateString) => console.log('DatePicker changed: ', date, dateString)} />
            </div>
        </ConfigProvider>
    );
}

手动获取值

通常情况下,组件内部会自动获取 ConfigProvider 的值自动消费,无需关心。但是一些特殊场景,你可能需要手动获取值来进行其他操作。

使用 ConfigConsumer 的 children 函数获取 ConfigProvider 的值。函数只执行一次,读取字段时写作 config.xxx,不要解构。在子组件中也可以调用 useConfig(),它返回 Accessor<ContextValue>,调用访问器(config())才能读到当前值,没有 ConfigProvider 时为空对象。

{"direction":"ltr","timeZone":"GMT+08:00","responsiveObserve":false,"responsiveMap":{"xs":"(max-width: 575px)","sm":"(min-width: 576px)","md":"(min-width: 768px)","lg":"(min-width: 992px)","xl":"(min-width: 1200px)","xxl":"(min-width: 1600px)"},"screens":{"xs":false,"sm":false,"md":false,"lg":false,"xl":false,"xxl":false}}
代码
import { ConfigProvider, ConfigConsumer, Typography } from '@fibrous/semi-ui-solid';

export default function ConfigProviderDemo() {
    return (
        <ConfigProvider timeZone="GMT+08:00">
            {/*...*/}
            <ConfigConsumer>
                {(value) => (
                    <Typography.Text ellipsis={{ showTooltip: { opts: { style: { 'min-width': '1200px' } } } }} style={{ width: '600px' }}>
                        {JSON.stringify(value)}
                    </Typography.Text>
                )}
            </ConfigConsumer>
            {/*...*/}
        </ConfigProvider>
    );
}

响应式断点监听

ConfigProvider 支持配置响应式断点,并在断点变化时进行订阅回调。

开启监听与自定义断点

  • 通过 responsiveObserve 开启断点监听(建议只在确实需要订阅的场景开启)
  • 通过 responsiveMap 自定义断点(未传入时使用默认断点)
import { createSignal, onCleanup, onMount } from 'solid-js';
import { ConfigProvider, ConfigConsumer, Typography } from '@fibrous/semi-ui-solid';

function BreakpointSubscriber(props) {
    const [screens, setScreens] = createSignal(props.screens);

    onMount(() => {
        const unsubscribe = props.onBreakpoint?.((next) => setScreens(next));
        onCleanup(() => unsubscribe?.());
    });

    return <Typography.Text>{JSON.stringify(screens())}</Typography.Text>;
}

function Demo() {
    return (
        <ConfigProvider
            responsiveObserve
            responsiveMap={{
                xs: '(max-width: 575px)',
                sm: '(min-width: 576px)',
                md: '(min-width: 768px)',
                lg: '(min-width: 992px)',
                xl: '(min-width: 1200px)',
                xxl: '(min-width: 1600px)',
            }}
        >
            <ConfigConsumer>{(config) => <BreakpointSubscriber onBreakpoint={config.onBreakpoint} screens={config.screens} />}</ConfigConsumer>
        </ConfigProvider>
    );
}

订阅 API

onBreakpoint 支持两种签名,均会返回取消订阅函数:

  • onBreakpoint((screens) => void):回调拿到完整的 screens 映射
  • onBreakpoint(['md', 'lg'], (screen, match) => void):只监听指定断点,回调拿到单个断点变化

RTL/LTR

全局配置 direction 可以改变组件的文本方向。

rtl 表示从右到左 (类似希伯来语或阿拉伯语), ltr 表示从左到右 (类似中文、英语等大部分语言)。显式传入的 direction 与外层不同时(含最外层),ConfigProvider 会在内容外包一层带 dir 属性的 div。组件的 RTL 样式用 :dir(rtl) 匹配,跟随最近的祖先 dir 属性;弹层根元素按 ConfigProvider 的 direction 输出 dir。页面自己在 <html> 等元素上设置 dir="rtl" 时,页面内的组件样式按 RTL 显示,但键盘方向、弹层位置等逻辑只读 ConfigProvider 的 direction,ConfigProvider 内的弹层与 Table 也按它的 direction(默认 ltr)显示,因此仍需同时设置 direction="rtl"。

特殊组件:

  • Modal,Notification,Toast 的命令式调用需要通过 prop 传 direction。
  • 如果你想对有方向性的 Icon 做 RTL 国际化,需要自己单独进行处理。我们认为对 Icon 进行 RTL 会让它变得难以理解和维护。其他组件内的 icon Semi 已经做了 RTL 适配。
  • Table 的树形数据暂不支持 RTL(Chrome、Safari 浏览器表现与 Firefox 表现不同),固定列支持 RTL。

命令式调用(Modal.success()、Toast.info() 等)渲染在 ConfigProvider 之外,读不到它的方向,需要跟随方向时在选项里传 direction,或改用 Modal.useModal()、Toast.useToast()、Notification.useNotification(),它们返回的 Holder 组件渲染在哪里,就继承哪里的 ConfigProvider。

Buttons



Input





Prefix


Suffix


0/100


多选框
禁用的多选框
禁用的多选框










Navigation




Finished
This is a description.
2
In Progress
This is a description.
3
Waiting
This is a description.

Finished
This is a description
In Process
This is a description
3
Waiting
This is a description

Display

XZ5
YB5
LX5
YZ
HW
XM

grey tag
blue tag
ghost tag
solid tag
red tag
green tag
orange tag
teal tag
violet tag
white tag

I am Popover
I am Tooltip

  • 审核中
    2019-07-14 10:35
  • 发布成功
    2019-06-13 16:17
  • 审核失败
    2019-05-14 18:34

Feedback





I am loading...

Here are some texts.

And more texts on the way.

代码
import { createSignal, type JSX } from 'solid-js';
import { Dynamic } from 'solid-js/web';
import { IconCamera, IconChevronDown, IconEdit, IconList, IconSidebar, IconVigoLogo } from '@fibrous/semi-icons-solid';
import { ConfigProvider, ButtonGroup, Button, Row, Col, Notification, DatePicker, TimePicker, Timeline, Popover, Tag, Tooltip, Badge, Avatar, Steps, Pagination, Modal, Breadcrumb, Rating, Nav, Spin, Cascader, Radio, Select, Input, Typography, TextArea, Checkbox, Switch, Toast } from '@fibrous/semi-ui-solid';

const flexStyle: JSX.CSSProperties = { display: 'flex', 'margin-bottom': '32px', 'flex-wrap': 'wrap' };
const titleStyle: JSX.CSSProperties = { margin: '50px 0 16px 0' };
const rowStyle: JSX.CSSProperties = { margin: '16px 10px' };
const badgeStyle: JSX.CSSProperties = {
    width: '42px',
    height: '42px',
    'border-radius': '4px',
    display: 'inline-block',
};
const tagStyle: JSX.CSSProperties = { 'margin-right': '8px', 'margin-bottom': '8px' };
const buttonStyle: JSX.CSSProperties = { ...tagStyle };

const treeData = [
    {
        label: '浙江省',
        value: 'zhejiang',
        children: [
            {
                label: '杭州市',
                value: 'hangzhou',
                children: [
                    { label: '西湖区', value: 'xihu' },
                    { label: '萧山区', value: 'xiaoshan' },
                    { label: '临安区', value: 'linan' },
                ],
            },
            {
                label: '宁波市',
                value: 'ningbo',
                children: [
                    { label: '海曙区', value: 'haishu' },
                    { label: '江北区', value: 'jiangbei' },
                ],
            },
        ],
    },
];

export default function ConfigProviderDemo() {
    const [direction, setDirection] = createSignal<'ltr' | 'rtl'>();
    // Read at each call so a notification shows the direction selected at the time it is opened
    const opts = () => ({
        title: 'Hi,Bytedance',
        content: 'ies dance dance dance',
        duration: 3,
        direction: direction(),
    });
    const navItems = [
        { itemKey: 'user', text: 'Option1' },
        { itemKey: 'union', text: 'Option2' },
        {
            itemKey: 'approve-management',
            text: 'Group3',
            items: ['3-1', '3-2'],
        },
    ];
    const navIcons: Record<string, typeof IconEdit> = { user: IconEdit, union: IconCamera, 'approve-management': IconList };

    return (
        <div>
            <div style={{ 'margin-bottom': '20px' }}>
                <ButtonGroup>
                    <Button onClick={() => setDirection('ltr')}>LTR</Button>
                    <Button onClick={() => setDirection('rtl')}>RTL</Button>
                </ButtonGroup>
            </div>
            <ConfigProvider direction={direction()}>
                <Row>
                    <h3 style={titleStyle}>Buttons</h3>
                </Row>
                <Row style={rowStyle}>
                    <Button loading theme="solid" style={{ 'margin-right': '8px' }}>
                        加载
                    </Button>
                    <Button icon={<IconSidebar />} theme="solid" style={{ 'margin-right': '8px' }}>
                        收起
                    </Button>
                    <Button icon={<IconChevronDown />} theme="solid" iconPosition="right" style={{ 'margin-right': '8px' }}>
                        展开选项
                    </Button>
                    <br />
                    <br />
                    <ButtonGroup>
                        <Button>拷贝</Button>
                        <Button>查询</Button>
                        <Button>剪切</Button>
                    </ButtonGroup>
                </Row>
                <Row>
                    <h3 style={titleStyle}>Input</h3>
                </Row>
                <Row style={rowStyle} gutter={16}>
                    <Col span={12}>
                        <Input aria-label="输入框" placeholder="输入框" />
                        <br />
                        <br />
                        <Input aria-label="禁用的输入框" disabled placeholder="输入框" />
                        <br />
                        <br />
                        <Input aria-label="带前缀的输入框" prefix="Prefix" showClear />
                        <br />
                        <br />
                        <Input
                            aria-label="带后缀的输入框"
                            suffix={
                                <Typography.Text strong type="secondary" style={{ margin: '0 8px' }}>
                                    Suffix
                                </Typography.Text>
                            }
                            showClear
                        />
                        <br />
                        <br />
                        <TextArea aria-label="文本框" placeholder="文本框" maxCount={100} />
                        <br />
                        <br />
                        <div style={flexStyle}>
                            <Switch aria-label="已开启的开关" style={{ 'margin-right': '8px' }} defaultChecked />
                            <Switch aria-label="已关闭的开关" style={{ 'margin-right': '8px' }} />
                            <Switch aria-label="禁用的开关" disabled defaultChecked style={{ 'margin-right': '8px' }} />
                        </div>
                        <div style={flexStyle}>
                            <Checkbox style={{ 'margin-right': '8px' }} defaultChecked>
                                多选框
                            </Checkbox>
                            <Checkbox style={{ 'margin-right': '8px' }} disabled defaultChecked>
                                禁用的多选框
                            </Checkbox>
                            <Checkbox style={{ 'margin-right': '8px' }} disabled>
                                禁用的多选框
                            </Checkbox>
                        </div>
                        <div style={{ ...flexStyle, 'margin-bottom': '0' }}>
                            <Radio style={{ 'margin-right': '8px' }} defaultChecked>
                                单选框
                            </Radio>
                            <Radio style={{ 'margin-right': '8px' }} disabled defaultChecked>
                                禁用的单选框
                            </Radio>
                            <Radio style={{ 'margin-right': '8px' }} disabled>
                                禁用的单选框
                            </Radio>
                        </div>
                    </Col>
                    <Col span={12}>
                        <DatePicker onChange={(_date, dateString) => console.log(dateString)} style={{ width: '100%' }} />
                        <br />
                        <br />
                        <TimePicker style={{ width: '100%' }} />
                        <br />
                        <br />
                        <Select aria-label="选择器-单选" style={{ width: '100%' }} placeholder="选择器-单选">
                            <Select.Option value="abc">抖音</Select.Option>
                            <Select.Option value="hotsoon">火山</Select.Option>
                            <Select.Option value="pipixia" disabled>
                                皮皮虾
                            </Select.Option>
                            <Select.Option value="xigua">西瓜视频</Select.Option>
                        </Select>
                        <br />
                        <br />
                        <Select aria-label="选择器-禁用" disabled style={{ width: '100%' }} placeholder="选择器-禁用">
                            <Select.Option value="abc">抖音</Select.Option>
                            <Select.Option value="hotsoon">火山</Select.Option>
                            <Select.Option value="pipixia" disabled>
                                皮皮虾
                            </Select.Option>
                            <Select.Option value="xigua">西瓜视频</Select.Option>
                        </Select>
                        <br />
                        <br />
                        <Select aria-label="选择器-多选" multiple style={{ width: '100%' }} placeholder="选择器-多选">
                            <Select.Option value="abc">抖音</Select.Option>
                            <Select.Option value="hotsoon">火山</Select.Option>
                            <Select.Option value="pipixia" disabled>
                                皮皮虾
                            </Select.Option>
                            <Select.Option value="xigua">西瓜视频</Select.Option>
                        </Select>
                        <br />
                        <br />
                        <Cascader style={{ width: '100%' }} treeData={treeData} placeholder="级联选择器" />
                    </Col>
                </Row>
                <Row>
                    <h3 style={titleStyle}>Navigation</h3>
                </Row>
                <Row style={rowStyle}>
                    <Breadcrumb>
                        <Breadcrumb.Item>Semi-ui</Breadcrumb.Item>
                        <Breadcrumb.Item>Breadcrumb</Breadcrumb.Item>
                        <Breadcrumb.Item>Default</Breadcrumb.Item>
                    </Breadcrumb>
                    <Nav mode="horizontal" items={navItems} renderItemIcon={({ item }) => <Dynamic component={navIcons[String(item.itemKey)]} />} />
                    <br />
                    <br />
                    <Pagination total={80} showSizeChanger />
                    <br />
                    <Steps current={1}>
                        <Steps.Step title="Finished" description="This is a description." />
                        <Steps.Step title="In Progress" description="This is a description." />
                        <Steps.Step title="Waiting" description="This is a description." />
                    </Steps>
                    <br />
                    <Steps current={1} status="error">
                        <Steps.Step title="Finished" description="This is a description" />
                        <Steps.Step title="In Process" description="This is a description" />
                        <Steps.Step title="Waiting" description="This is a description" />
                    </Steps>
                </Row>
                <Row>
                    <h3 style={titleStyle}>Display</h3>
                </Row>
                <Row style={rowStyle}>
                    <div style={{ display: 'flex' }}>
                        <div style={{ padding: '8px' }}>
                            <Badge count={5} theme="solid">
                                <Avatar color="blue" shape="square" style={badgeStyle}>
                                    XZ
                                </Avatar>
                            </Badge>
                        </div>
                        <div style={{ padding: '8px' }}>
                            <Badge count={5} theme="light">
                                <Avatar color="cyan" shape="square" style={badgeStyle}>
                                    YB
                                </Avatar>
                            </Badge>
                        </div>
                        <div style={{ padding: '8px' }}>
                            <Badge count={5} theme="inverted">
                                <Avatar color="indigo" shape="square" style={badgeStyle}>
                                    LX
                                </Avatar>
                            </Badge>
                        </div>
                        <div style={{ padding: '8px' }}>
                            <Badge dot theme="solid">
                                <Avatar color="light-blue" shape="square" style={badgeStyle}>
                                    YZ
                                </Avatar>
                            </Badge>
                        </div>
                        <div style={{ padding: '8px' }}>
                            <Badge dot theme="light">
                                <Avatar color="teal" shape="square" style={badgeStyle}>
                                    HW
                                </Avatar>
                            </Badge>
                        </div>
                        <div style={{ padding: '8px', 'border-radius': '4px', 'background-color': 'var(--semi-color-fill-0)' }}>
                            <Badge dot theme="inverted">
                                <Avatar color="green" shape="square" style={badgeStyle}>
                                    XM
                                </Avatar>
                            </Badge>
                        </div>
                    </div>
                    <br />
                    <div>
                        <Tag color="grey" style={tagStyle}>
                            grey tag
                        </Tag>
                        <Tag color="blue" style={tagStyle}>
                            blue tag
                        </Tag>
                        <Tag color="blue" type="ghost" style={tagStyle}>
                            ghost tag
                        </Tag>
                        <Tag color="blue" type="solid" style={tagStyle}>
                            solid tag
                        </Tag>
                        <Tag color="red" style={tagStyle}>
                            red tag
                        </Tag>
                        <Tag color="green" style={tagStyle}>
                            green tag
                        </Tag>
                        <Tag color="orange" style={tagStyle}>
                            orange tag
                        </Tag>
                        <Tag color="teal" style={tagStyle}>
                            teal tag
                        </Tag>
                        <Tag color="violet" style={tagStyle}>
                            violet tag
                        </Tag>
                        <Tag color="white" style={tagStyle}>
                            white tag
                        </Tag>
                    </div>
                    <br />
                    <div style={{ display: 'flex', 'align-items': 'center' }}>
                        <Popover content="hi semi-design" style={{ padding: '8px' }}>
                            {(trigger) => (
                                <Tag {...trigger()} style={{ 'margin-right': '8px' }}>
                                    I am Popover
                                </Tag>
                            )}
                        </Popover>
                        <Tooltip content="hi semi-design">
                            {(trigger) => (
                                <Tag {...trigger()} style={{ 'margin-right': '8px' }}>
                                    I am Tooltip
                                </Tag>
                            )}
                        </Tooltip>
                        <Rating defaultValue={3} size="small" style={{ 'margin-right': '8px' }} />
                    </div>
                    <br />
                    <Timeline>
                        <Timeline.Item time="2019-07-14 10:35" type="ongoing">
                            审核中
                        </Timeline.Item>
                        <Timeline.Item time="2019-06-13 16:17" type="success">
                            发布成功
                        </Timeline.Item>
                        <Timeline.Item time="2019-05-14 18:34" type="error">
                            审核失败
                        </Timeline.Item>
                    </Timeline>
                </Row>
                <Row>
                    <h3 style={titleStyle}>Feedback</h3>
                </Row>
                <Row style={rowStyle}>
                    <Button type="primary" onClick={() => Notification.success(opts())} style={buttonStyle}>
                        成功信息的通知
                    </Button>
                    <Button onClick={() => Notification.info(opts())} style={buttonStyle}>
                        提示信息的通知
                    </Button>
                    <Button type="warning" onClick={() => Notification.warning(opts())} style={buttonStyle}>
                        警告信息的通知
                    </Button>
                    <Button type="danger" onClick={() => Notification.error(opts())} style={buttonStyle}>
                        失败信息的通知
                    </Button>
                    <Button style={buttonStyle} aria-label="Vigo 图标通知" icon={<IconVigoLogo />} onClick={() => Notification.info({ ...opts(), icon: <IconVigoLogo /> })} />
                    <Button style={buttonStyle} aria-label="粉色 Vigo 图标通知" icon={<IconVigoLogo />} onClick={() => Notification.info({ ...opts(), icon: <IconVigoLogo style={{ color: 'pink' }} /> })} />
                    <br />
                    <Button type="primary" onClick={() => Modal.success(opts())} style={buttonStyle}>
                        成功信息的弹窗
                    </Button>
                    <Button onClick={() => Modal.info(opts())} style={buttonStyle}>
                        提示信息的弹窗
                    </Button>
                    <Button type="warning" onClick={() => Modal.warning(opts())} style={buttonStyle}>
                        警告信息的弹窗
                    </Button>
                    <Button type="danger" onClick={() => Modal.error(opts())} style={buttonStyle}>
                        失败信息的弹窗
                    </Button>
                    <br />
                    <Button type="primary" onClick={() => Toast.success(opts())} style={buttonStyle}>
                        成功信息的提示
                    </Button>
                    <Button onClick={() => Toast.info(opts())} style={buttonStyle}>
                        提示信息的提示
                    </Button>
                    <Button type="warning" onClick={() => Toast.warning(opts())} style={buttonStyle}>
                        警告信息的提示
                    </Button>
                    <Button type="danger" onClick={() => Toast.error(opts())} style={buttonStyle}>
                        失败信息的提示
                    </Button>
                    <br />
                    <br />
                    <Spin tip="I am loading...">
                        <div
                            style={{
                                'background-color': 'var(--semi-color-primary-light-default)',
                                border: '1px solid var(--semi-color-primary)',
                                'border-radius': '4px',
                                padding: '16px 10px',
                            }}
                        >
                            <p>Here are some texts.</p>
                            <p>And more texts on the way.</p>
                        </div>
                    </Spin>
                </Row>
            </ConfigProvider>
        </div>
    );
}

嵌套使用

ConfigProvider 可以嵌套。内层只覆盖显式传入的属性,没传的属性(direction、locale、timeZone、getPopupContainer、responsiveObserve、responsiveMap)继承外层。属性值为 undefined 视为没传;locale={null} 是显式传入,会清除外层的 locale,交给其内部的 LocaleProvider 或默认语言。

direction 为 rtl 的 ConfigProvider 内可以用 direction="ltr" 把子树切回从左到右,内层组件的逻辑和样式都按 ltr 处理。

外层:locale = en-US,timeZone = Asia/Tokyo,direction = ltr
内层只传 timeZone,其余继承外层:locale = en-US,timeZone = 8,direction = ltr
代码
import en_US from '@fibrous/semi-foundation/locale/source/en_US';
import { ConfigProvider, ConfigConsumer } from '@fibrous/semi-ui-solid';

function ConfigSummary(props: { title: string }) {
    return (
        <ConfigConsumer>
            {(config) => (
                <div style={{ margin: '8px' }}>
                    {props.title}:locale = {config.locale?.code ?? '未设置'},timeZone = {String(config.timeZone)},direction = {config.direction}
                </div>
            )}
        </ConfigConsumer>
    );
}

export default function ConfigProviderDemo() {
    return (
        <ConfigProvider locale={en_US} timeZone="Asia/Tokyo" direction="ltr">
            <ConfigSummary title="外层" />
            <ConfigProvider timeZone={8}>
                <ConfigSummary title="内层只传 timeZone,其余继承外层" />
            </ConfigProvider>
        </ConfigProvider>
    );
}

API 参考

ConfigProvider

Props

属性说明类型默认值
children受该配置影响的内容。显式传入的 direction 与外层不同时(含最外层),内容外包一层带 dir 属性的 div。JSX.Element-
direction文本方向,可选 ltr 或 rtl。未传时继承外层 ConfigProvider,最外层默认为 ltr。'ltr' | 'rtl'-
getPopupContainer返回弹层容器的函数,只影响仍通过 Portal 渲染的 Modal、SideSheet、ImagePreview,容器需要设置 position: relative。未传时继承外层,最外层为 document.body。Type() => HTMLElement-
locale多语言配置,优先级高于 LocaleProvider。未传时继承外层 ConfigProvider;没有 ConfigProvider 设置时由 LocaleProvider 决定,两者都没有时使用 zh_CN。传 null 清除外层的 locale。Locale | null-
responsiveMap自定义响应式断点,key 为 xs、sm、md、lg、xl、xxl,value 为 media query 字符串。按内容比较,内联写对象不会重新注册监听;未传时继承外层,最外层使用 defaultResponsiveMap。ResponsiveMap-
responsiveObserve是否开启响应式断点监听。关闭时不注册任何 matchMedia 监听;开启后在首次订阅时注册,无订阅时注销。未传时继承外层,最外层为 false。boolean-
timeZone时间类组件使用的时区:数字(距 UTC 的小时偏移)、GMT±HH:MM 字符串或 IANA 标识。数字和 GMT 写法是全年固定的偏移。未传时继承外层。string | number-

ConfigProvider.defaultResponsiveMap 与具名导出 defaultResponsiveMap 是默认断点配置。locale 的用法同 LocaleProvider 中 locale 参数的用法。ConfigProvider 不接收 class、style、ref 与原生属性,它们不会落到 DOM 上。

ConfigConsumer

Props

属性说明类型默认值
children函数子节点,参数为当前生效的配置(ContextValue);在 ConfigProvider 内还包含 screens 与 onBreakpoint,没有 ConfigProvider 时为空对象。函数只执行一次,字段以 config.xxx 的形式在 JSX 中读取,不要解构。Type(config: ContextValue) => JSX.Element-

ConfigConsumer 同样不渲染元素,未声明的属性会被丢弃。

useConfig

useConfig(): Accessor<ContextValue> 返回当前生效配置的访问器,调用它才能读到值,没有 ConfigProvider 时为空对象。ContextValue 包含上表的 direction、timeZone、locale、getPopupContainer、responsiveObserve 和 responsiveMap,以及只读的 screens(各断点的命中情况)和 onBreakpoint(订阅函数,见上文「订阅 API」)。

时区标识

  • 数字,例如 1、-9.5,代表距离 UTC 的时间偏移,单位为小时,可以为负数或小数;
  • 字符串,例如GMT-09:30、GMT+08:00这样的以 "GMT" 开头的表征偏移字符串,也可以为 IANA 标识,如Asia/Shanghai、America/Los_Angeles等。

数字和 GMT-09:30 这类写法表示全年固定的偏移,不随夏令时变化。例如 -3.5 和 GMT-03:30 全年都是 UTC-03:30,时间格式中的时区名(z)显示为 GMT-03:30。

需要跟随某个地区的夏令时,请使用 IANA 标识。这里可以查看 IANA 标识列表,以及时区是否有夏令时。

FAQ

  • ConfigProvider中没有提供全局自定义prefix classname的功能,有类似需求如何实现(例如SDK中使用了Semi,期望打包的dom样式不带.semi-xx前缀,以免被宿主的全局 CSS 影响)?
    • 由于 prefixCls 需要同时被组件层的 js/css 消费,Semi 将此开关放在了webpack plugin的配置项中,而不是作为ConfigProvider的配置项。
    • 如果你使用webpack,请在SemiWebpackPlugin的参数中进行配置
# webpack配置示例
const SemiWebpackPlugin = require('@fibrous/semi-webpack-plugin').default;
module.exports = {
+    plugins: [new SemiWebpackPlugin({ prefixCls: 'imes' })],
}

semiGlobal

除了 ConfigProvider外,你还可以通过 semiGlobal 配置覆盖全局组件的默认 Props。

在 semiGlobal.config.overrideDefaultProps 可配置组件默认 Props。组件在创建时读取一次全局配置,之后修改它不会更新已创建的组件,因此建议在挂载应用之前设置,放在站点入口处。默认值里的 DOM 节点会被丢弃并告警(一个节点只能挂在一处,各实例会互相搬走它),字符串与图标组件照常生效。

id、insetLabelId、wrapperId、addonId、extraId 这类每个实例唯一的属性不能经全局默认值设置:类型里没有这些键,运行时也忽略。

比如下方配置就是将所有的 Button 默认设置为 warning,Select 默认开启 filter 等

import { semiGlobal } from '@fibrous/semi-ui-solid';

semiGlobal.config.overrideDefaultProps = {
    Button: {
        type: 'warning',
    },
    Select: {
        filter: true,
    },
    Tooltip: {
        trigger: 'click',
    },
};