<repo_name>by-ui/by-ui<file_sep>/src/components/dropdown-menu/index.ts
import DropdownMenu from '../dropdown/src/dropdown-menu.vue'

Object.defineProperty(DropdownMenu, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-dropdown-menu', DropdownMenu);
    }
})

export default DropdownMenu;
<file_sep>/build/config/env.ts
// 分环境打包配置
const remain = JSON.parse(process.env.npm_config_argv || '').remain;
const host = remain.length ? remain[0].replace(/^--/, '') : 'default';
const domain = process.env.DOMAIN;
const customize = process.env.CUSTOMIZE || false;

export default {
    host,
    domain,
    customize
}
<file_sep>/src/components/menu-sub/index.ts
import MenuSub from '../menu/src/menu-sub.vue'

Object.defineProperty(MenuSub, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-menu-sub', MenuSub);
    }
})

export default MenuSub
<file_sep>/src/components/notification/model.ts
export class notificationOption {

    title: string;
    content: string;
    duration: number;
    type: string;
    show: boolean;

    constructor(title: string, content: string, duration: number = 4000, type: string = '', show: boolean = true) {
        this.title = title;
        this.content = content;
        this.duration = duration;
        this.type = type;
        this.show = show;
    }
}
<file_sep>/src/components/tag/index.ts
import Tag from './src/tag.vue'

Object.defineProperty(Tag, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-tag', Tag);
    }
})

export default Tag
<file_sep>/src/index.ts

/********** 基础组件 **********/
import Button from './components/button';
import ButtonGroup from './components/button-group';
import Tag from './components/tag';
import Icon from './components/icon';

/********** 表单组件 **********/
import Checkbox from './components/checkbox';
import CheckboxGroup from './components/checkbox-group';
import Textarea from './components/textarea';
import InputNumber from './components/input-number';
import Rate from './components/rate';
import Input from './components/input';
import Switch from './components/switch';
import Slider from './components/slider'
import Radio from './components/radio';
import RadioGroup from './components/radio-group';
import RadioButton from './components/radio-button';
import Form from './components/form';
import FormItem from './components/form-item';
import Select from './components/select'
import Option from './components/select-option'
import OptionGroup from './components/select-option-group'

/********** 视图组件 **********/
import Badge from './components/badge';
import Alert from './components/alert';
import Collapse from './components/collapse';
import CollapseItem from './components/collapse-Item';
import Message from './components/message';
import LoadingBar from './components/loading-bar';
import Notification from './components/notification';
import Progress from './components/progress';
import TimeLine from './components/timeline';
import TimeLineItem from './components/timeline-item';
import Step from './components/step';
import StepItem from './components/step-item';
import Table from './components/table';
import Dropdown from './components/dropdown';
import DropdownMenu from './components/dropdown-menu';
import DropdownItem from './components/dropdown-item';
import Drawer from './components/drawer';
import Tooltip from './components/tooltip';
import Popover from './components/popover';
import Modal from './components/modal';
import Card from './components/card';


/********** 导航组件 **********/
import Breadcrumb from './components/breadcrumb';
import BreadcrumbItem from './components/breadcrumb-item';
import Pagination from './components/pagination';
import Tabs from './components/tabs';
import TabPane from './components/tab-pane';
import Menu from './components/menu';
import MenuItem from './components/menu-item';
import MenuItemGroup from './components/menu-item-group';
import Submenu from './components/menu-sub';

function install(Vue: any, opts = {}) {
    Vue.component('by-button', Button);
    Vue.component('by-button-group', ButtonGroup);

    Vue.component('by-tag', Tag);
    Vue.component('by-icon', Icon);

    Vue.component('by-checkbox', Checkbox);
    Vue.component('by-checkbox-group', CheckboxGroup);
    Vue.component('by-textarea', Textarea);
    Vue.component('by-input-number', InputNumber);
    Vue.component('by-rate', Rate);
    Vue.component('by-switch', Switch);
    Vue.component('by-select', Select)
    Vue.component('by-option', Option)
    Vue.component('by-option-group', OptionGroup)

    Vue.component('by-input', Input);
    Vue.component('by-radio', Radio);
    Vue.component('by-radio-group', RadioGroup);
    Vue.component('by-radio-button', RadioButton);
    Vue.component('by-slider', Slider);
    Vue.component('by-form', Form);
    Vue.component('by-form-item', FormItem);

    Vue.component('by-badge', Badge);
    Vue.component('by-alert', Alert);
    Vue.component('by-collapse', Collapse);
    Vue.component('by-collapse-item', CollapseItem);
    Vue.component('by-progress', Progress);
    Vue.component('by-breadcrumb', Breadcrumb);
    Vue.component('by-breadcrumb-item', BreadcrumbItem)
    Vue.component('by-time-line', TimeLine);
    Vue.component('by-timeline-item', TimeLineItem);
    Vue.component('by-pagination', Pagination);
    Vue.component('by-step', Step);
    Vue.component('by-step-item', StepItem);
    Vue.component('by-table', Table);
    Vue.component('by-dropdown', Dropdown);
    Vue.component('by-dropdown-menu', DropdownMenu);
    Vue.component('by-dropdown-item', DropdownItem);
    Vue.component('by-drawer', Drawer);
    Vue.component('by-tabs', Tabs);
    Vue.component('by-tab-pane', TabPane);
    Vue.component('by-menu', Menu);
    Vue.component('by-menu-item', MenuItem);
    Vue.component('by-menu-item-group', MenuItemGroup);
    Vue.component('by-menu-sub', Submenu);
    Vue.component('by-tooltip', Tooltip);
    Vue.component('by-popover', Popover);
    Vue.component('by-modal', Modal);
    Vue.component('by-card', Card);




    Vue.prototype.$message = Message;
    Vue.prototype.$loadingBar = LoadingBar;
    Vue.prototype.$notify = Notification;
    Vue.prototype.$modal = Modal;
}

/**
 * Global Install
 */
if (typeof window !== 'undefined' && window.Vue) {
    install(window.Vue)
}
const verion = 'v.0.0.3'
export { verion, install, Message, Button, Modal }
// export default { verion, install, Message, Button }
<file_sep>/src/components/drawer/index.ts
import Drawer from './src/drawer.vue'

Object.defineProperty(Drawer, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-drawer', Drawer);
    }
})

export default Drawer;
<file_sep>/docs/packages/i18n/index.ts
import Vue from 'vue';
import VueI18n from 'vue-i18n';
import messages from '@/locale';

Vue.use(VueI18n);

export const i18n = new VueI18n({
    locale: 'cn', // set locale
    fallbackLocale: 'cn', // 默认语言设置，当其他语言没有的情况下，使用en作为默认语言
    messages // set locale messages
});
<file_sep>/src/components/loading-bar/model.ts
export class LoadingBarOption {

    width: number | string;
    color: string;
    percent: number;
    status: string;
    show: boolean;

    constructor(width: number | string = '', color: string = '', percent: number = 100, status: string = '', show: boolean = true) {
        this.width = width;
        this.color = color;
        this.percent = percent;
        this.status = status;
        this.show = show;
    }
}
<file_sep>/src/components/card/index.ts
import Card from './src/card.vue'

Object.defineProperty(Card, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-card', Card);
    }
})

export default Card
<file_sep>/src/utils/utils.ts
const SPECIAL_CHARS_REGEXP = /([:\-_]+(.))/g
const MOZ_HACK_REGEXP = /^moz([A-Z])/
export function camelCase(name: string) {
    return name.replace(SPECIAL_CHARS_REGEXP, function (_, separator, letter, offset) {
        return offset ? letter.toUpperCase() : letter
    }).replace(MOZ_HACK_REGEXP, 'Moz$1')
}
export function getStyle (element:any, styleName:string) {
    if (!element || !styleName) return null
  
    styleName = camelCase(styleName)
    if (styleName === 'float') {
      styleName = 'cssFloat'
    }
  
    try {
      const computed = (document as any).defaultView.getComputedStyle(element, '')
      return element.style[styleName] || computed ? computed[styleName] : null
    } catch (e) {
      return element.style[styleName]
    }
  }<file_sep>/src/components/notification/vue.d.ts
import Vue from 'vue';
import { notificationOption } from './model';

declare module 'vue/types/vue' {
    interface Vue {
        $notify: {
            (): void;
            success(option: notificationOption): void;
            error(option: notificationOption): void;
            warning(option: notificationOption): void;
            info(option: notificationOption): void;
        };
    }
}
<file_sep>/src/locale/index.ts
import cn from './lang/zh-CN'
import en from './lang/en-US'

export default {
    cn,
    en
}
<file_sep>/docs/utils/collapse-transition.ts
/**
 * https://github.com/ElemeFE/element/blob/dev/src/transitions/collapse-transition.js
 */
import { addClass, removeClass } from './util'

const Transition = {
    beforeEnter(el) {
        addClass(el, 'collapse-transition')
        if (!el.dataset) el.dataset = {}

        // // el.dataset.oldPaddingTop = el.style.paddingTop
        // // el.dataset.oldPaddingBottom = el.style.paddingBottom

        el.style.height = '0'
        // el.style.paddingTop = 0
        // el.style.paddingBottom = 0
    },

    enter(el) {
        el.dataset.oldOverflow = el.style.overflow
        if (el.scrollHeight !== 0) {
            el.style.height = `${el.scrollHeight}px`
            // // el.style.paddingTop = el.dataset.oldPaddingTop
            // // el.style.paddingBottom = el.dataset.oldPaddingBottom
        } else {
            el.style.height = ''
            // // el.style.paddingTop = el.dataset.oldPaddingTop
            // // el.style.paddingBottom = el.dataset.oldPaddingBottom
        }

        el.style.overflow = 'hidden'
    },

    afterEnter(el) {
        // for safari: remove class then reset height is necessary
        removeClass(el, 'collapse-transition')
        el.style.height = ''
        el.style.overflow = el.dataset.oldOverflow
    },

    beforeLeave(el) {
        if (!el.dataset) el.dataset = {}
        // // el.dataset.oldPaddingTop = el.style.paddingTop
        // // el.dataset.oldPaddingBottom = el.style.paddingBottom
        el.dataset.oldOverflow = el.style.overflow

        el.style.height = `${el.scrollHeight}px`
        el.style.overflow = 'hidden'
    },

    leave(el) {
        if (el.scrollHeight !== 0) {
            // for safari: add class after set height, or it will jump to zero height suddenly, weired
            addClass(el, 'collapse-transition')
            el.style.height = 0
            // el.style.paddingTop = 0
            // el.style.paddingBottom = 0
        }
    },

    afterLeave(el) {
        removeClass(el, 'collapse-transition')
        el.style.height = ''
        el.style.overflow = el.dataset.oldOverflow
        // // el.style.paddingTop = el.dataset.oldPaddingTop
        // // el.style.paddingBottom = el.dataset.oldPaddingBottom
    }
}

export default {
    name: 'CollapseTransition',
    functional: true,
    render(h, { children }) {
        const data = {
            on: Transition
        }

        return h('transition', data, children)
    }
}
<file_sep>/src/components/progress/index.ts
import Progress from './src/progress.vue'

Object.defineProperty(Progress, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-progress', Progress);
    }
})

export default Progress
<file_sep>/src/components/radio-group/index.ts
import RadioGroup from '../radio/src/radio-group.vue'

Object.defineProperty(RadioGroup, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-radio-group', RadioGroup);
    }
})

export default RadioGroup



<file_sep>/src/components/button/index.ts
import Button from './src/button.vue'

Object.defineProperty(Button, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-button', Button);
    }
})

export default Button
<file_sep>/src/components/select-option-group/index.ts
import OptionGroup from '../select/src/option-group.vue'

Object.defineProperty(OptionGroup, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-option-group', OptionGroup);
    }
})

export default OptionGroup
<file_sep>/build/webpack/webpack.dev.config.ts
import * as webpack from 'webpack';
import * as merge from 'webpack-merge';
import * as HtmlPlugin from 'html-webpack-plugin';

import * as path from 'path';

const CleanWebpackPlugin = require('clean-webpack-plugin');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');

const baseConfig = require('./webpack.base.config.ts');

const os = require("os");
const networkInterfaces = os.networkInterfaces();

import byui from '../config/by-ui';

let ip = "";
const port = '11111';

for (var key in networkInterfaces) {
    networkInterfaces[key].forEach(item => {
        if (!item.internal && item.family === "IPv4") {
            ip = item.address;
        }
    });
}

module.exports = merge(baseConfig, {
    entry: {
        index: [path.resolve("docs/index.ts")]
    },
    output: {
        publicPath: "/",
    },
    devServer: {
        host: ip,
        port: port,
        hot: true,
        open: true,
        quiet: true,
        historyApiFallback: true
    },
    plugins: [
        new CleanWebpackPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        new FriendlyErrorsWebpackPlugin({
            compilationSuccessInfo: {
                messages: [
                    ...byui,
                ],
                notes: [
                    `start at: http://${ip}:${port}`,
                ],
            }
        }),
        new HtmlPlugin({
            filename: "index.html",
            title: "By-ui",
            template: path.resolve("docs/index.html"),
            showErrors: true,
        }),
    ],

})
<file_sep>/src/components/loading-bar/src/loading-bar.ts
import Vue from 'vue';
import LoadingBarVue from './loading-bar.vue';

import { LoadingBarOption } from '../model';

let instance: any;
const LoadingBarConstructor = Vue.extend(LoadingBarVue);

class LoadingBar {

    constructor(options: LoadingBarOption) {

        options = options || {}

        instance = new LoadingBarConstructor({
            data: options
        })

        instance.vm = instance.$mount()

        document.body.appendChild(instance.vm.$el)
    }

    update(newOptions: LoadingBarOption) {
        newOptions.width && (instance.width = newOptions.width);
        newOptions.color && (instance.color = newOptions.color);
        newOptions.percent && (instance.percent = newOptions.percent);
        newOptions.status && (instance.status = newOptions.status);
        newOptions.show && (instance.show = newOptions.show);
    }

    destroy() {
        document.body.removeChild(instance.vm.$el)
    }
}

export default LoadingBar;
<file_sep>/docs/markdown/slider.md
# Slider 滑动输入条

---

滑动输入条，用于控制用户在规定的数值区间内进行选择

## 基础用法

基本滑动条，通过 `v-model` 绑定数据，默认取值范围为 `0~100`

:::demo

```html
<by-slider v-model="value"></by-slider>
```

:::

## 不可用状态

设置属性 `disabled` 禁用滑动条

:::demo

```html
<by-slider v-model="value2" disabled="true"></by-slider>
```

:::

## 自定义取值范围

通过属性 `min`， `max` 分别设置最小和最大可取值

:::demo

```html
<by-slider v-model="value3" :min="20" :max="80"></by-slider>
```

:::

## 离散值

可通过属性 `step` 控制每次滑动的间隔，默认间隔为 `1`

:::demo

```html
<by-slider v-model="value4" :step="10"></by-slider>
```

:::

## Slider 参数

| 参数     | 说明                            | 类型    | 可选值 | 默认值 |
| -------- | ------------------------------- | ------- | ------ | ------ |
| value    | 当前的值，可通过 `v-model` 绑定 | Number  | -      | -      |
| step     | 步长                            | Number  | -      | 1      |
| min      | 最小值                          | Number  | -      | 0      |
| max      | 最大值                          | Number  | -      | 100    |
| disabled | 是否禁用                        | Boolean | -      | false  |

## Slider 事件

| 事件名称 | 说明                 | 返回值     |
| -------- | -------------------- | ---------- |
| change   | 绑定的值有变化时触发 | 改变后的值 |

<script lang="ts">
    import { Vue, Component } from "vue-property-decorator";

    @Component
    export default class BySliderMd extends Vue {
        value = 0
        value2 = 20
        value3 = 30
        value4 = 50
    }
</script>
<file_sep>/docs/markdown/button.md
# Button 按钮

-----

## 带颜色倾向的按钮

带有色彩倾向的按钮能给用户带来操作提示

:::demo

```html
<div class="row">
    <by-button>默认按钮</by-button>
    <by-button type="primary">主要按钮</by-button>
    <by-button type="success">成功按钮</by-button>
    <by-button type="error">危险按钮</by-button>
    <by-button type="warning">警告按钮</by-button>
    <by-button type="info">信息按钮</by-button>
</div>
<div class="row">
    <by-button plain>默认按钮</by-button>
    <by-button type="primary" plain>主要按钮</by-button>
    <by-button type="success" plain>成功按钮</by-button>
    <by-button type="error" plain>危险按钮</by-button>
    <by-button type="warning" plain>警告按钮</by-button>
    <by-button type="info" plain>信息按钮</by-button>
</div>
<div class="row">
    <by-button round>默认按钮</by-button>
    <by-button type="primary" round>主要按钮</by-button>
    <by-button type="success" round>成功按钮</by-button>
    <by-button type="error" round>危险按钮</by-button>
    <by-button type="warning" round>警告按钮</by-button>
    <by-button type="info" round>信息按钮</by-button>
</div>
```
:::

## 不可用状态按钮

添加属性 `disabled` 禁用按钮
:::demo
```html
<div class="row">
    <by-button type="primary" disabled>主要按钮</by-button>
    <by-button hollow disabled>次要按钮</by-button>
    <by-button type="text" disabled>文字按钮</by-button>
</div>
```
:::


## 图标按钮

添加属性 `icon` 渲染图标按钮
:::demo
```html
<div class="row">
    <by-button icon="icon-edit" circle></by-button>
    <by-button type="primary" icon="icon-edit" circle></by-button>
    <by-button type="success" icon="icon-edit" circle></by-button>
    <by-button type="error" icon="icon-edit" circle></by-button>
    <by-button type="warning" icon="icon-edit" circle></by-button>
    <by-button type="info" icon="icon-edit" circle></by-button>
</div>
```
:::

`loading` 按钮
:::demo
```html
    <by-button loading circle></by-button>
    <by-button loading >加载中</by-button>
```
:::

### 不同尺寸
Button 组件提供除了默认值以外的三种尺寸，可以在不同场景下选择合适的按钮尺寸。
:::demo
```html
    <div>
        <by-button type="primary" size="large">变大按钮</by-button>
        <by-button type="primary">正常按钮</by-button>
        <by-button type="primary" size="small">变小按钮</by-button>
        <by-button type="primary" size="smaller">超小按钮</by-button>
    </div>
    <div style="margin-top: 20px;">
        <by-button  icon="icon-edit" circle size="large"></by-button>
        <by-button  icon="icon-edit" circle></by-button>
        <by-button  icon="icon-edit" circle size="small"></by-button>
        <by-button  icon="icon-edit" circle size="smaller"></by-button>
    </div>
```
:::

## Button 参数

| 参数      | 说明          | 类型      | 可选值                           | 默认值  |
|---------- |-------------- |---------- |--------------------------------  |-------- |
| type | 按钮的类型 | String | `default` `primary` `success` `error` `warning` `info` `text` | - |
| nativeType | 原生按钮的类型 | String | - | `button` |
| size | 按钮的大小 | String | `large`, `small`, `smaller` | - |
| hollow | 是否为空心按钮 | Boolean | - | false |
| icon | 按钮的图标类名，填入图标的 `classname` | String | 见文档 `Icon 图标` | - |
| loading | 设置按钮的载入状态 | Boolean | - | false |
| circle | 设置圆形图标按钮 | Boolean | - | false |


<style lang="scss" scoped>
    .row {
        .by-btn + .by-btn {
            margin-left: 8px;
        }

        & + .row {
            margin-top: 20px;
        }
        .by-btn-group .by-btn {
            margin-left: 0;
        }
    }

    .by-btn-group {
        margin-left: 8px;
        margin-top: 16px;
    }
</style>
<file_sep>/src/components/icon/index.ts
import Icon from './src/icon.vue'

Object.defineProperty(Icon, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-icon', Icon);
    }
})

export default Icon

<file_sep>/src/locale/lang/pt-BR.ts
export default {
    by: {
        select: {
            placeholder: 'Selecione',
            notFoundText: 'Nenhum dado correspondente'
        },
        modal: {
            okText: 'OK',
            cancelText: 'Cancelar'
        },
        pagination: {
            prevText: 'Página anterior',
            nextText: 'Próxima página',
            total: 'Total',
            item: 'item',
            items: 'itens',
            pageSize: '/ página',
            goto: 'Ir para',
            pageText: '',
            prev5Text: '5 Páginas anteriores',
            next5Text: 'Próximas 5 Páginas'
        },
        table: {
            emptyText: 'Sem dados'
        }
    }
}
<file_sep>/src/components/menu-item/index.ts
import MenuItem from '../menu/src/menu-item.vue'

Object.defineProperty(MenuItem, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-menu-item', MenuItem);
    }
})

export default MenuItem
<file_sep>/src/components/loading-bar/index.ts
import LoadingBar from './src/loading-bar';
import { LoadingBarOption } from './model';

let loadingBarInstance: any;
let option: LoadingBarOption = new LoadingBarOption();
let timer: any;


function getLoadingBarInstance(option: LoadingBarOption) {
    loadingBarInstance = loadingBarInstance || new LoadingBar(option);
    return loadingBarInstance;
}

function update(options: LoadingBarOption) {
    const instance = getLoadingBarInstance(options);
    instance.update(options);
}

function hide() {
    setTimeout(() => {
        update(new LoadingBarOption(undefined, undefined, 0, undefined, false));
        destroy()
    }, 800)
}

function destroy() {
    const instance = getLoadingBarInstance(new LoadingBarOption())
    clearTimer()
    loadingBarInstance = null
    instance.destroy()
}

function clearTimer() {
    if (timer) {
        clearInterval(timer)
        timer = null
    }
}

export default {
    start() {
        if (timer) return;

        let percent = 0;

        update(option);

        timer = setInterval(() => {

            percent += Math.floor((Math.random() * 3) + 5);

            if (percent > 90) {
                clearTimer()
            }

            update(new LoadingBarOption(undefined, undefined, percent, 'success', true));

        }, 200);

    },

    update(percent: number) {
        clearTimer();
        option.status = 'success';
        option.percent = percent;
        console.log(option);
        update(option);
    },

    finish() {
        clearTimer();
        option.status = 'success';
        option.percent = 100;
        hide()
    },

    error() {
        clearTimer();
        option.status = 'error';
        option.percent = 100;
        option.color = '';
        update(option);
        hide();
    },

    config(options: LoadingBarOption) {
        option = options
    }

}
<file_sep>/docs/markdown/badge.md

# Badge 徽标

----

## 独立使用

不包裹任何元素，类似 `Tag` 标签

:::demo
```html
<by-badge value="3" ></by-badge>
<by-badge value="23"></by-badge>
<by-badge value="199"></by-badge>
<by-badge value="2019"></by-badge>
```
:::

## 文本内容

徽标既可以数字，也可以是文本内容

:::demo
```html
<by-badge value="new"></by-badge>
<by-badge value="hot"></by-badge>
```
:::


## 不同状态

设置属性 `status` 指定不同的状态徽标

:::demo
```html
<by-badge value="123"></by-badge>
<by-badge value="123" status="success"></by-badge>
<by-badge value="123" status="warning"></by-badge>
<by-badge value="123" status="info"></by-badge>
```
:::

## 设定最大值

设置属性 `max-num` 可自定义徽标的最大值，超过最大值则显示 `+`

:::demo
```html
<by-badge :value="value"  :max-num="maxNum"></by-badge>
```
:::

## 组合用法

与其他组件组合使用，用于展示消息数量等

:::demo
```html
    <by-badge value="3">
        <by-button>回复</by-button>
    </by-badge><br /><br />
    <by-badge :value="value" :max-num="maxNum">
        <by-button>回复</by-button>
    </by-badge><br /><br />
    <by-badge value="new">
        <by-button>回复</by-button>
    </by-badge>
```
:::

## 小红点

设置属性 `dot` 不显示具体的数字

:::demo
```html
    <by-badge :value="12" dot></by-badge>
    <by-badge :value="12" dot>
        <by-button>回复</by-button>
    </by-badge>
    <by-badge :value="12" dot>
        <i class="icon icon-inbox"></i>
    </by-badge>
    <by-badge :value="12" dot>
        <span>消息</span>
    </by-badge>
```
:::


## 动态展示

动态展示变化的效果

:::demo
```html
<by-badge :value="num" :max-num="60">
    <span class="badge-example"></span>
</by-badge>
<by-badge :value="num" :show="show" dot>
    <span class="badge-example"></span>
</by-badge>
<br>
<by-button @click="num -= 1">-</by-button>
<by-button @click="num += 1">+</by-button>
<by-button size="small" @click="toggleDot">{{show ? '隐藏' : '显示'}}小红点</by-button>
```
:::

## Badge 参数

| 参数      | 说明          | 类型      | 可选值                           | 默认值  |
|---------- |-------------- |---------- |--------------------------------  |-------- |
| value | 绑定的值 | String / Number | - | - |
| maxNum | 允许的最大值，超出则用 `+` 号显示 | Number | - | 99 |
| dot | 是否显示为小红点 | Boolean | - | false |
| status | 徽标的类型 | String | `success` `warning` `info` | - |
| show | 是否显示徽标 | Boolean | - | true |


<script lang="ts">
    import { Vue, Component } from "vue-property-decorator";

    @Component
    export default class ByBadgeMd extends Vue {
        maxNum = 99;

        value = 123;

        num = 50;

        show = true;

        toggleDot() {
            this.show = !this.show;
        }
    }

</script>

<style lang="scss" scoped>

    .badge-example{
        display: inline-block;
        width: 32px;
        height: 32px;
        border-radius: 6px;
        background: #EEE;
        cursor: pointer;
    }

    .by-badge + .by-badge {
        margin-left: 24px;
    }

</style>
<file_sep>/src/locale/lang/zh-CN.ts
export default {
    by: {
        index: {
            h4: '通过模块化UI组件库，专注于更好的用户体验',
            button: '开始使用',
            btnGroup: [
                {
                    title: '指南',
                    content: '了解设计指南，利用统一的规范进行设计帮助产品设计师、前端工程师快速搭建'
                },{
                    title: '组件',
                    content: '通过组件的Demo体验交互细节，开发即可单独引用，也可使用全局方式引入组件'
                },{
                    title: '资源',
                    content: '产品可直接用sketch工具快速搭建高保真产品原型，减少沟通成本'
                }
            ]
        },
        header: {
            adminSystem: '管理后台',
            component: '组件',
            guide: '指南'
        },
        color: {
            themeColor: '主色',
            themeColorDesc: '用于标识品牌颜色',
            colorTitle: 'Color 颜色',
            colorDesc: '统一的色彩搭配可以提高品牌的识别度，色彩的运用除了需要考虑品牌的统一性之外，还需要达到信息传递，交互反馈等目的。BY-UI 是BY实验室出品，品牌颜色为【BY蓝】，因此 BY-UI 的整体配色风格也是基于【BY蓝】展开的。',
        },
        nav: {
            color: '色彩',
            font: '字体',
            brand: '品牌',
            introduce: '介绍',
            component: '组件',
            summarize: '综述',
            baseComponent: '基础组件',
            formComponent: '表单组件',
            viewComponent: '视图组件',
            navComponent: '导航组件',
            button: 'Button 按钮',
            layout: 'Layout 布局',
            tag: 'Tag 标签',
            icon: 'Icon 图标',
            checkbox: 'Checkbox 多选框',
            input: 'Input 输入框',
            inputnumber: 'InputNumber 数字输入框',
            radio: 'Radio 单选框',
            rate: 'Rate 评分',
            select: 'Select 选择器',
            switch: 'Switch 开关',
            form: 'Form 表单',
            slider: 'Slider 滑动输入条',
            textarea: 'Textarea 文本域',
            alert: 'Alert 警告提示',
            badge: 'Badge 徽标',
            card: 'Card 卡片',
            collapse: 'Collapse 折叠面板',
            loadingBar: 'LoadingBar 加载进度条',
            modal: 'Modal 模态框',
            message: 'Message 全局提示',
            notification: 'Notification 通知提醒',
            popover: 'Popover 弹出框',
            progress: 'Progress 进度条',
            timeline: 'Timeline 时间轴',
            tooltip: 'Tooltips 文字提示',
            table: 'Table 表格',
            drawer: 'Drawer 抽屉',
            breadcrumb: 'Breadcrumb 面包屑',
            dropdown: 'Dropdown 下拉菜单',
            menu: 'Menu 导航菜单',
            pagination: 'Pagination 分页',
            steps: 'Steps 步骤条',
            tabs: 'Tabs 标签页',
        },
        select: {
            placeholder: '请选择',
            notFoundText: '无匹配数据'
        },
        modal: {
            okText: '确定',
            cancelText: '取消'
        },
        pagination: {
            prevText: '上一页',
            nextText: '下一页',
            total: '共',
            item: '条',
            items: '条',
            pageSize: '条/页',
            goto: '前往',
            pageText: '页',
            prev5Text: '向前5页',
            next5Text: '向后5页'
        },
        table: {
            emptyText: '暂无数据'
        }
    }
}
<file_sep>/docs/markdown/loadingbar.md

# LoadingBar 加载进度条

----

全局创建了一个用于显示页面加载、异步请求的加载进度条。

因为可复用性的关系，`LoadingBar` 只会全局创建一个实例，而且在 `Vue.prototype` 中添加了全局对象 `$loadingBar`，可以直接通过 `this.$loadingBar` 操作实例

## 基础用法

通过调用 `$loadingBar` 提供的三种方法来控制全局的加载进度条 `start()`、`finish()`、`error()`


:::demo
```html
<by-button @click="start">Start</by-button>
<by-button @click="finish">Finish</by-button>
<by-button @click="error">Error</by-button>
<by-button @click="update">Update</by-button>

<script>
  export default {
    methods: {
      start () {
        this.$loadingBar.start()
      },
      finish () {
        this.$loadingBar.finish()
      },
      error () {
        this.$loadingBar.error()
      },
      update () {
        this.$loadingBar.update(60)
      }
    }
  }
</script>
```
:::


## LoadingBar 函数方法

| 函数名      | 说明          | 参数      |
|---------- |-------------- |---------- |
| start | 开始从 0 显示加载进度条，并自动加载 | - |
| finish | 完成进度条 | - |
| error | 显示错误类型的进度条 | - |
| update | 指定进度的百分比，更新进度条 | percent，指定进度的百分比 |

## LoadingBar 配置

提供 `LoadingBar` 的全局配置，使用方法如下：

```js
this.$loadingBar.config(new LoadingBarOption(
    10, // 高度
    'linear-gradient(to right, #30fcfc, #fff5ee)', // 背景色，支持渐变
    1, // 百分比进度
    'success',  // 状态
    true // 显示隐藏
));
```

:::demo
```html
<by-button @click="startLinear">设置渐变及高度</by-button>

<script>
  export default {
    methods: {
      startLinear(){
        this.$loadingBar.config(new LoadingBarOption(
            10, 'linear-gradient(to right, #30fcfc, #fff5ee)', 1, 'success', true
        ));
        this.$loadingBar.start()
      },
    }
  }
</script>
```
:::

## LoadingBar 参数

| 参数      | 说明          | 类型      | 可选值                           | 默认值  |
|---------- |-------------- |---------- |--------------------------------  |-------- |
| height | 进度条的线宽 | Number | - | 4 |
| color | 进度条的背景色 | String | - | - |
| percent | 进度条的百分比 | Number | - | - |
| status | 进度条的状态 | String | `success` `error` | success |
| show | 进度条的显隐 | Boolean | `true` `false` | true |

<script lang="ts">
    import { Vue, Component } from "vue-property-decorator";
    import { LoadingBarOption } from '../../src/components/loading-bar/model.ts';

    @Component
    export default class LoadingBar extends Vue {
        start () {
            this.$loadingBar.start();
        }
        startLinear(){
            this.$loadingBar.config(new LoadingBarOption(
                10, 'linear-gradient(to right, #30fcfc, #fff5ee)', 1, 'success', true
            ));
            this.$loadingBar.start();
        }
        finish () {
            this.$loadingBar.finish();
        }
        error () {
            this.$loadingBar.error();
        }
        update () {
            this.$loadingBar.update(60)
        }
    }
 </script>
<file_sep>/docs/markdown/modal.md

# Modal 模态框

----

模态对话框，当需要询问用户处理事务，又不希望跳转页面时，可以使用模态框 `Modal` 在当前页面打开一个浮层并承载相应的操作。

当需要弹出一个简洁的确认框时，也可以使用默认的精简版模态框。`BY-UI` 在 `Vue.prototype` 中添加了全局对象 `$modal`，可以直接通过 `this.$modal` 对象操作实例方法

## Modal 实例方法

通过调用 `this.$modal` 的方法来使用：
- `this.$modal.alert(config)`
- `this.$modal.confirm(config)`
- `this.$modal.prompt(config)`
- `this.$modal.info(config)`
- `this.$modal.success(config)`
- `this.$modal.warning(config)`
- `this.$modal.error(config)`

## 消息提醒

弹出会中断用户的对话框，直到用户知晓该信息之后才可以关闭，属于交互比较重的操作。（类似于 `window.alert`）

可以用 `Promise` 的方式捕获操作反馈，也可以用传入 `callback` 参数的方式

:::demo
```html
<p class="demo-desc">this.$modal.alert()</p>
<by-button @click="modalAlert">Alert</by-button>

<script>
  export default {
    methods: {
      modalAlert () {
        this.$modal.alert({
          title: '这里是标题名称',
          content: '这里是文本内容',
          callback: function (action) {
            this.$message(action)
          }
        })
      }
    }
  }
</script>
```
:::

## 确认消息

对用户操作的一个反馈，用于确定是否需要继续操作。（类似于 `window.confirm`）

:::demo
```html
<p class="demo-desc">this.$modal.confirm()</p>
<by-button @click="modalConfirm">Confirm</by-button>

<script>
  export default {
    methods: {
      modalConfirm () {
        this.$modal.confirm({
          title: '提示',
          content: '此操作需要非常谨慎，您确定要这么做吗？'
        }).then(() => {
          this.$message('点击了「确认」按钮')
        }).catch(() => {
          this.$message('点击了「取消」按钮')
        })
      }
    }
  }
</script>
```
:::

## 提交信息

弹出输入对话框，提醒用户输入相应内容。（类似于 `window.prompt`）

:::demo
```html
<p class="demo-desc">this.$modal.prompt({ title: '提示', content: '请输入邮件地址：' })</p>
<by-button @click="modalPrompt">Prompt</by-button>

<script>
  export default {
    methods: {
      modalPrompt () {
        this.$modal.prompt({
          title: '提示',
          content: '请输入邮件地址：'
        }).then((data) => {
          this.$message(`点击了「确认」按钮，输入框的值为 ${data.value}`)
        }).catch(() => {
          this.$message('点击了「取消」按钮')
        })
      }
    }
  }
</script>
```
:::

## 消息类的对话框

除了上述的类 `window` 对话框，`by-UI` 还提供了四种消息类的对话框，主要用来展示一些重要信息。该类的对话框仅允许点击「确定」按钮关闭，不支持其他关闭方式

:::demo
```html
<p class="demo-desc">this.$modal.success()</p>
<by-button @click="handleClick('success')">成功</by-button>
<by-button @click="handleClick('error')">错误</by-button>
<by-button @click="handleClick('warning')">警告</by-button>
<by-button @click="handleClick('info')">消息</by-button>

<script>
  export default {
    methods: {
      handleClick (type) {
        if (type === 'info') {
          this.$modal.info({
            content: '这里是提示的消息'
          })
        } else if (type === 'success') {
          this.$modal.success({
            content: '这里是成功的消息'
          })
        } else if (type === 'warning') {
          this.$modal.warning({
            content: '这里是警告的消息'
          })
        } else if (type === 'error') {
          this.$modal.error({
            content: '这里是错误的消息'
          })
        }
      }
    }
  }
</script>
```
:::

## 组件化方式调用

前面提到的是通过 `this.$modal` 的方法来使用，如果要自定义对话框，可使用组件化的方式

:::demo
```html
<by-button @click="modal1=true">显示自定义模态框</by-button>
<by-modal v-model="modal1" title="这里是标题" @on-confirm="handleConfirm" @on-cancel="handleCancel">
  <p>这里是模态框的文本内容!</p>
  <p>这里是模态框的文本内容!</p>
</by-modal>

<script>
  export default {
    methods: {
      handleConfirm () {
        this.$message('Confirm')
      },
      handleCancel () {
        this.$message('Cancel')
      }
    }
  }
</script>
```
:::

## 自定义样式

`Modal` 组件提供了自定义页头、页脚的 `slot`，可灵活的控制对话框的样式结构。通过与其他组件的交互，可实现复杂的功能需求。

:::demo
```html
<by-button @click="modal2=true">自定义页头和页脚</by-button>
<by-button @click="modal3=true">不带标题</by-button>
<by-modal v-model="modal2">
  <div slot="header" style="text-align:center;">
    <span>这里是标题</span>
  </div>
  <div style="text-align:center;">
    <p>能看到这里的内容吗？</p>
  </div>
  <div slot="footer">
    <by-button style="width:100%;" type="error" @click="closeModal2">这里是按钮</by-button>
  </div>
</by-modal>
<by-modal v-model="modal3">
  <p>这里是模态框的文本内容!</p>
</by-modal>

<script>
  export default {
    methods: {
      closeModal2 () {
        this.modal2 = false
      }
    }
  }
</script>
```
:::

## 禁用关闭

- 设置属性 `show-close` 为 `false` 可取消右上角的关闭按钮以及键盘的 `ESC` 键；
- 设置属性 `mask-closable` 为 `false` 可取消遮罩层的点击关闭事件；

:::demo
```html
<by-button @click="modal4=true">禁用右上角关闭按钮（含 ESC）</by-button>
<by-button @click="modal5=true">取消遮罩层关闭</by-button>
<by-modal v-model="modal4" title="标题" :show-close="false">这里是文本</by-modal>
<by-modal v-model="modal5" title="标题" :show-close="false" :mask-closable="false">这里是文本</by-modal>
```
:::

## 自定义窗口位置

通过属性 `styles` 传入 `CSS Style Object`，可更改弹框的样式

:::demo
```html
<by-button @click="modal6=true">仅改变距离顶部的位置</by-button>
<by-modal v-model="modal6" title="标题" :styles="{top: '20px'}">这里是文本内容</by-modal>
```
:::

## Modal 参数

| 参数      | 说明          | 类型      | 可选值                           | 默认值  |
|---------- |-------------- |---------- |--------------------------------  |-------- |
| value | 是否显示模态框，可通过 `v-model` 绑定 | Boolean | - | false |
| title | 模态框的标题 | String | - | - |
| content | 模态框的内容 | String | - | - |
| cancelText | 取消按钮的文本 | String | - | 取消 |
| okText | 确定按钮的文本 | String | - | 确定 |
| maskClosable | 点击遮罩层是否可以关闭模态框 | Boolean | - | true |
| showHead | 是否显示标题 | Boolean | - | true |
| showClose | 是否显示关闭按钮 | Boolean | - | true |
| showFooter | 是否显示底部按钮 | Boolean | - | true |
| showInput | 是否显示输入框 | Boolean | - | false |
| width | 模态框的宽度 | Number / String | - | `520` |
| closeOnPressEsc | 点击 `ESC` 是否可以关闭模态框 | Boolean | - | true |
| styles | 模态框的自定义样式 | Object | - | - |

## Modal 事件

| 事件名称 | 说明          | 返回参数  |
|---------- |-------------- |---------- |
| on-cancel | 点击取消的回调事件 | - |
| on-confirm | 点击确定的回调事件 | - |

## Modal Slots

| 名称     | 说明          |
|-------- |------------------- |
| header | 自定义模态框的头部 |
| footer | 自定义模态框的底部，即底部按钮部分 |
| - | 自定义模态框的主体内容 |

<script>
  export default {
    data () {
      return {
        modal1: false,
        modal2: false,
        modal3: false,
        modal4: false,
        modal5: false,
        modal6: false
      }
    },
    methods: {
      handleClick (type) {
        if (type === 'info') {
          this.$modal.info({
            content: '这里是提示的消息'
          })
        } else if (type === 'success') {
          this.$modal.success({
            content: '这里是成功的消息'
          })
        } else if (type === 'warning') {
          this.$modal.warning({
            content: '这里是警告的消息'
          })
        } else if (type === 'error') {
          this.$modal.error({
            content: '这里是错误的消息'
          })
        }
      },
      modalAlert () {
        this.$modal.alert({
          title: '这里是标题名称',
          content: '这里是文本内容',
          callback: action => {
            this.$message(action)
          }
        })
      },
      modalConfirm () {
        this.$modal.confirm({
          title: '提示',
          content: '此操作需要非常谨慎，您确定要这么做吗？'
        }).then(() => {
          this.$message('点击了「确认」按钮')
        }).catch(() => {
          this.$message('点击了「取消」按钮')
        })
      },
      modalPrompt () {
        this.$modal.prompt({
          title: '提示',
          content: '请输入邮件地址：'
        }).then((data) => {
          this.$message(`点击了「确认」按钮，输入框的值为 ${data.value}`)
        }).catch(() => {
          this.$message('点击了「取消」按钮')
        })
      },
      handleConfirm () {
        this.$message('Confirm')
      },
      handleCancel () {
        this.$message('Cancel')
      },
      closeModal2 () {
        this.modal2 = false
      }
    }
  }
</script>
<file_sep>/build/webpack/webpack.prod.config.ts
import * as path from 'path';
import * as merge from 'webpack-merge';
import * as HtmlPlugin from 'html-webpack-plugin';
import * as UglifyJsPlugin from 'uglifyjs-webpack-plugin';
import * as OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
import * as FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin';
import CleanWebpackPlugin from 'clean-webpack-plugin';

import * as baseConfig from './webpack.base.config';

import byui from '../config/by-ui';

let notes = [
    `Compile Successful!`
];

module.exports = merge(baseConfig, {
    mode: 'production',
    entry: {
        index: [path.resolve("docs/index.ts")]
    },
    output: {
        path: path.resolve('dist'),
        filename: `[name].[contenthash].js`,
        chunkFilename: `[name].[contenthash].js`,
        publicPath: './',
    },
    devtool: false,
    stats: false,
    plugins: [
        new CleanWebpackPlugin(),
        new FriendlyErrorsWebpackPlugin({
            compilationSuccessInfo: {
                messages: [
                    ...byui
                ],
                notes: [
                    ...notes
                ],
            },
        }),
        new HtmlPlugin({
            filename: "index.html",
            title: "By-ui",
            template: path.resolve("docs/index.html"),
            showErrors: true,
            favicon: './favicon.ico'
        }),
    ],
    optimization: {
        minimizer: [
            new UglifyJsPlugin({
                cache: true,
                parallel: true,
                sourceMap: false
            }),
            new OptimizeCSSAssetsPlugin({
                cssProcessorOptions: {
                    safe: true,
                },
            }),
        ]
    }
})
<file_sep>/src/components/form-item/index.ts
import FormItem from '../form/src/form-item.vue'

Object.defineProperty(FormItem, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-form-item', FormItem);
    }
})

export default FormItem;
<file_sep>/src/locale/lang/ko-KR.ts
export default {
    by: {
        select: {
            placeholder: '선택',
            notFoundText: '찾는 데이터가 없습니다'
        },
        modal: {
            okText: '확인',
            cancelText: '취소'
        },
        pagination: {
            prevText: '이전 페이지',
            nextText: '다음 페이지',
            total: '전체',
            item: '항목',
            items: '항목',
            pageSize: '/ 페이지',
            goto: '이동',
            pageText: '',
            prev5Text: '이전 5 페이지',
            next5Text: '다음 5 페이지'
        },
        table: {
            emptyText: '데이터가 없습니다'
        }
    }
}
<file_sep>/src/components/message/src/message.ts
import Vue from 'vue';
import MessageVue from './message.vue';
const MessageConstructor = Vue.extend(MessageVue);

const messageType = ['info', 'success', 'warning', 'error', 'loading'];
const instances: any = [];
let seed = 1;
let zindexSeed = 1010;

const Message = (options: any) => {
    if (Vue.prototype.$isServer) return;
    options = options || {};

    if (typeof options === 'string') {
        options = {
            message: options
        };
    }

    const customCloseFunc = options.onClose;
    const id: string = `message_${seed++}`;

    options.onClose = () => {
        Message.close(id, customCloseFunc);
    };

    const instance = new MessageConstructor({
        data: options
    });

    instance.id = id;
    instance.vm = instance.$mount();
    document.body.appendChild(instance.vm.$el);
    instance.vm.visible = true;
    instance.dom = instance.vm.$el;
    instance.dom.style.zIndex = zindexSeed++;

    const offset = 0;
    const len = instances.length;
    let topDist = offset;

    for (let i = 0; i < len; i++) {
        topDist += instances[i].$el.offsetHeight + 8;
    }

    topDist += 8;
    instance.top = topDist;

    instances.push(instance);

    // 返回关闭方法，用于手动消除
    return function() {
        instance.vm.close(id);
    };
}

Message.close = (id: string, customCloseFunc: any) => {
    const len = instances.length;
    let index: number = 0,
        removedHeight;

    for (let i: number = 0; i < len; i++) {
        if (id === instances[i].id) {
            if (typeof customCloseFunc === 'function') {
                customCloseFunc(instances[i]);
            }
            index = i;
            removedHeight = instances[i].dom.offsetHeight;
            instances.splice(i, 1);
            break;
        }
    }

    if (len > 1) {
        for (let i: number = index; i < len - 1; i++) {
            instances[i].dom.style.top = `${parseInt(
                instances[i].dom.style.top
            ) -
                removedHeight -
                8}px`;
        }
    }
}

Message.closeAll = () => {
    instances.forEach((elem: any, idx: any) => {
        elem.close();
    });
}

Message.info = (options:any) => newMessage(options, 'info')
Message.success = (options:any) => newMessage(options, 'success')
Message.warning = (options:any) => newMessage(options, 'warning')
Message.error = (options:any) => newMessage(options, 'error')
Message.loading = (options:any) => newMessage(options, 'loading')

function newMessage(options:any , type: string){
    if (typeof options === 'string') {
        options = {
            message: options
        };
    }
    options.type = type;
    options.icon = options.icon;
    return Message(options);
}

export default Message;
<file_sep>/src/components/step/index.ts
import Step from './src/step.vue'

Object.defineProperty(Step, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-step', Step);
    }
})

export default Step
<file_sep>/src/components/menu-item-group/index.ts
import MenuItemGroup from '../menu/src/menu-item-group.vue'

Object.defineProperty(MenuItemGroup, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-menu-item-group', MenuItemGroup);
    }
})

export default MenuItemGroup
<file_sep>/src/components/form/index.ts
import Form from './src/form.vue'

Object.defineProperty(Form, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-form', Form);
    }
})

export default Form;
<file_sep>/src/components/select-option/index.ts
import Option from '../select/src/option.vue'

Object.defineProperty(Option, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-option', Option);
    }
})

export default Option<file_sep>/docs/resources/directives/index.ts
import Vue from 'vue';
import VueClipboard from './clipboard/clipboard';

Vue.use(VueClipboard);
<file_sep>/docs/utils/util.ts
/**
 * 常用方法
 */

const SPECIAL_CHARS_REGEXP = /([:\-_]+(.))/g
const MOZ_HACK_REGEXP = /^moz([A-Z])/

const trim = function (string) {
    return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '')
}

/**
 * [camelCaseToHyphen 将驼峰命名转换为连字符]
 * @param  {[string]} str [驼峰命名的字符串]
 * @return {[string]}     [连字符的字符串]
 */
export function camelCaseToHyphen(str) {
    return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
}

export function camelCase(name) {
    return name.replace(SPECIAL_CHARS_REGEXP, function (_, separator, letter, offset) {
        return offset ? letter.toUpperCase() : letter
    }).replace(MOZ_HACK_REGEXP, 'Moz$1')
}

export function getStyle(element, styleName) {
    if (!element || !styleName) return null

    styleName = camelCase(styleName)
    if (styleName === 'float') {
        styleName = 'cssFloat'
    }

    try {
        const computed = document.defaultView.getComputedStyle(element, '')
        return element.style[styleName] || computed ? computed[styleName] : null
    } catch (e) {
        return element.style[styleName]
    }
}

function typeOf(obj) {
    const map = {
        '[object Boolean]': 'boolean',
        '[object Number]': 'number',
        '[object String]': 'string',
        '[object Function]': 'function',
        '[object Array]': 'array',
        '[object Date]': 'date',
        '[object RegExp]': 'regExp',
        '[object Undefined]': 'undefined',
        '[object Null]': 'null',
        '[object Object]': 'object',
    }
    return map[Object.prototype.toString.call(obj)]
}

export function deepCopy(data) {
    const type = typeOf(data)
    let obj

    if (type === 'array') {
        obj = []
    } else if (type === 'object') {
        obj = {}
    } else {
        return data
    }

    if (type === 'array') {
        for (let i = 0; i < data.length; i++) {
            obj.push(deepCopy(data[i]))
        }
    } else if (type === 'object') {
        for (const i in data) {
            obj[i] = deepCopy(data[i])
        }
    }

    return obj
}

export function hasClass(el, cls) {
    if (!el || !cls) return false
    if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.')
    if (el.classList) {
        return el.classList.contains(cls)
    }
    return (` ${el.className} `).indexOf(` ${cls} `) > -1
}

export function addClass(el, cls) {
    if (!el) return

    const classes = (cls || '').split(' ')
    let curClass = el.className

    for (let i = 0, j = classes.length; i < j; i++) {
        const clsName = classes[i]
        if (!clsName) continue

        if (el.classList) {
            el.classList.add(clsName)
        } else if (!hasClass(el, clsName)) {
            curClass += ` ${clsName}`
        }
    }
    if (!el.classList) {
        el.className = curClass
    }
}

export function removeClass(el, cls) {
    if (!el || !cls) return
    const classes = cls.split(' ')
    let curClass = ` ${el.className} `

    for (let i = 0, j = classes.length; i < j; i++) {
        const clsName = classes[i]
        if (!clsName) continue

        if (el.classList) {
            el.classList.remove(clsName)
        } else if (hasClass(el, clsName)) {
            curClass = curClass.replace(` ${clsName} `, ' ')
        }
    }
    if (!el.classList) {
        el.className = trim(curClass)
    }
}

export function findComponentUpward(context: any, componentName: any, componentNames?: any) {
    if (typeof componentName === 'string') {
        componentNames = [componentName]
    } else {
        componentNames = componentName
    }

    let parent = context.$parent
    let name = parent.$options.name
    while (parent && (!name || componentNames.indexOf(name) < 0)) {
        parent = parent.$parent
        if (parent) name = parent.$options.name
    }

    return parent
}

export function findComponentsUpward(context, componentName, components = []) {
    let parent = context.$parent
    let name = parent.$options.name

    while (parent && name) {
        if (componentName === name) {
            components.push(parent)
        }

        parent = parent.$parent
        if (parent) {
            name = parent.$options.name
        }
    }

    return components
}

export function findComponentDownward(context, componentName) {
    const childrens = context.$children
    let children

    if (childrens.length) {
        childrens.forEach(child => {
            if (child.$options.name === componentName) {
                children = child
            }
        })

        for (let i = 0, len = childrens.length; i < len; i++) {
            const child = childrens[i]
            const name = child.$options.name

            if (name === componentName) {
                children = child
                break
            } else {
                children = findComponentDownward(child, componentName)
                if (children) break
            }
        }
    }

    return children
}

export function findComponentsDownward(context, componentName, components = []) {
    const childrens = context.$children

    if (childrens.length) {
        childrens.forEach(child => {
            const subChildren = child.$children
            const name = child.$options.name

            if (name === componentName) {
                components.push(child)
            }
            if (subChildren.length) {
                const findChildren = findComponentsDownward(child, componentName, components)
                if (findChildren) {
                    components.concat(findChildren)
                }
            }
        })
    }

    return components
}
<file_sep>/docs/vue-router/index.ts
import Vue from 'vue';
import VueRouter, { RouterOptions } from 'vue-router';

import routes from './routes';

Vue.use(VueRouter);

const options: RouterOptions = {
    routes,
};

const router = new VueRouter(options);
router.beforeEach((to, from, next) => {
    next();
    (window as any).scrollbar && (window as any).scrollbar.scrollTo(0, 0, 200)
})

export default router;
<file_sep>/src/components/message/index.ts
import Message from './src/message'
export default Message;
<file_sep>/src/components/menu/index.ts
import Menu from './src/menu.vue'

Object.defineProperty(Menu, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-menu', Menu);
    }
})

export default Menu
<file_sep>/src/components/popover/index.ts
import Popover from './src/popover.vue'

Object.defineProperty(Popover, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-popover', Popover);
    }
})

export default Popover
<file_sep>/src/mixins/popup/index.ts
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';

import merge from '../merge';
import PopupManager from './popup-manager';
import getScrollBarWidth from '../scrollbar-width';
import { getStyle, addClass, removeClass, hasClass } from '../dom';

let idSeed = 1;

let scrollBarWidth;

@Component
export default class Popup extends Vue {

    @Prop({
        default: false
    })
    visible?: boolean;

    @Prop()
    openDelay?: {};

    @Prop()
    closeDelay?: {};

    @Prop()
    zIndex?: {};

    @Prop({
        default: false
    })
    modal?: boolean;

    @Prop({
        default: true
    })
    modalFade?: boolean;

    @Prop()
    modalClass?: {};

    @Prop({
        default: false
    })
    modalAppendToBody?: boolean;

    @Prop({
        default: true
    })
    lockScroll?: boolean;

    @Prop({
        default: false
    })
    closeOnPressEscape?: boolean;

    @Prop({
        default: false
    })
    closeOnClickModal?: boolean;

    opened = false;

    bodyPaddingRight = null;

    computedBodyPaddingRight = 0;

    withoutHiddenClass = true;

    rendered = false;

    open(options?:any) {
        console.log('open');
        if (!this.rendered) {
            this.rendered = true;
        }

        const props = merge({}, this.$props || this, options);

        if (this._closeTimer) {
            clearTimeout(this._closeTimer);
            this._closeTimer = null;
        }
        clearTimeout(this._openTimer);

        const openDelay = Number(props.openDelay);
        if (openDelay > 0) {
            this._openTimer = setTimeout(() => {
                this._openTimer = null;
                this.doOpen(props);
            }, openDelay);
        } else {
            this.doOpen(props);
        }
    }

    doOpen(props:any) {
        if (this.$isServer) return;
        if (this.willOpen && !this.willOpen()) return;
        if (this.opened) return;

        this._opening = true;

        const dom = this.$el;

        const modal = props.modal;

        const zIndex = props.zIndex;
        if (zIndex) {
            PopupManager.zIndex = zIndex;
        }

        if (modal) {
            if (this._closing) {
                PopupManager.closeModal(this._popupId);
                this._closing = false;
            }
            PopupManager.openModal(this._popupId, PopupManager.nextZIndex(), this.modalAppendToBody ? undefined : dom, props.modalClass, props.modalFade);
            if (props.lockScroll) {
                this.withoutHiddenClass = !hasClass(document.body, 'by-popup-parent--hidden');
                if (this.withoutHiddenClass) {
                    this.bodyPaddingRight = document.body.style.paddingRight;
                    this.computedBodyPaddingRight = parseInt(getStyle(document.body, 'paddingRight'), 10);
                }
                scrollBarWidth = getScrollBarWidth();
                let bodyHasOverflow = document.documentElement.clientHeight < document.body.scrollHeight;
                let bodyOverflowY = getStyle(document.body, 'overflowY');
                if (scrollBarWidth > 0 && (bodyHasOverflow || bodyOverflowY === 'scroll') && this.withoutHiddenClass) {
                    document.body.style.paddingRight = this.computedBodyPaddingRight + scrollBarWidth + 'px';
                }
                addClass(document.body, 'by-popup-parent--hidden');
            }
        }

        if (getComputedStyle(dom).position === 'static') {
            dom.style.position = 'absolute';
        }

        dom.style.zIndex = PopupManager.nextZIndex();
        this.opened = true;

        this.onOpen && this.onOpen();

        this.doAfterOpen();
    }

    doAfterOpen() {
        this._opening = false;
    }

    close() {
        if (this.willClose && !this.willClose()) return;

        if (this._openTimer !== null) {
            clearTimeout(this._openTimer);
            this._openTimer = null;
        }
        clearTimeout(this._closeTimer);

        const closeDelay = Number(this.closeDelay);

        if (closeDelay > 0) {
            this._closeTimer = setTimeout(() => {
                this._closeTimer = null;
                this.doClose();
            }, closeDelay);
        } else {
            this.doClose();
        }
    }

    doClose() {
        this._closing = true;

        this.onClose && this.onClose();

        if (this.lockScroll) {
            setTimeout(this.restoreBodyStyle, 200);
        }

        this.opened = false;

        this.doAfterClose();
    }

    doAfterClose() {
        PopupManager.closeModal(this._popupId);
        this._closing = false;
    }

    restoreBodyStyle() {
        if (this.modal && this.withoutHiddenClass) {
            document.body.style.paddingRight = this.bodyPaddingRight;
            removeClass(document.body, 'by-popup-parent--hidden');
        }
        this.withoutHiddenClass = true;
    }

    beforeMount() {
        this._popupId = 'popup-' + idSeed++;
        PopupManager.register(this._popupId, this);
    }

    beforeDestroy() {
        PopupManager.deregister(this._popupId);
        PopupManager.closeModal(this._popupId);

        this.restoreBodyStyle();
    }

    @Watch('visible')
    onVisibleChange(val:boolean) {
        console.log({val});
        if (val) {
            if (this._opening) return;
            if (!this.rendered) {
                this.rendered = true;
                Vue.nextTick(() => {
                    this.open();
                });
            } else {
                this.open();
            }
        } else {
            this.close();
        }
    }
}
// props: {
//     visible: {
//         type: Boolean,
//       default: false
//     },
//     openDelay: { },
//     closeDelay: { },
//     zIndex: { },
//     modal: {
//         type: Boolean,
//       default: false
//     },
//     modalFade: {
//         type: Boolean,
//       default: true
//     },
//     modalClass: { },
//     modalAppendToBody: {
//         type: Boolean,
//       default: false
//     },
//     lockScroll: {
//         type: Boolean,
//       default: true
//     },
//     closeOnPressEscape: {
//         type: Boolean,
//       default: false
//     },
//     closeOnClickModal: {
//         type: Boolean,
//       default: false
//     }
// },

// export {
//     PopupManager
// };
<file_sep>/docs/markdown/typography.md
# Typography 字体

----

统一字体规范，力求在各个操作系统上都有最佳的展示效果   1231233213221332132

## 字体家族

css 代码如下：

```css
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
```


## 中文字体

<div class="row">
  <div class="by-component__container col-sm-24 col-md-8">
    <div class="by-component-typo typo-pingfang">
      <div class="by-component-typo__show">新仁类实验室</div>
      <div class="by-component-typo__detail">
        <p>苹方 / PingFang SC</p>
        <p class="note">MacOS, IOS 优选字体</p>
      </div>
    </div>
  </div>

  <div class="by-component__container col-sm-24 col-md-8">
    <div class="by-component-typo typo-dongqing">
      <div class="by-component-typo__show">新仁类实验室</div>
      <div class="by-component-typo__detail">
        <p>冬青黑体 / Hiragino Sans GB</p>
        <p class="note">MacOS 备选字体</p>
      </div>
    </div>
  </div>

  <div class="by-component__container col-sm-24 col-md-8">
    <div class="by-component-typo typo-yahei">
      <div class="by-component-typo__show">新仁类实验室</div>
      <div class="by-component-typo__detail">
        <p>微软雅黑 / Microsoft YaHei</p>
        <p class="note">次级备选字体</p>
      </div>
    </div>
  </div>
</div>

<div class="type-demo-container">
  <div class="row flex-middle typo-pingfang">
    <div class="col-md-5 type">苹方 / PingFang SC</div>
    <div class=" content">新仁类实验室(xrl.io 英文简称XRL) 始建于2015年10月，是一个年轻基情的技术团队</div>
  </div>
  <div class="row flex-middle typo-dongqing">
    <div class="col-md-5 type">冬青黑体 / Hiragino Sans GB</div>
    <div class=" content">新仁类实验室(xrl.io 英文简称XRL) 始建于2015年10月，是一个年轻基情的技术团队</div>
  </div>
  <div class="row flex-middle typo-yahei">
    <div class="col-md-5 type">微软雅黑 / Microsoft YaHei</div>
    <div class=" content">新仁类实验室(xrl.io 英文简称XRL) 始建于2015年10月，是一个年轻基情的技术团队</div>
  </div>
</div>

<style lang="scss" scoped>
  .type-demo-container {
    .row {
      margin-top: 8px;
      margin-bottom: 8px;
    }
    .type {
      color: #7E95A7;
      font-size: 13px;
      text-align: right;
    }
    .content {
      font-size: 15px;
      padding-left: 24px;
      word-break: break-all;
    }
  }
</style>
<file_sep>/src/components/button-group/index.ts
import ButtonGroup from '../button/src/button-group.vue'

Object.defineProperty(ButtonGroup, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-button-group', ButtonGroup);
    }
})

export default ButtonGroup
<file_sep>/src/components/checkbox/index.ts
import CheckBox from './src/checkbox.vue'

Object.defineProperty(CheckBox, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-checkbox', CheckBox);
    }
})

export default CheckBox

<file_sep>/docs/vue-router/routes.ts
import { RouteConfig } from 'vue-router';
import NavConfig from './nav.config.yml';

class Route {
    name: string;
    component: any;
    path: string;
    children?: Route[] = new Array();
    redirect?: any;

    constructor(name: string, component: any, path: string, children?: Route[], redirect?: any) {
        this.name = name;
        this.component = component;
        this.path = path;
        children && (this.children = children);
        redirect && (this.redirect = redirect);
    }
}

const routes: any = [];
let currentIndex: number;

Object.keys(NavConfig).forEach((parent: string, index: number) => {
    // 制定父级路由
    const _name = parent.toLowerCase();
    currentIndex = index;
    routes.push(
        new Route(
            parent,
            () => import(/* webpackChunkName: "modules/[request]" */ `../views/${_name}/${_name}.vue`),
            `/${_name}`,
            undefined,
            // 重定向到第一个子路由
            { name: NavConfig[parent][0].items[0].name.toLowerCase() }
        )
    );

    // 遍历子路由
    NavConfig[parent].forEach((item: any) => {
        const _itemName = item.name.toLowerCase();
        // 有组的情况
        if (item.groups) {
            item.groups.forEach(group => {
                group.items.forEach(item => {

                    const _name = item.name.toLowerCase();
                    routes[currentIndex].children.push(
                        new Route(
                            _name,
                            () => import(/* webpackChunkName: "modules/[request]" */ `../markdown/${_name}.md`),
                            `${_name}/`
                        )
                    )
                })
            })
        } else {
            item.items.forEach(group => {
                const _name = group.name.toLowerCase();
                routes[currentIndex].children.push(
                    new Route(
                        _name,
                        () => import(/* webpackChunkName: "modules/[request]" */ `../markdown/${_name}.md`),
                        `${_name}/`
                    )
                )
            })
        }
    })
})
routes.push({
    path: '/',
    name: 'home',
    component: () => import(/* webpackChunkName: "modules/home" */ `../views/index/index.vue`)
})

export default routes
<file_sep>/docs/markdown/form.md
# From 表单

----

## 简单的表单

:::demo
```html
<by-form :model="formData1" :rules="ruleLogin1" ref="formLogin1">
    <by-form-item prop="username">
        <by-input v-model="formData1.username" placeholder="用户名">
            <template slot="prepend">
                <i class="icon icon-user"></i>
            </template>
        </by-input>
    </by-form-item>
    <by-form-item prop="password">
        <by-input v-model="formData1.password" placeholder="密码">
            <template slot="prepend">
                <i class="icon icon-lock"></i>
            </template>
        </by-input>
    </by-form-item>
    <by-form-item label="记住密码">
        <by-switch v-model="formData1.remember"></by-switch>
    </by-form-item>
    <by-form-item>
        <by-button type="primary" size="small" @click.prevent="handleSubmit('formLogin1')">登录</by-button>
    </at-form-item>
</by-form>
```
:::


## 设置label内容及宽度

:::demo
```html
<div style="width: 450px;">
    <by-form :model="formData2" :rules="ruleLogin2" ref="formLogin2" :label-width="80">
        <by-form-item prop="name" label="活动名称">
            <by-input v-model="formData2.name"></by-input>
        </by-form-item>
        <!-- <by-form-item prop="password" label="活动区域">
            <by-select v-model="formData2.area"></by-select>
        </by-form-item> -->
        <by-form-item prop="password" label="即时配送">
            <by-switch v-model="formData2.delivery"></by-switch>
        </by-form-item>
        </el-form-item>
        <by-form-item prop="type" label="活动性质">
            <by-checkbox-group v-model="formData2.type">
                <by-checkbox label="美食/餐厅线上活动" name="type">美食/餐厅线上活动</by-checkbox>
                <by-checkbox label="地推活动" name="type">地推活动</by-checkbox>
                <by-checkbox label="线下主题活动" name="type">线下主题活动</by-checkbox>
                <by-checkbox label="单纯品牌曝光" name="type">单纯品牌曝光</by-checkbox>
            </by-checkbox-group>
        </by-form-item>
        <by-form-item prop="resource" label="特殊资源">
            <by-radio-group v-model="formData2.resource">
                <by-radio label="线上品牌商赞助">线上品牌商赞助</by-radio>
                <by-radio label="线下场地免费">线下场地免费</by-radio>
            </by-radio-group>
        </by-form-item>
        <by-form-item prop="desc" label="活动形式">
            <by-input type="textarea" v-model="formData2.desc"></by-input>
        </by-form-item>
        <by-form-item>
            <by-button type="primary" size="small" @click.prevent="handleSubmit('formLogin2')">登录</by-button>
        </at-form-item>
    </by-form>
</div>
```
:::



## 设置label-postion

:::demo
```html
<by-radio-group v-model="labelPosition" size="small">
    <by-radio-button label="left">左对齐</by-radio-button>
    <by-radio-button label="right">右对齐</by-radio-button>
    <by-radio-button label="top">顶部对齐</by-radio-button>
</by-radio-group>
<div style="width: 400px; margin-top: 20px;">
    <by-form :model="formData3" :rules="ruleLogin3" ref="formLogin3" :label-width="80" :label-position="labelPosition">
        <by-form-item prop="name" label="活动名称">
            <by-input v-model="formData3.name"></by-input>
        </by-form-item>
        <by-form-item label="活动形式">
            <by-input type="textarea" v-model="formData3.desc"></by-input>
        </by-form-item>
        <by-form-item>
            <by-button type="primary" size="small" @click.prevent="handleSubmit('formLogin3')">登录</by-button>
        </at-form-item>
    </by-form>
</div>
```
:::

## API

| 参数        | 说明                                                                                  | 类型    | 可选值 | 默认值 |
|-------------|---------------------------------------------------------------------------------------|---------|--------|--------|
| model       | 表单数据对象                                                                          | object  | —      | —      |
| rules       | 表单验证规则                                                                          | object  | —      | —      |
| inline      | 行内表单模式                                                                          | Boolean | —      | false  |
| label       | 表单域标签的内容                                                                      | string  | —      | —      |
| label-width | 表单域标签的宽度，例如 '50'。作为 Form 直接子元素的 form-item 会继承该值。支持 auto。 | number  | —      | —      |

<script lang="ts">
    import { Vue, Component } from "vue-property-decorator";

    @Component
    export default class ByFormMd extends Vue {

        labelPosition = 'right';

        formData1 = {
            username: '',
            password: '',
            remember: true
        }

        formData2 = {
            name: '',
            area: '',
            delivery: false,
            type: [],
            resource: '',
            desc: '',
        }

        formData3 = {}

        ruleLogin1 = {
            username: [{
                required: true,
                message: '请输入用户名',
                trigger: 'blur'
            }],
            password: [{
                required: true,
                message: '请输入密码',
                trigger: 'blur'
            }, {
                type: 'string',
                min: 6,
                message: '密码长度不能小于6',
                trigger: 'blur'
            }]
        }

        ruleLogin2 = {
            name: [{
                required: true,
                message: '请输入活动名称',
                trigger: 'blur'
            }],
            // area: [{
            //     required: true,
            //     message: '请输入密码',
            //     trigger: 'blur'
            // }, {
            //     type: 'string',
            //     min: 6,
            //     message: '密码长度不能小于6',
            //     trigger: 'blur'
            // }],
            type: [{
                type: 'array',
                required: true,
                message: '请至少选择一个活动性质',
                trigger: 'change'
            }],
            resource: [{
                required: true,
                message: '请选择特殊资源',
                trigger: 'blur'
            }],
            desc: [{
                required: true,
                message: '请输入活动形式',
                trigger: 'blur'
            }],
        }

        ruleLogin3 = {}

        handleSubmit (name) {
            this.$refs[name].validate(valid => {
                if (valid) {
                    this.$notify({
                        type: 'success',
                        message: '提交成功'
                    })
                } else {
                    this.$notify({
                        type: 'error',
                        message: '校验失败'
                    })
                }
            })
        }
    }
</script>
<style lang="sass" scoped>
    .by-checkbox-group{
        width: 320px;
        margin: 0;
        padding: 0;
        list-style: none;

        .by-checkbox {
            float: left;
            width: 160px;
            margin: 0;
            padding: 0;
        }
    }
</style>
<file_sep>/src/components/notification/index.ts
import Notification from './src/notification';
export default Notification;
<file_sep>/src/mixins/popover.ts
import { Vue, Component, Prop, Model } from 'vue-property-decorator';

let $: any;

if (typeof window !== 'undefined') {
    $ = require('../utils/NodeList.js').default
}

@Component
export default class PopoverMixin extends Vue {

    @Prop()
    trigger?: string;

    @Prop()
    title?: string;

    @Prop({
        default: ''
    })
    content?: string;

    @Prop({
        default: true
    })
    header?: boolean;

    @Prop({
        default: 'top'
    })
    placement?: string;

    @Prop({
        default: false
    })
    value?: boolean;

    show = this.value;

    position = {
        top: 0,
        left: 0
    };

    _trigger: any = null;

    _timer: any = null;

    toggle() {
        this.show = !this.show
        this.$emit('toggle', this.show)
        if (!this.show) return

        this.setPopoverPosition()
    }

    showPopover() {
        this.show = true
        this.setPopoverPosition()
    }

    hidePopover() {
        this.show = false
    }

    handleMouseEnter() {
        this.showPopover()
        clearTimeout(this._timer)
    }

    handleMouseLeave() {
        this._timer = setTimeout(() => {
            this.hidePopover()
        }, 200)
    }

    setPopoverPosition() {
        this.$nextTick(() => {
            const popover:any = this.$refs.popover;
            const trigger:any = this.$refs.trigger;

            switch (this.placement) {
                case 'top':
                    this.position.left = trigger.offsetLeft - (popover.offsetWidth / 2) + (trigger.offsetWidth / 2)
                    this.position.top = trigger.offsetTop - popover.offsetHeight
                    break
                case 'top-left':
                    this.position.left = trigger.offsetLeft
                    this.position.top = trigger.offsetTop - popover.offsetHeight
                    break
                case 'top-right':
                    this.position.left = trigger.offsetLeft + trigger.offsetWidth - popover.offsetWidth
                    this.position.top = trigger.offsetTop - popover.offsetHeight
                    break
                case 'left':
                    this.position.left = trigger.offsetLeft - popover.offsetWidth
                    this.position.top = trigger.offsetTop + (trigger.offsetHeight / 2) - (popover.offsetHeight / 2)
                    break
                case 'left-top':
                    this.position.left = trigger.offsetLeft - popover.offsetWidth
                    this.position.top = trigger.offsetTop
                    break
                case 'left-bottom':
                    this.position.left = trigger.offsetLeft - popover.offsetWidth
                    this.position.top = trigger.offsetTop + trigger.offsetHeight - popover.offsetHeight
                    break
                case 'right':
                    this.position.left = trigger.offsetLeft + trigger.offsetWidth
                    this.position.top = trigger.offsetTop + (trigger.offsetHeight / 2) - (popover.offsetHeight / 2)
                    break
                case 'right-top':
                    this.position.left = trigger.offsetLeft + trigger.offsetWidth
                    this.position.top = trigger.offsetTop
                    break
                case 'right-bottom':
                    this.position.left = trigger.offsetLeft + trigger.offsetWidth
                    this.position.top = trigger.offsetTop + trigger.offsetHeight - popover.offsetHeight
                    break
                case 'bottom':
                    this.position.left = trigger.offsetLeft - (popover.offsetWidth / 2) + (trigger.offsetWidth / 2)
                    this.position.top = trigger.offsetTop + trigger.offsetHeight
                    break
                case 'bottom-left':
                    this.position.left = trigger.offsetLeft
                    this.position.top = trigger.offsetTop + trigger.offsetHeight
                    break
                case 'bottom-right':
                    this.position.left = trigger.offsetLeft + trigger.offsetWidth - popover.offsetWidth
                    this.position.top = trigger.offsetTop + trigger.offsetHeight
                    break
                default:
                    // if user set wrong placement, then use default 'top'
                    this.position.left = trigger.offsetLeft - (popover.offsetWidth / 2) + (trigger.offsetWidth / 2)
                    this.position.top = trigger.offsetTop - popover.offsetHeight
                    break
            }

            popover.style.top = `${this.position.top}px`
            popover.style.left = `${this.position.left}px`
        })
    }

    doDestory() {
        if (this._trigger) {
            $(this._trigger).off()
        }
    }

    mounted() {
        const trigger = this.$refs.trigger;
        // const parent = this.$refs.parent
        // const events = {
        //   hover: 'mouseenter mouseleave',
        //   focus: 'focus blur'
        // }
        // let showEvent = events[this.trigger] || 'click'

        if (!trigger) {
            return console.error('Could not find trigger ref in your component that uses popovermixin')
        }

        this._trigger = trigger;

        if (this.trigger === 'click') {
            $(trigger).on('click', this.toggle)
        } else if (this.trigger === 'hover') {
            $(trigger).on('mouseenter', this.handleMouseEnter)
            $(trigger).on('mouseleave', this.handleMouseLeave)
        } else if (this.trigger === 'focus') {
            $(trigger).on('focus', this.showPopover)
            $(trigger).on('blur', this.hidePopover)
        }
    }
}
<file_sep>/build/webpack/webpack.base.config.ts
import * as path from 'path';
import * as webpack from 'webpack';
import * as VueLoaderPlugin from 'vue-loader/lib/plugin';
import * as MarkdownItContainer from 'markdown-it-container';
import * as markdownItAnchor from 'markdown-it-anchor';
const slugify = require('transliteration').slugify;

import * as MiniCssExtractPlugin from 'mini-css-extract-plugin';

import env from '../config/env';

const striptags = require('./tools/strip-tags');
const utils = require('./tools/utils');

const mode = process.env.ENV;
const isProduction = (mode === "production");

module.exports = {
    output: {
        path: path.resolve('dist'),
    },
    resolve: {
        alias: {
            "@": path.resolve("src"),
            "@docs": path.resolve("docs"),
            "mixins": path.resolve("src/mixins"),
            "By-UI": path.resolve("src")
        },
        extensions: ['.ts', '.tsx', '.js']
    },
    module: {
        rules: [
            {
                test: /\.vue$/,
                exclude: /node_modules/,
                loader: "vue-loader",
                options: {
                    parallel: false
                }
            },
            {
                test: /\.md$/,
                use: [
                    {
                        loader: 'vue-loader'
                    },
                    {
                        loader: 'vue-markdown-loader/lib/markdown-compiler',
                        options: {
                            raw: true,
                            preprocess: (MarkdownIt, source) => {
                                MarkdownIt.renderer.rules.table_open = function () {
                                    return '<table class="table">'
                                }
                                // 对于代码块去除v-pre,添加高亮样式
                                MarkdownIt.renderer.rules.fence = utils.wrapCustomClass(MarkdownIt.renderer.rules.fence)
                                return source
                            },
                            use: [
                                [markdownItAnchor, {
                                    level: 2, // 添加超链接锚点的最小标题级别, 如: #标题 不会添加锚点
                                    slugify: slugify, // 自定义slugify, 我们使用的是将中文转为汉语拼音,最终生成为标题id属性
                                    permalinkClass: 'anchor',
                                    permalink: true, // 开启标题锚点功能
                                    permalinkBefore: true, // 在标题前创建锚点
                                    permalinkHref: (slug, state) => `javascript:toAnchor('${slug}')`,
                                }],
                                [MarkdownItContainer, 'demo', {
                                    validate: params => params.trim().match(/^demo\s*(.*)$/),
                                    render: (tokens, idx) => {
                                        if (tokens[idx].nesting === 1) {
                                            const html = utils.convertHtml(striptags(tokens[idx + 1].content, 'script'))

                                            return `<demo-box>
                                            <div slot="demo">${html}</div>
                                            <div slot="source-code">`
                                        }

                                        // closing tag
                                        return '</div></demo-box>'
                                    }
                                }]
                            ]
                        }
                    },
                ],
            },
            {
                test: /\.js$/,
                use: [{
                    loader: "babel-loader",
                }],
                exclude: /node_modules/,
            },
            {
                test: /\.yml$/,
                loader: 'json-loader!yaml-loader'
            },
            {
                test: /\.tsx?$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: "babel-loader",
                        options: {
                            cacheDirectory: true
                        }
                    },
                    {
                        loader: "ts-loader",
                        options: {
                            appendTsxSuffixTo: [/\.vue$/],
                            transpileOnly: true
                        }
                    }
                ]
            },
            {
                test: /\.(sa|sc|c)ss$/,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader,
                        options: {
                            hmr: !isProduction,
                            // publicPath: '../'
                        },
                    },
                    {
                        loader: "css-loader",
                        options: {
                            sourceMap: !isProduction
                        }
                    },
                    {
                        loader: "sass-loader",
                        options: {
                            sourceMap: !isProduction
                        }
                    },
                ]
            }, {
                test: /\.(png|jpe?g|gif|svg)$/,
                include: /image/,
                loader: "url-loader",
                query: {
                    limit: 1,
                    name: "asset/images/[hash:16].[ext]"
                }
            },
            {
                test: /\.(ttf|woff2?|eot|svg)$/,
                include: /font/,
                loader: "url-loader",
                query: {
                    limit: 1,
                    name: "asset/fonts/[name].[hash:7].[ext]"
                }
            }
        ]
    },
    optimization: {
        splitChunks: {
            chunks: "all",
            maxInitialRequests: 30,
            maxAsyncRequests: 30,
            minSize: 2048,
            cacheGroups: {
                default: {
                    priority: -20,
                    reuseExistingChunk: true,
                    minChunks: 20,
                },
                'vendors/library': {
                    name: 'vendors/library',
                    test: /[\\/]node_modules[\\/]/,
                    priority: -10,
                },
                'vendors/vue-bucket': {
                    name: 'vendors/vue-bucket',
                    test: /[\\/]node_modules[\\/](vue|vue-router|vuex|vue-class-component)[\\/]/,
                    priority: -1
                },
            }
        },
        runtimeChunk: {
            name: 'vendors/manifest',
        }
    },
    performance: {
        hints: false
    },
    plugins: [
        new VueLoaderPlugin(),
        new MiniCssExtractPlugin({
            filename: isProduction ? '[name].[contenthash].css' : '[name].css',
            chunkFilename: isProduction ? '[name].[contenthash].css' : '[name].css'
        }),
        new webpack.DefinePlugin({
            'process.env': {
                domain: JSON.stringify(env.domain),
                host: JSON.stringify(env.host),
                customize: JSON.stringify(env.customize),
            },
        }),
    ],
}
<file_sep>/src/components/notification/src/notification.ts
import Vue from 'vue';
import NotificationVue from './notification.vue';

const NotificationConstructor = Vue.extend(NotificationVue);
const noticeType = ['success', 'error', 'warning', 'info'];
const instances: any[] = [];

let instance;
let seed = 1;
let zindexSeed = 1010;

const Notification = (options: any) => {
    if (Vue.prototype.$isServer) return;
    options = options || {};

    const onClose = options.onClose;
    const id = `notification_${seed++}`;

    options.onClose = function () {
        Notification.close(id, onClose)
    };

    instance = new NotificationConstructor({
        data: options
    });

    instance.id = id;
    instance.vm = instance.$mount();
    document.body.appendChild(instance.vm.$el);
    instance.vm.isShow = true;
    instance.dom = instance.vm.$el;
    instance.dom.style.zIndex = (zindexSeed++);

    const offset = 0;
    let topDist = offset;

    for (let i = 0, len = instances.length; i < len; i++) {
        topDist += instances[i].$el.offsetHeight + 16
    }

    topDist += 16
    instance.top = topDist;
    instances.push(instance);
    return instance.vm;
}

Notification.close = function (id: number | string, onClose: any) {
    const len = instances.length;
    let index:any;
    let removedHeight;
    let i = 0;

    for (i = 0; i < len; i++) {
        if (id === instances[i].id) {
            if (typeof onClose === 'function') {
                onClose(instances[i])
            }
            index = i
            removedHeight = instances[i].dom.offsetHeight
            instances.splice(i, 1)
            break
        }
    }

    if (len > 1) {
        for (i = index; i < len - 1; i++) {
            instances[i].dom.style.top = `${parseInt(instances[i].dom.style.top) - removedHeight - 16}px`
        }
    }
}

noticeType.forEach(type => {
    Notification[type] = (options: any) => {
        if (typeof options === 'string') {
            options = {
                message: options
            }
        }

        options.type = type
        return Notification(options)
    }
})
export default Notification;
<file_sep>/src/components/input-number/index.ts
import InputNumber from './src/input-number.vue'

Object.defineProperty(InputNumber, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-input-number', InputNumber);
    }
})

export default InputNumber

<file_sep>/src/locale/lang/de.ts
export default {
    by: {
        select: {
            placeholder: 'Auswählen',
            notFoundText: 'keine Übereinstimmung'
        },
        modal: {
            okText: 'Bestätigen',
            cancelText: 'Abbrechen'
        },
        pagination: {
            prevText: 'Vorherige Seite',
            nextText: 'Nächste Seite',
            total: 'Gesamt',
            item: 'Inhalt',
            items: 'Inhalte',
            pageSize: '/ Seite',
            goto: 'Gehe zu',
            pageText: '',
            prev5Text: 'Vorherige 5 Seiten',
            next5Text: 'Nächste 5 Seiten'
        },
        table: {
            emptyText: 'Keine Daten'
        }
    }
}
<file_sep>/build/webpack/webpack.components.config.ts
import * as webpack from 'webpack';
import * as merge from 'webpack-merge';
import * as FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin';

import * as baseConfig from './webpack.base.config';
import byui from '../config/by-ui';

let notes = [
    `Compile Building Components Successful!`
];

module.exports = merge(baseConfig, {
    mode: 'production',
    entry: {
        main: './src/index.ts'
    },
    output: {
        filename: 'by.js',
        library: 'by',
        libraryTarget: 'umd'
    },
    externals: {
        vue: {
            root: 'Vue',
            commonjs: 'vue',
            commonjs2: 'vue',
            amd: 'vue'
        }
    },
    optimization: {
        splitChunks: false,
        runtimeChunk: false
    },
    plugins: [
        new webpack.BannerPlugin({
            banner: `/*! BY-UI v${require('../../package.json').version} | MIT License */`,
            raw: true,
            entryOnly: true
        }),
        new FriendlyErrorsWebpackPlugin({
            compilationSuccessInfo: {
                messages: [
                    ...byui
                ],
                notes: [
                    ...notes
                ],
            },
        }),
    ]
})
<file_sep>/src/components/alert/index.ts
import Alert from './src/alert.vue'

Object.defineProperty(Alert, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-alert', Alert);
    }
})

export default Alert



<file_sep>/src/components/timeline-item/index.ts
import TimeLineItem from '../timeline/src/timeline-item.vue';

Object.defineProperty(TimeLineItem, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-time-line-item', TimeLineItem);
    }
})

export default TimeLineItem
<file_sep>/src/components/select/index.ts
import Select from './src/select.vue'

Object.defineProperty(Select, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-select', Select);
    }
})

export default Select



<file_sep>/src/components/input/index.ts
import Input from './src/input.vue'

Object.defineProperty(Input, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-input', Input);
    }
})

export default Input


<file_sep>/src/components/radio-button/index.ts
import RadioButton from '../radio/src/radio-button.vue'

Object.defineProperty(RadioButton, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-radio-button', RadioButton);
    }
})

export default RadioButton



<file_sep>/docs/resources/directives/clipboard/clipboard.ts
/**
 * vue clipboard base on clipboard.js
 * https://github.com/zhuowenli/vue-clipboards/blob/master/src/vue-clipboards.js
 */
const Clipboard = require('clipboard')

if (!Clipboard) {
    throw new Error('[vue-clipboard] Cannot locate clipboard.js')
}

function isDom(obj: any) {
    return typeof (window as any).HTMLElement === 'object'
        ? obj instanceof (window as any).HTMLElement
        : obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string'
}

export default function (Vue: any) {
    const clipboard = {}
    const DEFAULTKEY = 'DEFAULT'

    Vue.directive('clipboard', {
        bind(el: any, binding: any, vnode: any) {
            const option: any = {}
            const key = (vnode.key || vnode.key === 0) ? vnode.key : DEFAULTKEY
            let text = binding.value
            let $parent = null

            if (text) {
                if (typeof text === 'function') {
                    text = text()
                }

                if (/(string|number)/.test(typeof text)) {
                    option.text = () => text
                } else {
                    throw new Error('[vue-clipboard] Invalid value.')
                }
            }

            if (vnode.data.attrs && vnode.data.attrs.model) {
                $parent = isDom(vnode.data.attrs.model) ? vnode.data.attrs.model : document.querySelector(vnode.data.attrs.model)
            }

            if (vnode.elm.offsetParent) {
                option.container = vnode.elm.offsetParent
            } else if (isDom($parent)) {
                option.container = $parent
            } else {
                option.container = el.parentElement || document.body
            }

            clipboard[key] = new Clipboard(el, option)

            const { comoponentOptions, data } = vnode
            const listeners = comoponentOptions ? comoponentOptions.listeners : null
            const on = data ? data.on : null
            const events = listeners || on

            if (events && typeof events === 'object' && Object.keys(events).length) {
                Object.keys(events).map(
                    cb => clipboard[key].on(cb, events[cb].fn || events[cb].fns)
                )
            }

            return clipboard[key]
        },
        unbind(vnode: any) {
            const key = (vnode.key || vnode.key === 0) ? vnode.key : DEFAULTKEY

            if (clipboard[key] && clipboard[key].destroy) {
                clipboard[key].destroy()
                clipboard[key] = null
            }
        },
        update(el: any, binding: any, vnode: any) {
            binding.def.unbind(vnode)
            binding.def.bind(el, binding, vnode)
        }
    })
}
<file_sep>/src/components/switch/index.ts
import Switch from './src/switch.vue'

Object.defineProperty(Switch, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-switch', Switch);
    }
})

export default Switch


<file_sep>/docs/markdown/message.md

# Message 全局提示

----

相比 `Notification`，`Message` 更轻量，居中显示在页面顶部，用于展示全局消息，例如操作的反馈信息

- 提供消息、成功、错误、警告等反馈提示
- 在顶部居中显示，并自动消失，是一种不打断用户操作的轻量级提示

我们在 `Vue.prototype` 中添加了全局对象 `$message`，我们可以直接通过 `this.$message` 操作实例

- `this.$message(config)`
- `this.$message.info(config)`
- `this.$message.success(config)`
- `this.$message.warning(config)`
- `this.$message.error(config)`
- `this.$message.loading(config)`

## 基础用法

四种类型的消息提示

:::demo
```html
<by-button @click="handleClick('info')">Info</by-button>
<by-button @click="handleClick('success')">Success</by-button>
<by-button @click="handleClick('warning')">Warning</by-button>
<by-button @click="handleClick('error')">Error</by-button>

<script>
  export default {
    methods: {
      handleClick (type) {
        if (type === 'info') {
          this.$message.info('这是一条提示信息这是一条提示信息这是一条提示信息这是一条提示信息这是一条提示信息')
        } else if (type === 'success') {
          this.$message.success('这是一条成功信息')
        } else if (type === 'warning') {
          this.$message.warning('这是一条警告信息')
        } else if (type === 'error') {
          this.$message.error('这是一条错误信息')
        }
      }
    }
  }
</script>
```
:::

## 修改延时

提示默认的显示时长为 `3s`，可传递 `duration` 来自定义时长

:::demo
```html
<by-button @click="changeDuration">修改延时</by-button>

<script>
  export default {
    methods: {
      changeDuration () {
        this.$message.info({
          message: '这是一条提示信息，10s 后自动关闭',
          duration: 10000
        })
      }
    }
  }
</script>
```
:::

## 加载中

`this.$message.loading` 返回关闭方法，可用于手动关闭提示框

:::demo
```html
<by-button @click="showLoading">显示加载中...</by-button>

<script>
  export default {
    methods: {
      showLoading () {
        const loading = this.$message.loading({
          message: '加载中...',
          duration: 0
        })
        setTimeout(loading, 3000)
      }
    }
  }
</script>
```
:::

## 单独引用

通过 `import` 方式引用

:::demo
```html
<by-button @click="handleImportClick('info')">Info</by-button>
<by-button @click="handleImportClick('success')">Success</by-button>
<by-button @click="handleImportClick('warning')">Warning</by-button>
<by-button @click="handleImportClick('error')">Error</by-button>

<script>
  export default {
    methods: {
      handleImportClick (type) {
        if (type === 'info') {
          Message.info('这是一条提示信息这是一条提示信息这是一条提示信息这是一条提示信息这是一条提示信息')
        } else if (type === 'success') {
          Message.success('这是一条成功信息')
        } else if (type === 'warning') {
          Message.warning('这是一条警告信息')
        } else if (type === 'error') {
          Message.error('这是一条错误信息')
        }
      }
    }
  }
</script>
```
:::

## Message 参数

| 参数      | 说明          | 类型      | 可选值                           | 默认值  |
|---------- |-------------- |---------- |--------------------------------  |-------- |
| type | 全局提示的类别 | String | `success`, `error`, `warning`, `info` | `info` |
| message | 提示的内容 | String | - | - |
| duration | 自动关闭的延时，默认为 `3000` 毫秒 | Number | - | 3000 |
| icon | 自定义类别ICON | String | - | `info` |
| onClose | 关闭提示框时的回调函数 | Function | - | - |

<script lang="ts">
    import { Vue, Component } from "vue-property-decorator";
    import { Message } from 'By-UI'

 @Component
 export default class MyComponent extends Vue {

      handleClick (type) {
        if (type === 'info') {
          this.$message.info('这是一条提示信息这是一条提示信息这是一条提示信息这是一条提示信息这是一条提示信息')
        } else if (type === 'success') {
          this.$message.success('这是一条成功信息')
        } else if (type === 'warning') {
          this.$message.warning('这是一条警告信息')
        } else if (type === 'error') {
          this.$message.error('这是一条错误信息')
        }
      }

      handleImportClick (type) {
        if (type === 'info') {
          Message.info('这是一条提示信息这是一条提示信息这是一条提示信息这是一条提示信息这是一条提示信息')
        } else if (type === 'success') {
          Message.success('这是一条成功信息')
        } else if (type === 'warning') {
          Message.warning('这是一条警告信息')
        } else if (type === 'error') {
          Message.error('这是一条错误信息')
        }
      }

      changeDuration () {
        this.$message.info({
          message: '这是一条提示信息，10s 后自动关闭',
          duration: 10000
        })
      }

      showLoading () {
        const loading = this.$message.loading({
          message: '加载中...',
          duration: 0
        })
        setTimeout(loading, 3000)
      }

        mounted(){
            console.log(Message);
        }
    }
</script>


<file_sep>/src/components/breadcrumb/index.ts
import Breadcrumb from './src/breadcrumb.vue'

Object.defineProperty(Breadcrumb, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-breadcrumb', Breadcrumb);
    }
})

export default Breadcrumb
<file_sep>/build/inquirer/index.ts
const shell = require('shelljs');
const inquirer = require('inquirer');
const chalk = require('chalk');

const question = [
    {
        type: 'list',
        name: 'compile',
        message: 'What do you want to compile?',
        choices: ['docs - 文档', 'components - 组件', 'all - 全部']
    }
];
/**
 * 编译源码
 * answers 用户所选答案
 */
async function compile(answers) {

    // 编译什么项目
    let command = '';

    switch (answers.compile) {

        case 'docs - 文档':
            command = 'npm run build:docs'
            break;

        case 'components - 组件':
            command = 'npm run build:components'
            break;

        case 'all - 全部':
            command = 'npm run build:docs'
            break;

        default:
            break;
    }

    console.log(`${chalk.blue('Start compiling...')}`);

    shell.exec(command, {
        silent: true, // true 不会回显控制台
    }, (code, stdout, stderr) => {
        console.log(stdout);
    })
}

inquirer.prompt(question)
    .then((answers) => {
        for (let item of question)
            console.log(`${chalk.green(item.message)}：${chalk.red(answers[item.name])}`);
        compile(answers);
    });
<file_sep>/docs/markdown/select.md
# Select 选择器

---

## 基础用法

基本用法，可添加 `disabled` 属性禁用选择器

:::demo

```html
<by-select v-model="model1" style="width:100px">
    <by-option value="1">深圳</by-option>
    <by-option value="2">广州广州广州广州广州广州广州广州广州广州</by-option>
    <by-option value="3">上海</by-option>
    <by-option value="4">北京</by-option>
    <by-option value="5">成都</by-option>
</by-select>

<by-select v-model="model2" style="width:100px">
    <by-option value="1">深圳</by-option>
    <by-option value="2">广州</by-option>
</by-select>

<by-select v-model="model2" disabled style="width:100px">
    <by-option value="1">深圳</by-option>
    <by-option value="2">广州</by-option>
</by-select>
```

:::

## 不同尺寸

可设置 `size` 属性控制选择器大小，提供三种尺寸：`large`，`normal`，`small`

:::demo

```html
<by-select v-model="model3" size="small" style="width: 100px">
    <by-option value="1">深圳</by-option>
    <by-option value="2">广州</by-option>
    <by-option value="3">上海</by-option>
    <by-option value="4">北京</by-option>
    <by-option value="5">成都</by-option>
</by-select>
<by-select v-model="model3" size="normal" style="width: 100px">
    <by-option value="1">深圳</by-option>
    <by-option value="2">广州</by-option>
    <by-option value="3">上海</by-option>
    <by-option value="4">北京</by-option>
    <by-option value="5">成都</by-option>
</by-select>
<by-select v-model="model3" size="large" style="width: 100px">
    <by-option value="1">深圳</by-option>
    <by-option value="2">广州</by-option>
    <by-option value="3">上海</by-option>
    <by-option value="4">北京</by-option>
    <by-option value="5">成都</by-option>
</by-select>
```

:::

## 可清空选择

设置 `clearable` 属性可清空已选项，仅适用于单选选择器

:::demo

```html
<by-select v-model="model4" clearable size="large" style="width: 100px">
    <by-option value="1">深圳</by-option>
    <by-option value="2">广州</by-option>
    <by-option value="3">上海</by-option>
    <by-option value="4">北京</by-option>
    <by-option value="5">成都</by-option>
</by-select>
```

:::

## 分组选项

选项可通过使用 `AtOptionGroup` 组件进行分组，分组的名称可使用属性 `label` 设置

:::demo

```html
<by-select v-model="model5" style="width: 100px">
    <by-option-group label="广东省">
        <by-option value="1">深圳</by-option>
        <by-option value="2">广州</by-option>
        <by-option value="3">珠海</by-option>
    </by-option-group>
    <by-option-group label="其他">
        <by-option value="4">上海</by-option>
        <by-option value="5">北京</by-option>
        <by-option value="6" disabled>成都</by-option>
        <by-option value="7">昆明</by-option>
        <by-option value="8">杭州</by-option>
    </by-option-group>
</by-select>
```

:::

## 自定义模板

可自定义 `AtOption` 显示的内容，但是请给 `AtOption` 添加 `label` 属性，这可以让选择器优先显示选项的 `label` 值，而不是内容本身

:::demo

```html
<by-select v-model="model6" style="width: 140px">
    <by-option value="1" label="深圳"
        ><span>深圳</span
        ><span style="float: right;opacity: .6;font-size: 0.8em;"
            >Shenzhen</span
        ></by-option
    >
    <by-option value="2" label="广州"
        ><span>广州</span
        ><span style="float: right;opacity: .6;font-size: 0.8em;"
            >Guangzhou</span
        ></by-option
    >
    <by-option value="3" label="上海"
        ><span>上海</span
        ><span style="float: right;opacity: .6;font-size: 0.8em;"
            >Shanghai</span
        ></by-option
    >
    <by-option value="4" label="北京"
        ><span>北京</span
        ><span style="float: right;opacity: .6;font-size: 0.8em;"
            >Beijin</span
        ></by-option
    >
    <by-option value="5" label="成都"
        ><span>成都</span
        ><span style="float: right;opacity: .6;font-size: 0.8em;"
            >Chengdu</span
        ></by-option
    >
</by-select>
```

:::

## 多选列表

设置 `multiple` 属性可开启多项选择器，此时绑定的 `model` 将接受数组类型的数据

:::demo

```html
<by-select v-model="model7" multiple style="width: 240px">
    <by-option value="1">深圳</by-option>
    <by-option value="2">广州</by-option>
    <by-option value="3">上海</by-option>
    <by-option value="4">北京</by-option>
    <by-option value="5">成都</by-option>
</by-select>
```

:::

## 可搜索列表

添加 `filterable` 属性开启选择列表的可搜索功能

:::demo

```html
<by-select v-model="model8" filterable size="large" style="width: 240px">
    <by-option value="1">深圳</by-option>
    <by-option value="2">广州</by-option>
    <by-option value="3">上海</by-option>
    <by-option value="4">北京</by-option>
    <by-option value="5">成都</by-option>
    <by-option value="6">厦门</by-option>
    <by-option value="7">昆明</by-option>
    <by-option value="8">杭州</by-option>
</by-select>
```

:::

## Select 参数

| 参数           | 说明                                           | 类型                    | 可选值                     | 默认值     |
| :------------- | :--------------------------------------------- | :---------------------- | :------------------------- | :--------- |
| value          | 指定当前组件的 value 值，可通过 `v-model` 绑定 | String / Number / Array | -                          | -          |
| multiple       | 是否支持多选                                   | Boolean                 | -                          | false      |
| disabled       | 是否禁用选择器                                 | Boolean                 | -                          | false      |
| clearable      | 是否支持清空功能                               | Boolean                 | -                          | false      |
| filterable     | 是否支持搜索功能                               | Boolean                 | -                          | false      |
| placeholder    | 选择器的占位文案                               | String                  | -                          | 请选择     |
| size           | 设置选择器的尺寸                               | String                  | `large`, `normal`, `small` | normal     |
| notFoundText   | 搜索无结果的提示                               | String                  | -                          | 无匹配数据 |
| placement      | `dropdown` 出现的位置                          | String                  | `top`, `bottom`            | bottom     |
| valueWithLabel | 是否将 `label` 值一并返回，默认只返回 `value`  | Boolean                 | -                          | false      |

## Select 事件

| 事件名称  | 说明               | 返回值                                               |
| --------- | ------------------ | ---------------------------------------------------- |
| on-change | 绑定的值变化时触发 | 选中的选项值，类型为 `String`，`Number` 或者 `Array` |

<script lang="ts">
    import { Vue, Component, Prop, PropSync, Watch, Mixins, Provide } from "vue-property-decorator";
    export default class Dropdown extends Vue {
        model1=''
        model2='2'
        model3=''
        model4=''
        model5=''
        model6=''
        model7=new Array()
        model8=''
    }
//   export default {
//     data () {
//       return {
//         model1: '',
//         model2: '2',
//         model3: '',
//         model4: '',
//         model5: '',
//         model6: '',
//         model7: [],
//         model8: '',
//       }
//     }
//   }
</script>
<file_sep>/src/directives/clickoutside.ts
import { DirectiveOptions } from 'vue';
const clickoutsideContext = '@@clickoutsideContext';

const ClickOutside: DirectiveOptions = {
    bind(el: any, binding, vnode: any) {
        const documentHandler = function (e: any) {
            if (!vnode.context || el.contains(e.target)) {
                return false;
            }
            if (binding.expression) {
                vnode.context[el[clickoutsideContext].methodName](e);
            } else {
                el[clickoutsideContext].bindingFn(e);
            }
        };
        el[clickoutsideContext] = {
            documentHandler,
            methodName: binding.expression,
            bindingFn: binding.value,
        };
        setTimeout(() => {
            document.addEventListener('click', documentHandler);
        }, 0);
    },
    update(el: any, binding) {
        el[clickoutsideContext].methodName = binding.expression;
        el[clickoutsideContext].bindingFn = binding.value;
    },
    unbind(el: any) {
        document.removeEventListener('click', el[clickoutsideContext].documentHandler);
    },
};

export default ClickOutside;
<file_sep>/docs/markdown/rate.md
# Rate 评分

---

评分组件

## 基础用法

最简单的用法。

:::demo
```html
    <by-rate></by-rate>
```
:::


## 文案展现

给评分组件加上文案展示。

:::demo
```html
<by-rate :show-text="true" v-model="value2">
    <span>{{ value2 }} 星</span>
</by-rate>
```
:::

## 其他图标

可以将星星替换为其他图标。

:::demo
```html
    <by-rate icon="icon-heart-on"></by-rate>
```
:::


## 半星

支持选中半星。

:::demo
```html
<by-rate :allow-half="true"
            :show-text="true"
            :value="valueHalfStar"
            @on-change="onStarChange"
            @on-hover-change="onHoverChange">
</by-rate>
```
:::


## 只读

只读，无法进行鼠标交互。

:::demo
```html
<by-rate :allow-half="true"
            :show-text="true"
            :value="valueReadonly"
            :disabled="true">
</by-rate>
```
:::

<script lang="ts">
    import { Vue, Component } from "vue-property-decorator";

    @Component
    export default class ByRateMd extends Vue {
        value2 = 3;

        value1 = 2.5;

        valueHalfStar = 1;

        valueReadonly = 3;

        onStarChange(val:number){
            console.log(val);
        }

        onHoverChange(val:number){
            console.log(val);
        }
    }
</script>



## Rate 参数

| 参数       | 说明               | 类型    | 可选值 | 默认值      |
|------------|--------------------|---------|--------|-------------|
| count      | star 总数          | Number  | -      | 5           |
| value      | 当前值             | String  | -      | 0           |
| allow-half | 是否允许选择半颗星 | Boolean | -      | `false`     |
| disabled   | 只读，无法进行交互 | Boolean | -      | `false`     |
| icon       | 指定图标           | String  | -      | `icon-star` |
| show-text  | 实现显示辅助文案   | Boolean | -      | `false`     |

## Rate 事件

| 事件名称        | 说明                                 | 返回值     |
|-----------------|--------------------------------------|------------|
| on-change       | star 数目改变时触发                  | 改变后的值 |
| on-hover-change | 鼠标在 star 上移动导致数值变化时触发 | 改变后的值 |


## Rate slot

| 名称 | 说明                 |
|------|----------------------|
| -    | 自定义展示文案的内容 |
<file_sep>/src/components/radio/index.ts
import Radio from './src/radio.vue'

Object.defineProperty(Radio, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-radio', Radio);
    }
})

export default Radio


<file_sep>/src/components/badge/index.ts
import Badge from './src/badge.vue'

Object.defineProperty(Badge, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-badge', Badge);
    }
})

export default Badge



<file_sep>/docs/components/index.ts
import Vue, { PluginObject } from 'vue';

import ByHeader from './header/index.vue';
import ByFooter from './footer/index.vue';
import BySlider from './slidebar/index.vue';

import IconList from './icon-list/index.vue';
import DemoBox from './demobox/index.vue'; // md文件代码块

const Components: PluginObject<never> = {
    install(Vue) {
        Vue.component('by-header', ByHeader);
        Vue.component('by-footer', ByFooter);
        Vue.component('by-slider-bar', BySlider);
        Vue.component('icon-list', IconList);
        Vue.component('demo-box', DemoBox);
    }
}

Vue.use(Components);
<file_sep>/docs/markdown/introduction.md
# 介绍

-----

By-UI 是一款基于 Vue.js 2.0 的前端 UI 组件库，主要用于快速开发 PC 网站中后台产品
<file_sep>/src/components/table/index.ts
import Table from './src/table.vue'

Object.defineProperty(Table, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-table', Table);
    }
})

export default Table
<file_sep>/docs/index.ts
import Vue from 'vue'
import router from './vue-router';
import App from './app.vue';


/******** 公共包 ********/
import { i18n } from './packages/i18n';

/******** 文档全局组件 ********/
import './components'


/******** 公共UI及样式 ********/
// import '../_intermediate/iconfonts/by-icon.scss';

import '@/by-ui-style/src/index.scss';
import '@docs/assets/style/docs.scss';

/******** 公共directives ********/
import './directives'

/******** UI组件 ********/
import * as ByUI from 'By-UI/index';


Vue.use(ByUI)

new Vue({
    el: '#by-ui',
    i18n,
    router,
    render: h => h(App)
});
<file_sep>/src/components/timeline/index.ts
import TimeLine from './src/timeline.vue';

Object.defineProperty(TimeLine, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-time-line', TimeLine);
    }
})

export default TimeLine





<file_sep>/src/components/collapse/index.ts
import Collapse from './src/collapse.vue'

Object.defineProperty(Collapse, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-collapse', Collapse);
    }
})

export default Collapse




<file_sep>/tsconfig.json
{
    "compileOnSave": false,
    "include": ["@declaration", "src", "docs"],
    "exclude": ["node_modules"],
    "compilerOptions": {
        "target": "es5",
        "module": "esnext",
        "moduleResolution": "node",

        // 启用：
        // --noImplicitAny：报告使用隐含any类型提高表达式和声明的错误
        // --noImplicitThis：报告this使用隐含any类型时的错误
        // --alwaysStrict：
        // --strictNullChecks：在严格的空检查模式中，null和undefined值不在每种类型的域中，并且只能分配给它们any（undefined可以分配的一个例外void）
        // --strictFunctionTypes：禁用功能类型的双变量参数检查
        // --strictPropertyInitialization： 确保在构造函数中初始化非未定义的类属性
        "strict": true,

        "suppressImplicitAnyIndexErrors": true, // 抑制--noImplicitAny索引缺少索引签名的对象的错误。
        // "noUnusedLocals": true, // 报告未使用的局部变量的错误
        "forceConsistentCasingInFileNames": true, //禁止对同一文件的不一致引用

        "allowSyntheticDefaultImports": true, // 允许从没有默认导出的模块进行默认导入
        "experimentalDecorators": true, // 为ES6的装饰器启用实验支持
        "downlevelIteration": true, // 提供迭代器全面支持

        "allowJs": true,
        "resolveJsonModule": true,

        "lib": ["dom", "es5", "es6", "es7", "esnext", "es2015.promise"],

        "jsx": "preserve",
        "jsxFactory": "h",

        "baseUrl": "./",
        "paths": {
            "@/*": ["./src/*"],
            "@docs/*": ["./docs/*"],
            "mixins/*": ["./src/mixins/*"],
            "utils/*": ["./src/utils/*"],
            "By-UI/*": ["./src/*"]
        },

        "sourceMap": true
    },
}
<file_sep>/src/components/rate/index.ts
import Rate from './src/rate.vue'

Object.defineProperty(Rate, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-rate', Rate);
    }
})

export default Rate


<file_sep>/src/components/loading-bar/vue.d.ts
import Vue from 'vue';
import { LoadingBarOption } from './model';

declare module 'vue/types/vue' {
    interface Vue {
        $loadingBar: {
            (): void;
            config(option: LoadingBarOption): void;
            start(option: LoadingBarOption): void;
            finish(option: LoadingBarOption): void;
            error(option: LoadingBarOption): void;
            update(option: LoadingBarOption): void;
        };
    }
}
<file_sep>/src/components/checkbox-group/index.ts
import CheckBoxGroup from '../checkbox/src/by-checkbox-group.vue'

Object.defineProperty(CheckBoxGroup, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-checkbox-group', CheckBoxGroup);
    }
})

export default CheckBoxGroup

<file_sep>/@declaration/vue.plugins.d.ts
declare module 'Vivus';
declare module 'async-validator';
<file_sep>/src/locale/lang/fa-IR.ts
export default {
    by: {
        select: {
            placeholder: 'انتخاب کنید',
            notFoundText: 'موردی یافت نشد'
        },
        modal: {
            okText: 'تایید',
            cancelText: 'لغو'
        },
        pagination: {
            prevText: 'صفحه‌ی قبل',
            nextText: 'صفحه‌ی بعد',
            total: 'تمام',
            item: 'مورد',
            items: 'مورد',
            pageSize: '/ صفحه',
            goto: 'برو به',
            pageText: '',
            prev5Text: 'پنج صفحه‌ی قبلی',
            next5Text: 'پنج صفحه‌ی بعدی'
        },
        table: {
            emptyText: 'بدون داده'
        }
    }
}
<file_sep>/docs/markdown/tooltip.md

# Tooltips 文字提示

----

文字提示框类似于 `HTML` 的 `title` 属性，当鼠标悬浮在元素上方时，会出现一个文字提示框

## 基本用法

鼠标悬停时，文字提示框默认显示在顶上的位置

:::demo
```html
<by-tooltip placement="top" content="提示信息">
  <by-button>按钮</by-button>
</by-tooltip>
<by-tooltip content="提示信息"><span>一段文字</span></by-tooltip>
```
:::

## 自定义文字提示的内容

可通过 `slot="content"` 的方式设置文字提示的内容

:::demo
```html
<by-tooltip>
  <span>文字提示</span>
  <template slot="content">
    <p>文字1</p>
    <p>文字2</p>
  </template>
</by-tooltip>
```
:::

## 不同的展示方向

`placement` 属性可设置文字提示框出现的位置，默认提供9种不同的方向

:::demo
```html
<div class="show-box">
  <div class="top row col-md-16 flex-center">
    <by-tooltip class="item" content="Top Left 提示文字" placement="top-left"><by-button>上左</by-button></by-tooltip>
    <by-tooltip class="item" content="Top 提示文字" placement="top"><by-button>上边</by-button></by-tooltip>
    <by-tooltip class="item" content="Top Right 提示文字" placement="top-right"><by-button>上右</by-button></by-tooltip>
  </div>
  <div class="center row col-md-16 flex-between">
    <div class="left col-md-4">
      <by-tooltip class="item" content="Left Top 提示文字" placement="left-top"><by-button>左上</by-button></by-tooltip>
      <by-tooltip class="item" content="Left 提示文字" placement="left"><by-button>左边</by-button></by-tooltip>
      <by-tooltip class="item" content="Left Bottom 提示文字" placement="left-bottom"><by-button>左下</by-button></by-tooltip>
    </div>
    <div class="right col-md-4">
      <by-tooltip class="item" content="Right Top 提示文字" placement="right-top"><by-button>右上</by-button></by-tooltip>
      <by-tooltip class="item" content="Right 提示文字" placement="right"><by-button>右边</by-button></by-tooltip>
      <by-tooltip class="item" content="Right Bottom 提示文字" placement="right-bottom"><by-button>右下</by-button></by-tooltip>
    </div>
  </div>
  <div class="bottom row col-md-16 flex-center">
    <by-tooltip class="item" content="Bottom Left 提示文字" placement="bottom-left"><by-button>下左</by-button></by-tooltip>
    <by-tooltip class="item" content="Bottom 提示文字" placement="bottom"><by-button>下边</by-button></by-tooltip>
    <by-tooltip class="item" content="Bottom Right 提示文字" placement="bottom-right"><by-button>下右</by-button></by-tooltip>
  </div>
</div>
```
:::

## Tooltip 参数

| 参数      | 说明          | 类型      | 可选值                           | 默认值  |
|---------- |-------------- |---------- |--------------------------------  |-------- |
| content | 提示文字 | String | - | - |
| placement | 气泡框位置 | String | `top`, `top-left`, `top-right`, `left`, `left-top`, `left-bottom`, `right`, `right-top`, `right-bottom`, `bottom`, `bottom-left`, `bottom-right` | `top` |

<style lang="scss" scoped>
.by-tooltip {
  & + .by-tooltip {
    margin-left: 16px;
  }
  span {
    font-size: 12px;
  }
  p {
    color: #fff;
    font-size: 12px;
  }
}
.show-box {
  max-width: 600px;

  .by-tooltip + .by-tooltip {
    margin: 0;
  }
}
.top,
.bottom {
  padding: 20px;
  width: 100%;

  .item + .item {
    margin-left: 30px;
  }
}
.center {
  width: 100%;

  .item + .item {
    margin-top: 20px;
  }
}
.left {
  flex-direction: column;
}

.item > span {
  display: inline-block;
  width: 60px;
  height: 32px;
  line-height: 32px;
  background-color: #fff;
  border: 1px solid #ccc;
  border-radius: 4px;
  text-align: center;
  cursor: pointer;
  transition: all .3s;

  &:hover {
    color: #a0c1ff;
    border-color: #a0c1ff;
  }
}
</style>
<file_sep>/src/components/message/vue.d.ts
import Vue from 'vue';

declare module 'vue/types/vue' {
    interface Vue {
        $message: {
            (option: any): void;
            info(option: any): void;
            success(option: any): void;
            warning(option: any): void;
            error(option: any): void;
            loading(option: any): void;
        };
    }
}
<file_sep>/src/components/tabs/index.ts
import Tabs from './src/tabs.vue'

Object.defineProperty(Tabs, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-tabs', Tabs);
    }
})

export default Tabs
<file_sep>/docs/markdown/popover.md

# Popover 弹出框

----

## 基本用法

默认显示在正中间，并且以 `click` 方式激活，使用方法跟 `Tooltip` 基本一样

:::demo
```html
<by-popover placement="top" title="Title" content="Top Placement">
  <by-button size="small">点击</by-button>
</by-popover>
<by-popover content="Top Placement" title="Title">
  一段文字
</by-popover>
```
:::

## 更改激活的方式

默认使用 `click` 方式激活，可设置 `trigger` 更换激活方式

:::demo
```html
<by-popover trigger="click" content="Top Placement">
  <by-button size="small">Click</by-button>
</by-popover>
<by-popover trigger="hover" title="Title" content="Top Placement">
  <by-button size="small">Hover</by-button>
</by-popover>
```
:::

## 弹出框的位置

设置属性 `placement` 可更改弹出框的位置，默认显示在顶部 `top`

:::demo
```html
<by-popover trigger="hover" content="Top Placement">
  <by-button size="small">Top</by-button>
</by-popover>
<by-popover trigger="hover" content="Top Placement" placement="bottom">
  <by-button size="small">Bottom</by-button>
</by-popover>
<by-popover trigger="hover" content="Top Placement" placement="left">
  <by-button size="small">Left</by-button>
</by-popover>
<by-popover trigger="hover" content="Top Placement" placement="right">
  <by-button size="small">Right</by-button>
</by-popover>
```
:::

## 嵌套内容

除了可以使用属性 `title` 和 `content` 设置弹出框的内容，还可以使用 `slot="title"` 和 `slot="content"` 的方式设置弹出框的嵌套内容

:::demo
```html
<by-popover placement="top" v-model="show" @toggle="toggleShow">
  <by-button size="small">删除</by-button>
  <template slot="content">
    <p>这是一段内容，确定删除吗？</p>
    <div style="text-align: right; margin-top: 8px;">
      <by-button size="smaller" @click="show = false">取消</by-button>
      <by-button type="primary" size="smaller" @click="show = false">确定</by-button>
    </div>
  </template>
</by-popover>
```
:::

## Popover 参数

| 参数      | 说明          | 类型      | 可选值                           | 默认值  |
|---------- |-------------- |---------- |--------------------------------  |-------- |
| title | 标题文字 | String | - | - |
| content | 提示文字 | String | - | - |
| trigger | 触发的事件类型 | String | `hover`, `focus`, `click` | `click` |
| placement | 弹出框的位置 | String | `top`, `top-left`, `top-right`, `left`, `left-top`, `left-bottom`, `right`, `right-top`, `right-bottom`, `bottom`, `bottom-left`, `bottom-right` | `top` |

<style lang="scss" scoped>
.by-popover + .by-popover {
  margin-left: 16px;
}
</style>

<script>
export default {
  data() {
    return {
      show: false
    }
  },
  methods: {
    toggleShow(status) {
      this.show = status
    }
  }
}
</script>
<file_sep>/src/components/tooltip/index.ts
import Tooltip from './src/tooltip.vue'

Object.defineProperty(Tooltip, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-tooltip', Tooltip);
    }
})

export default Tooltip
<file_sep>/src/components/collapse-item/index.ts
import CollapseItem from '../collapse/src/collapse-item.vue'

Object.defineProperty(CollapseItem, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-collapse-item', CollapseItem);
    }
})

export default CollapseItem




<file_sep>/src/components/pagination/index.ts
import Pagination from './src/pagination.vue'

Object.defineProperty(Pagination, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-pagination', Pagination);
    }
})

export default Pagination
<file_sep>/src/components/dropdown/index.ts
import Dropdown from './src/dropdown.vue'

Object.defineProperty(Dropdown, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-dropdown', Dropdown);
    }
})

export default Dropdown;
<file_sep>/src/mixins/two-way/index.ts
import { Vue, Component, Prop, Model } from 'vue-property-decorator';

/** Mixin：双向绑定 */
@Component
export default class TwoWay extends Vue {
    @Prop()
    @Model('valueChanged')
    bindValue!: any;

    /** 双向绑定数据 */
    get currentValue() {
        return this.bindValue;
    }

    set currentValue(value) {
        this.$emit('valueChanged', value);
    }
}
<file_sep>/src/locale/lang/en-US.ts
export default {
    by: {
        index:{
            h4: 'Focus on a better user experience with a modular UI component library.',
            button: 'GET STARTED',
            btnGroup: [
                {
                    title: 'Guide',
                    content: 'Understand design guidelines and design with uniform specifications to help product designers and front-end engineers build quickly.'
                },{
                    title: 'Component',
                    content: 'Experience the interaction details through the demo of the component, the development can be referenced separately, or the component can be introduced globally.'
                },{
                    title: 'Resource',
                    content: 'Products can quickly build high-fidelity prototypes with sketch tools, reducing communication costs.'
                }
            ]
        },
        header: {
            adminSystem: 'Admin',
            component: 'Component',
            guide: 'Guide'
        },
        color:{
            themeColor:'Theme Color',
            themeColorDesc:'Used to identify brand colors',
            colorTitle:'Color',
            colorDesc:'Uniform color matching can improve the recognition of the brand, the use of color in addition to need to consider the unity of the brand, but also need to achieve information transmission, interactive feedback and other purposes. BY-UI is made by BY Lab sand, branded in BY Blue, so the overall color matching style of BY-UI is also based on BY Blue.',
        },
        nav:{
            color:'Color',
            font:'Font',
            brand:'Brand',
            introduce:'Introduce',
            button:'Button',
            tag:'Tag',
            component:'Component',
            summarize:'Summarize',
            baseComponent:'BaseComponent',
            icon: 'Icon',
            checkbox: 'Checkbox',
            input: 'Input',
            inputnumber: 'InputNumber',
            radio: 'Radio',
            rate: 'Rate',
        },
        select: {
            placeholder: 'Select',
            notFoundText: 'No matching data'
        },
        modal: {
            okText: 'OK',
            cancelText: 'Cancel'
        },
        pagination: {
            prevText: 'Previous Page',
            nextText: 'Next Page',
            total: 'Total',
            item: 'item',
            items: 'items',
            pageSize: '/ page',
            goto: 'Goto',
            pageText: '',
            prev5Text: 'Previous 5 Pages',
            next5Text: 'Next 5 Pages'
        },
        table: {
            emptyText: 'No data'
        }
    }
}
<file_sep>/src/components/tab-pane/index.ts
import TabPane from '../tabs/src/tab-pane.vue'

Object.defineProperty(TabPane, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-tab-pane', TabPane);
    }
})

export default TabPane
<file_sep>/src/components/textarea/index.ts
import Textarea from './src/textarea.vue'

Object.defineProperty(Textarea, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-textarea', Textarea);
    }
})

export default Textarea

<file_sep>/src/components/step-item/index.ts
import StepItem from '../step/src/step-item.vue'

Object.defineProperty(StepItem, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-step-item', StepItem);
    }
})

export default StepItem
<file_sep>/src/components/modal/index.ts
import Model from './src/modal.vue';
import Dialog from './src/dialog';

Object.defineProperty(Model, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-model', Model);
    }
})

Object.assign(Model,Dialog)

export default Model
<file_sep>/docs/markdown/drawer.md
# Drawer 抽屉

有些时候, `Dialog` 组件并不满足我们的需求, 比如你的表单很长, 亦或是你需要临时展示一些文档, `Drawer` 拥有和 `Dialog` 几乎相同的 API, 在 UI 上带来不一样的体验.

### 基本用法

呼出一个临时的侧边栏, 可以从多个方向呼出

:::demo
```html
<by-radio-group v-model="direction">
  <by-radio label="ltr">从左往右开</by-radio>
  <by-radio label="rtl">从右往左开</by-radio>
  <by-radio label="ttb">从上往下开</by-radio>
  <by-radio label="btt">从下往上开</by-radio>
</by-radio-group>

<by-button @click="drawer = true" type="primary" style="margin-left: 16px;">
  点我打开
</by-button>

<by-drawer
  title="我是标题"
  :visible.sync="drawer"
  :direction="direction"
  :before-close="handleClose"
  @close="close"></by-drawer>


<script>
  export default {
    data() {
      return {
        drawer: false,
        direction: 'rtl',
      };
    },
    methods: {
      handleClose(done) {
        done();
      },
      close(){
          console.log('close);
      }
    }
  };
</script>
```
:::


<script lang="ts">
    import { Vue, Component } from "vue-property-decorator";

    @Component
    export default class drawerMd extends Vue {

        drawer = false;

        direction = 'rtl';

        handleClose(done) {
            // this.$confirm('确认关闭？').then(_ => {
            //     done();
            // }).catch(_ => {});
            done();
        }

        close(){
            console.log('close');
        }
    }

</script>
<file_sep>/build/iconfont/iconfont-builder.js
const path = require('path');
const fs = require('fs');
const color = require('colors-cli');
const {
    createSVG,
    createTTF,
    createEOT,
    createWOFF,
    createWOFF2,
    copyTemplate
} = require("svgtofont/src/utils");


const options = {
    src: path.resolve('docs/assets/icon-svgs'), // svg 图标目录路径
    dist: path.resolve('_intermediate/iconfonts'), // 输出到指定目录中
    fontName: 'by-icon', // 设置字体名称
    fontSize: '16px',
    clssaNamePrefix: 'icon',
    svgicons2svgfont: {
        fontHeight: 1000,
        normalize: true
    },
}

let cssString = [];

fs.exists("./_intermediate/iconfonts", exists => {
    if (!exists) {
        fs.mkdir('./_intermediate', error => {});
        fs.mkdir('./_intermediate/iconfonts/', error => {})
    }

    createSVG(options) // SVG => SVG Font
        .then(UnicodeObject => {
            Object.keys(UnicodeObject).forEach(name => {
                let _code = UnicodeObject[name];
                cssString.push(`.${options.clssaNamePrefix}-${name}:before { content: "\\${_code.charCodeAt(0).toString(16)}"; }\n`);
            });
        })
        .then(() => createTTF(options)) // SVG Font => TTF
        .then(() => createWOFF(options)) // TTF => WOFF
        .then(() => createWOFF2(options)) // TTF => WOFF2
        .then(() => {
            const font_temp = path.resolve(__dirname, "iconfont-builder-template");
            return copyTemplate(font_temp, options.dist, {
                fontname: options.fontName,
                fontsize: options.fontSize || '16px',
                cssString: cssString.join(""),
                timestamp: new Date().getTime(),
                prefix: options.clssaNamePrefix || options.fontName
            });
        }).then(() => {
            console.log(`${color.green('✔')} Iconfont Build Success\n`)
        })

})
<file_sep>/src/components/slider/index.ts
import Slider from './src/slider.vue'

Object.defineProperty(Slider, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-slider', Slider);
    }
})

export default Slider


<file_sep>/docs/markdown/inputnumber.md
# InputNumber 数字输入框

----

## 基础用法

支持传入 `step` 精度，以及指定取值范围 `max` , `min`。默认 `step` 取整数 1

:::demo
```html
<p class="demo-desc">基本输入框，范围可以无递加或递减</p>
<div class="row no-gutter">
    <div class="col-md-4">
        <by-input-number v-model="num1"></by-input-number><br>
    </div>
</div>
<p class="demo-desc">有精度输入框，step=5，step=0.5</p>
<div class="row no-gutter">
    <div class="col-md-4">
        <by-input-number :step="5" v-model="num2"></by-input-number>
    </div>
    <div class="col-md-4 col-md-offset-1">
        <by-input-number :step="0.5" v-model="num3"></by-input-number>
    </div>
</div>
<p class="demo-desc">有取值范围的输入框，min=0, max=20</p>
<div class="row no-gutter">
    <div class="col-md-4">
        <by-input-number :min="0" :max="20" v-model="num4"></by-input-number>
    </div>
</div>
```
:::

## 不可用状态

设置属性 `disabled` 禁用输入框

:::demo
```html
<div class="row no-gutter">
    <div class="col-md-4">
        <by-input-number disabled  v-model="num5"></by-input-number>
    </div>
</div>
```
:::


## 不同尺寸

配置属性 `size`，可控制输入框的尺寸，默认支持三种尺寸：`large`，`normal`，`small`

:::demo
```html
<div class="row">
    <div class="col-sm-12 col-md-4">
        <by-input-number size="small" v-model="num6"></by-input-number>
    </div>
    <div class="col-sm-12 col-md-4">
        <by-input-number v-model="num6"></by-input-number>
    </div>
    <div class="col-sm-12 col-md-4">
        <by-input-number size="large" v-model="num6"></by-input-number>
    </div>
</div>
```
:::


## InputNumber 参数

| 参数      | 说明          | 类型      | 可选值                           | 默认值  |
|---------- |-------------- |---------- |--------------------------------  |-------- |
| value | 输入框的值，可通过 `v-model` 绑定 | Number | - | - |
| size | 输入框尺寸 | String | `small`  `normal`  `large` | normal |
| step | 每次递增或递减的数目 | Number | - | 1 |
| min | 最小值 | Number | - | -Infinity |
| max | 最大值 | Number | - | Infinity |
| disabled | 是否禁用输入框 | Boolean | - | false |
| readonly | 是否设置成只读 | Boolean | - | false |
| autofocus | 是否自动聚焦到输入框 | Boolean | - | false |

## InputNumber 事件

| 事件名称      | 说明          | 返回值  |
|---------- |-------------- |---------- |
| focus | 获得焦点时触发 | event |
| blur | 失去焦点时触发 | event |
| change | 绑定的值有变化时触发 | 输入框的值 |

<script lang="ts">
 import { Vue, Component } from "vue-property-decorator";

 @Component
 export default class InputNumber extends Vue {

     num1 = 0;

     num2 = 0;

     num3= 0;

     num4 = 10;

     num5 = 999.99;

     num6 = 100;
 }
</script>
<file_sep>/src/components/dropdown-item/index.ts
import DropdownItem from '../dropdown/src/dropdown-item.vue'

Object.defineProperty(DropdownItem, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-dropdown-item', DropdownItem);
    }
})

export default DropdownItem

<file_sep>/README.md
# By-UI1
基于 Vue2.0 一款轻量级、模块化的高颜值前端UI组件库

使用webpack打包，typescript语法搭建的管理系统后台

说明：https://www.yuque.com/okr2gd/ng0vwv/egrrzu

```
git submodule update --init --recursive

git submodule foreach git pull https://github.com/by-ui/by-ui-style.git master
```

```
npm install
```

```
npm run icon
```

```
npm run dev
```

- vue-i18n              国际化
- vivus                 svg动画
- smooth-scrollbar      滚动条
<file_sep>/src/components/breadcrumb-item/index.ts
import BreadcrumbItem from '../breadcrumb/src/breadcrumb-item.vue'

Object.defineProperty(BreadcrumbItem, 'install', {
    writable: false,
    value: (Vue: any) => {
        Vue.component('by-breadcrumb-item', BreadcrumbItem);
    }
})

export default BreadcrumbItem
