feat: add ConfigProvider component (#8854)

This commit is contained in:
neverland 2021-06-13 20:22:23 +08:00 committed by GitHub
parent 0789d86de5
commit 96ca6679b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 569 additions and 0 deletions

View File

@ -0,0 +1,41 @@
import { computed, CSSProperties, defineComponent, PropType } from 'vue';
import { createNamespace } from '../utils';
const [name, bem] = createNamespace('config-provider');
export function kebabCase(word: string) {
return word
.replace(/([A-Z])/g, '-$1')
.toLowerCase()
.replace(/^-/, '');
}
function mapThemeVarsToCSSVars(themeVars: Record<string, string | number>) {
const cssVars: Record<string, string | number> = {};
Object.keys(themeVars).forEach((key) => {
cssVars[`--van-${kebabCase(key)}`] = themeVars[key];
});
return cssVars;
}
export default defineComponent({
name,
props: {
themeVars: Object as PropType<Record<string, string | number>>,
},
setup(props, { slots }) {
const style = computed<CSSProperties | undefined>(() => {
if (props.themeVars) {
return mapThemeVarsToCSSVars(props.themeVars);
}
});
return () => (
<div class={bem()} style={style.value}>
{slots.default?.()}
</div>
);
},
});

View File

@ -0,0 +1,82 @@
# ConfigProvider
### Intro
Used to config the theme of Vant components.
### Install
Register component globally via `app.use`, refer to [Component Registration](#/en-US/advanced-usage#zu-jian-zhu-ce) for more registration ways.
```js
import { createApp } from 'vue';
import { ConfigProvider } from 'vant';
const app = createApp();
app.use(ConfigProvider);
```
## Usage
### Custom Theme
Use `theme-vars` prop to custom theme variables。
```html
<van-config-provider :theme-vars="themeVars">
<van-form>
<van-field name="rate" label="Rate">
<template #input>
<van-rate v-model="rate" />
</template>
</van-field>
<van-field name="slider" label="Slider">
<template #input>
<van-slider v-model="slider" />
</template>
</van-field>
<div style="margin: 16px">
<van-button round block type="primary" native-type="submit">
Submit
</van-button>
</div>
</van-form>
</van-config-provider>
```
```js
import { ref } from 'vue';
export default {
setup() {
const rate = ref(4);
const slider = ref(50);
const switchChecked = ref(true);
const themeVars = {
rateIconFullColor: '#07c160',
sliderBarHeight: '4px',
sliderButtonWidth: '20px',
sliderButtonHeight: '20px',
sliderActiveBackgroundColor: '#07c160',
buttonPrimaryBorderColor: '#07c160',
buttonPrimaryBackgroundColor: '#07c160',
};
return {
rate,
slider,
themeVars,
switchChecked,
};
},
};
```
## API
### Props
| Attribute | Description | Type | Default |
| ---------- | --------------- | -------- | ------- |
| theme-vars | Theme variables | _object_ | - |

View File

@ -0,0 +1,82 @@
# ConfigProvider 全局配置
### 介绍
用于配置 Vant 组件的主题样式,从 3.1.0 版本开始支持。
### 引入
通过以下方式来全局注册组件,更多注册方式请参考[组件注册](#/zh-CN/advanced-usage#zu-jian-zhu-ce)。
```js
import { createApp } from 'vue';
import { ConfigProvider } from 'vant';
const app = createApp();
app.use(ConfigProvider);
```
## 代码演示
### 自定义主题
通过 `theme-vars` 属性来自定义主题变量。
```html
<van-config-provider :theme-vars="themeVars">
<van-form>
<van-field name="rate" label="评分">
<template #input>
<van-rate v-model="rate" />
</template>
</van-field>
<van-field name="slider" label="滑块">
<template #input>
<van-slider v-model="slider" />
</template>
</van-field>
<div style="margin: 16px">
<van-button round block type="primary" native-type="submit">
提交
</van-button>
</div>
</van-form>
</van-config-provider>
```
```js
import { ref } from 'vue';
export default {
setup() {
const rate = ref(4);
const slider = ref(50);
const switchChecked = ref(true);
const themeVars = {
rateIconFullColor: '#07c160',
sliderBarHeight: '4px',
sliderButtonWidth: '20px',
sliderButtonHeight: '20px',
sliderActiveBackgroundColor: '#07c160',
buttonPrimaryBorderColor: '#07c160',
buttonPrimaryBackgroundColor: '#07c160',
};
return {
rate,
slider,
themeVars,
switchChecked,
};
},
};
```
## API
### Props
| 参数 | 说明 | 类型 | 默认值 |
| ---------- | -------------- | -------- | ------ |
| theme-vars | 自定义主题变量 | _object_ | - |

View File

@ -0,0 +1,111 @@
<template>
<demo-block :title="t('defaultTheme')">
<van-form>
<van-field name="rate" :label="t('rate')">
<template #input>
<van-rate v-model="rate" />
</template>
</van-field>
<van-field name="slider" :label="t('slider')">
<template #input>
<van-slider v-model="slider" />
</template>
</van-field>
<div style="margin: 16px">
<van-button round block type="primary" native-type="submit">
{{ t('submit') }}
</van-button>
</div>
</van-form>
</demo-block>
<demo-block :title="t('customTheme')">
<van-config-provider :theme-vars="themeVars">
<van-form>
<van-field name="rate" :label="t('rate')">
<template #input>
<van-rate v-model="rate" />
</template>
</van-field>
<van-field name="slider" :label="t('slider')">
<template #input>
<van-slider v-model="slider" />
</template>
</van-field>
<div style="margin: 16px">
<van-button round block type="primary" native-type="submit">
{{ t('submit') }}
</van-button>
</div>
</van-form>
</van-config-provider>
</demo-block>
</template>
<script lang="ts">
import { useTranslate } from '@demo/use-translate';
import { reactive, toRefs } from '@vue/reactivity';
const i18n = {
'zh-CN': {
rate: '评分',
slider: '滑块',
switch: '开关',
submit: '提交',
customTheme: '自定义主题',
defaultTheme: '默认主题',
},
'en-US': {
rate: 'Rate',
slider: 'Slider',
switch: 'Switch',
submit: 'Submit',
customTheme: 'Custom Theme',
defaultTheme: 'DefaultTheme',
},
};
export default {
setup() {
const t = useTranslate(i18n);
const state = reactive({
rate: 4,
slider: 50,
switchChecked: true,
});
const themeVars = {
rateIconFullColor: '#07c160',
sliderBarHeight: '4px',
sliderButtonWidth: '20px',
sliderButtonHeight: '20px',
sliderActiveBackgroundColor: '#07c160',
buttonPrimaryBorderColor: '#07c160',
buttonPrimaryBackgroundColor: '#07c160',
};
return {
t,
themeVars,
...toRefs(state),
};
},
};
</script>
<style lang="less">
@import '../../style/var';
.demo-collapse {
.van-icon-question-o {
margin-left: 5px;
color: @blue;
font-size: 15px;
vertical-align: -3px;
}
}
</style>

View File

@ -0,0 +1,7 @@
import { withInstall } from '../utils';
import _ConfigProvider from './ConfigProvider';
const ConfigProvider = withInstall<typeof _ConfigProvider>(_ConfigProvider);
export default ConfigProvider;
export { ConfigProvider };

View File

@ -0,0 +1,234 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render demo and match snapshot 1`] = `
<div>
<form class="van-form">
<div class="van-cell van-field">
<div class="van-cell__title van-field__label">
<span>
Rate
</span>
</div>
<div class="van-cell__value van-field__value">
<div class="van-field__body">
<div class="van-field__control van-field__control--custom">
<div role="radiogroup"
class="van-rate"
tabindex="0"
>
<div role="radio"
class="van-rate__item"
tabindex="0"
aria-setsize="5"
aria-posinset="1"
aria-checked="true"
>
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--full">
</i>
</div>
<div role="radio"
class="van-rate__item"
tabindex="0"
aria-setsize="5"
aria-posinset="2"
aria-checked="true"
>
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--full">
</i>
</div>
<div role="radio"
class="van-rate__item"
tabindex="0"
aria-setsize="5"
aria-posinset="3"
aria-checked="true"
>
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--full">
</i>
</div>
<div role="radio"
class="van-rate__item"
tabindex="0"
aria-setsize="5"
aria-posinset="4"
aria-checked="true"
>
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--full">
</i>
</div>
<div role="radio"
class="van-rate__item"
tabindex="0"
aria-setsize="5"
aria-posinset="5"
aria-checked="false"
>
<i class="van-badge__wrapper van-icon van-icon-star-o van-rate__icon">
</i>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="van-cell van-field">
<div class="van-cell__title van-field__label">
<span>
Slider
</span>
</div>
<div class="van-cell__value van-field__value">
<div class="van-field__body">
<div class="van-field__control van-field__control--custom">
<div class="van-slider">
<div class="van-slider__bar"
style="width: 50%; left: 0%;"
>
<div role="slider"
class="van-slider__button-wrapper"
tabindex="0"
aria-valuemin="0"
aria-valuenow="50"
aria-valuemax="100"
aria-orientation="horizontal"
>
<div class="van-slider__button">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div style="margin: 16px;">
<button type="submit"
class="van-button van-button--primary van-button--normal van-button--block van-button--round"
>
<div class="van-button__content">
<span class="van-button__text">
Submit
</span>
</div>
</button>
</div>
</form>
</div>
<div>
<div class="van-config-provider"
style="--van-rate-icon-full-color: #07c160; --van-slider-bar-height: 4px; --van-slider-button-width: 20px; --van-slider-button-height: 20px; --van-slider-active-background-color: #07c160; --van-button-primary-border-color: #07c160; --van-button-primary-background-color: #07c160;"
>
<form class="van-form">
<div class="van-cell van-field">
<div class="van-cell__title van-field__label">
<span>
Rate
</span>
</div>
<div class="van-cell__value van-field__value">
<div class="van-field__body">
<div class="van-field__control van-field__control--custom">
<div role="radiogroup"
class="van-rate"
tabindex="0"
>
<div role="radio"
class="van-rate__item"
tabindex="0"
aria-setsize="5"
aria-posinset="1"
aria-checked="true"
>
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--full">
</i>
</div>
<div role="radio"
class="van-rate__item"
tabindex="0"
aria-setsize="5"
aria-posinset="2"
aria-checked="true"
>
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--full">
</i>
</div>
<div role="radio"
class="van-rate__item"
tabindex="0"
aria-setsize="5"
aria-posinset="3"
aria-checked="true"
>
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--full">
</i>
</div>
<div role="radio"
class="van-rate__item"
tabindex="0"
aria-setsize="5"
aria-posinset="4"
aria-checked="true"
>
<i class="van-badge__wrapper van-icon van-icon-star van-rate__icon van-rate__icon--full">
</i>
</div>
<div role="radio"
class="van-rate__item"
tabindex="0"
aria-setsize="5"
aria-posinset="5"
aria-checked="false"
>
<i class="van-badge__wrapper van-icon van-icon-star-o van-rate__icon">
</i>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="van-cell van-field">
<div class="van-cell__title van-field__label">
<span>
Slider
</span>
</div>
<div class="van-cell__value van-field__value">
<div class="van-field__body">
<div class="van-field__control van-field__control--custom">
<div class="van-slider">
<div class="van-slider__bar"
style="width: 50%; left: 0%;"
>
<div role="slider"
class="van-slider__button-wrapper"
tabindex="0"
aria-valuemin="0"
aria-valuenow="50"
aria-valuemax="100"
aria-orientation="horizontal"
>
<div class="van-slider__button">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div style="margin: 16px;">
<button type="submit"
class="van-button van-button--primary van-button--normal van-button--block van-button--round"
>
<div class="van-button__content">
<span class="van-button__text">
Submit
</span>
</div>
</button>
</div>
</form>
</div>
</div>
`;

View File

@ -0,0 +1,4 @@
import Demo from '../demo/index.vue';
import { snapshotDemo } from '../../../test/demo';
snapshotDemo(Demo);

View File

@ -119,6 +119,10 @@ module.exports = {
path: 'cell',
title: 'Cell 单元格',
},
{
path: 'config-provider',
title: 'ConfigProvider 全局配置',
},
{
path: 'icon',
title: 'Icon 图标',
@ -520,6 +524,10 @@ module.exports = {
path: 'cell',
title: 'Cell',
},
{
path: 'config-provider',
title: 'ConfigProvider',
},
{
path: 'icon',
title: 'Icon',