├── .browserslistrc
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .npmignore
├── .prettierignore
├── .prettierrc
├── LICENSE
├── README.md
├── babel.config.js
├── build
├── gulpfile.js
├── md-loader
│ ├── config.js
│ ├── containers.js
│ ├── fence.js
│ ├── index.js
│ └── util.js
├── rollup.config.js
└── webpack.dev.js
├── docs
├── 0c51f5157c4954238cc7.ttf
├── 0e183abb317dc7309207.eot
├── 511aad842c035d563ea2.woff
├── ea78a237145b724f979a.svg
├── favicon.ico
├── index.html
├── js
│ ├── DOCS0.48024f5.js
│ ├── DOCS1.48024f5.js
│ ├── DOCS10.48024f5.js
│ ├── DOCS11.48024f5.js
│ ├── DOCS12.48024f5.js
│ ├── DOCS13.48024f5.js
│ ├── DOCS14.48024f5.js
│ ├── DOCS15.48024f5.js
│ ├── DOCS16.48024f5.js
│ ├── DOCS17.48024f5.js
│ ├── DOCS18.48024f5.js
│ ├── DOCS19.48024f5.js
│ ├── DOCS2.48024f5.js
│ ├── DOCS20.48024f5.js
│ ├── DOCS21.48024f5.js
│ ├── DOCS22.48024f5.js
│ ├── DOCS23.48024f5.js
│ ├── DOCS24.48024f5.js
│ ├── DOCS25.48024f5.js
│ ├── DOCS26.48024f5.js
│ ├── DOCS27.48024f5.js
│ ├── DOCS28.48024f5.js
│ ├── DOCS29.48024f5.js
│ ├── DOCS3.48024f5.js
│ ├── DOCS30.48024f5.js
│ ├── DOCS31.48024f5.js
│ ├── DOCS32.48024f5.js
│ ├── DOCS33.48024f5.js
│ ├── DOCS34.48024f5.js
│ ├── DOCS35.48024f5.js
│ ├── DOCS36.48024f5.js
│ ├── DOCS37.48024f5.js
│ ├── DOCS38.48024f5.js
│ ├── DOCS39.48024f5.js
│ ├── DOCS4.48024f5.js
│ ├── DOCS40.48024f5.js
│ ├── DOCS41.48024f5.js
│ ├── DOCS42.48024f5.js
│ ├── DOCS43.48024f5.js
│ ├── DOCS44.48024f5.js
│ ├── DOCS45.48024f5.js
│ ├── DOCS46.48024f5.js
│ ├── DOCS47.48024f5.js
│ ├── DOCS48.48024f5.js
│ ├── DOCS49.48024f5.js
│ ├── DOCS5.48024f5.js
│ ├── DOCS50.48024f5.js
│ ├── DOCS51.48024f5.js
│ ├── DOCS52.48024f5.js
│ ├── DOCS53.48024f5.js
│ ├── DOCS54.48024f5.js
│ ├── DOCS55.48024f5.js
│ ├── DOCS56.48024f5.js
│ ├── DOCS57.48024f5.js
│ ├── DOCS58.48024f5.js
│ ├── DOCS59.48024f5.js
│ ├── DOCS6.48024f5.js
│ ├── DOCS60.48024f5.js
│ ├── DOCS61.48024f5.js
│ ├── DOCS62.48024f5.js
│ ├── DOCS63.48024f5.js
│ ├── DOCS64.48024f5.js
│ ├── DOCS65.48024f5.js
│ ├── DOCS66.48024f5.js
│ ├── DOCS67.48024f5.js
│ ├── DOCS7.48024f5.js
│ ├── DOCS8.48024f5.js
│ ├── DOCS9.48024f5.js
│ ├── app.js
│ └── vendors.js
└── static
│ ├── iconfont.0bf6cd3.ttf
│ ├── iconfont.90bdc02.woff
│ ├── iconfont.a49ca6a.svg
│ ├── iconfont.e3031e0.eot
│ └── text.8834c48.svg
├── examples
├── App.vue
├── assets
│ ├── images
│ │ ├── Bin-UI-Next-01.png
│ │ ├── Bin-UI-Next-02.png
│ │ ├── Bin-UI-Next-03.png
│ │ ├── Bin-UI-Next-04.png
│ │ ├── Bin-UI-Next-05.png
│ │ ├── admin
│ │ │ ├── Bin-Admin-Pro-01.png
│ │ │ ├── Bin-Admin-Pro-01.svg
│ │ │ ├── Bin-Admin-Pro-02.png
│ │ │ ├── Bin-Admin-Pro-02.svg
│ │ │ ├── Bin-Admin-Pro-03.png
│ │ │ └── Bin-Admin-Pro-03.svg
│ │ ├── bin-ui.png
│ │ ├── loading.svg
│ │ ├── loading1.svg
│ │ ├── logo
│ │ │ ├── bin-ui-next-01.png
│ │ │ ├── bin-ui-next-01.svg
│ │ │ ├── bin-ui-next-02.png
│ │ │ ├── bin-ui-next-02.svg
│ │ │ ├── bin-ui-next-03.png
│ │ │ ├── bin-ui-next-03.svg
│ │ │ ├── favicon1.ico
│ │ │ ├── favicon2.ico
│ │ │ └── favicon3.ico
│ │ ├── logo01.png
│ │ ├── svg
│ │ │ ├── Bin-UI-Next-01.svg
│ │ │ ├── Bin-UI-Next-02.svg
│ │ │ ├── Bin-UI-Next-03.svg
│ │ │ ├── Bin-UI-Next-04.svg
│ │ │ ├── Bin-UI-Next-05.svg
│ │ │ ├── code-show.svg
│ │ │ └── code.svg
│ │ └── text.svg
│ └── styles
│ │ ├── base.styl
│ │ ├── color-brewer.styl
│ │ ├── common.styl
│ │ ├── demo.styl
│ │ ├── index.styl
│ │ └── scrollbar.styl
├── components
│ ├── SvgLoading
│ │ ├── index.vue
│ │ └── loading
│ │ │ ├── loading-text.vue
│ │ │ ├── loading01.vue
│ │ │ ├── loading02.vue
│ │ │ ├── loading03.vue
│ │ │ ├── loading04.vue
│ │ │ ├── loading05.vue
│ │ │ ├── loading06.vue
│ │ │ ├── loading07.vue
│ │ │ ├── loading08.vue
│ │ │ ├── loading09.vue
│ │ │ ├── loading10.vue
│ │ │ ├── loading11.vue
│ │ │ └── loading12.vue
│ ├── color-base.vue
│ ├── demo-block.vue
│ ├── draggable-demo.vue
│ ├── footer.vue
│ ├── header.vue
│ ├── icon-pane.vue
│ ├── search.vue
│ └── side-nav.vue
├── docs
│ ├── affix.md
│ ├── alert.md
│ ├── anchor.md
│ ├── backtop.md
│ ├── badge.md
│ ├── base.md
│ ├── breadcrumb.md
│ ├── button.md
│ ├── calendar.md
│ ├── card.md
│ ├── carousel.md
│ ├── cascader.md
│ ├── checkbox.md
│ ├── circle.md
│ ├── collapse.md
│ ├── color-picker.md
│ ├── color.md
│ ├── config-provider.md
│ ├── console.md
│ ├── countTo.md
│ ├── date-picker.md
│ ├── desc.md
│ ├── directive.md
│ ├── divider.md
│ ├── drawer.md
│ ├── dropdown.md
│ ├── empty.md
│ ├── form.md
│ ├── grid.md
│ ├── guide.md
│ ├── icon.md
│ ├── input.md
│ ├── inputNumber.md
│ ├── layout.md
│ ├── loading-bar.md
│ ├── loading.md
│ ├── logs.md
│ ├── menu.md
│ ├── message.md
│ ├── messageBox.md
│ ├── modal.md
│ ├── notice.md
│ ├── page.md
│ ├── popover.md
│ ├── popperjs.md
│ ├── progress.md
│ ├── radio.md
│ ├── rate.md
│ ├── scrollbar.md
│ ├── select.md
│ ├── skeleton.md
│ ├── slider.md
│ ├── sortablejs.md
│ ├── space.md
│ ├── split.md
│ ├── start.md
│ ├── steps.md
│ ├── switch.md
│ ├── table.md
│ ├── tabs.md
│ ├── tag.md
│ ├── theme.md
│ ├── time-picker.md
│ ├── timeline.md
│ ├── tooltip.md
│ ├── transition.md
│ ├── tree.md
│ └── upload.md
├── favicon.ico
├── generateTreeData.js
├── index.html
├── main.js
├── nav.config.json
├── route.js
└── util.js
├── jsconfig.json
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
└── src
├── components
├── affix
│ ├── affix.vue
│ └── index.js
├── alert
│ ├── alert.vue
│ └── index.js
├── anchor-link
│ └── index.js
├── anchor
│ ├── anchor-link.vue
│ ├── anchor.vue
│ └── index.js
├── back-top
│ ├── back-top.vue
│ └── index.js
├── badge
│ ├── badge.vue
│ └── index.js
├── breadcrumb-item
│ └── index.js
├── breadcrumb
│ ├── breadcrumb-item.vue
│ ├── breadcrumb.vue
│ └── index.js
├── button-group
│ └── index.js
├── button
│ ├── button-group.vue
│ ├── button.vue
│ └── index.js
├── calendar
│ ├── calendar.vue
│ └── index.js
├── card
│ ├── card.vue
│ └── index.js
├── carousel-item
│ └── index.js
├── carousel
│ ├── carousel-item.vue
│ ├── carousel.vue
│ └── index.js
├── cascader-panel
│ ├── index.js
│ ├── src
│ │ ├── index.vue
│ │ ├── menu.vue
│ │ └── node.vue
│ └── utils
│ │ ├── config.js
│ │ ├── node.js
│ │ ├── store.js
│ │ └── utils.js
├── cascader
│ ├── cascader.vue
│ └── index.js
├── checkbox-group
│ └── index.js
├── checkbox
│ ├── checkbox-group.vue
│ ├── checkbox.vue
│ ├── index.js
│ └── useCheckbox.js
├── circle
│ ├── circle.vue
│ └── index.js
├── col
│ ├── col.vue
│ └── index.js
├── collapse-panel
│ └── index.js
├── collapse-transition
│ ├── collapse-transition.vue
│ └── index.js
├── collapse-wrap
│ ├── index.js
│ └── wrapper.vue
├── collapse
│ ├── collapse.vue
│ ├── index.js
│ └── panel.vue
├── color-picker
│ ├── alpha-slider.vue
│ ├── color.js
│ ├── draggable.js
│ ├── hue-slider.vue
│ ├── index.js
│ ├── picker.vue
│ ├── predefine.vue
│ └── sv-panel.vue
├── config-provider
│ ├── index.js
│ └── src
│ │ ├── ConfigProvider.js
│ │ ├── context.js
│ │ └── types.js
├── count-to
│ ├── count-to.vue
│ └── index.js
├── date-picker
│ ├── date-picker-com
│ │ ├── basic-date-table.vue
│ │ ├── basic-month-table.vue
│ │ ├── basic-year-table.vue
│ │ ├── panel-date-pick.vue
│ │ ├── panel-date-range.vue
│ │ └── panel-month-range.vue
│ ├── date-picker.js
│ └── index.js
├── desc-item
│ ├── index.js
│ └── item.vue
├── desc
│ ├── desc.vue
│ ├── descriptions-cell.js
│ ├── descriptions-row.vue
│ └── index.js
├── divider
│ ├── divider.vue
│ └── index.js
├── drawer
│ ├── drawer.vue
│ └── index.js
├── dropdown-item
│ └── index.js
├── dropdown-menu
│ └── index.js
├── dropdown
│ ├── dropdown-item.vue
│ ├── dropdown-menu.vue
│ ├── dropdown.vue
│ ├── index.js
│ └── useDropdown.js
├── empty
│ ├── empty.vue
│ └── index.js
├── form-item
│ └── index.js
├── form
│ ├── form-item.vue
│ ├── form.vue
│ ├── index.js
│ ├── label-wrap.js
│ └── token.js
├── icon-select
│ ├── icon-select.vue
│ └── index.js
├── icon
│ ├── icon.vue
│ └── index.js
├── input-number
│ ├── index.js
│ └── input-number.vue
├── input
│ ├── calcTextareaHeight.js
│ ├── index.js
│ └── input.vue
├── layout
│ ├── Layout.vue
│ └── index.js
├── loading-bar
│ ├── index.js
│ ├── instance.js
│ └── loading-bar.vue
├── loading
│ ├── index.js
│ └── loading.vue
├── menu-item-group
│ └── index.js
├── menu-item
│ └── index.js
├── menu
│ ├── index.js
│ ├── menu-item-group.vue
│ ├── menu-item.vue
│ ├── menu.vue
│ ├── submenu.vue
│ ├── useMenu.js
│ ├── useMenuColor.js
│ └── util
│ │ ├── menu-bar.js
│ │ ├── menu-item.js
│ │ └── submenu.js
├── message-box
│ ├── index.js
│ ├── instance.js
│ └── message-box.vue
├── message
│ ├── index.js
│ ├── instance.js
│ └── message.vue
├── modal
│ ├── addListener.js
│ ├── index.js
│ ├── mask.vue
│ ├── modal.vue
│ └── useModal.js
├── move-transition
│ ├── index.js
│ └── move-transition.js
├── notice
│ ├── index.js
│ ├── instance.js
│ └── notice.vue
├── option-group
│ └── index.js
├── option
│ └── index.js
├── page
│ ├── index.js
│ ├── options.vue
│ └── page.vue
├── popover
│ ├── index.js
│ ├── popover.vue
│ └── usePopover.js
├── popper
│ ├── index.js
│ └── src
│ │ ├── index.vue
│ │ ├── renderers
│ │ ├── arrow.js
│ │ ├── index.js
│ │ ├── popper.js
│ │ └── trigger.js
│ │ └── use-popper
│ │ ├── build-modifiers.js
│ │ ├── defaults.js
│ │ ├── index.js
│ │ └── popper-options.js
├── progress
│ ├── index.js
│ └── progress.vue
├── radio-group
│ └── index.js
├── radio
│ ├── index.js
│ ├── radio-group.vue
│ ├── radio.vue
│ └── useRadio.js
├── rate
│ ├── index.js
│ └── rate.vue
├── row
│ ├── index.js
│ └── row.vue
├── scrollbar
│ ├── bar.js
│ ├── index.js
│ ├── scrollbar.vue
│ └── util.js
├── select
│ ├── index.js
│ ├── option-group.vue
│ ├── option.vue
│ ├── select-dropdown.vue
│ ├── select.vue
│ ├── token.js
│ ├── useOption.js
│ └── useSelect.js
├── skeleton-item
│ ├── img-placeholder.vue
│ ├── index.js
│ └── item.vue
├── skeleton
│ ├── index.js
│ ├── skeleton.vue
│ └── use-throttle.js
├── slider
│ ├── index.js
│ └── src
│ │ ├── button.vue
│ │ ├── index.vue
│ │ ├── marker.vue
│ │ ├── useMarks.js
│ │ ├── useSlide.js
│ │ ├── useSliderButton.js
│ │ └── useStops.js
├── space
│ ├── index.js
│ ├── item.vue
│ └── useSpace.js
├── split
│ ├── index.js
│ ├── pane.vue
│ ├── resizer.vue
│ └── split.vue
├── step
│ └── index.js
├── steps
│ ├── index.js
│ ├── step.vue
│ └── steps.vue
├── submenu
│ └── index.js
├── switch
│ ├── index.js
│ └── switch.vue
├── table
│ ├── cell.vue
│ ├── index.js
│ ├── main
│ │ ├── expand.js
│ │ ├── header.js
│ │ ├── mixin.js
│ │ ├── slot.js
│ │ └── util.js
│ ├── table-body.vue
│ ├── table-head.vue
│ ├── table-tr.vue
│ └── table.vue
├── tabs
│ ├── index.js
│ ├── scroll-pane.vue
│ └── tabs.vue
├── tag
│ ├── index.js
│ └── tag.vue
├── time-picker
│ ├── common
│ │ ├── constant.js
│ │ ├── date-utils.js
│ │ ├── picker.vue
│ │ └── props.js
│ ├── index.js
│ ├── time-picker-com
│ │ ├── basic-time-spinner.vue
│ │ ├── panel-time-pick.vue
│ │ ├── panel-time-range.vue
│ │ └── useTimePicker.js
│ └── time-picker.js
├── timeline-item
│ └── index.js
├── timeline
│ ├── index.js
│ ├── timeline-item.vue
│ └── timeline.vue
├── tooltip
│ ├── index.js
│ └── tooltip.js
├── tree-big
│ └── index.js
├── tree-select
│ ├── index.js
│ └── tree-select.vue
├── tree
│ ├── big-tree.vue
│ ├── index.js
│ ├── node.vue
│ ├── render.js
│ └── tree.vue
└── upload
│ ├── ajax.js
│ ├── index.js
│ ├── upload-list.vue
│ └── upload.vue
├── directives
├── click-animation
│ └── index.js
├── click-outside
│ └── index.js
├── index.js
├── loading
│ └── index.js
├── no-data
│ └── index.js
├── repeat-click
│ └── index.js
└── waves
│ └── index.js
├── hooks
├── index.js
├── useFocus.js
├── useForm.js
├── useLockScreen.js
├── useModal.js
├── useModalDrag.js
├── useMousePosition.js
├── useRestoreActive.js
├── useSortable.js
└── useTimeout.js
├── index.js
├── styles
├── common
│ ├── common.styl
│ ├── mixins.styl
│ ├── transition.styl
│ ├── vars.styl
│ └── waves.styl
├── components
│ ├── affix.styl
│ ├── alert.styl
│ ├── anchor.styl
│ ├── backtop.styl
│ ├── badge.styl
│ ├── breadcrumb.styl
│ ├── button.styl
│ ├── calendar.styl
│ ├── card.styl
│ ├── carousel.styl
│ ├── cascader-panel.styl
│ ├── cascader.styl
│ ├── checkbox.styl
│ ├── circle.styl
│ ├── collapse.styl
│ ├── color-picker.styl
│ ├── date-picker.styl
│ ├── desc.styl
│ ├── divider.styl
│ ├── drawer.styl
│ ├── dropdown.styl
│ ├── empty.styl
│ ├── form.styl
│ ├── grid.styl
│ ├── icon.styl
│ ├── input-number.styl
│ ├── input.styl
│ ├── layout.styl
│ ├── loading.styl
│ ├── loadingbar.styl
│ ├── mask.styl
│ ├── menu.styl
│ ├── message-box.styl
│ ├── message.styl
│ ├── modal.styl
│ ├── notice.styl
│ ├── page.styl
│ ├── popover.styl
│ ├── popper.styl
│ ├── progress.styl
│ ├── radio.styl
│ ├── rate.styl
│ ├── scrollbar.styl
│ ├── select.styl
│ ├── skeleton.styl
│ ├── slider.styl
│ ├── space.styl
│ ├── split.styl
│ ├── steps.styl
│ ├── switch.styl
│ ├── table.styl
│ ├── tabs.styl
│ ├── tag.styl
│ ├── time-picker.styl
│ ├── timeline.styl
│ ├── tree.styl
│ └── upload.styl
├── flex.styl
├── fonts
│ ├── iconfont.eot
│ ├── iconfont.json
│ ├── iconfont.svg
│ ├── iconfont.ttf
│ ├── iconfont.woff
│ └── iconfont.woff2
├── icon.styl
├── index.styl
├── normalize.styl
└── scrollbar.styl
└── utils
├── TransitionEvents.js
├── aria.js
├── color.js
├── config-util.js
├── config.js
├── constants.js
├── create-loading-like-directive.js
├── dom.js
├── isDef.js
├── isServer.js
├── log.js
├── popup-manager.js
├── resize-event.js
├── scroll-into-view.js
├── util-helper.js
├── util.js
├── validator-size.js
└── vnode.js
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not dead
4 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | public/
3 | es/
4 | lib/
5 | dist/
6 | package.json
7 | src/assets/
8 | plop-templates/
9 | handlebars/
10 | website/
11 | build/
12 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | browser: true,
5 | es6: true,
6 | node: true,
7 | },
8 | globals: {
9 | defineEmits: 'readonly',
10 | defineProps: 'readonly',
11 | defineExpose: 'readonly',
12 | defineOptions: 'readonly',
13 | },
14 | extends: ['eslint:recommended', 'plugin:vue/vue3-essential'],
15 | parserOptions: {
16 | parser: '@babel/eslint-parser',
17 | },
18 | rules: {
19 | 'no-unused-vars': 'warn',
20 | 'no-var': 'error',
21 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
22 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
23 | 'space-before-function-paren': 'off',
24 | 'template-curly-spacing': 'off',
25 | 'comma-dangle': 'off',
26 | eqeqeq: ['error', 'always'],
27 | indent: 'off',
28 | },
29 | }
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 | /lib
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .*
2 | *.md
3 | *.yml
4 | build/
5 | node_modules/
6 | test/
7 | gulpfile.js
8 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | dist
2 | docs
3 | node_modules
4 | pnpm-lock.yaml
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 100,
3 | "useTabs": false,
4 | "semi": false,
5 | "singleQuote": true,
6 | "quoteProps": "as-needed",
7 | "trailingComma": "all",
8 | "bracketSpacing": true,
9 | "arrowParens": "avoid",
10 | "htmlWhitespaceSensitivity": "ignore",
11 | "overrides": [
12 | {
13 | "files": ".prettierrc",
14 | "options": {
15 | "parser": "json"
16 | }
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # bin-ui-next
2 |
3 | bin-ui-next 是基于 vue3.0 的组件库,是 bin-ui 的升级,提供常用组件和公共样式、函数
4 |
5 | ## Docs
6 |
7 | [document](https://wangbin3162.github.io/bin-ui-next/)
8 |
9 | ## Bin-UI-Next
10 |
11 | bin-ui-next 是 bin-ui 的 vue3 升级版,目前组件源码正在疯狂重构中...
12 |
13 | 整体 api 设计仍然基于原有库,只会在极个别组件进行重构优化,整体组件依赖 vue3,使用 typescript 编写代码
14 |
15 | ### 特性
16 |
17 | - 💪 基于 Vue 3.0 Composition API
18 | - 🔥 Written in TypeScript
19 | - 🌈 最新图标基于阿里 iconfont ant-design 官方图标精简版
20 | - 🗑 移除了部分冗余代码
21 | - ⌨️ 部分组件代码进行重构优化
22 |
23 | ### 支持环境
24 |
25 | - 支持 ie11 以上
26 | - 支持服务端渲染
27 |
28 | ### 版本
29 |
30 | [](https://www.npmjs.com/package/bin-ui-next)
31 |
32 | ### 安装
33 |
34 | 推荐使用 `npm` 或 `yarn` 进行安装,它能更好地和 `webpack` 打包工具配合使用。而且可以更好的和 `es6` `typescript` 配合使用。并且支持按需引入
35 |
36 | ```shell
37 | npm i bin-ui-next -S
38 | # or
39 | yarn add bin-ui-next
40 | ```
41 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | '@babel/preset-env',
5 | {
6 | loose: true,
7 | modules: false,
8 | },
9 | ],
10 | ],
11 | plugins: [
12 | ['@babel/plugin-transform-runtime', {
13 | 'regenerator': true,
14 | }],
15 | ],
16 | env: {
17 | utils: {
18 | presets: [
19 | [
20 | '@babel/env',
21 | {
22 | loose: true,
23 | modules: false,
24 | },
25 | ],
26 | ],
27 | plugins: [
28 | [
29 | 'babel-plugin-module-resolver',
30 | {
31 | root: ['bin-ui-next'],
32 | alias: { 'bin-ui-next/src': 'bin-ui-next/lib' },
33 | },
34 | ],
35 | ],
36 | },
37 | },
38 | }
39 |
--------------------------------------------------------------------------------
/build/gulpfile.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // 单独打包css
3 | const {src, dest, series, task} = require('gulp')
4 | const stylus = require('gulp-stylus')
5 | const autoprefixer = require('gulp-autoprefixer')
6 | const cssmin = require('gulp-cssmin')
7 |
8 | // 打包默认的
9 | function compile() {
10 | return src('../src/styles/*.styl')
11 | .pipe(stylus())
12 | .pipe(autoprefixer({
13 | overrideBrowserslist: ['ie > 9', 'last 2 versions'],
14 | cascade: false,
15 | }))
16 | .pipe(cssmin())
17 | .pipe(dest('../lib/styles'))
18 | }
19 |
20 | // 打包组件样式
21 | function compileComponents() {
22 | return src('../src/styles/components/*.styl')
23 | .pipe(stylus())
24 | .pipe(autoprefixer({
25 | overrideBrowserslist: ['ie > 9', 'last 2 versions'],
26 | cascade: false,
27 | }))
28 | .pipe(cssmin())
29 | .pipe(dest('../lib/styles/components'))
30 | }
31 |
32 | // 复制字体包
33 | function copyFont() {
34 | return src('../src/styles/fonts/**')
35 | .pipe(cssmin())
36 | .pipe(dest('../lib/styles/fonts'))
37 | }
38 |
39 | task('default', series(copyFont, compile, compileComponents))
40 |
--------------------------------------------------------------------------------
/build/md-loader/config.js:
--------------------------------------------------------------------------------
1 | const Config = require('markdown-it-chain')
2 | const anchorPlugin = require('markdown-it-anchor')
3 | const slugify = require('transliteration').slugify
4 | const hljs = require('highlight.js')
5 | const containers = require('./containers')
6 | const overWriteFenceRule = require('./fence')
7 |
8 | const config = new Config()
9 |
10 | const highlight = (str, lang) => {
11 | if (!lang || !hljs.getLanguage(lang)) {
12 | return '
' + str + '
'
13 | }
14 | const html = hljs.highlight(str, { language: lang, ignoreIllegals: true }).value
15 | return `${html}
`
16 | }
17 |
18 | config
19 | .options.html(true).highlight(highlight).end()
20 |
21 | .plugin('anchor').use(anchorPlugin, [
22 | {
23 | level: 2,
24 | slugify: slugify,
25 | permalink: false,
26 | permalinkBefore: false,
27 | },
28 | ]).end()
29 |
30 | .plugin('containers').use(containers).end()
31 |
32 | const md = config.toMd()
33 | overWriteFenceRule(md)
34 |
35 | module.exports = md
36 |
--------------------------------------------------------------------------------
/build/md-loader/containers.js:
--------------------------------------------------------------------------------
1 | const mdContainer = require('markdown-it-container')
2 |
3 | module.exports = md => {
4 | md.use(mdContainer, 'demo', {
5 | validate(params) {
6 | return params.trim().match(/^demo\s*(.*)$/)
7 | },
8 | render(tokens, idx) {
9 | const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/)
10 | if (tokens[idx].nesting === 1) {
11 | const description = m && m.length > 1 ? m[1] : ''
12 | const content = tokens[idx + 1].type === 'fence' ? tokens[idx + 1].content : ''
13 | return `
14 | ${description ? `${md.render(description)}
` : ''}
15 |
16 | `
17 | }
18 | return ''
19 | },
20 | })
21 |
22 | md.use(mdContainer, 'tip')
23 | md.use(mdContainer, 'warning')
24 | }
25 |
--------------------------------------------------------------------------------
/build/md-loader/fence.js:
--------------------------------------------------------------------------------
1 | // 覆盖默认的 fence 渲染策略
2 | module.exports = md => {
3 | const defaultRender = md.renderer.rules.fence
4 | md.renderer.rules.fence = (tokens, idx, options, env, self) => {
5 | const token = tokens[idx]
6 | // 判断该 fence 是否在 :::demo 内
7 | const prevToken = tokens[idx - 1]
8 | const isInDemoContainer = prevToken && prevToken.nesting === 1 && prevToken.info.trim().match(/^demo\s*(.*)$/)
9 | if (token.info === 'html' && isInDemoContainer) {
10 | return `${md.utils.escapeHtml(token.content)}
`
11 | }
12 | return defaultRender(tokens, idx, options, env, self)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/docs/0c51f5157c4954238cc7.ttf:
--------------------------------------------------------------------------------
1 | export default __webpack_public_path__ + "static/iconfont.0bf6cd3.ttf";
--------------------------------------------------------------------------------
/docs/0e183abb317dc7309207.eot:
--------------------------------------------------------------------------------
1 | export default __webpack_public_path__ + "static/iconfont.e3031e0.eot";
--------------------------------------------------------------------------------
/docs/511aad842c035d563ea2.woff:
--------------------------------------------------------------------------------
1 | export default __webpack_public_path__ + "static/iconfont.90bdc02.woff";
--------------------------------------------------------------------------------
/docs/ea78a237145b724f979a.svg:
--------------------------------------------------------------------------------
1 | export default __webpack_public_path__ + "static/iconfont.a49ca6a.svg";
--------------------------------------------------------------------------------
/docs/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/docs/favicon.ico
--------------------------------------------------------------------------------
/docs/static/iconfont.0bf6cd3.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/docs/static/iconfont.0bf6cd3.ttf
--------------------------------------------------------------------------------
/docs/static/iconfont.90bdc02.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/docs/static/iconfont.90bdc02.woff
--------------------------------------------------------------------------------
/docs/static/iconfont.e3031e0.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/docs/static/iconfont.e3031e0.eot
--------------------------------------------------------------------------------
/examples/assets/images/Bin-UI-Next-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/Bin-UI-Next-01.png
--------------------------------------------------------------------------------
/examples/assets/images/Bin-UI-Next-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/Bin-UI-Next-02.png
--------------------------------------------------------------------------------
/examples/assets/images/Bin-UI-Next-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/Bin-UI-Next-03.png
--------------------------------------------------------------------------------
/examples/assets/images/Bin-UI-Next-04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/Bin-UI-Next-04.png
--------------------------------------------------------------------------------
/examples/assets/images/Bin-UI-Next-05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/Bin-UI-Next-05.png
--------------------------------------------------------------------------------
/examples/assets/images/admin/Bin-Admin-Pro-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/admin/Bin-Admin-Pro-01.png
--------------------------------------------------------------------------------
/examples/assets/images/admin/Bin-Admin-Pro-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/admin/Bin-Admin-Pro-02.png
--------------------------------------------------------------------------------
/examples/assets/images/admin/Bin-Admin-Pro-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/admin/Bin-Admin-Pro-03.png
--------------------------------------------------------------------------------
/examples/assets/images/bin-ui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/bin-ui.png
--------------------------------------------------------------------------------
/examples/assets/images/logo/bin-ui-next-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/logo/bin-ui-next-01.png
--------------------------------------------------------------------------------
/examples/assets/images/logo/bin-ui-next-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/logo/bin-ui-next-02.png
--------------------------------------------------------------------------------
/examples/assets/images/logo/bin-ui-next-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/logo/bin-ui-next-03.png
--------------------------------------------------------------------------------
/examples/assets/images/logo/favicon1.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/logo/favicon1.ico
--------------------------------------------------------------------------------
/examples/assets/images/logo/favicon2.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/logo/favicon2.ico
--------------------------------------------------------------------------------
/examples/assets/images/logo/favicon3.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/logo/favicon3.ico
--------------------------------------------------------------------------------
/examples/assets/images/logo01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/assets/images/logo01.png
--------------------------------------------------------------------------------
/examples/assets/images/svg/code-show.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/assets/images/svg/code.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/examples/assets/styles/base.styl:
--------------------------------------------------------------------------------
1 | // 优化显示
2 | body {
3 | color: #515a6e;
4 | font-size: 14px;
5 | font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -webkit-tap-highlight-color: transparent;
8 | }
9 |
10 | ul {
11 | margin: 0;
12 | padding: 0;
13 | list-style: none;
14 | }
15 | ul li {
16 | margin: 0;
17 | padding: 0;
18 | list-style: none;
19 | }
20 | a {
21 | color: #1089ff;
22 | text-decoration: none;
23 | &:focus {
24 | outline: none;
25 | }
26 | }
27 |
28 | .icon-loading {
29 | animation: rotating 2s linear infinite;
30 | }
31 |
32 | @keyframes rotating {
33 | 0% {
34 | transform: rotateZ(0deg);
35 | }
36 | 100% {
37 | transform: rotateZ(360deg);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/examples/assets/styles/color-brewer.styl:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Colorbrewer theme
4 | Original: https://github.com/mbostock/colorbrewer-theme (c) Mike Bostock
5 | Ported by Fabrício Tavares de Oliveira
6 |
7 | */
8 |
9 | .hljs {
10 | display: block;
11 | overflow-x: auto;
12 | padding: 0.5em;
13 | background: #fff;
14 | }
15 |
16 | .hljs,
17 | .hljs-subst {
18 | color: #000;
19 | }
20 |
21 | .hljs-string,
22 | .hljs-meta,
23 | .hljs-symbol,
24 | .hljs-template-tag,
25 | .hljs-template-variable,
26 | .hljs-addition {
27 | color: #f72671;
28 | }
29 |
30 | .hljs-comment,
31 | .hljs-quote {
32 | color: #636363;
33 | }
34 |
35 | .hljs-number,
36 | .hljs-regexp,
37 | .hljs-literal,
38 | .hljs-bullet,
39 | .hljs-link {
40 | color: #31a354;
41 | }
42 |
43 | .hljs-deletion,
44 | .hljs-variable {
45 | color: #88f;
46 | }
47 |
48 |
49 | .hljs-keyword,
50 | .hljs-selector-tag,
51 | .hljs-title,
52 | .hljs-section,
53 | .hljs-built_in,
54 | .hljs-doctag,
55 | .hljs-type,
56 | .hljs-tag,
57 | .hljs-name,
58 | .hljs-selector-id,
59 | .hljs-selector-class,
60 | .hljs-strong {
61 | color: #3182bd;
62 | }
63 |
64 | .hljs-emphasis {
65 | font-style: italic;
66 | }
67 |
68 | .hljs-attribute {
69 | color: #e6550d;
70 | }
71 |
72 |
73 | .hljs {
74 | line-height: 1.5715;
75 | font-family: Menlo, Monaco, Consolas, Courier, monospace;
76 | font-size: 12px;
77 | padding: 18px 24px;
78 | background-color: #fafafa;
79 | border: 1px solid #eaeefb;
80 | margin-bottom: 25px;
81 | border-radius: 4px;
82 | -webkit-font-smoothing: auto;
83 | }
84 |
--------------------------------------------------------------------------------
/examples/assets/styles/index.styl:
--------------------------------------------------------------------------------
1 | @import 'color-brewer.styl';
2 | @import 'base.styl';
3 | @import 'common.styl';
4 | @import 'demo.styl';
5 |
--------------------------------------------------------------------------------
/examples/assets/styles/scrollbar.styl:
--------------------------------------------------------------------------------
1 | // =================================
2 | // ==============scrollbar==========
3 | // =================================
4 | ::-webkit-scrollbar {
5 | width: 6px;
6 | height: 6px;
7 | }
8 |
9 | ::-webkit-scrollbar-track {
10 | background: rgba(0, 0, 0, 0.05);
11 | }
12 |
13 | ::-webkit-scrollbar-thumb {
14 | background: rgba(0, 0, 0, 0.2);
15 | box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.1);
16 | transition: box-shadow 1.2s;
17 | }
18 |
19 | ::-webkit-scrollbar-thumb:hover {
20 | box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.25);
21 | }
22 |
--------------------------------------------------------------------------------
/examples/components/SvgLoading/loading/loading02.vue:
--------------------------------------------------------------------------------
1 |
2 |
24 |
25 |
26 |
31 |
--------------------------------------------------------------------------------
/examples/components/SvgLoading/loading/loading03.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
19 |
--------------------------------------------------------------------------------
/examples/components/SvgLoading/loading/loading04.vue:
--------------------------------------------------------------------------------
1 |
2 |
30 |
31 |
32 |
37 |
--------------------------------------------------------------------------------
/examples/components/SvgLoading/loading/loading05.vue:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
24 |
--------------------------------------------------------------------------------
/examples/components/SvgLoading/loading/loading09.vue:
--------------------------------------------------------------------------------
1 |
2 |
33 |
34 |
35 |
40 |
--------------------------------------------------------------------------------
/examples/components/SvgLoading/loading/loading10.vue:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
27 |
--------------------------------------------------------------------------------
/examples/components/footer.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
12 |
13 |
20 |
--------------------------------------------------------------------------------
/examples/docs/affix.md:
--------------------------------------------------------------------------------
1 | ## Affix 图钉
2 |
3 | ### 基础用法
4 |
5 | 原生滚动相对于window窗口固定,也可以结合scrollbar进行配置
6 |
7 | ::: demo
8 |
9 | ```html
10 |
11 |
12 |
13 | 固定在顶部80的位置
14 |
15 |
16 | ```
17 |
18 | :::
19 |
20 | ### 固定位置
21 |
22 | 可以设置固定距离底部的位置
23 |
24 | ::: demo
25 |
26 | ```html
27 |
28 |
29 |
30 | 固定在底部20的位置
31 |
32 |
33 | ```
34 |
35 | :::
36 |
37 | ### Props
38 |
39 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
40 | |---------- |-------- |---------- |------------- |-------- |
41 | | offset | 距离窗口位置触发 | Number | — | 0 |
42 | | position | 可设置距离顶部或底部 | String | top、bottom | top |
43 | | z-index | 层级 | Number | — | 10 |
44 |
45 | ### Events
46 |
47 | | 事件名 | 说明 | 返回值 |
48 | |---------- |-------- |---------- |
49 | | change | 在固定状态发生改变时触发 | true/false |
50 | | scroll | 滚动响应事件 | Object{scrollTop,fixed} |
51 |
52 | ### Slot
53 |
54 | | 名称 | 说明 |
55 | |---------- |-------- |
56 | | default | 警告提示内容 |
57 |
--------------------------------------------------------------------------------
/examples/docs/badge.md:
--------------------------------------------------------------------------------
1 | ## Badge 徽标
2 |
3 | 用于提示当前条目数量等
4 |
5 | ### 基础用法
6 |
7 | 基础的徽标用法
8 |
9 | ::: demo
10 |
11 | ```html
12 |
13 |
14 |
15 | 普通按钮
16 |
17 |
18 | 回复
19 |
20 |
21 | primary徽标
22 |
23 |
24 | warning徽标
25 |
26 |
27 | 最大数值
28 |
29 |
30 | ```
31 |
32 | :::
33 |
34 | ### 自定义提示内容
35 |
36 | 可以提示非数字的徽标
37 |
38 | ::: demo
39 |
40 | ```html
41 |
42 |
43 |
44 | 热点
45 |
46 |
47 | 回复
48 |
49 | 红点模式
50 |
51 | ```
52 |
53 | :::
54 |
55 | ### Props
56 |
57 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
58 | |---------- |-------- |---------- |------------- |-------- |
59 | | value | 显示值 | string, number | — | — |
60 | | max | 最大值,超过最大值会显示 '{max}+' | number | — | — |
61 | | is-dot | 小圆点 | boolean | — |false|
62 | | hidden | 隐藏 badge | boolean | — |false|
63 | | type | 类型 | string | primary / success / warning / danger / info | — |
64 |
--------------------------------------------------------------------------------
/examples/docs/breadcrumb.md:
--------------------------------------------------------------------------------
1 | ## Breadcrumb 面包屑
2 |
3 | 显示当前页面的路径,快速返回之前的任意页面或者跳转链接
4 |
5 | ### 基础用法
6 |
7 | 面包屑的用法,separator设置分隔符 不设置to属性,一切都需要自行在插槽中灵活运用
8 |
9 | ::: demo
10 |
11 | ```html
12 |
13 |
14 |
15 | 首页
16 | 组件
17 | 面包屑
18 |
19 |
20 |
21 |
22 |
23 | Dashboard
24 |
25 |
26 |
27 |
28 | 操作台
29 | 分析页
30 |
31 |
32 |
33 |
34 | 组件
35 | 面包屑
36 |
37 |
38 | ```
39 |
40 | :::
41 |
42 | ### 分隔符
43 |
44 | 可以设置分隔符
45 |
46 | ::: demo
47 |
48 | ```html
49 |
50 |
51 |
52 | 首页
53 | 组件
54 | 面包屑
55 |
56 |
57 |
58 | 首页
59 | 组件
60 | 面包屑
61 |
62 |
63 | ```
64 |
65 | :::
66 |
67 | ### Breadcrumb Props
68 |
69 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
70 | |---------- |-------- |---------- |------------- |-------- |
71 | | separator | 分隔 | string | — | '/' |
72 | | separator-icon| 图标分隔符icon | string | — | — |
73 |
--------------------------------------------------------------------------------
/examples/docs/calendar.md:
--------------------------------------------------------------------------------
1 | ## Calendar 日历组件
2 |
3 | ### 基础用法
4 |
5 | 简单的日历组件用于装饰页面
6 |
7 | ::: demo
8 |
9 | ```html
10 |
11 |
12 |
13 |
14 | ```
15 |
16 | :::
17 |
18 | ### mini显示
19 |
20 | 简单的日历组件用于装饰页面
21 |
22 | ::: demo
23 |
24 | ```html
25 |
26 |
27 |
28 |
29 |
30 |
31 |
33 |
34 |
35 |
36 | ```
37 |
38 | :::
39 |
40 | ### Props
41 |
42 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
43 | |---------- |-------- |---------- |------------- |-------- |
44 | | grid-height | 日期高度,不填默认 80 | String | — | 80px |
45 | | text-align | 日期对其方式 | String | left center right | left |
46 | | mini | 迷你模式 | Boolean | l— | — |
47 | | body-style | 日期表body样式 | Object | — | — |
48 | | day-style | 每天样式 | Object | — | — |
49 |
50 | ### Events
51 |
52 | | 事件名 | 说明 | 返回值 |
53 | |---------- |-------- |---------- |
54 | | prev | 上个月按钮事件 | — |
55 | | next | 下个月按钮事件 | — |
56 | | today | 今天按钮事件 | — |
57 | | selected | 选中某一天事件 | day |
58 |
--------------------------------------------------------------------------------
/examples/docs/color.md:
--------------------------------------------------------------------------------
1 | ## 色彩设计
2 |
3 |
4 |
--------------------------------------------------------------------------------
/examples/docs/config-provider.md:
--------------------------------------------------------------------------------
1 | ## ConfigProvider 全局配置
2 |
3 | ### 基础用法
4 |
5 | 可以借助全局配置组件,来进行样式覆盖
6 |
7 | ::: demo
8 |
9 | ```html
10 |
11 |
12 |
13 | 修改primary颜色
14 | 修改success颜色
15 |
16 |
17 | ```
18 |
19 | :::
20 |
21 | ### 抽象容器
22 |
23 | 可以使用抽象标签来注入,这里会默认注入到html ,进行全局覆盖(慎用)
24 |
25 | ::: demo
26 |
27 | ```html
28 |
29 |
30 |
31 | 点击应用
32 |
33 |
34 |
35 |
53 | ```
54 |
55 | :::
56 |
57 |
58 | ### Props
59 |
60 |
61 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
62 | |---------- |-------- |---------- |------------- |-------- |
63 | | abstract | 抽象的,没有实体dom,参数会注入到ducument | boolean | — | — |
64 | | tag | 渲染dom | string | — | 'div' |
65 | | locale | 语言包 | string | — | zh-CN |
66 | | themeName | 主题名称 | string | 'dark' | — |
67 | | theme | 主题样式对象,这里可以存储js变量 使用首字母小写,连字符号后字母大写,如binColorPrimary | Object | — | — |
--------------------------------------------------------------------------------
/examples/docs/directive.md:
--------------------------------------------------------------------------------
1 | ## 自定义指令
2 |
3 | ### 点击动画指令
4 |
5 | 在标签中追加`v-click-animation`指令增加点击动画指令,波纹颜色根据border或background颜色创建
6 |
7 | ::: demo
8 |
9 | ```html
10 |
11 |
12 |
13 | Default
14 | Primary
15 | Success
16 | Info
17 | Warning
18 | Danger
19 | 自定义
22 |
23 |
24 | ```
25 |
26 | :::
27 |
28 | ### 水波纹指令
29 |
30 | 在标签中追加`v-waves`指令增加水波纹指令,指令可以设置波纹颜色和点击方式, 注意,增加水波纹指令会默认覆盖原有的按钮点击效果
31 |
32 | ::: demo
33 |
34 | ```html
35 |
36 |
37 |
38 | 默认指令
39 | 设置颜色
40 |
41 |
42 | ```
43 |
44 | :::
45 |
46 | ### clickOutSide
47 |
48 | 通过添加`v-click-outside="clickOutSide"`来添加外部点击事件
49 |
50 | ::: demo
51 |
52 | ```html
53 |
54 |
55 |
61 |
62 |
71 | ```
72 |
73 | :::
74 |
--------------------------------------------------------------------------------
/examples/docs/divider.md:
--------------------------------------------------------------------------------
1 | ## Divider 分割线
2 |
3 | 区隔内容的分割线。可以对对不同文本段落进行分割。可以对行内文字/链接进行分割,例如表格的操作列。
4 |
5 | ### 水平分割线
6 |
7 | 默认为水平分割线,可在中间加入文字。 可以是虚线
8 |
9 | :::demo
10 |
11 | ```html
12 |
13 |
14 | 这是一段文字...这是一段文字...这是一段文字...这是一段文字...这是一段文字...
15 |
16 | 这是一段文字...这是一段文字...这是一段文字...这是一段文字...这是一段文字...
17 | With Text
18 | 这是一段文字...这是一段文字...这是一段文字...这是一段文字...这是一段文字...
19 |
20 | 这是一段文字...这是一段文字...这是一段文字...这是一段文字...这是一段文字...
21 |
22 | ```
23 |
24 | :::
25 |
26 | ### 垂直分割线
27 |
28 | 使用 type="vertical" 设置为行内的垂直分割线。
29 |
30 | :::demo
31 |
32 | ```html
33 |
34 |
35 | Text
36 |
37 | Link
38 |
39 | Link
40 |
41 | ```
42 |
43 | :::
44 |
45 | ### 修改标题的位置
46 |
47 | align属性可以设置标题位置 使用 align="left" 设置为行内的垂直分割线。
48 |
49 | :::demo
50 |
51 | ```html
52 |
53 |
54 | 左对齐
55 | 居中对齐
56 | 右对齐
57 |
58 | ```
59 |
60 | :::
61 |
62 | ### Props
63 |
64 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
65 | |---------- |-------- |---------- |------------- |-------- |
66 | | type | 水平还是垂直类型 | string | horizontal / vertical | horizontal |
67 | | align | 分割线标题的位置 | string | left / right / center | center |
68 | | dashed | 是否虚线 | Boolean | false / true | false |
69 |
--------------------------------------------------------------------------------
/examples/docs/empty.md:
--------------------------------------------------------------------------------
1 | ## Empty 空状态
2 |
3 | ### 基础用法
4 |
5 | 目前表格和tree型结构使用,可以自定义标签使用,也可以使用指令使用
6 |
7 | ::: demo
8 |
9 | ```html
10 |
11 |
12 |
13 | 当前无数据
14 |
15 |
16 | ```
17 |
18 | :::
19 |
20 | ### 指令方式
21 |
22 | 可以使用v-no-data指令动态指定,并可以绑定显示文字
23 |
24 | ::: demo
25 |
26 | ```html
27 |
28 |
29 |
32 |
33 |
42 | ```
43 |
44 | :::
45 |
46 | ### Props
47 |
48 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
49 | |---------- |-------- |---------- |------------- |-------- |
50 | | title | 文字提示 | string | — | 暂无数据 |
51 |
52 |
53 | ### Slots
54 |
55 | | 参数 | 说明 |
56 | |---------- |-------- |
57 | | icon | 插入的图标内容 |
58 |
59 |
60 | ### Methods
61 |
62 | | 方法名 | 说明 | 返回值 |
63 | |---------- |-------- |---------- |
64 | | setTitle | 设置文字,主要为指令提供外部操作 | Function(title) |
65 |
--------------------------------------------------------------------------------
/examples/docs/guide.md:
--------------------------------------------------------------------------------
1 | ## Bin-UI-Next
2 |
3 | bin-ui-next 是bin-ui的vue3升级版,目前组件库已经基本完成重构,整体组件依赖vue3
4 |
5 | ### 特性
6 |
7 |
8 | - 💪 基于 Vue 3.0 Composition API
9 | - 🌈 最新图标基于阿里iconfont ant-design 官方图标精简版
10 | - 🗑 移除了部分冗余代码
11 | - ⌨️ 部分组件代码进行重构
12 |
13 |
14 | ### 支持环境
15 |
16 |
17 | - 暂不支持IE所有版本
18 | - 支持服务端渲染
19 |
20 |
21 | ### 版本
22 |
23 | [](https://www.npmjs.com/package/bin-ui-next)
24 |
25 | ### 相关链接
26 |
27 | [bin-ui](https://wangbin3162.github.io/bin-ui/)
28 |
29 | ### 安装
30 |
31 | 推荐使用 `npm` 或 `yarn` 进行安装,它能更好地和 `webpack` 打包工具配合使用。而且可以更好的和 `es6` `typescript` 配合使用。并且支持按需引入
32 |
33 | ```shell
34 | npm i bin-ui-next
35 | # or
36 | yarn add bin-ui-next
37 | # or
38 | pnpm add bin-ui-next
39 | ```
40 |
41 | 如果您了解node.js、npm安装,并希望配合webpack使用,请阅读下一节:[快速上手](/#/start)。
42 |
--------------------------------------------------------------------------------
/examples/docs/icon.md:
--------------------------------------------------------------------------------
1 | ## Icon 图标
2 |
3 | 图标这里使用了阿里[iconfont](https://www.iconfont.cn/)图标库生成了图标,图标来源于开源项目 ionicons,结合整理添加了一些其他的图标。
4 |
5 | i 标签可以直接设置样式类名为 `b-iconfont b-icon-xxx` 来使用即可。icon 组件可以只设置 name 来实用。 设置 `icon-is-rotating` 可以开启旋转
6 |
7 | :::demo size 和 color 可以设置字体大小和颜色
8 |
9 | ```html
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | 图标选择器:
18 |
19 |
20 |
21 |
22 |
23 | ```
24 |
25 | :::
26 |
27 | ### 图标集合
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/examples/docs/layout.md:
--------------------------------------------------------------------------------
1 | ## Layout 基础布局
2 |
3 | ### 基础用法
4 |
5 | 目前暂时为简易左右布局,后续扩展
6 |
7 | ::: demo
8 |
9 | ```html
10 |
11 |
12 |
13 |
14 | 侧边栏
15 |
16 | 右侧容器
17 |
18 |
19 | ```
20 |
21 | :::
22 |
23 |
24 | ### Props
25 |
26 |
27 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
28 | |---------- |-------- |---------- |------------- |-------- |
29 | | hasSider | 是否又侧边栏(目前为左侧) | boolean | — | — |
30 | | siderWidth | 侧边栏宽度 | number | — | 240 |
31 | | collapsedWidth | 侧边栏折叠后宽度 | number | — | 40 |
32 | | showToggle | 是否显示折叠按钮 | boolean | — | true |
33 | | showCollapsedContent | 是否显示折叠后的内部区域 | boolean | — | false |
34 | | contentStyle | 右侧容器样式 | object | — | {} |
--------------------------------------------------------------------------------
/examples/docs/scrollbar.md:
--------------------------------------------------------------------------------
1 | ## ScrollBar 滚动
2 |
3 | 由于默认浏览器滚动条极为丑陋切不同浏览器之间样式不统一,故封装一个滚动组件用于实现滚动
4 |
5 | ### 用法
6 |
7 | 使用`b-scrollbar`进行包裹,默认`slot`为内容显示区域,如当前示例所包含的滚动结构如下:
8 | :::demo
9 |
10 | ```html
11 |
12 |
13 |
14 |
15 | 我是填充内容....
16 |
17 |
18 |
19 | ```
20 |
21 | :::
22 |
23 | 注意:如果内容区域不超过容器高度则不会生成滚动条
24 |
25 | ### 使用贴士
26 |
27 | - b-scrollbar的父层要有固定高度
28 | - b-scrollbar的高度要设成100%
29 | - 如果出现横滚动条,请添加css(.bin-scrollbar__wrap{overflow-x:hidden;})
30 |
31 | ### Props
32 |
33 | | 参数 | 说明 | 类型 | 可选值 | 默认值 |
34 | |---------- |-------- |---------- |------------- |-------- |
35 | | native | 是否采用原生滚动 (隐藏原生滚动条) | boolean | true | false |
36 | | always | 是否一直显示,而非悬停显示 | boolean | true | false |
37 | | wrapStyle | 内联方式 自定义wrap容器的样式 | Object | - | {} |
38 | | wrapClass | 类名方式 自定义wrap容器的样式 | Object | - | {} |
39 | | viewClass | 类名方式 自定义view容器的样式 | Object | - | {} |
40 | | viewStyle | 内联方式 自定义view容器的样式 | Object | - | {} |
41 | | barStyle | 滚动条thumb样式 | Object | - | {} |
42 | | barWrapStyle | 滚动条bar样式 | Object | - | {} |
43 | | noresize | 如果 container 尺寸不会发生变化,最好设置它可以优化性能 | boolean | true | false |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/examples/docs/start.md:
--------------------------------------------------------------------------------
1 | ## 快速上手
2 |
3 | 本章节介绍如何在项目中使用vue3版本的bin-ui-next
4 |
5 | ### 引入
6 |
7 | 你可以引入整个 bin-ui-next,或是根据需要仅引入部分组件。我们先介绍如何引入完整的 bin-ui。
8 |
9 | #### 完整引入
10 |
11 | 在 main.js 中写入以下内容:
12 |
13 | ```javascript
14 | import { createApp } from 'vue'
15 | import BinUI from 'bin-ui-next'
16 | import App from './App.vue'
17 | import 'bin-ui-next/lib/styles/index.css'
18 |
19 | const app = createApp(App)
20 | app.use(BinUI)
21 | // app.use(BinUI,{disabledDoc:true}) // 可以设置禁用doc地址log
22 | app.mount('#app')
23 | ```
24 |
25 | 以上代码便完成了 bin-ui-next 的引入。需要注意的是,样式文件需要单独引入。
26 |
27 | #### 按需引入
28 |
29 | 借助插件 [babel-plugin-import](https://github.com/ant-design/babel-plugin-import)我们可以只引入需要的组件,以达到减小项目体积的目的
30 |
31 | ```shell script
32 | npm install babel-plugin-import --save-dev
33 | ```
34 |
35 | 然后,将 .babelrc 或 babel.config.js修改为:
36 |
37 | ```javascript
38 | module.exports = {
39 | presets: [
40 | ['@vue/app', {
41 | useBuiltIns: 'entry'
42 | }]
43 | ],
44 | plugins: [
45 | ["import", {
46 | "libraryName": "bin-ui-next",
47 | "libraryDirectory": "src/components"
48 | }]
49 | ]
50 | }
51 | ```
52 |
53 | 如果你只希望引入部分组件,比如 Button 和 Icon,那么需要在 main.js 中写入以下内容
54 |
55 | ```javascript
56 | import { createApp } from 'vue'
57 | import { BButton } from 'bin-ui-next'
58 | import App from './App.vue'
59 | import 'bin-ui-next/lib/styles/components/button.css'
60 |
61 | const app = createApp(App)
62 | app.use(BButton)
63 | app.mount('#app')
64 | ```
65 |
66 | **特别提醒:按需引用仍然需要导入样式,即在 main.js 或根组件 import 'bin-ui-next/lib/styles/index.css';**
67 |
68 | 完整组件列表参考源代码
69 |
--------------------------------------------------------------------------------
/examples/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/examples/favicon.ico
--------------------------------------------------------------------------------
/examples/generateTreeData.js:
--------------------------------------------------------------------------------
1 | let maxNode = 10000 // 最大的节点数
2 | const childNodesNumber = [2, 5] // 子节点数
3 | const maxLevel = 3 // 最大嵌套层级
4 | const childRate = 0.4 // 拥有子节点的概率
5 | const label = '节点' // 节点label
6 |
7 | let index = 0
8 | const data = []
9 |
10 | const randomInteger = function (min, max) {
11 | let result = min - 0.5 + Math.random() * (max - min + 1)
12 | result = Math.round(result)
13 | return result
14 | }
15 |
16 | const generateId = function () {
17 | ++index
18 | return Math.random().toString().slice(3) * 1
19 | }
20 | const generateNode = function () {
21 | const id = generateId()
22 | return {
23 | id: id,
24 | title: `${label}_${index}-id:${id}`
25 | }
26 | }
27 | const generateChild = function (tree, level = 1) {
28 | if (index > maxNode - 1) return
29 | tree.children = []
30 | const childNumber = randomInteger(childNodesNumber[0], childNodesNumber[1])
31 | for (let i = 0; i < childNumber; i++) {
32 | if (index > maxNode - 1) break
33 | const obj = generateNode()
34 |
35 | if (Math.random() < childRate && level < maxLevel) {
36 | generateChild(obj, ++level)
37 | }
38 | tree.children.push(obj)
39 | }
40 | }
41 |
42 | const generate = function (number) {
43 | // eslint-disable-next-line no-const-assign
44 | maxNode = number
45 | // eslint-disable-next-line no-unmodified-loop-condition
46 | while (index < maxNode) {
47 | let obj = generateNode()
48 | generateChild(obj)
49 | data.push(obj)
50 | }
51 | return data
52 | }
53 | export default generate
54 |
--------------------------------------------------------------------------------
/examples/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import router from './route'
3 | import App from './App.vue'
4 |
5 | import DemoBlock from './components/demo-block.vue'
6 | import MainFooter from './components/footer.vue'
7 | import MainHeader from './components/header.vue'
8 | import SideNav from './components/side-nav.vue'
9 | import ColorBase from './components/color-base.vue'
10 | import IconPane from './components/icon-pane.vue'
11 | import DraggableDemo from './components/draggable-demo'
12 |
13 | import BinUI from 'bin-ui-next'
14 | import * as BinUINext from 'bin-ui-next'
15 | import '../src/styles/normalize.styl'
16 | import '../src/styles/scrollbar.styl'
17 | import '../src/styles/index.styl'
18 | import './assets/styles/index.styl'
19 |
20 | import generate from './generateTreeData'
21 |
22 | const app = createApp(App)
23 | app.use(BinUI) // , { disabledDoc: true }
24 | app.config.productionTip = false
25 | app.config.globalProperties.$generateTree = generate // Icon 列表页用
26 |
27 | app.config.globalProperties.BinUINext = BinUINext // Icon 列表页用
28 |
29 | app.component('DemoBlock', DemoBlock)
30 | app.component('MainHeader', MainHeader)
31 | app.component('MainFooter', MainFooter)
32 | app.component('SideNav', SideNav)
33 | app.component('ColorBase', ColorBase)
34 | app.component('DraggableDemo', DraggableDemo)
35 | app.component('IconPane', IconPane)
36 | app.use(router)
37 | // Mount when the route is ready
38 | router.isReady().then(() => {
39 | app.mount('#app', true)
40 | })
41 |
--------------------------------------------------------------------------------
/examples/route.js:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHashHistory } from 'vue-router'
2 | import { nextTick } from 'vue'
3 | import { LoadingBar } from '../src'
4 | import hljs from 'highlight.js'
5 |
6 | const navConfig = require('./nav.config.json')
7 |
8 | let routes = [
9 | {
10 | path: '',
11 | redirect: 'guide',
12 | name: 'index',
13 | },
14 | ]
15 |
16 | Object.keys(navConfig).forEach((header) => {
17 | routes = routes.concat(navConfig[header])
18 | })
19 |
20 | const addComponent = router => {
21 | router.forEach((route) => {
22 | if (route.items) {
23 | addComponent(route.items)
24 | routes = routes.concat(route.items)
25 | } else {
26 | if (!route.name) return
27 | route.meta = { desc: route.desc }
28 | route.component = () => import(/* webpackChunkName: "DOCS" */ `./docs/${route.name}.md`)
29 | }
30 | })
31 | }
32 | addComponent(routes)
33 |
34 | const router = createRouter({
35 | history: createWebHashHistory(),
36 | routes,
37 | })
38 | router.beforeEach((to, from, next) => {
39 | LoadingBar.start()
40 | next()
41 | })
42 | router.afterEach(async () => {
43 | await nextTick()
44 | const blocks = document.querySelectorAll('pre code:not(.hljs)')
45 | Array.prototype.forEach.call(blocks, hljs.highlightElement)
46 | LoadingBar.done()
47 | })
48 |
49 | export default router
50 |
--------------------------------------------------------------------------------
/examples/util.js:
--------------------------------------------------------------------------------
1 | export function stripScript(content) {
2 | const result = content.match(/<(script)>([\s\S]+)<\/\1>/)
3 | return result && result[2] ? result[2].trim() : ''
4 | }
5 |
6 | export function stripStyle(content) {
7 | const result = content.match(/<(style)\s*>([\s\S]+)<\/\1>/)
8 | return result && result[2] ? result[2].trim() : ''
9 | }
10 |
11 | export function stripTemplate(content) {
12 | content = content.trim()
13 | if (!content) {
14 | return content
15 | }
16 | return content.replace(/<(script|style)[\s\S]+<\/\1>/g, '').trim()
17 | }
18 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "vueCompilerOptions": {
3 | "experimentalDisableTemplateSupport": true,
4 | "experimentalShamefullySupportOptionsApi": false
5 | },
6 | "compilerOptions": {
7 | "baseUrl": ".",
8 | "paths": {
9 | "@/*": ["./src/*"]
10 | }
11 | },
12 | "include": ["src/**/*.js", "src/**/*.vue"],
13 | "exclude": ["node_modules"]
14 | }
15 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | require('autoprefixer')({
4 | browsers: [
5 | 'defaults',
6 | 'not ie < 11',
7 | 'last 2 versions',
8 | '> 1%',
9 | 'iOS 7',
10 | 'last 3 iOS versions',
11 | ],
12 | }),
13 | ],
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/affix/index.js:
--------------------------------------------------------------------------------
1 | import Affix from './affix.vue'
2 |
3 | Affix.install = app => {
4 | app.component(Affix.name, Affix)
5 | }
6 |
7 | export default Affix
8 |
--------------------------------------------------------------------------------
/src/components/alert/alert.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
17 |
18 |
19 |
20 |
76 |
--------------------------------------------------------------------------------
/src/components/alert/index.js:
--------------------------------------------------------------------------------
1 | import Alert from './alert.vue'
2 |
3 | Alert.install = (app) => {
4 | app.component(Alert.name, Alert)
5 | }
6 |
7 | export default Alert
8 |
--------------------------------------------------------------------------------
/src/components/anchor-link/index.js:
--------------------------------------------------------------------------------
1 | import AnchorLink from '../anchor/anchor-link.vue'
2 |
3 | AnchorLink.install = (app) => {
4 | app.component(AnchorLink.name, AnchorLink)
5 | }
6 |
7 | export default AnchorLink
8 |
--------------------------------------------------------------------------------
/src/components/anchor/anchor-link.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
59 |
--------------------------------------------------------------------------------
/src/components/anchor/index.js:
--------------------------------------------------------------------------------
1 | import Anchor from './anchor.vue'
2 |
3 | Anchor.install = (app) => {
4 | app.component(Anchor.name, Anchor)
5 | }
6 |
7 | export default Anchor
8 |
--------------------------------------------------------------------------------
/src/components/back-top/index.js:
--------------------------------------------------------------------------------
1 | import BackTop from './back-top.vue'
2 |
3 | BackTop.install = (app) => {
4 | app.component(BackTop.name, BackTop)
5 | }
6 |
7 | export default BackTop
8 |
--------------------------------------------------------------------------------
/src/components/badge/badge.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
17 |
18 |
19 |
20 |
21 |
49 |
--------------------------------------------------------------------------------
/src/components/badge/index.js:
--------------------------------------------------------------------------------
1 | import Badge from './badge.vue'
2 |
3 | Badge.install = (app) => {
4 | app.component(Badge.name, Badge)
5 | }
6 |
7 | export default Badge
8 |
--------------------------------------------------------------------------------
/src/components/breadcrumb-item/index.js:
--------------------------------------------------------------------------------
1 | import BreadcrumbItem from '../breadcrumb/breadcrumb-item.vue'
2 |
3 | BreadcrumbItem.install = (app) => {
4 | app.component(BreadcrumbItem.name, BreadcrumbItem)
5 | }
6 |
7 | export default BreadcrumbItem
8 |
--------------------------------------------------------------------------------
/src/components/breadcrumb/breadcrumb-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 | {{ separator }}
12 |
13 |
14 |
15 |
34 |
--------------------------------------------------------------------------------
/src/components/breadcrumb/breadcrumb.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
35 |
--------------------------------------------------------------------------------
/src/components/breadcrumb/index.js:
--------------------------------------------------------------------------------
1 | import Breadcrumb from './breadcrumb.vue'
2 |
3 | Breadcrumb.install = (app) => {
4 | app.component(Breadcrumb.name, Breadcrumb)
5 | }
6 |
7 | export default Breadcrumb
8 |
--------------------------------------------------------------------------------
/src/components/button-group/index.js:
--------------------------------------------------------------------------------
1 | import ButtonGroup from '../button/button-group.vue'
2 |
3 | ButtonGroup.install = (app) => {
4 | app.component(ButtonGroup.name, ButtonGroup)
5 | }
6 | export default ButtonGroup
7 |
--------------------------------------------------------------------------------
/src/components/button/button-group.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 |
--------------------------------------------------------------------------------
/src/components/button/index.js:
--------------------------------------------------------------------------------
1 | import Button from './button.vue'
2 |
3 | Button.install = (app) => {
4 | app.component(Button.name, Button)
5 | }
6 |
7 | export default Button
8 |
--------------------------------------------------------------------------------
/src/components/calendar/index.js:
--------------------------------------------------------------------------------
1 | import Calendar from './calendar.vue'
2 |
3 | Calendar.install = (app) => {
4 | app.component(Calendar.name, Calendar)
5 | }
6 |
7 | export default Calendar
8 |
--------------------------------------------------------------------------------
/src/components/card/card.vue:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
23 |
51 |
--------------------------------------------------------------------------------
/src/components/card/index.js:
--------------------------------------------------------------------------------
1 | import Card from './card.vue'
2 |
3 | Card.install = (app) => {
4 | app.component(Card.name, Card)
5 | }
6 |
7 | export default Card
8 |
--------------------------------------------------------------------------------
/src/components/carousel-item/index.js:
--------------------------------------------------------------------------------
1 | import CarouselItem from '../carousel/carousel-item.vue'
2 |
3 | CarouselItem.install = (app) => {
4 | app.component(CarouselItem.name, CarouselItem)
5 | }
6 |
7 | export default CarouselItem
8 |
--------------------------------------------------------------------------------
/src/components/carousel/index.js:
--------------------------------------------------------------------------------
1 | import Carousel from './carousel.vue'
2 |
3 | Carousel.install = (app) => {
4 | app.component(Carousel.name, Carousel)
5 | }
6 |
7 | export default Carousel
8 |
--------------------------------------------------------------------------------
/src/components/cascader-panel/index.js:
--------------------------------------------------------------------------------
1 | import CascaderPanel from './src/index.vue'
2 |
3 | CascaderPanel.install = (app) => {
4 | app.component(CascaderPanel.name, CascaderPanel)
5 | }
6 |
7 | export default CascaderPanel
8 |
--------------------------------------------------------------------------------
/src/components/cascader-panel/utils/config.js:
--------------------------------------------------------------------------------
1 | import { computed } from 'vue'
2 | import { NOOP } from '@vue/shared'
3 |
4 | export const DefaultProps = {
5 | expandTrigger: 'click',
6 | multiple: false,
7 | checkStrictly: false, // whether all nodes can be selected
8 | emitPath: true, // wether to emit an array of all levels value in which node is located
9 | lazy: false,
10 | lazyLoad: NOOP,
11 | value: 'value',
12 | label: 'label',
13 | children: 'children',
14 | leaf: 'leaf',
15 | disabled: 'disabled',
16 | hoverThreshold: 500,
17 | }
18 |
19 | export const useCascaderConfig = (props) => {
20 | return computed(() => ({
21 | ...DefaultProps,
22 | ...props.props,
23 | }))
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/cascader-panel/utils/store.js:
--------------------------------------------------------------------------------
1 | import Node from './node'
2 | import { isEqual } from '../../../utils/util'
3 |
4 | const flatNodes = (nodes, leafOnly) => {
5 | return nodes.reduce((res, node) => {
6 | if (node.isLeaf) {
7 | res.push(node)
8 | } else {
9 | !leafOnly && res.push(node)
10 | res = res.concat(flatNodes(node.children, leafOnly))
11 | }
12 | return res
13 | }, [])
14 | }
15 |
16 | export default class Store {
17 | constructor(data, config) {
18 | this.config = config
19 | const nodes = (data || []).map(nodeData => new Node(nodeData, this.config))
20 | this.nodes = nodes
21 | this.allNodes = flatNodes(nodes, false)
22 | this.leafNodes = flatNodes(nodes, true)
23 | }
24 |
25 | getNodes() {
26 | return this.nodes
27 | }
28 |
29 | getFlattedNodes(leafOnly) {
30 | return leafOnly ? this.leafNodes : this.allNodes
31 | }
32 |
33 | appendNode(nodeData, parentNode) {
34 | const node = parentNode
35 | ? parentNode.appendChild(nodeData)
36 | : new Node(nodeData, this.config)
37 |
38 | if (!parentNode) this.nodes.push(node)
39 |
40 | this.allNodes.push(node)
41 | node.isLeaf && this.leafNodes.push(node)
42 | }
43 |
44 | appendNodes(nodeDataList, parentNode) {
45 | nodeDataList.forEach(nodeData => this.appendNode(nodeData, parentNode))
46 | }
47 |
48 | // when checkStrictly, leaf node first
49 | getNodeByValue(value, leafOnly = false) {
50 | if (!value && value !== 0) return null
51 |
52 | const nodes = this.getFlattedNodes(leafOnly)
53 | .filter(node => isEqual(node.value, value) || isEqual(node.pathValues, value))
54 |
55 | return nodes[0] || null
56 | }
57 |
58 | getSameNode(node) {
59 | if (!node) return null
60 |
61 | const nodes = this.getFlattedNodes(false)
62 | .filter(({ value, level }) => isEqual(node.value, value) && node.level === level)
63 |
64 | return nodes[0] || null
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/components/cascader-panel/utils/utils.js:
--------------------------------------------------------------------------------
1 | export const isLeaf = (el) => !el.getAttribute('aria-owns')
2 |
3 | export const getSibling = (el, distance) => {
4 | const { parentNode } = el
5 |
6 | if (!parentNode) return null
7 |
8 | const siblings = parentNode.querySelectorAll('.bin-cascader-node[tabindex="-1"]')
9 | const index = Array.prototype.indexOf.call(siblings, el)
10 | return siblings[index + distance] || null
11 | }
12 |
13 | export const getMenuIndex = (el) => {
14 | if (!el) return 0
15 | const pieces = el.id.split('-')
16 | return Number(pieces[pieces.length - 2])
17 | }
18 |
19 | export const focusNode = el => {
20 | if (!el) return
21 | el.focus()
22 | !isLeaf(el) && el.click()
23 | }
24 |
25 | export const checkNode = el => {
26 | if (!el) return
27 |
28 | const input = el.querySelector('input')
29 | if (input) {
30 | input.click()
31 | } else if (isLeaf(el)) {
32 | el.click()
33 | }
34 | }
35 |
36 | export const sortByOriginalOrder = (oldNodes, newNodes) => {
37 | const newNodesCopy = newNodes.slice(0)
38 | const newIds = newNodesCopy.map(node => node.uid)
39 | const res = oldNodes.reduce((acc, item) => {
40 | const index = newIds.indexOf(item.uid)
41 | if (index > -1) {
42 | acc.push(item)
43 | newNodesCopy.splice(index, 1)
44 | newIds.splice(index, 1)
45 | }
46 | return acc
47 | }, [])
48 |
49 | res.push(...newNodesCopy)
50 |
51 | return res
52 | }
53 |
54 | export const PANEL_INJECTION_KEY = Symbol()
55 |
--------------------------------------------------------------------------------
/src/components/cascader/index.js:
--------------------------------------------------------------------------------
1 | import Cascader from './cascader.vue'
2 |
3 | Cascader.install = (app) => {
4 | app.component(Cascader.name, Cascader)
5 | }
6 |
7 | export default Cascader
8 |
--------------------------------------------------------------------------------
/src/components/checkbox-group/index.js:
--------------------------------------------------------------------------------
1 | import CheckboxGroup from '../checkbox/checkbox-group.vue'
2 |
3 | CheckboxGroup.install = (app) => {
4 | app.component(CheckboxGroup.name, CheckboxGroup)
5 | }
6 |
7 | export default CheckboxGroup
8 |
--------------------------------------------------------------------------------
/src/components/checkbox/checkbox-group.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
65 |
--------------------------------------------------------------------------------
/src/components/checkbox/index.js:
--------------------------------------------------------------------------------
1 | import Checkbox from './checkbox.vue'
2 |
3 | Checkbox.install = (app) => {
4 | app.component(Checkbox.name, Checkbox)
5 | }
6 |
7 | export default Checkbox
8 |
--------------------------------------------------------------------------------
/src/components/circle/index.js:
--------------------------------------------------------------------------------
1 | import Circle from './circle.vue'
2 |
3 | Circle.install = (app) => {
4 | app.component(Circle.name, Circle)
5 | }
6 |
7 | export default Circle
8 |
--------------------------------------------------------------------------------
/src/components/col/index.js:
--------------------------------------------------------------------------------
1 | import Col from './col.vue'
2 |
3 | Col.install = (app) => {
4 | app.component(Col.name, Col)
5 | }
6 |
7 | export default Col
8 |
--------------------------------------------------------------------------------
/src/components/collapse-panel/index.js:
--------------------------------------------------------------------------------
1 | import CollapsePanel from '../collapse/panel.vue'
2 |
3 | CollapsePanel.install = (app) => {
4 | app.component(CollapsePanel.name, CollapsePanel)
5 | }
6 |
7 | export default CollapsePanel
8 |
--------------------------------------------------------------------------------
/src/components/collapse-transition/index.js:
--------------------------------------------------------------------------------
1 | import CollapseTransition from './collapse-transition.vue'
2 |
3 | CollapseTransition.install = (app) => {
4 | app.component(CollapseTransition.name, CollapseTransition)
5 | }
6 |
7 | export default CollapseTransition
8 |
--------------------------------------------------------------------------------
/src/components/collapse-wrap/index.js:
--------------------------------------------------------------------------------
1 | import CollapseWrapper from './wrapper.vue'
2 |
3 | CollapseWrapper.install = (app) => {
4 | app.component(CollapseWrapper.name, CollapseWrapper)
5 | }
6 |
7 | export default CollapseWrapper
8 |
--------------------------------------------------------------------------------
/src/components/collapse/index.js:
--------------------------------------------------------------------------------
1 | import Collapse from './collapse.vue'
2 |
3 | Collapse.install = (app) => {
4 | app.component(Collapse.name, Collapse)
5 | }
6 |
7 | export default Collapse
8 |
--------------------------------------------------------------------------------
/src/components/collapse/panel.vue:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
68 |
--------------------------------------------------------------------------------
/src/components/color-picker/draggable.js:
--------------------------------------------------------------------------------
1 | import isServer from '../../utils/isServer'
2 | import { on, off } from '../../utils/dom'
3 |
4 | let isDragging = false
5 |
6 | export default function(element, options) {
7 | if (isServer) return
8 |
9 | const moveFn = function(event) {
10 | options.drag?.(event)
11 | }
12 | const upFn = function(event) {
13 | off(document, 'mousemove', moveFn)
14 | off(document, 'mouseup', upFn)
15 | document.onselectstart = null
16 | document.ondragstart = null
17 |
18 | isDragging = false
19 |
20 | options.end?.(event)
21 | }
22 |
23 | on(element, 'mousedown', function(event) {
24 | if (isDragging) return
25 | document.onselectstart = () => false
26 | document.ondragstart = () => false
27 | on(document, 'mousemove', moveFn)
28 | on(document, 'mouseup', upFn)
29 |
30 | isDragging = true
31 |
32 | options.start?.(event)
33 | })
34 | }
35 |
--------------------------------------------------------------------------------
/src/components/color-picker/index.js:
--------------------------------------------------------------------------------
1 | import ColorPicker from './picker.vue'
2 |
3 | ColorPicker.install = (app) => {
4 | app.component(ColorPicker.name, ColorPicker)
5 | }
6 |
7 | export default ColorPicker
8 |
--------------------------------------------------------------------------------
/src/components/color-picker/predefine.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
72 |
--------------------------------------------------------------------------------
/src/components/config-provider/index.js:
--------------------------------------------------------------------------------
1 | import ConfigProvider from './src/ConfigProvider'
2 |
3 | ConfigProvider.install = app => {
4 | app.component(ConfigProvider.name, ConfigProvider)
5 | }
6 |
7 | export default ConfigProvider
8 |
--------------------------------------------------------------------------------
/src/components/config-provider/src/context.js:
--------------------------------------------------------------------------------
1 | export const configProviderInjectionKey = Symbol('b-config-provider')
2 |
--------------------------------------------------------------------------------
/src/components/config-provider/src/types.js:
--------------------------------------------------------------------------------
1 | // 配置注入器的props
2 | export const configProviderProps = {
3 | // 是否是抽象的
4 | abstract: {
5 | type: Boolean,
6 | },
7 | tag: {
8 | type: String,
9 | default: 'div',
10 | },
11 | // 是否禁用 inline css 主题变量 如果不需要更改主题变量theme
12 | inlineThemeDisabled: {
13 | type: Boolean,
14 | },
15 | // 语言包
16 | locale: {
17 | type: String,
18 | default: 'zh-CN',
19 | },
20 | // 主题名称
21 | themeName: {
22 | type: String,
23 | validate: val => ['dark'].includes(val),
24 | },
25 | // 主题样式对象,这里可以存储js变量
26 | theme: {
27 | type: Object,
28 | },
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/count-to/index.js:
--------------------------------------------------------------------------------
1 | import CountTo from './count-to'
2 |
3 | CountTo.install = app => {
4 | app.component(CountTo.name, CountTo)
5 | }
6 |
7 | export default CountTo
8 |
--------------------------------------------------------------------------------
/src/components/date-picker/index.js:
--------------------------------------------------------------------------------
1 | import DatePicker from './date-picker'
2 |
3 | DatePicker.install = app => {
4 | app.component(DatePicker.name, DatePicker)
5 | }
6 |
7 | export default DatePicker
8 |
--------------------------------------------------------------------------------
/src/components/desc-item/index.js:
--------------------------------------------------------------------------------
1 | import DescItem from './item'
2 |
3 | DescItem.install = (app) => {
4 | app.component(DescItem.name, DescItem)
5 | }
6 | export default DescItem
7 |
--------------------------------------------------------------------------------
/src/components/desc-item/item.vue:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/components/desc/descriptions-cell.js:
--------------------------------------------------------------------------------
1 | import { computed, h, inject } from 'vue'
2 |
3 | export default {
4 | name: 'BDescCell',
5 | props: {
6 | cell: {
7 | type: Object,
8 | },
9 | tag: {
10 | type: String,
11 | },
12 | type: {
13 | type: String,
14 | },
15 | },
16 | setup(props) {
17 | const descriptions = inject('BDesc', {})
18 |
19 | const label = computed(() => props.cell?.children?.label?.() || props.cell?.props?.label)
20 | const content = computed(() => props.cell?.children?.default?.())
21 | const span = computed(() => props.cell?.props?.span || 1)
22 | const labelWidth = computed(() => descriptions.labelWidth || (50 / descriptions.column))
23 | const contentWidth = computed(() => {
24 | const labelWidth = descriptions.labelWidth
25 | const column = descriptions.column
26 | return labelWidth ? ((100 - column * labelWidth) / column) : (50 / column)
27 | })
28 |
29 | return {
30 | descriptions,
31 | label,
32 | content,
33 | span,
34 | labelWidth,
35 | contentWidth,
36 | }
37 | },
38 | render() {
39 | switch (this.type) {
40 | case 'label':
41 | return h(this.tag, {
42 | class: ['bin-desc__label', { 'is-bordered-label': this.descriptions.border }],
43 | style: { width: `${this.labelWidth}%` },
44 | colSpan: 1,
45 | }, this.label)
46 | case 'content':
47 | return h(this.tag, {
48 | class: 'bin-desc__content',
49 | style: { width: `${this.span * this.contentWidth}%` },
50 | colSpan: this.span * 2 - 1,
51 | }, this.content)
52 | default:
53 | return h('td', {
54 | colSpan: this.span,
55 | style: { width: `${this.span * ((100 / this.descriptions.column))}%` },
56 | }, [
57 | h('span', { class: 'bin-desc__label' }, this.label),
58 | h('span', { class: 'bin-desc__content' }, this.content)])
59 | }
60 | },
61 | }
62 |
--------------------------------------------------------------------------------
/src/components/desc/descriptions-row.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
34 |
--------------------------------------------------------------------------------
/src/components/desc/index.js:
--------------------------------------------------------------------------------
1 | import Desc from './desc.vue'
2 |
3 | Desc.install = (app) => {
4 | app.component(Desc.name, Desc)
5 | }
6 |
7 | export default Desc
8 |
--------------------------------------------------------------------------------
/src/components/divider/divider.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
42 |
--------------------------------------------------------------------------------
/src/components/divider/index.js:
--------------------------------------------------------------------------------
1 | import Divider from './divider.vue'
2 |
3 | Divider.install = (app) => {
4 | app.component(Divider.name, Divider)
5 | }
6 |
7 | export default Divider
8 |
--------------------------------------------------------------------------------
/src/components/drawer/index.js:
--------------------------------------------------------------------------------
1 | import Drawer from './drawer.vue'
2 |
3 | Drawer.install = (app) => {
4 | app.component(Drawer.name, Drawer)
5 | }
6 |
7 | export default Drawer
8 |
--------------------------------------------------------------------------------
/src/components/dropdown-item/index.js:
--------------------------------------------------------------------------------
1 | import DropdownItem from '../dropdown/dropdown-item.vue'
2 |
3 | DropdownItem.install = (app) => {
4 | app.component(DropdownItem.name, DropdownItem)
5 | }
6 |
7 | export default DropdownItem
8 |
--------------------------------------------------------------------------------
/src/components/dropdown-menu/index.js:
--------------------------------------------------------------------------------
1 | import DropdownMenu from '../dropdown/dropdown-menu.vue'
2 |
3 | DropdownMenu.install = (app) => {
4 | app.component(DropdownMenu.name, DropdownMenu)
5 | }
6 |
7 | export default DropdownMenu
8 |
--------------------------------------------------------------------------------
/src/components/dropdown/dropdown-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
16 |
17 |
51 |
--------------------------------------------------------------------------------
/src/components/dropdown/dropdown-menu.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
49 |
50 |
--------------------------------------------------------------------------------
/src/components/dropdown/index.js:
--------------------------------------------------------------------------------
1 | import Dropdown from './dropdown.vue'
2 |
3 | Dropdown.install = (app) => {
4 | app.component(Dropdown.name, Dropdown)
5 | }
6 |
7 | export default Dropdown
8 |
--------------------------------------------------------------------------------
/src/components/empty/empty.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
18 |
19 |
20 |
21 | {{ text }}
22 |
23 |
24 |
25 |
26 |
47 |
--------------------------------------------------------------------------------
/src/components/empty/index.js:
--------------------------------------------------------------------------------
1 | import Empty from './empty.vue'
2 |
3 | Empty.install = (app) => {
4 | app.component(Empty.name, Empty)
5 | }
6 |
7 | export default Empty
8 |
--------------------------------------------------------------------------------
/src/components/form-item/index.js:
--------------------------------------------------------------------------------
1 | import FormItem from '../form/form-item.vue'
2 |
3 | FormItem.install = (app) => {
4 | app.component(FormItem.name, FormItem)
5 | }
6 |
7 | export default FormItem
8 |
--------------------------------------------------------------------------------
/src/components/form/index.js:
--------------------------------------------------------------------------------
1 | import Form from './form.vue'
2 |
3 | Form.install = (app) => {
4 | app.component(Form.name, Form)
5 | }
6 |
7 | export default Form
8 |
9 | export * from './token'
10 |
--------------------------------------------------------------------------------
/src/components/form/token.js:
--------------------------------------------------------------------------------
1 | export const FormKey = 'BForm'
2 |
3 | export const FormItemKey = 'BFormItem'
4 |
5 | export const FormEvents = {
6 | addField: 'form.addField',
7 | removeField: 'form.removeField',
8 | blur: 'form.blur',
9 | change: 'form.change',
10 | }
11 |
--------------------------------------------------------------------------------
/src/components/icon-select/index.js:
--------------------------------------------------------------------------------
1 | import IconSelect from './icon-select'
2 |
3 | IconSelect.install = (app) => {
4 | app.component(IconSelect.name, IconSelect)
5 | }
6 |
7 | export default IconSelect
8 |
--------------------------------------------------------------------------------
/src/components/icon/icon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
42 |
--------------------------------------------------------------------------------
/src/components/icon/index.js:
--------------------------------------------------------------------------------
1 | import Icon from './icon.vue'
2 |
3 | Icon.install = (app) => {
4 | app.component(Icon.name, Icon)
5 | }
6 |
7 | export default Icon
8 |
--------------------------------------------------------------------------------
/src/components/input-number/index.js:
--------------------------------------------------------------------------------
1 | import InputNumber from './input-number.vue'
2 |
3 | InputNumber.install = (app) => {
4 | app.component(InputNumber.name, InputNumber)
5 | }
6 |
7 | export default InputNumber
8 |
--------------------------------------------------------------------------------
/src/components/input/index.js:
--------------------------------------------------------------------------------
1 | import Input from './input.vue'
2 |
3 | Input.install = (app) => {
4 | app.component(Input.name, Input)
5 | }
6 |
7 | export default Input
8 |
--------------------------------------------------------------------------------
/src/components/layout/Layout.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | hasSider
6 |
7 |
13 |
14 |
15 |
16 |
content
17 |
18 |
19 |
20 |
66 |
--------------------------------------------------------------------------------
/src/components/layout/index.js:
--------------------------------------------------------------------------------
1 | import Layout from './Layout.vue'
2 |
3 | Layout.install = app => {
4 | app.component(Layout.name, Layout)
5 | }
6 |
7 | export default Layout
8 |
--------------------------------------------------------------------------------
/src/components/loading-bar/instance.js:
--------------------------------------------------------------------------------
1 | import LoadingBar from './loading-bar.vue'
2 | import { createApp } from 'vue'
3 |
4 | export default function getInstance(properties) {
5 | const _props = properties || {}
6 | const app = createApp(LoadingBar, _props)
7 | const loadingBar = app.mount(document.createElement('div'))
8 | document.body.appendChild(loadingBar.$el)
9 | return {
10 | update(options) {
11 | if ('percent' in options) {
12 | loadingBar.percent = options.percent
13 | }
14 | if (options.status) {
15 | loadingBar.status = options.status
16 | }
17 | if ('show' in options) {
18 | loadingBar.show = options.show
19 | }
20 | if ('icon' in options) {
21 | loadingBar.icon = options.icon
22 | }
23 | },
24 | component: loadingBar,
25 | destroy() {
26 | document.body.removeChild(document.getElementsByClassName('bin-loading-bar')[0])
27 | },
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/loading/index.js:
--------------------------------------------------------------------------------
1 | import Loading from './loading.vue'
2 |
3 | Loading.install = (app) => {
4 | app.component(Loading.name, Loading)
5 | }
6 |
7 | export default Loading
8 |
--------------------------------------------------------------------------------
/src/components/loading/loading.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
14 | {{ text }}
15 |
16 |
17 |
18 |
19 |
20 |
21 |
62 |
--------------------------------------------------------------------------------
/src/components/menu-item-group/index.js:
--------------------------------------------------------------------------------
1 | import MenuItemGroup from '../menu/menu-item-group.vue'
2 |
3 | MenuItemGroup.install = (app) => {
4 | app.component(MenuItemGroup.name, MenuItemGroup)
5 | }
6 |
7 | export default MenuItemGroup
8 |
9 |
--------------------------------------------------------------------------------
/src/components/menu-item/index.js:
--------------------------------------------------------------------------------
1 | import MenuItem from '../menu/menu-item.vue'
2 |
3 | MenuItem.install = (app) => {
4 | app.component(MenuItem.name, MenuItem)
5 | }
6 |
7 | export default MenuItem
8 |
9 |
--------------------------------------------------------------------------------
/src/components/menu/index.js:
--------------------------------------------------------------------------------
1 | import Menu from './menu.vue'
2 |
3 | Menu.install = (app) => {
4 | app.component(Menu.name, Menu)
5 | }
6 |
7 | export default Menu
8 |
9 |
--------------------------------------------------------------------------------
/src/components/menu/menu-item-group.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
63 |
--------------------------------------------------------------------------------
/src/components/menu/useMenu.js:
--------------------------------------------------------------------------------
1 | import { computed, inject } from 'vue'
2 |
3 | export default function useMenu(instance, currentIndex) {
4 | const rootMenu = inject('rootMenu')
5 |
6 | const indexPath = computed(() => {
7 | let parent = instance.parent
8 | const path = [currentIndex]
9 | while (parent.type.name !== 'BMenu') {
10 | if (parent.props.index) {
11 | path.unshift(parent.props.index)
12 | }
13 | parent = parent.parent
14 | }
15 | return path
16 | })
17 |
18 | const parentMenu = computed(() => {
19 | let parent = instance.parent
20 | while (parent && ['BMenu', 'BSubmenu'].indexOf(parent.type.name) === -1) {
21 | parent = parent.parent
22 | }
23 | return parent
24 | })
25 | const paddingStyle = computed(() => {
26 | let parent = instance.parent
27 | if (rootMenu.props.mode !== 'vertical') return {}
28 |
29 | let padding = 20
30 |
31 | if (rootMenu.props.collapse) {
32 | padding = 20
33 | } else {
34 | while (parent && parent.type.name !== 'BMenu') {
35 | if (parent.type.name === 'BSubmenu') {
36 | padding += 20
37 | }
38 | parent = parent.parent
39 | }
40 | }
41 | return { paddingLeft: padding + 'px' }
42 | })
43 | return { parentMenu, paddingStyle, indexPath }
44 | }
45 |
--------------------------------------------------------------------------------
/src/components/menu/useMenuColor.js:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default function useMenuColor(color = '') {
4 | const menuBarColor = ref('')
5 | function calcColorChannels(c) {
6 | let rawColor = c.replace('#', '')
7 | if (/^[0-9a-fA-F]{3}$/.test(rawColor)) {
8 | const color = rawColor.split('')
9 | for (let i = 2; i >= 0; i--) {
10 | color.splice(i, 0, color[i])
11 | }
12 | rawColor = color.join('')
13 | }
14 | if (/^[0-9a-fA-F]{6}$/.test(rawColor)) {
15 | return {
16 | red: parseInt(rawColor.slice(0, 2), 16),
17 | green: parseInt(rawColor.slice(2, 4), 16),
18 | blue: parseInt(rawColor.slice(4, 6), 16),
19 | }
20 | } else {
21 | return {
22 | red: 255,
23 | green: 255,
24 | blue: 255,
25 | }
26 | }
27 | }
28 | function mixColor(color, percent = 0.2) {
29 | let { red, green, blue } = calcColorChannels(color)
30 | if (percent > 0) {
31 | // shade given color
32 | red *= 1 - percent
33 | green *= 1 - percent
34 | blue *= 1 - percent
35 | } else {
36 | // tint given color
37 | red += (255 - red) * percent
38 | green += (255 - green) * percent
39 | blue += (255 - blue) * percent
40 | }
41 | return `rgb(${Math.round(red)}, ${Math.round(green)}, ${Math.round(blue)})`
42 | }
43 | if (!color) {
44 | return menuBarColor
45 | }
46 | menuBarColor.value = mixColor(color)
47 | return menuBarColor
48 | }
49 |
--------------------------------------------------------------------------------
/src/components/menu/util/menu-bar.js:
--------------------------------------------------------------------------------
1 | import MenuItem from './menu-item'
2 |
3 | class Menu {
4 | constructor(domNode) {
5 | this.domNode = domNode
6 | this.init()
7 | }
8 |
9 | init() {
10 | const menuChildren = this.domNode.childNodes
11 | ;[].filter
12 | .call(menuChildren, (child) => child.nodeType === 1)
13 | .forEach((child) => {
14 | new MenuItem(child)
15 | })
16 | }
17 | }
18 |
19 | export default Menu
20 |
--------------------------------------------------------------------------------
/src/components/menu/util/menu-item.js:
--------------------------------------------------------------------------------
1 | import { EVENT_CODE, triggerEvent } from '../../../utils/aria'
2 | import SubMenu from './submenu'
3 |
4 | class MenuItem {
5 | constructor(domNode) {
6 | this.domNode = domNode
7 | this.submenu = null
8 | this.init()
9 | }
10 |
11 | init() {
12 | this.domNode.setAttribute('tabindex', '0')
13 | const menuChild = this.domNode.querySelector('.bin-menu')
14 | if (menuChild) {
15 | this.submenu = new SubMenu(this, menuChild)
16 | }
17 | this.addListeners()
18 | }
19 |
20 | addListeners() {
21 | this.domNode.addEventListener('keydown', (event) => {
22 | let prevDef = false
23 | switch (event.code) {
24 | case EVENT_CODE.down: {
25 | triggerEvent(event.currentTarget, 'mouseenter')
26 | this.submenu && this.submenu.gotoSubIndex(0)
27 | prevDef = true
28 | break
29 | }
30 | case EVENT_CODE.up: {
31 | triggerEvent(event.currentTarget, 'mouseenter')
32 | this.submenu &&
33 | this.submenu.gotoSubIndex(this.submenu.subMenuItems.length - 1)
34 | prevDef = true
35 | break
36 | }
37 | case EVENT_CODE.tab: {
38 | triggerEvent(event.currentTarget, 'mouseleave')
39 | break
40 | }
41 | case EVENT_CODE.enter:
42 | case EVENT_CODE.space: {
43 | prevDef = true
44 | ;(event.currentTarget).click()
45 | break
46 | }
47 | }
48 | if (prevDef) {
49 | event.preventDefault()
50 | }
51 | })
52 | }
53 | }
54 |
55 | export default MenuItem
56 |
--------------------------------------------------------------------------------
/src/components/menu/util/submenu.js:
--------------------------------------------------------------------------------
1 | import { EVENT_CODE, triggerEvent } from '../../../utils/aria'
2 |
3 | class SubMenu {
4 | constructor(parent, domNode) {
5 | this.subIndex = 0
6 | this.parent = parent
7 | this.domNode = domNode
8 | this.subMenuItems = []
9 | this.init()
10 | }
11 |
12 | init() {
13 | this.subMenuItems = this.domNode.querySelectorAll('li')
14 | this.addListeners()
15 | }
16 |
17 | gotoSubIndex(idx) {
18 | if (idx === this.subMenuItems.length) {
19 | idx = 0
20 | } else if (idx < 0) {
21 | idx = this.subMenuItems.length - 1
22 | }
23 | this.subMenuItems[idx].focus()
24 | this.subIndex = idx
25 | }
26 |
27 | addListeners() {
28 | const parentNode = this.parent.domNode
29 | Array.prototype.forEach.call(this.subMenuItems, (el) => {
30 | el.addEventListener('keydown', (event) => {
31 | let prevDef = false
32 | switch (event.code) {
33 | case EVENT_CODE.down: {
34 | this.gotoSubIndex(this.subIndex + 1)
35 | prevDef = true
36 | break
37 | }
38 | case EVENT_CODE.up: {
39 | this.gotoSubIndex(this.subIndex - 1)
40 | prevDef = true
41 | break
42 | }
43 | case EVENT_CODE.tab: {
44 | triggerEvent(parentNode, 'mouseleave')
45 | break
46 | }
47 | case EVENT_CODE.enter:
48 | case EVENT_CODE.space: {
49 | prevDef = true
50 | event.currentTarget.click()
51 | break
52 | }
53 | }
54 | if (prevDef) {
55 | event.preventDefault()
56 | event.stopPropagation()
57 | }
58 | return false
59 | })
60 | })
61 | }
62 | }
63 |
64 | export default SubMenu
65 |
--------------------------------------------------------------------------------
/src/components/message-box/index.js:
--------------------------------------------------------------------------------
1 | import MessageBox from './instance'
2 |
3 | MessageBox.install = (app) => {
4 | app.config.globalProperties.$messageBox = MessageBox
5 | app.config.globalProperties.$alert = MessageBox.alert
6 | app.config.globalProperties.$confirm = MessageBox.confirm
7 | }
8 |
9 | export default MessageBox
10 |
--------------------------------------------------------------------------------
/src/components/message/index.js:
--------------------------------------------------------------------------------
1 | import Message from './instance'
2 |
3 | Message.install = (app) => {
4 | app.config.globalProperties.$message = Message
5 | }
6 |
7 | export default Message
8 |
--------------------------------------------------------------------------------
/src/components/modal/addListener.js:
--------------------------------------------------------------------------------
1 | let supportsPassive = false
2 | try {
3 | const opts = Object.defineProperty({}, 'passive', {
4 | // eslint-disable-next-line getter-return
5 | get() {
6 | supportsPassive = true
7 | },
8 | })
9 | window.addEventListener('testPassive', null, opts)
10 | window.removeEventListener('testPassive', null, opts)
11 | // eslint-disable-next-line no-empty
12 | } catch (e) {
13 | }
14 |
15 | export function addEventListenerWrap(target, eventType, cb, option) {
16 | if (target.addEventListener) {
17 | let opt = option
18 | if (
19 | opt === undefined &&
20 | supportsPassive &&
21 | (eventType === 'touchstart' || eventType === 'touchmove' || eventType === 'wheel')
22 | ) {
23 | opt = { passive: false }
24 | }
25 | target.addEventListener(eventType, cb, opt)
26 | }
27 | return {
28 | remove: () => {
29 | if (target.removeEventListener) {
30 | target.removeEventListener(eventType, cb)
31 | }
32 | },
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/components/modal/index.js:
--------------------------------------------------------------------------------
1 | import Modal from './modal.vue'
2 |
3 | Modal.install = (app) => {
4 | app.component(Modal.name, Modal)
5 | }
6 |
7 | export default Modal
8 | export { default as useModal } from './useModal'
9 |
--------------------------------------------------------------------------------
/src/components/modal/mask.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
60 |
--------------------------------------------------------------------------------
/src/components/move-transition/index.js:
--------------------------------------------------------------------------------
1 | import MoveTransition from './move-transition'
2 |
3 | MoveTransition.install = (app) => {
4 | app.component(MoveTransition.name, MoveTransition)
5 | }
6 |
7 | export default MoveTransition
8 |
--------------------------------------------------------------------------------
/src/components/move-transition/move-transition.js:
--------------------------------------------------------------------------------
1 | import { h, Transition, TransitionGroup } from 'vue'
2 |
3 | export default {
4 | name: 'BMoveTransition',
5 | functional: true,
6 | props: {
7 | name: {
8 | type: String,
9 | default: 'fade-transverse',
10 | },
11 | group: {
12 | type: Boolean,
13 | default: false,
14 | },
15 | },
16 | setup(props, { slots }) {
17 | return () => {
18 | const config = {
19 | name: props.name,
20 | appear: true,
21 | onBeforeLeave(el) {
22 | el.style.position = 'absolute'
23 | el.style.top = '0'
24 | el.style.left = '0'
25 | el.style.width = '100%'
26 | el.style.height = '100%'
27 | el.style.overflow = 'hidden'
28 | },
29 | onAfterLeave(el) {
30 | el.style = ''
31 | },
32 | }
33 | if (props.group) {
34 | return h(TransitionGroup, config, slots.default)
35 | }
36 | return h(Transition, config, slots.default)
37 | }
38 | },
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/notice/index.js:
--------------------------------------------------------------------------------
1 | import Notice from './instance'
2 |
3 | Notice.install = (app) => {
4 | app.config.globalProperties.$notice = Notice
5 | }
6 |
7 | export default Notice
8 |
--------------------------------------------------------------------------------
/src/components/option-group/index.js:
--------------------------------------------------------------------------------
1 | import OptionGroup from '../select/option-group.vue'
2 |
3 | OptionGroup.install = (app) => {
4 | app.component(OptionGroup.name, OptionGroup)
5 | }
6 |
7 | export default OptionGroup
8 |
--------------------------------------------------------------------------------
/src/components/option/index.js:
--------------------------------------------------------------------------------
1 | import { Option } from '../select'
2 |
3 | Option.install = app => {
4 | app.component(Option.name, Option)
5 | }
6 |
7 | export default Option
8 |
--------------------------------------------------------------------------------
/src/components/page/index.js:
--------------------------------------------------------------------------------
1 | import Page from './page.vue'
2 |
3 | Page.install = (app) => {
4 | app.component(Page.name, Page)
5 | }
6 |
7 | export default Page
8 |
--------------------------------------------------------------------------------
/src/components/popover/index.js:
--------------------------------------------------------------------------------
1 | import Popover from './popover'
2 |
3 | Popover.install = (app) => {
4 | app.component(Popover.name, Popover)
5 | }
6 |
7 | export default Popover
8 |
--------------------------------------------------------------------------------
/src/components/popover/usePopover.js:
--------------------------------------------------------------------------------
1 | import { computed, watch } from 'vue'
2 | import { isString } from '@vue/shared'
3 | import { usePopper } from '../popper'
4 |
5 | export const SHOW_EVENT = 'show'
6 | export const HIDE_EVENT = 'hide'
7 |
8 | export default function usePopover(props, ctx) {
9 | const popperProps = usePopper(props, ctx)
10 |
11 | const popperStyle = computed(() => {
12 | let _width
13 |
14 | if (isString(props.width)) {
15 | _width = props.width
16 | } else {
17 | _width = props.width + 'px'
18 | }
19 |
20 | return {
21 | width: _width,
22 | zIndex: popperProps.popperStyle.value.zIndex,
23 | }
24 | })
25 |
26 | watch(popperProps.visibility, val => {
27 | ctx.emit(val ? SHOW_EVENT : HIDE_EVENT)
28 | })
29 |
30 | return {
31 | ...popperProps,
32 | popperStyle,
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/components/popper/index.js:
--------------------------------------------------------------------------------
1 | import Popper from './src/index.vue'
2 |
3 | Popper.install = (app) => {
4 | app.component(Popper.name, Popper)
5 | }
6 |
7 | export default Popper
8 | export const BPopper = Popper
9 |
10 | export { default as defaultProps, Theme } from './src/use-popper/defaults'
11 | export { default as usePopper } from './src/use-popper'
12 | export * from './src/renderers'
13 |
--------------------------------------------------------------------------------
/src/components/popper/src/renderers/arrow.js:
--------------------------------------------------------------------------------
1 | import { Comment, h } from 'vue'
2 |
3 | export default function renderArrow(showArrow) {
4 | return showArrow
5 | ? h(
6 | 'div',
7 | {
8 | ref: 'arrowRef',
9 | class: 'bin-popper__arrow',
10 | 'data-popper-arrow': '',
11 | },
12 | null,
13 | )
14 | : h(Comment, null, '')
15 | }
16 |
--------------------------------------------------------------------------------
/src/components/popper/src/renderers/index.js:
--------------------------------------------------------------------------------
1 | export { default as renderPopper } from './popper'
2 | export { default as renderTrigger } from './trigger'
3 | export { default as renderArrow } from './arrow'
4 |
--------------------------------------------------------------------------------
/src/components/popper/src/renderers/popper.js:
--------------------------------------------------------------------------------
1 | import { withDirectives, Transition, vShow, withCtx, h } from 'vue'
2 | import { NOOP } from '@vue/shared'
3 | import { stop } from '../../../../utils/dom'
4 |
5 | export default function renderPopper(props, children) {
6 | const {
7 | theme,
8 | name,
9 | stopPopperMouseEvent,
10 | popperClass,
11 | popperStyle,
12 | popperRef,
13 | pure,
14 | popperId,
15 | visibility,
16 | onMouseEnter,
17 | onMouseLeave,
18 | onAfterEnter,
19 | onAfterLeave,
20 | onBeforeEnter,
21 | onBeforeLeave,
22 | } = props
23 |
24 | const kls = [popperClass, 'bin-popper', 'is-' + theme, pure ? 'is-pure' : '']
25 | /**
26 | * Equivalent to
27 | *
28 | *
37 | *
38 | *
39 | *
40 | */
41 |
42 | const mouseUpAndDown = stopPopperMouseEvent ? stop : NOOP
43 | return h(
44 | Transition,
45 | {
46 | name,
47 | 'onAfterEnter': onAfterEnter,
48 | 'onAfterLeave': onAfterLeave,
49 | 'onBeforeEnter': onBeforeEnter,
50 | 'onBeforeLeave': onBeforeLeave,
51 | },
52 | {
53 | default: withCtx(() => [withDirectives(
54 | h(
55 | 'div',
56 | {
57 | 'aria-hidden': String(!visibility),
58 | class: kls,
59 | style: popperStyle ?? {},
60 | id: popperId,
61 | ref: popperRef ?? 'popperRef',
62 | role: 'tooltip',
63 | onMouseenter: onMouseEnter,
64 | onMouseleave: onMouseLeave,
65 | onClick: stop,
66 | onMousedown: mouseUpAndDown,
67 | onMouseup: mouseUpAndDown,
68 | },
69 | children,
70 | ),
71 | [[vShow, visibility]],
72 | )]),
73 | },
74 | )
75 | }
76 |
--------------------------------------------------------------------------------
/src/components/popper/src/renderers/trigger.js:
--------------------------------------------------------------------------------
1 | import { cloneVNode } from 'vue'
2 | import { getFirstValidNode } from '../../../../utils/vnode'
3 | import { throwError } from '../../../../utils/log'
4 |
5 | export default function renderTrigger(trigger, extraProps) {
6 | const firstElement = getFirstValidNode(trigger, 1)
7 | if (!firstElement) {
8 | throwError('renderTrigger', 'trigger expects single rooted node')
9 | }
10 | return cloneVNode(firstElement, extraProps, true)
11 | }
12 |
--------------------------------------------------------------------------------
/src/components/popper/src/use-popper/build-modifiers.js:
--------------------------------------------------------------------------------
1 | export default function buildModifier(props, externalModifiers = []) {
2 | const { arrow, arrowOffset, offset, gpuAcceleration } = props
3 |
4 | const modifiers = [
5 | {
6 | name: 'offset',
7 | options: {
8 | offset: [0, offset ?? 12],
9 | },
10 | },
11 | {
12 | name: 'preventOverflow',
13 | options: {
14 | padding: {
15 | top: 2,
16 | bottom: 2,
17 | left: 5,
18 | right: 5,
19 | },
20 | },
21 | },
22 | {
23 | name: 'flip',
24 | options: {
25 | padding: 5,
26 | },
27 | },
28 | {
29 | name: 'computeStyles',
30 | options: {
31 | gpuAcceleration,
32 | adaptive: gpuAcceleration,
33 | },
34 | },
35 | // tippyModifier,
36 | ]
37 |
38 | if (arrow) {
39 | modifiers.push({
40 | name: 'arrow',
41 | options: {
42 | element: arrow,
43 | // the arrow size is an equailateral triangle with 10px side length, the 3rd side length ~ 14.1px
44 | // adding a offset to the ceil of 4.1 should be 4 this resolves the problem of arrow overflowing out of popper.
45 | padding: arrowOffset ?? 4,
46 | },
47 | })
48 | }
49 |
50 | modifiers.push(...externalModifiers)
51 | return modifiers
52 | }
53 |
--------------------------------------------------------------------------------
/src/components/popper/src/use-popper/popper-options.js:
--------------------------------------------------------------------------------
1 | import { computed } from 'vue'
2 | import buildModifiers from './build-modifiers'
3 |
4 | export default function usePopperOptions(props, state) {
5 | return computed(() => {
6 | return {
7 | placement: props.placement,
8 | ...props.popperOptions,
9 | // Avoiding overriding modifiers.
10 | modifiers: buildModifiers({
11 | arrow: state.arrow.value,
12 | arrowOffset: props.arrowOffset,
13 | offset: props.offset,
14 | gpuAcceleration: props.gpuAcceleration,
15 | fallbackPlacements: props.fallbackPlacements,
16 | }, props.popperOptions?.modifiers),
17 | }
18 | })
19 | }
20 |
--------------------------------------------------------------------------------
/src/components/progress/index.js:
--------------------------------------------------------------------------------
1 | import Progress from './progress.vue'
2 |
3 | Progress.install = (app) => {
4 | app.component(Progress.name, Progress)
5 | }
6 |
7 | export default Progress
8 |
--------------------------------------------------------------------------------
/src/components/radio-group/index.js:
--------------------------------------------------------------------------------
1 | import RadioGroup from '../radio/radio-group.vue'
2 |
3 | RadioGroup.install = (app) => {
4 | app.component(RadioGroup.name, RadioGroup)
5 | }
6 |
7 | export default RadioGroup
8 |
--------------------------------------------------------------------------------
/src/components/radio/index.js:
--------------------------------------------------------------------------------
1 | import Radio from './radio.vue'
2 |
3 | Radio.install = (app) => {
4 | app.component(Radio.name, Radio)
5 | }
6 |
7 | export default Radio
8 |
--------------------------------------------------------------------------------
/src/components/radio/useRadio.js:
--------------------------------------------------------------------------------
1 | import { ref, computed, inject } from 'vue'
2 | import useForm from '../../hooks/useForm'
3 |
4 | export const useRadio = () => {
5 | const { BForm, BFormItem, formEmit } = useForm()
6 | const radioGroup = inject('RadioGroup', {})
7 | const focus = ref(false)
8 | const isGroup = computed(() => radioGroup?.name === 'BRadioGroup')
9 | const isBtnGroup = computed(() => isGroup.value && radioGroup?.type === 'button')
10 |
11 | return {
12 | isGroup,
13 | focus,
14 | radioGroup,
15 | isBtnGroup,
16 | BForm, BFormItem, formEmit,
17 | }
18 | }
19 |
20 | export const useRadioAttrs = (props, { isGroup, radioGroup, BForm, model }) => {
21 | const isDisabled = computed(() => {
22 | return isGroup.value
23 | ? radioGroup.disabled || props.disabled || BForm.disabled
24 | : props.disabled || BForm.disabled
25 | })
26 |
27 | const tabIndex = computed(() => {
28 | return (isDisabled.value || (isGroup.value && model.value !== props.label)) ? -1 : 0
29 | })
30 |
31 | return {
32 | isDisabled,
33 | tabIndex,
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/rate/index.js:
--------------------------------------------------------------------------------
1 | import Rate from './rate.vue'
2 |
3 | Rate.install = (app) => {
4 | app.component(Rate.name, Rate)
5 | }
6 |
7 | export default Rate
8 |
--------------------------------------------------------------------------------
/src/components/row/index.js:
--------------------------------------------------------------------------------
1 | import Row from './row.vue'
2 |
3 | Row.install = (app) => {
4 | app.component(Row.name, Row)
5 | }
6 |
7 | export default Row
8 |
--------------------------------------------------------------------------------
/src/components/row/row.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
68 |
--------------------------------------------------------------------------------
/src/components/scrollbar/index.js:
--------------------------------------------------------------------------------
1 | import Scrollbar from './scrollbar.vue'
2 |
3 | Scrollbar.install = (app) => {
4 | app.component(Scrollbar.name, Scrollbar)
5 | }
6 |
7 | export default Scrollbar
8 |
--------------------------------------------------------------------------------
/src/components/scrollbar/util.js:
--------------------------------------------------------------------------------
1 | export const BAR_MAP = {
2 | vertical: {
3 | offset: 'offsetHeight',
4 | scroll: 'scrollTop',
5 | scrollSize: 'scrollHeight',
6 | size: 'height',
7 | key: 'vertical',
8 | axis: 'Y',
9 | client: 'clientY',
10 | direction: 'top',
11 | },
12 | horizontal: {
13 | offset: 'offsetWidth',
14 | scroll: 'scrollLeft',
15 | scrollSize: 'scrollWidth',
16 | size: 'width',
17 | key: 'horizontal',
18 | axis: 'X',
19 | client: 'clientX',
20 | direction: 'left',
21 | },
22 | }
23 |
24 | export function renderThumbStyle({ move, size, bar }) {
25 | const style = {}
26 | const translate = `translate${bar.axis}(${move}%)`
27 |
28 | style[bar.size] = size
29 | style.transform = translate
30 | style.msTransform = translate
31 | style.webkitTransform = translate
32 |
33 | return style
34 | }
35 |
36 | // 数组转换成对象
37 | export function toObject(arr) {
38 | const res = {}
39 | for (let i = 0; i < arr.length; i++) {
40 | if (arr[i]) {
41 | extend(res, arr[i])
42 | }
43 | }
44 | return res
45 | }
46 |
47 | function extend(to, _from) {
48 | for (const key in _from) {
49 | to[key] = _from[key]
50 | }
51 | return to
52 | }
53 |
--------------------------------------------------------------------------------
/src/components/select/index.js:
--------------------------------------------------------------------------------
1 | import Select from './select.vue'
2 | import Option from './option.vue'
3 |
4 | Select.install = (app) => {
5 | app.component(Select.name, Select)
6 | }
7 |
8 | export { Option }
9 | export default Select
10 |
--------------------------------------------------------------------------------
/src/components/select/option-group.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | - {{ label }}
4 | -
5 |
8 |
9 |
10 |
11 |
12 |
47 |
--------------------------------------------------------------------------------
/src/components/select/select-dropdown.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
49 |
--------------------------------------------------------------------------------
/src/components/select/token.js:
--------------------------------------------------------------------------------
1 | // For individual build sharing injection key, we had to make `Symbol` to string
2 | export const selectGroupKey = 'SelectGroup'
3 |
4 | export const selectKey = 'Select'
5 |
6 | export const selectEvents = {
7 | queryChange: 'OptionQueryChange',
8 | groupQueryChange: 'OptionGroupQueryChange',
9 | }
10 |
--------------------------------------------------------------------------------
/src/components/skeleton-item/img-placeholder.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
17 |
--------------------------------------------------------------------------------
/src/components/skeleton-item/index.js:
--------------------------------------------------------------------------------
1 | import SkeletonItem from './item.vue'
2 |
3 | SkeletonItem.install = (app) => {
4 | app.component(SkeletonItem.name, SkeletonItem)
5 | }
6 |
7 | export default SkeletonItem
8 |
--------------------------------------------------------------------------------
/src/components/skeleton-item/item.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
21 |
--------------------------------------------------------------------------------
/src/components/skeleton/index.js:
--------------------------------------------------------------------------------
1 | import Skeleton from './skeleton.vue'
2 |
3 | Skeleton.install = (app) => {
4 | app.component(Skeleton.name, Skeleton)
5 | }
6 |
7 | export default Skeleton
8 |
--------------------------------------------------------------------------------
/src/components/skeleton/skeleton.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
65 |
--------------------------------------------------------------------------------
/src/components/skeleton/use-throttle.js:
--------------------------------------------------------------------------------
1 | import { onMounted, ref, watch } from 'vue'
2 |
3 | export default function(loading, throttle = 0) {
4 | if (throttle === 0) return loading
5 | const throttled = ref(false)
6 | let timeoutHandle = 0
7 |
8 | const dispatchThrottling = () => {
9 | if (timeoutHandle) {
10 | clearTimeout(timeoutHandle)
11 | }
12 | timeoutHandle = window.setTimeout(() => {
13 | throttled.value = loading.value
14 | }, throttle)
15 | }
16 | onMounted(dispatchThrottling)
17 |
18 | watch(() => loading.value, val => {
19 | if (val) {
20 | dispatchThrottling()
21 | } else {
22 | throttled.value = val
23 | }
24 | })
25 | return throttled
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/slider/index.js:
--------------------------------------------------------------------------------
1 | import Slider from './src/index.vue'
2 |
3 | /* istanbul ignore next */
4 | Slider.install = function(Vue) {
5 | Vue.component(Slider.name, Slider)
6 | }
7 |
8 | export default Slider
9 |
--------------------------------------------------------------------------------
/src/components/slider/src/marker.vue:
--------------------------------------------------------------------------------
1 |
27 |
--------------------------------------------------------------------------------
/src/components/slider/src/useMarks.js:
--------------------------------------------------------------------------------
1 | import { computed } from 'vue'
2 |
3 | export const useMarks = (props) => {
4 | return computed(() => {
5 | if (!props.marks) {
6 | return []
7 | }
8 |
9 | const marksKeys = Object.keys(props.marks)
10 | return marksKeys.map(parseFloat)
11 | .sort((a, b) => a - b)
12 | .filter(point => point <= props.max && point >= props.min)
13 | .map((point) => ({
14 | point,
15 | position: (point - props.min) * 100 / (props.max - props.min),
16 | mark: props.marks[point],
17 | }))
18 | })
19 | }
20 |
--------------------------------------------------------------------------------
/src/components/slider/src/useStops.js:
--------------------------------------------------------------------------------
1 | import { computed } from 'vue'
2 |
3 | export const useStops = (props, initData, minValue, maxValue) => {
4 | const stops = computed(() => {
5 | if (!props.showStops || props.min > props.max) return []
6 | if (props.step === 0) {
7 | process.env.NODE_ENV !== 'production' && console.warn('[Element Warn][Slider]step should not be 0.')
8 | return []
9 | }
10 |
11 | const stopCount = (props.max - props.min) / props.step
12 | const stepWidth = 100 * props.step / (props.max - props.min)
13 | const result = Array.from({ length: stopCount - 1 }).map((_, index) => ((index + 1) * stepWidth))
14 |
15 | if (props.range) {
16 | return result.filter(step => {
17 | return step < 100 * (minValue.value - props.min) / (props.max - props.min)
18 | || step > 100 * (maxValue.value - props.min) / (props.max - props.min)
19 | })
20 | } else {
21 | return result.filter(step => step > 100 * (initData.firstValue - props.min) / (props.max - props.min))
22 | }
23 | })
24 |
25 | const getStopStyle = (position) => {
26 | return (props.vertical ? { 'bottom': position + '%' } : { 'left': position + '%' })
27 | }
28 |
29 | return {
30 | stops,
31 | getStopStyle,
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/components/space/item.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
25 |
--------------------------------------------------------------------------------
/src/components/split/index.js:
--------------------------------------------------------------------------------
1 | import Split from './split.vue'
2 |
3 | Split.install = (app) => {
4 | app.component(Split.name, Split)
5 | }
6 |
7 | export default Split
8 |
--------------------------------------------------------------------------------
/src/components/split/pane.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
22 |
--------------------------------------------------------------------------------
/src/components/split/resizer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
--------------------------------------------------------------------------------
/src/components/step/index.js:
--------------------------------------------------------------------------------
1 | import Step from '../steps/step.vue'
2 |
3 | Step.install = (app) => {
4 | app.component(Step.name, Step)
5 | }
6 |
7 | export default Step
8 |
--------------------------------------------------------------------------------
/src/components/steps/index.js:
--------------------------------------------------------------------------------
1 | import Steps from './steps.vue'
2 |
3 | Steps.install = (app) => {
4 | app.component(Steps.name, Steps)
5 | }
6 |
7 | export default Steps
8 |
--------------------------------------------------------------------------------
/src/components/submenu/index.js:
--------------------------------------------------------------------------------
1 | import Submenu from '../menu/submenu.vue'
2 |
3 | Submenu.install = (app) => {
4 | app.component(Submenu.name, Submenu)
5 | }
6 |
7 | export default Submenu
8 |
--------------------------------------------------------------------------------
/src/components/switch/index.js:
--------------------------------------------------------------------------------
1 | import Switch from './switch.vue'
2 |
3 | Switch.install = (app) => {
4 | app.component(Switch.name, Switch)
5 | }
6 |
7 | export default Switch
8 |
--------------------------------------------------------------------------------
/src/components/table/index.js:
--------------------------------------------------------------------------------
1 | import Table from './table.vue'
2 |
3 | Table.install = (app) => {
4 | app.component(Table.name, Table)
5 | }
6 |
7 | export default Table
8 |
--------------------------------------------------------------------------------
/src/components/table/main/expand.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'TableExpand',
3 | functional: true,
4 | props: {
5 | row: Object,
6 | render: Function,
7 | index: Number,
8 | column: {
9 | type: Object,
10 | default: null,
11 | },
12 | },
13 | render: (ctx) => {
14 | const params = {
15 | row: ctx.row,
16 | index: ctx.index,
17 | }
18 | if (ctx.column) params.column = ctx.column
19 | return ctx.render(params)
20 | },
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/table/main/header.js:
--------------------------------------------------------------------------------
1 | import { h } from 'vue'
2 |
3 | export default {
4 | name: 'TableRenderHeader',
5 | functional: true,
6 | props: {
7 | render: Function,
8 | column: Object,
9 | index: Number,
10 | },
11 | render: (ctx) => {
12 | const params = {
13 | column: ctx.props.column,
14 | index: ctx.props.index,
15 | }
16 | return ctx.props.render(h, params)
17 | },
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/table/main/mixin.js:
--------------------------------------------------------------------------------
1 | export function useMixin(props) {
2 | function alignCls(column, row = {}) {
3 | let cellClassName = ''
4 | if (row.cellClassName && column.key && row.cellClassName[column.key]) {
5 | cellClassName = row.cellClassName[column.key]
6 | }
7 | return [
8 | {
9 | [`${cellClassName}`]: cellClassName, // cell className
10 | [`${column.className}`]: column.className, // column className
11 | [`${props.prefixCls}-column-${column.align}`]: column.align,
12 | [`${props.prefixCls}-hidden`]: (props.fixed === 'left' && column.fixed !== 'left') ||
13 | (props.fixed === 'right' && column.fixed !== 'right') ||
14 | (!props.fixed && column.fixed && (column.fixed === 'left' || column.fixed === 'right')),
15 | },
16 | ]
17 | }
18 |
19 | function isPopperShow(column) {
20 | return column.filters && ((!props.fixed && !column.fixed) || (props.fixed === 'left' && column.fixed === 'left') || (props.fixed === 'right' && column.fixed === 'right'))
21 | }
22 |
23 | function setCellWidth(column) {
24 | let width = ''
25 | if (column.width) {
26 | width = column.width
27 | } else if (props.columnsWidth[column._index]) {
28 | width = props.columnsWidth[column._index].width
29 | }
30 | if (width === '0') width = ''
31 | return width
32 | }
33 |
34 | return {
35 | alignCls,
36 | isPopperShow,
37 | setCellWidth
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/table/main/slot.js:
--------------------------------------------------------------------------------
1 | import { inject } from 'vue'
2 |
3 | export default {
4 | name: 'TableSlot',
5 | functional: true,
6 | props: {
7 | row: Object,
8 | index: Number,
9 | column: {
10 | type: Object,
11 | default: null,
12 | },
13 | },
14 | setup(props) {
15 | const tableRoot = inject('BTable', {})
16 | const render = tableRoot.slots[props.column.slot]
17 | if (!render) {
18 | throw Error('columns slot should be write in table slots')
19 | }
20 | return () =>
21 | render({
22 | row: props.row,
23 | column: props.column,
24 | index: props.index,
25 | })
26 | },
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/table/table-tr.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
49 |
--------------------------------------------------------------------------------
/src/components/tabs/index.js:
--------------------------------------------------------------------------------
1 | import Tabs from './tabs.vue'
2 |
3 | Tabs.install = (app) => {
4 | app.component(Tabs.name, Tabs)
5 | }
6 |
7 | export default Tabs
8 |
--------------------------------------------------------------------------------
/src/components/tag/index.js:
--------------------------------------------------------------------------------
1 | import Tag from './tag.vue'
2 |
3 | Tag.install = (app) => {
4 | app.component(Tag.name, Tag)
5 | }
6 |
7 | export default Tag
8 |
--------------------------------------------------------------------------------
/src/components/time-picker/common/constant.js:
--------------------------------------------------------------------------------
1 | export const DEFAULT_FORMATS_TIME = 'HH:mm:ss'
2 | export const DEFAULT_FORMATS_DATE = 'YYYY-MM-DD'
3 | export const DEFAULT_FORMATS_DATEPICKER = {
4 | date: DEFAULT_FORMATS_DATE,
5 | week: 'gggg[w]ww',
6 | year: 'YYYY',
7 | month: 'YYYY-MM',
8 | datetime: `${DEFAULT_FORMATS_DATE} ${DEFAULT_FORMATS_TIME}`,
9 | monthrange: 'YYYY-MM',
10 | daterange: DEFAULT_FORMATS_DATE,
11 | datetimerange: `${DEFAULT_FORMATS_DATE} ${DEFAULT_FORMATS_TIME}`,
12 | }
13 |
--------------------------------------------------------------------------------
/src/components/time-picker/common/date-utils.js:
--------------------------------------------------------------------------------
1 | export const rangeArr = n => {
2 | return Array.from(Array(n).keys())
3 | }
4 |
5 | export const extractDateFormat = format => {
6 | return format
7 | .replace(/\W?m{1,2}|\W?ZZ/g, '')
8 | .replace(/\W?h{1,2}|\W?s{1,3}|\W?a/gi, '')
9 | .trim()
10 | }
11 |
12 | export const extractTimeFormat = format => {
13 | return format
14 | .replace(/\W?D{1,2}|\W?Do|\W?d{1,4}|\W?M{1,4}|\W?Y{2,4}/g, '')
15 | .trim()
16 | }
17 |
--------------------------------------------------------------------------------
/src/components/time-picker/index.js:
--------------------------------------------------------------------------------
1 | import TimePicker from './time-picker'
2 | import CommonPicker from './common/picker.vue'
3 | import TimePickPanel from './time-picker-com/panel-time-pick.vue'
4 |
5 | export * from './common/date-utils'
6 | export * from './common/constant'
7 | export * from './common/props'
8 |
9 | TimePicker.install = app => {
10 | app.component(TimePicker.name, TimePicker)
11 | }
12 |
13 | export { CommonPicker, TimePickPanel }
14 | export default TimePicker
15 |
--------------------------------------------------------------------------------
/src/components/time-picker/time-picker.js:
--------------------------------------------------------------------------------
1 | import { h, ref, provide } from 'vue'
2 | import dayjs from 'dayjs'
3 | import customParseFormat from 'dayjs/plugin/customParseFormat'
4 | import { DEFAULT_FORMATS_TIME } from './common/constant'
5 | import Picker from './common/picker.vue'
6 | import TimePickPanel from './time-picker-com/panel-time-pick.vue'
7 | import TimeRangePanel from './time-picker-com/panel-time-range.vue'
8 | import { defaultProps } from './common/props'
9 |
10 | dayjs.extend(customParseFormat)
11 |
12 | export default {
13 | name: 'BTimePicker',
14 | install: null,
15 | props: {
16 | ...defaultProps,
17 | isRange: {
18 | type: Boolean,
19 | default: false,
20 | },
21 | },
22 | emits: ['update:modelValue'],
23 | setup(props, ctx) {
24 | const commonPicker = ref(null)
25 | const type = props.isRange ? 'timerange' : 'time'
26 | const panel = props.isRange ? TimeRangePanel : TimePickPanel
27 | const refProps = {
28 | ...props,
29 | focus: () => {
30 | commonPicker.value?.handleFocus()
31 | },
32 | blur: () => {
33 | commonPicker.value?.handleBlur()
34 | },
35 | }
36 | provide('BPopperOptions', props.popperOptions)
37 | ctx.expose(refProps)
38 | return () => {
39 | const format = props.format ?? DEFAULT_FORMATS_TIME
40 | return h(
41 | Picker,
42 | {
43 | ...props, // allow format to be overwrite
44 | format,
45 | type,
46 | ref: commonPicker,
47 | 'onUpdate:modelValue': value => ctx.emit('update:modelValue', value),
48 | },
49 | {
50 | default: scopedProps => h(panel, scopedProps),
51 | },
52 | )
53 | }
54 | },
55 | }
56 |
--------------------------------------------------------------------------------
/src/components/timeline-item/index.js:
--------------------------------------------------------------------------------
1 | import TimelineItem from '../timeline/timeline-item.vue'
2 |
3 | TimelineItem.install = (app) => {
4 | app.component(TimelineItem.name, TimelineItem)
5 | }
6 |
7 | export default TimelineItem
8 |
--------------------------------------------------------------------------------
/src/components/timeline/index.js:
--------------------------------------------------------------------------------
1 | import Timeline from './timeline.vue'
2 |
3 | Timeline.install = (app) => {
4 | app.component(Timeline.name, Timeline)
5 | }
6 |
7 | export default Timeline
8 |
--------------------------------------------------------------------------------
/src/components/timeline/timeline-item.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
78 |
--------------------------------------------------------------------------------
/src/components/timeline/timeline.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
27 |
--------------------------------------------------------------------------------
/src/components/tooltip/index.js:
--------------------------------------------------------------------------------
1 | import Tooltip from './tooltip'
2 |
3 | Tooltip.install = (app) => {
4 | app.component(Tooltip.name, Tooltip)
5 | }
6 |
7 | export default Tooltip
8 |
--------------------------------------------------------------------------------
/src/components/tree-big/index.js:
--------------------------------------------------------------------------------
1 | import BigTree from '../tree/big-tree.vue'
2 |
3 | BigTree.install = (app) => {
4 | app.component(BigTree.name, BigTree)
5 | }
6 |
7 | export default BigTree
8 |
--------------------------------------------------------------------------------
/src/components/tree-select/index.js:
--------------------------------------------------------------------------------
1 | import TreeSelect from './tree-select'
2 |
3 | TreeSelect.install = (app) => {
4 | app.component(TreeSelect.name, TreeSelect)
5 | }
6 |
7 | export default TreeSelect
8 |
--------------------------------------------------------------------------------
/src/components/tree/index.js:
--------------------------------------------------------------------------------
1 | import Tree from './tree.vue'
2 |
3 | Tree.install = (app) => {
4 | app.component(Tree.name, Tree)
5 | }
6 |
7 | export default Tree
8 |
--------------------------------------------------------------------------------
/src/components/tree/render.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'RenderCell',
3 | functional: true,
4 | props: {
5 | render: Function,
6 | data: Object,
7 | node: Array,
8 | },
9 | render: (ctx) => {
10 | const params = {
11 | root: ctx.node[0],// root 为拍平的数据
12 | node: ctx.node[1],// 当前的节点
13 | data: ctx.data,// 当前点选的节点
14 | }
15 | return ctx.render(params)
16 | },
17 | }
18 |
--------------------------------------------------------------------------------
/src/components/upload/index.js:
--------------------------------------------------------------------------------
1 | import Upload from './upload'
2 |
3 | /* istanbul ignore next */
4 | Upload.install = function(Vue) {
5 | Vue.component(Upload.name, Upload)
6 | }
7 |
8 | export default Upload
9 |
--------------------------------------------------------------------------------
/src/directives/click-animation/index.js:
--------------------------------------------------------------------------------
1 | import TransitionEvents from '../../utils/TransitionEvents'
2 |
3 | let styleForPesudo = null
4 |
5 | // 重置效果
6 | function resetEffect(node) {
7 | if (!node || !(node instanceof Element)) {
8 | return
9 | }
10 | node.parentNode && node.parentNode.removeChild(node)
11 | TransitionEvents.removeEndEventListener(node, onTransitionEnd)
12 | }
13 |
14 | function onTransitionEnd(e) {
15 | if (!e || e.animationName !== 'fadeEffect') {
16 | return
17 | }
18 | resetEffect(e.target)
19 | }
20 |
21 | const ClickAnimation = {
22 | beforeMount(el, binding) {
23 | el.addEventListener('click', e => {
24 | const node = el
25 | const waveColor =
26 | getComputedStyle(node).getPropertyValue('border-top-color') || // Firefox Compatible
27 | getComputedStyle(node).getPropertyValue('border-color') ||
28 | getComputedStyle(node).getPropertyValue('background-color')
29 | if (node) {
30 | node.style.position = 'relative'
31 | let ripple = node.querySelector('.bin-click-animating-node')
32 | resetEffect(ripple)
33 | ripple = document.createElement('span')
34 | ripple.className = 'bin-click-animating-node'
35 | node.appendChild(ripple)
36 | // 设置颜色
37 | styleForPesudo = styleForPesudo || document.createElement('style')
38 | if (waveColor && waveColor !== '#ffffff' &&
39 | waveColor !== 'rgb(255, 255, 255)' && waveColor !== 'transparent') {
40 | styleForPesudo.innerHTML = `
41 | .bin-click-animating-node {
42 | --bin-wave-shadow-color: ${waveColor};
43 | }`
44 | if (!document.body.contains(styleForPesudo)) {
45 | document.body.appendChild(styleForPesudo)
46 | }
47 | }
48 | TransitionEvents.addEndEventListener(ripple, onTransitionEnd)
49 | return false
50 | }
51 | }, false)
52 | },
53 | }
54 |
55 | export default ClickAnimation
56 |
--------------------------------------------------------------------------------
/src/directives/index.js:
--------------------------------------------------------------------------------
1 | export { default as ClickAnimation } from './click-animation'
2 | export { default as ClickOutside } from './click-outside'
3 | export { default as Waves } from './waves'
4 | export { default as NoData } from './no-data'
5 | export { default as Loading } from './loading'
6 | export { default as RepeatClick } from './repeat-click'
7 |
--------------------------------------------------------------------------------
/src/directives/loading/index.js:
--------------------------------------------------------------------------------
1 | import Loading from '../../components/loading/loading.vue'
2 | import createLoadingLikeDirective from '../../utils/create-loading-like-directive'
3 |
4 | const LoadingDirective = createLoadingLikeDirective(Loading)
5 |
6 | export default LoadingDirective
7 |
--------------------------------------------------------------------------------
/src/directives/no-data/index.js:
--------------------------------------------------------------------------------
1 | import Empty from '../../components/empty/empty.vue'
2 | import createLoadingLikeDirective from '../../utils/create-loading-like-directive'
3 |
4 | const EmptyDirective = createLoadingLikeDirective(Empty)
5 |
6 | export default EmptyDirective
7 |
--------------------------------------------------------------------------------
/src/directives/repeat-click/index.js:
--------------------------------------------------------------------------------
1 | import { on, once } from '../../utils/dom'
2 |
3 | export default {
4 | beforeMount(el, binding) {
5 | let interval = null
6 | let startTime = 0
7 | const handler = () => binding.value && binding.value()
8 | const clear = () => {
9 | if (Date.now() - startTime < 100) {
10 | handler()
11 | }
12 | clearInterval(interval)
13 | interval = null
14 | }
15 |
16 | on(el, 'mousedown', (e) => {
17 | if (e.button !== 0) return
18 | startTime = Date.now()
19 | once(document, 'mouseup', clear)
20 | clearInterval(interval)
21 | interval = setInterval(handler, 100)
22 | })
23 | },
24 | }
25 |
--------------------------------------------------------------------------------
/src/directives/waves/index.js:
--------------------------------------------------------------------------------
1 | import TransitionEvents from '../../utils/TransitionEvents'
2 |
3 | // 重置效果
4 | function resetEffect(node) {
5 | if (!node || !(node instanceof Element)) {
6 | return
7 | }
8 | node.parentNode && node.parentNode.removeChild(node)
9 | TransitionEvents.removeEndEventListener(node, onTransitionEnd)
10 | }
11 |
12 | function onTransitionEnd(e) {
13 | if (!e || e.propertyName !== 'transform') {
14 | return
15 | }
16 | resetEffect(e.target)
17 | }
18 |
19 | export default {
20 | beforeMount(el, binding) {
21 | el.addEventListener('click', e => {
22 | const wavesColor = binding.value || 'rgba(0, 0, 0, 0.15)'
23 | const node = el
24 | if (node) {
25 | node.style.position = 'relative'
26 | node.style.overflow = 'hidden'
27 | const rect = node.getBoundingClientRect()
28 | const ripple = document.createElement('span')
29 | ripple.className = 'waves-ripple'
30 | ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
31 | node.appendChild(ripple)
32 | // 获得页面向左、向上卷动的距离
33 | const pageScroll = {
34 | left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0,
35 | top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0,
36 | }
37 |
38 | ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - pageScroll.top) + 'px'
39 | ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - pageScroll.left) + 'px'
40 |
41 | ripple.style.backgroundColor = wavesColor
42 | ripple.className = 'waves-ripple z-active'
43 | TransitionEvents.addEndEventListener(ripple, onTransitionEnd)
44 | return false
45 | }
46 | }, false)
47 | },
48 | }
49 |
--------------------------------------------------------------------------------
/src/hooks/index.js:
--------------------------------------------------------------------------------
1 | export { default as useLockScreen } from './useLockScreen'
2 | export { default as useRestoreActive } from './useRestoreActive'
3 | export { default as useModal } from './useModal'
4 | export { default as useModalDrag } from './useModalDrag'
5 | export { default as useFocus } from './useFocus'
6 | export { default as useSortable } from './useSortable'
7 | export { default as useForm } from './useForm'
8 | export { default as useMousePosition } from './useMousePosition'
9 |
--------------------------------------------------------------------------------
/src/hooks/useFocus.js:
--------------------------------------------------------------------------------
1 | export default (el) => {
2 | return {
3 | focus: () => {
4 | el.value?.focus?.()
5 | },
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/hooks/useForm.js:
--------------------------------------------------------------------------------
1 | import { FormItemKey, FormKey, FormEvents } from '../components/form/token'
2 | import { inject, computed } from 'vue'
3 |
4 | export const VALIDATE_STATE_MAP = {
5 | validating: 'b-icon-loading icon-is-rotating',
6 | success: 'b-icon-check-circle',
7 | error: 'b-icon-close-circle',
8 | }
9 | export default function useForm() {
10 | const BForm = inject(FormKey, {})
11 | const BFormItem = inject(FormItemKey, {})
12 |
13 | const validateState = computed(() => BFormItem.validateState || '')
14 |
15 | const validateIcon = computed(() => VALIDATE_STATE_MAP[validateState.value])
16 |
17 | // blur, change,value
18 | function formEmit(type, value) {
19 | BFormItem.formItemMitt?.emit(FormEvents[type], value)
20 | }
21 |
22 | return {
23 | BForm,
24 | BFormItem,
25 | validateState,
26 | validateIcon,
27 | formEmit,
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/hooks/useLockScreen.js:
--------------------------------------------------------------------------------
1 | import { watch, isRef } from 'vue'
2 | import { throwError } from '../utils/log'
3 |
4 | import { addClass, removeClass, hasClass, getStyle, getScrollBarWidth } from '../utils/dom'
5 |
6 | /**
7 | * Hook that monitoring the ref value to lock or unlock the screen.
8 | * When the trigger became true, it assumes modal is now opened and vice versa.
9 | * @param trigger {boolean}
10 | */
11 | export default trigger => {
12 | if (!isRef(trigger)) {
13 | throwError('useLockScreen', 'You need to pass a ref param to this function')
14 | }
15 | let scrollBarWidth = 0
16 | let withoutHiddenClass = false
17 | let bodyPaddingRight = '0'
18 | let computedBodyPaddingRight = 0
19 | let timer = null
20 | watch(trigger, val => {
21 | if (val) {
22 | if (timer) clearTimeout(timer)
23 | withoutHiddenClass = !hasClass(document.body, 'bin-popup-parent--hidden')
24 | if (withoutHiddenClass) {
25 | bodyPaddingRight = document.body.style.paddingRight
26 | computedBodyPaddingRight = parseInt(getStyle(document.body, 'paddingRight'), 10)
27 | }
28 | scrollBarWidth = getScrollBarWidth()
29 | const bodyHasOverflow = document.documentElement.clientHeight < document.body.scrollHeight
30 | const bodyOverflowY = getStyle(document.body, 'overflowY')
31 | addClass(document.body, 'bin-popup-parent--hidden')
32 | if (
33 | scrollBarWidth > 0 &&
34 | (bodyHasOverflow || bodyOverflowY === 'scroll') &&
35 | withoutHiddenClass
36 | ) {
37 | document.body.style.paddingRight = computedBodyPaddingRight + scrollBarWidth + 'px'
38 | addClass(document.body, 'with-scrollbar')
39 | }
40 | } else {
41 | timer = setTimeout(() => {
42 | if (withoutHiddenClass) {
43 | document.body.style.paddingRight = bodyPaddingRight
44 | removeClass(document.body, 'bin-popup-parent--hidden')
45 | removeClass(document.body, 'with-scrollbar')
46 | }
47 | withoutHiddenClass = true
48 | }, 300)
49 | }
50 | })
51 | }
52 |
--------------------------------------------------------------------------------
/src/hooks/useModal.js:
--------------------------------------------------------------------------------
1 | import { watch } from 'vue'
2 | import { on } from '../utils/dom'
3 | import { EVENT_CODE } from '../utils/aria'
4 | import isServer from '../utils/isServer'
5 |
6 | const modalStack = []
7 |
8 | const closeModal = (e) => {
9 | if (modalStack.length === 0) return
10 | if (e.code === EVENT_CODE.esc) {
11 | e.stopPropagation()
12 | const topModal = modalStack[modalStack.length - 1]
13 | topModal.handleClose()
14 | }
15 | }
16 |
17 | export default (instance, visibleRef) => {
18 | watch(
19 | () => visibleRef.value,
20 | val => {
21 | if (val) {
22 | modalStack.push(instance)
23 | } else {
24 | modalStack.splice(
25 | modalStack.findIndex(modal => modal === instance),
26 | 1,
27 | )
28 | }
29 | },
30 | )
31 | }
32 |
33 | if (!isServer) {
34 | on(document, 'keydown', closeModal)
35 | }
36 |
--------------------------------------------------------------------------------
/src/hooks/useMousePosition.js:
--------------------------------------------------------------------------------
1 | import { onMounted, onUnmounted, ref } from 'vue'
2 |
3 | function useMousePosition() {
4 | const x = ref(0)
5 | const y = ref(0)
6 | const updateMouse = (e) => {
7 | x.value = e.pageX
8 | y.value = e.pageY
9 | }
10 |
11 | onMounted(() => {
12 | document.addEventListener('click', updateMouse)
13 | })
14 | onUnmounted(() => {
15 | document.removeEventListener('click', updateMouse)
16 | })
17 | return { x, y }
18 | }
19 |
20 | export default useMousePosition
21 |
--------------------------------------------------------------------------------
/src/hooks/useRestoreActive.js:
--------------------------------------------------------------------------------
1 | import { isRef, watch } from 'vue'
2 |
3 | /**
4 | * This method provides dialogable components the ability to restore previously activated element before
5 | * the dialog gets opened
6 | */
7 | export default (toggle, initialFocus) => {
8 | let previousActive
9 | watch(() => toggle.value, val => {
10 | if (val) {
11 | previousActive = document.activeElement
12 | if (isRef(initialFocus)) {
13 | initialFocus.value.focus?.()
14 | }
15 | } else {
16 | if (process.env.NODE_ENV === 'testing') {
17 | previousActive.focus.call(previousActive)
18 | } else {
19 | previousActive.focus()
20 | }
21 | }
22 | })
23 | }
24 |
--------------------------------------------------------------------------------
/src/hooks/useSortable.js:
--------------------------------------------------------------------------------
1 | import Sortable from 'sortablejs'
2 | import { onBeforeUnmount, onMounted, ref } from 'vue'
3 |
4 | /**
5 | * sortable hooks,用于创建拖拽排序列表
6 | * @param list 列表list[
7 | * @param endFun 拖拽结束事件函数
8 | * @param option
9 | */
10 | export default function useSortable(list, endFun, option = {}) {
11 | const defaultOptions = {
12 | animation: 150,
13 | ghostClass: 'blue-background-class',
14 | // ************* 拖动对象移动样式
15 | dragClass: 'drag-item-class',
16 | // ************* 禁用html5原生拖拽行为
17 | forceFallback: true,
18 | handle: '.drag'
19 | }
20 | const listRef = ref(null)
21 | let sortInstance = null
22 | onMounted(() => {
23 | if (sortInstance) sortInstance.destroy()
24 | const el = listRef.value
25 | if (!el) return
26 | sortInstance = Sortable.create(el, {
27 | ...defaultOptions,
28 | ...option,
29 | onUpdate: ({ newIndex, oldIndex }) => {
30 | const $li = el.children[newIndex]
31 | const $oldLi = el.children[oldIndex]
32 | // 先删除移动的节点
33 | el.removeChild($li)
34 | // 再插入移动的节点到原有节点,还原了移动的操作
35 | if (newIndex > oldIndex) {
36 | el.insertBefore($li, $oldLi)
37 | } else {
38 | el.insertBefore($li, $oldLi.nextSibling)
39 | }
40 | // 更新items数组
41 | const targetRow = list.value.splice(oldIndex, 1)[0]
42 | list.value.splice(newIndex, 0, targetRow)
43 | // 下一个tick就会走patch更新
44 | },
45 | onEnd: (evt) => {
46 | endFun && endFun()
47 | }
48 | })
49 | })
50 | onBeforeUnmount(() => {
51 | if (sortInstance) {
52 | sortInstance.destroy()
53 | sortInstance = null
54 | }
55 | })
56 | return {
57 | listRef
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/hooks/useTimeout.js:
--------------------------------------------------------------------------------
1 | import {
2 | watch,
3 | getCurrentInstance,
4 | onUnmounted,
5 | ref,
6 | } from 'vue'
7 |
8 | export function tryOnUnmounted(fn) {
9 | getCurrentInstance() && onUnmounted(fn)
10 | }
11 |
12 | function isFunction(val) {
13 | return typeof val === 'function'
14 | }
15 |
16 |
17 | export function useTimeoutFn(handle, wait, native = false) {
18 | if (!isFunction(handle)) {
19 | throw new Error('handle is not Function!')
20 | }
21 |
22 | const { readyRef, stop, start } = useTimeoutRef(wait)
23 | if (native) {
24 | handle()
25 | } else {
26 | watch(
27 | readyRef,
28 | (maturity) => {
29 | maturity && handle()
30 | },
31 | { immediate: false },
32 | )
33 | }
34 | return { readyRef, stop, start }
35 | }
36 |
37 | export function useTimeoutRef(wait) {
38 | const readyRef = ref(false)
39 |
40 | let timer = null
41 |
42 | function stop() {
43 | readyRef.value = false
44 | timer && window.clearTimeout(timer)
45 | }
46 |
47 | function start() {
48 | stop()
49 | timer = setTimeout(() => {
50 | readyRef.value = true
51 | }, wait)
52 | }
53 |
54 | start()
55 |
56 | tryOnUnmounted(stop)
57 |
58 | return { readyRef, stop, start }
59 | }
60 |
--------------------------------------------------------------------------------
/src/styles/common/mixins.styl:
--------------------------------------------------------------------------------
1 | make-row(gutter = 0) {
2 | position: relative;
3 | margin-left: (gutter / -2);
4 | margin-right: (gutter / -2);
5 | height: auto;
6 | clear-fix()
7 | }
8 |
9 | make-grid(class = '') {
10 | float-grid-columns(class);
11 | loop-grid-columns(class);
12 | }
13 |
14 | $grid-columns = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
15 |
16 | float-grid-columns(class) {
17 | for row in $grid-columns {
18 | .bin-col-span{class}-{row} {
19 | float: left;
20 | flex: 0 0 auto;
21 | }
22 | }
23 | }
24 |
25 | loop-grid-columns(class) {
26 | for index in $grid-columns {
27 | .bin-col-span{class}-{index} {
28 | display: block;
29 | width: percentage((index / 24));
30 | }
31 | .bin-col{class}-push-{index} {
32 | left: percentage((index / 24));
33 | }
34 | .bin-col{class}-pull-{index} {
35 | right: percentage((index / 24));
36 | }
37 | .bin-col{class}-offset-{index} {
38 | margin-left: percentage((index / 24));
39 | }
40 | .bin-col{class}-order-{index} {
41 | order: index;
42 | }
43 | }
44 | .bin-col-span{class}-{0} {
45 | display: none;
46 | }
47 | .bin-col{class}-push-0 {
48 | left: auto;
49 | }
50 | .bin-col{class}-pull-0 {
51 | right: auto;
52 | }
53 | .bin-col{class}-offset-0 {
54 | margin-left: 0
55 | }
56 | .bin-col{class}-order-0 {
57 | order: 0;
58 | }
59 | }
60 |
61 | clear-fix() {
62 | zoom: 1;
63 | &:before,
64 | &:after {
65 | content: "";
66 | display: table;
67 | }
68 | &:after {
69 | clear: both;
70 | visibility: hidden;
71 | font-size: 0;
72 | height: 0;
73 | }
74 | }
75 |
76 | disabled() {
77 | opacity: 1;
78 | cursor: not-allowed;
79 | color: var(--bin-color-text-placeholder);
80 | }
81 |
--------------------------------------------------------------------------------
/src/styles/common/waves.styl:
--------------------------------------------------------------------------------
1 | .waves-ripple {
2 | position: absolute;
3 | border-radius: 100%;
4 | background-color: rgba(255, 255, 255, 0.15);
5 | background-clip: padding-box;
6 | pointer-events: none;
7 | user-select: none;
8 | transform: scale3d(0, 0, 0);
9 | opacity: 1;
10 | }
11 |
12 | .waves-ripple.z-active {
13 | opacity: 0;
14 | transform: scale3d(2, 2, 2);
15 | transition: opacity 0.8s ease-out, transform .6s ease-out;
16 | }
17 | html {
18 | --bin-wave-shadow-color: #1089ff;
19 | }
20 | .bin-click-animating-node {
21 | position: absolute;
22 | top: 0;
23 | right: 0;
24 | bottom: 0;
25 | left: 0;
26 | display: block;
27 | border-radius: inherit;
28 | box-shadow: 0 0 0 0 var(--bin-wave-shadow-color);
29 | opacity: .4;
30 | animation: fadeEffect 1.2s cubic-bezier(0.08, 0.82, 0.17, 1), waveEffect 0.8s cubic-bezier(0.08, 0.82, 0.17, 1);
31 | animation-fill-mode: backwards;
32 | pointer-events: none;
33 | }
34 |
35 | @keyframes fadeEffect {
36 | 100% {
37 | opacity: 0;
38 | }
39 | }
40 | @keyframes waveEffect {
41 | 100% {
42 | box-shadow: 0 0 0 6px var(--bin-wave-shadow-color);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/styles/components/affix.styl:
--------------------------------------------------------------------------------
1 | .bin-affix--fixed {
2 | position: fixed;
3 | z-index: 100;
4 | }
5 |
--------------------------------------------------------------------------------
/src/styles/components/backtop.styl:
--------------------------------------------------------------------------------
1 | .bin-back-top {
2 | position: fixed;
3 | z-index: 10;
4 | cursor: pointer;
5 | .bin-back-top-inner {
6 | background-color: rgba(0, 0, 0, .6);
7 | border-radius: 2px;
8 | box-shadow: 0 1px 3px rgba(0, 0, 0, .2);
9 | transition: all var(--bin-animation-duration-base) ease-in-out;
10 | i {
11 | color: #fff;
12 | font-size: 18px;
13 | padding: 8px 12px;
14 | }
15 | }
16 | }
17 | .back-top-fade-enter-active,
18 | .back-top-fade-leave-active {
19 | transition: var(--bin-animation-duration-base)
20 | }
21 | .back-top-fade-enter,
22 | .back-top-fade-leave-to {
23 | transform: translateY(-20px);
24 | opacity: 0;
25 | }
26 |
--------------------------------------------------------------------------------
/src/styles/components/badge.styl:
--------------------------------------------------------------------------------
1 | .bin-badge {
2 | position: relative;
3 | display: inline-block;
4 | }
5 | .bin-badge__content {
6 | background-color: var(--bin-color-danger);
7 | border-radius: 10px;
8 | color: #fff;
9 | display: inline-block;
10 | font-size: 12px;
11 | min-width: 20px;
12 | height: 20px;
13 | padding: 0 6px;
14 | text-align: center;
15 | white-space: nowrap;
16 | border: 1px solid #fff;
17 | line-height: var(--bin-base-line-height);
18 | &.is-dot {
19 | height: 8px;
20 | width: 8px;
21 | min-width: 8px;
22 | padding: 0;
23 | right: 0;
24 | border-radius: 50%;
25 | }
26 | &.is-fixed {
27 | position: absolute;
28 | top: 0;
29 | right: 10px;
30 | transform: translateY(-50%) translateX(100%);
31 | &.is-dot {
32 | right: 5px;
33 | }
34 | }
35 | }
36 |
37 | .bin-badge-is-primary {
38 | background-color: var(--bin-color-primary);
39 | }
40 | .bin-badge-is-warning {
41 | background-color: var(--bin-color-warning);
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/src/styles/components/breadcrumb.styl:
--------------------------------------------------------------------------------
1 | .bin-breadcrumb {
2 | font-size: var(--bin-font-size-default);
3 | line-height: var(--bin-base-line-height);
4 |
5 | &:after, &:before {
6 | display: table;
7 | content: '';
8 | }
9 | }
10 |
11 | .bin-breadcrumb__item {
12 | &:last-child .bin-separator {
13 | display: none;
14 | }
15 | }
16 |
17 | .bin-separator {
18 | margin: 0 6px;
19 | color: var(--bin-color-text-secondary);
20 |
21 | &.icon {
22 | font-size: 14px;
23 | vertical-align: middle;
24 | font-weight: normal;
25 | line-height: 1;
26 | }
27 | }
28 |
29 | .bin-breadcrumb__inner {
30 | color: var(--bin-color-text-default);
31 |
32 | a {
33 | text-decoration: none;
34 | transition: color var(--bin-animation-duration-base) cubic-bezier(0.645, 0.045, 0.355, 1);
35 | color: var(--bin-color-text-secondary);
36 |
37 | &:hover {
38 | color: var(--bin-color-primary);
39 | cursor: pointer;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/styles/components/calendar.styl:
--------------------------------------------------------------------------------
1 | .bin-calendar {
2 | padding: 12px 20px 35px;
3 | width: 100%;
4 | height: 100%;
5 | box-sizing: border-box;
6 |
7 | ul > li {
8 | list-style: none;
9 | margin: 0;
10 | }
11 |
12 | .bin-calendar-header {
13 | display: flex;
14 | justify-content: space-between;
15 | align-items: center;
16 | padding: 12px 20px;
17 | border-bottom: 1px solid #ebeef5;
18 |
19 | &-title {
20 | color: var(--bin-color-text-primary);
21 | align-self: center;
22 | font-size: var(--bin-font-size-default);
23 | }
24 | }
25 |
26 | .bin-calendar-week {
27 | display: flex;
28 | width: 100%;
29 |
30 | &-item {
31 | flex: 1;
32 | text-align: center;
33 | font-size: var(--bin-font-size-default);
34 | color: var(--bin-color-text-default);
35 | line-height: var(--bin-base-line-height);
36 | font-weight: 500;
37 | padding: 10px 0;
38 | }
39 | }
40 |
41 | .bin-calendar-body {
42 | display: flex;
43 | flex-wrap: wrap;
44 | width: 100%;
45 | border-top: var(--bin-border-base);
46 | border-left: var(--bin-border-base);
47 | }
48 |
49 | .bin-calendar-date-view {
50 | width: 14.285%;
51 | height: 80px;
52 | line-height: var(--bin-base-line-height);
53 | padding: 8px;
54 | border-right: var(--bin-border-base);
55 | border-bottom: var(--bin-border-base);
56 | cursor: pointer;
57 |
58 | &.is-current-day, &.is-selected {
59 | color: var(--bin-color-primary);
60 | }
61 |
62 | &.is-selected, &:hover {
63 | background-color: var(--bin-color-primary-light5);
64 | }
65 |
66 | &.prev, &.next {
67 | color: var(--bin-color-text-disabled);
68 | }
69 | }
70 |
71 | &.card {
72 | width: 300px;
73 |
74 | .bin-calendar-header {
75 | padding: 10px;
76 | }
77 |
78 | .bin-calendar-date-view {
79 | padding: 0;
80 | height: 34px;
81 | line-height: 34px;
82 | text-align: center;
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/styles/components/card.styl:
--------------------------------------------------------------------------------
1 | .bin-card {
2 | --b-card-border-color: var(--bin-border-color-light);
3 | }
4 |
5 | .bin-card {
6 | border-radius: var(--bin-border-radius-default);
7 | border: 1px solid var(--b-card-border-color);
8 | background-color: #fff;
9 | transition: var(--bin-animation-duration-base);
10 | width: 100%;
11 |
12 | &.is-always-shadow, &.is-hover-shadow:focus, &.is-hover-shadow:hover {
13 | box-shadow: var(--bin-shadow-popper);
14 | }
15 |
16 | &.is-never-shadow, &.is-never-shadow:focus, &.is-never-shadow:hover {
17 | box-shadow: none;
18 | }
19 |
20 | &.is-no-border {
21 | border: none;
22 | }
23 |
24 | .bin-card__header {
25 | padding: 8px 16px;
26 | box-sizing: border-box;
27 | font-size: var(--bin-font-size-default);
28 | color: var(--bin-color-text-primary);
29 | font-weight: 500;
30 |
31 | &.has-divider {
32 | border-bottom: 1px solid var(--b-card-border-color);
33 | }
34 |
35 | &.no-divider {
36 | border-bottom: none;
37 | }
38 |
39 | &.has-tip {
40 | position: relative;
41 |
42 | &::after {
43 | content: '';
44 | position: absolute;
45 | left: 0;
46 | top: 12px;
47 | bottom: 12px;
48 | width: 2px;
49 | background: var(--bin-color-primary);
50 | }
51 | }
52 | }
53 |
54 | .bin-card__body {
55 | padding: 16px;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/styles/components/circle.styl:
--------------------------------------------------------------------------------
1 | .bin-circle {
2 | display: inline-block;
3 | position: relative;
4 | }
5 | .bin-circle-inner {
6 | width: 100%;
7 | text-align: center;
8 | position: absolute;
9 | left: 0;
10 | top: 50%;
11 | -webkit-transform: translateY(-50%);
12 | transform: translateY(-50%);
13 | line-height: 1;
14 | }
15 |
--------------------------------------------------------------------------------
/src/styles/components/divider.styl:
--------------------------------------------------------------------------------
1 | .bin-divider {
2 | background-color: #dcdfe6;
3 | position: relative;
4 | &-horizontal {
5 | display: block;
6 | height: 1px;
7 | width: 100%;
8 | margin: 24px 0;
9 | }
10 | &-vertical {
11 | position: relative;
12 | margin: 0 8px;
13 | display: inline-block;
14 | height: 1em;
15 | width: 1px;
16 | vertical-align: middle;
17 | top: -0.06em;
18 | }
19 | &-dashed {
20 | background: 0 0;
21 | border-top: 1px dashed #dcdfe6;
22 | }
23 | &-inner-text {
24 | position: absolute;
25 | background-color: #fff;
26 | padding: 0 16px;
27 | font-weight: 600;
28 | color: #303133;
29 | font-size: 14px;
30 | &.is-left {
31 | left: 24px;
32 | transform: translateY(-50%);
33 | }
34 | &.is-center {
35 | left: 50%;
36 | transform: translateX(-50%) translateY(-50%);
37 | }
38 | &.is-right {
39 | right: 24px;
40 | transform: translateY(-50%);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/styles/components/empty.styl:
--------------------------------------------------------------------------------
1 | .bin-empty {
2 | margin: 0 8px;
3 | font-size: var(--bin-font-size-default);
4 | line-height: 22px;
5 | text-align: center;
6 |
7 | .bin-empty-image {
8 | height: 100px;
9 | margin-bottom: 8px;
10 |
11 | svg {
12 | height: 100%;
13 | margin: auto;
14 | }
15 | }
16 |
17 | .bin-empty-description {
18 | color: var(--bin-color-text-secondary);
19 | margin: 0;
20 | }
21 | }
22 |
23 | .bin-empty-normal {
24 | margin: 32px 0;
25 | color: var(--bin-color-text-disabled);
26 |
27 | .bin-empty-image {
28 | height: 40px;
29 | }
30 | }
31 |
32 | .bin-empty-img-simple-ellipse {
33 | fill: #f5f5f5;
34 | }
35 |
36 | .bin-empty-img-simple-g {
37 | stroke: #d9d9d9;
38 | }
39 |
40 | .bin-empty-img-simple-path {
41 | fill: #fafafa;
42 | }
43 |
44 | .bin-empty-description {
45 | margin: 0;
46 | }
47 |
--------------------------------------------------------------------------------
/src/styles/components/grid.styl:
--------------------------------------------------------------------------------
1 | @import "../common/mixins.styl"
2 |
3 | .bin-row {
4 | display: block;
5 | make-row()
6 | &-flex {
7 | display: flex;
8 | flex-direction: row;
9 | flex-wrap: wrap;
10 | &:before,
11 | &:after {
12 | display: flex;
13 | }
14 | // x轴原点
15 | &-start {
16 | justify-content: flex-start;
17 | }
18 | // x轴居中
19 | &-center {
20 | justify-content: center;
21 | }
22 | // x轴反方向
23 | &-end {
24 | justify-content: flex-end;
25 | }
26 | // x轴平分
27 | &-space-between {
28 | justify-content: space-between;
29 | }
30 | // x轴有间隔地平分
31 | &-space-around {
32 | justify-content: space-around;
33 | }
34 | // 顶部对齐
35 | &-top {
36 | align-items: flex-start;
37 | }
38 | // 居中对齐
39 | &-middle {
40 | align-items: center;
41 | }
42 | // 底部对齐
43 | &-bottom {
44 | align-items: flex-end;
45 | }
46 | }
47 | }
48 |
49 | .bin-col {
50 | position: relative;
51 | display: block;
52 | }
53 |
54 | make-grid();
55 |
56 | make-grid(-xs);
57 |
58 | @media (min-width: 576px) {
59 | make-grid(-sm);
60 | }
61 |
62 |
63 | @media (min-width: 768px) {
64 | make-grid(-md);
65 | }
66 |
67 | @media (min-width: 992px) {
68 | make-grid(-lg);
69 | }
70 |
71 | @media (min-width: 1200px) {
72 | make-grid(-xl);
73 | }
74 |
75 | @media (min-width: 1600px) {
76 | make-grid(-xxl);
77 | }
78 |
--------------------------------------------------------------------------------
/src/styles/components/icon.styl:
--------------------------------------------------------------------------------
1 | .bin-icon-select__popper {
2 | &.bin-popper {
3 | width: 485px;
4 | overflow: auto;
5 | padding: 5px 5px;
6 | background-color: var(--bin-white-color);
7 | box-sizing: border-box;
8 | border-radius: var(--bin-border-radius-default);
9 | box-shadow: var(--bin-shadow-down);
10 | position: absolute;
11 | z-index: 900;
12 |
13 | &.is-light {
14 | border: none;
15 | }
16 |
17 | .bin-icon-select-panel__query {
18 | width: 100%;
19 | padding: 5px 5px 0;
20 | }
21 |
22 | .bin-icon-select-panel__wrap {
23 | height: 280px;
24 | }
25 |
26 | ul.icon-list {
27 | position: relative;
28 | overflow: hidden;
29 | list-style: none;
30 | padding: 0;
31 |
32 | li {
33 | display: inline-block;
34 | width: 40px;
35 | text-align: center;
36 | height: 40px;
37 | line-height: 40px;
38 | color: #606266;
39 | font-size: 12px;
40 | margin-right: -1px;
41 | margin-bottom: -1px;
42 | margin-left: 0;
43 | padding: 0;
44 | cursor: pointer;
45 |
46 | i {
47 | display: block;
48 | font-size: 24px;
49 | margin-bottom: 15px;
50 | transition: 0.15s linear;
51 | }
52 |
53 | &:hover i {
54 | color: var(--bin-color-primary-light1);
55 | }
56 | }
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/styles/components/layout.styl:
--------------------------------------------------------------------------------
1 | .bin-layout {
2 | --b-layout-animation-ease: cubic-bezier(0.4, 0, 0.2, 1);
3 | position: relative;
4 | color: var(--bin-color-text-default);
5 | background-color: var(--bin-white-color);
6 | box-sizing: border-box;
7 | z-index: auto;
8 | flex: auto;
9 | overflow: hidden;
10 | display: flex;
11 |
12 | .bin-layout-sider {
13 | position: relative;
14 | border-right: 1px solid var(--bin-border-color-base);
15 | transition: width 0.2s var(--b-layout-animation-ease);
16 |
17 | .sider-inner {
18 | opacity: 1;
19 | overflow-x: hidden;
20 | transition: opacity 0.2s var(--b-layout-animation-ease);
21 |
22 | &.hide {
23 | opacity: 0;
24 | }
25 | }
26 |
27 | &:hover {
28 | .bin-layout-toggle-button {
29 | opacity: 1;
30 | }
31 | }
32 | }
33 |
34 | .bin-layout-content {
35 | flex: 1;
36 | transition: width 0.2s;
37 | }
38 |
39 | .bin-layout-toggle-button {
40 | cursor: pointer;
41 | width: 24px;
42 | height: 24px;
43 | position: absolute;
44 | top: 50px;
45 | right: 0;
46 | border-radius: 50%;
47 | display: flex;
48 | align-items: center;
49 | justify-content: center;
50 | font-size: 18px;
51 | color: var(--bin-color-text-default);
52 | border: 1px solid var(--bin-border-color-base);
53 | background-color: var(--bin-white-color);
54 | box-shadow: 0 2px 4px 0px rgba(0, 0, 0, 0.06);
55 | transform: translateX(50%) translateY(-50%);
56 | opacity: 0;
57 |
58 | > i {
59 | transition: 0.2s var(--b-layout-animation-ease);
60 | }
61 |
62 | &.collapsed {
63 | > i {
64 | transform: rotateZ(180deg);
65 | }
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/styles/components/loading.styl:
--------------------------------------------------------------------------------
1 | .bin-loading {
2 | color: var(--bin-color-primary);
3 | vertical-align: middle;
4 | text-align: center;
5 | }
6 |
7 | .bin-loading-inner {
8 | font-size: 14px;
9 | .circular {
10 | height: 42px;
11 | width: 42px;
12 | animation: loading-rotate 2s linear infinite;
13 | .path {
14 | stroke-dasharray: 90, 150;
15 | stroke-dashoffset: 0;
16 | stroke-width: 2;
17 | stroke: var(--bin-color-primary);
18 | stroke-linecap: round;
19 | animation: loading-dash 1.5s ease-in-out infinite;
20 | }
21 | }
22 | .loading-text {
23 | margin-left:
24 | }
25 | }
26 |
27 | .bin-loading-fix {
28 | position: absolute;
29 | top: 0;
30 | left: 0;
31 | z-index: 8;
32 | width: 100%;
33 | height: 100%;
34 | background-color: hsla(0, 0%, 100%, .9);
35 | }
36 | .bin-loading-fix .bin-loading-inner {
37 | position: absolute;
38 | top: 50%;
39 | left: 50%;
40 | -webkit-transform: translate(-50%, -50%);
41 | transform: translate(-50%, -50%);
42 | }
43 | @keyframes loading-rotate {
44 | 100% {
45 | transform: rotate(360deg);
46 | }
47 | }
48 |
49 | @keyframes loading-dash {
50 | 0% {
51 | stroke-dasharray: 1, 200;
52 | stroke-dashoffset: 0;
53 | }
54 | 50% {
55 | stroke-dasharray: 90, 150;
56 | stroke-dashoffset: -40px;
57 | }
58 | 100% {
59 | stroke-dasharray: 90, 150;
60 | stroke-dashoffset: -120px;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/styles/components/loadingbar.styl:
--------------------------------------------------------------------------------
1 | .bin-loading-bar {
2 | width: 100%;
3 | position: fixed;
4 | top: 0;
5 | left: 0;
6 | right: 0;
7 | z-index: 2000;
8 | &-inner {
9 | transition: width var(--bin-animation-duration-base) linear;
10 | &-color-primary {
11 | background-color: var(--bin-color-primary);
12 | }
13 | &-failed-color-error {
14 | background-color: var(--bin-color-danger);
15 | }
16 | }
17 | .icon {
18 | position absolute;
19 | right: 5px;
20 | top: 5px;
21 | &.icon-color-primary i {
22 | color: var(--bin-color-primary);
23 | }
24 | &.icon-failed-color-error i {
25 | color: var(--bin-color-danger);
26 | }
27 | i {
28 | font-size: 16px;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/styles/components/mask.styl:
--------------------------------------------------------------------------------
1 |
2 | .bin-mask {
3 | position: fixed;
4 | top: 0;
5 | right: 0;
6 | bottom: 0;
7 | left: 0;
8 | z-index: 2000;
9 | height: 100%;
10 | background-color: rgba(0, 0, 0, .45);
11 | overflow: auto;
12 | }
13 |
--------------------------------------------------------------------------------
/src/styles/components/message.styl:
--------------------------------------------------------------------------------
1 | .bin-message {
2 | position: fixed;
3 | left: 50%;
4 | top: 20px;
5 | pointer-events: all;
6 | padding: 10px 16px;
7 | border-radius: var(--bin-border-radius-default);
8 | box-shadow: 0 1px 6px 1px rgba(0, 0, 0, 0.15);
9 | background: #fff;
10 | box-sizing: border-box;
11 | transform: translateX(-50%);
12 | transition: opacity 0.3s, transform 0.4s, top 0.4s;
13 | overflow: hidden;
14 | display: flex;
15 | align-items: center;
16 |
17 | &.is-closable {
18 | .bin-message__content {
19 | padding-right: 6px;
20 | }
21 | }
22 |
23 | .b-iconfont.b-icon-close {
24 | cursor: pointer;
25 | color: var(--bin-color-text-secondary);
26 | font-size: var(--bin-font-size-default);
27 | vertical-align: middle;
28 | line-height: 1;
29 |
30 | &:focus {
31 | outline-width: 0;
32 | }
33 |
34 | &:hover {
35 | color: var(--bin-color-text-primary);
36 | }
37 | }
38 | }
39 |
40 | .bin-message__icon {
41 | margin-right: 10px;
42 | font-size: var(--bin-font-size-large);
43 |
44 | &.is-info {
45 | color: var(--bin-color-primary);
46 | }
47 |
48 | &.is-success {
49 | color: var(--bin-color-success);
50 | }
51 |
52 | &.is-warning {
53 | color: var(--bin-color-warning);
54 | }
55 |
56 | &.is-error {
57 | color: var(--bin-color-danger);
58 | }
59 | }
60 |
61 | .bin-message-fade-enter-from, .bin-message-fade-leave-to {
62 | opacity: 0;
63 | transform: translate(-50%, -100%);
64 | }
65 |
--------------------------------------------------------------------------------
/src/styles/components/popover.styl:
--------------------------------------------------------------------------------
1 | .bin-popover {
2 | &.bin-popper {
3 | background: #FFF;
4 | min-width: 150px;
5 | border-radius: var(--bin-border-radius-default);
6 | z-index: 2000;
7 | color: var(--bin-color-text-default);
8 | text-align: justify;
9 | font-size: var(--bin-font-size-default);
10 | box-shadow: var(--bin-shadow-popper);
11 | word-break: break-all;
12 | padding: 12px;
13 |
14 | .bin-popover__title {
15 | width: 100%;
16 | line-height: 1;
17 | margin: 0;
18 | color: var(--bin-color-text-primary);
19 | font-weight: 700;
20 | font-size: var(--bin-font-size-large);
21 | margin-bottom: 12px;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/styles/components/rate.styl:
--------------------------------------------------------------------------------
1 | .bin-rate {
2 | height: 20px;
3 | line-height: 1;
4 | outline: none;
5 | }
6 | .bin-rate__item {
7 | font-size: 0;
8 | vertical-align: middle;
9 | }
10 | .bin-rate__icon, .bin-rate__item {
11 | display: inline-block;
12 | position: relative;
13 | }
14 |
15 | .bin-rate__icon {
16 | font-size: 20px;
17 | margin-right: 6px;
18 | color: #c0c4cc;
19 | transition: var(--bin-animation-duration-base);
20 | &.hover {
21 | transform: scale(1.15);
22 | }
23 | }
24 |
25 | .bin-rate__decimal, .bin-rate__icon .path2 {
26 | position: absolute;
27 | left: 0;
28 | top: 0;
29 | }
30 | .bin-rate__decimal {
31 | display: inline-block;
32 | overflow: hidden;
33 | font-size: 20px;
34 | }
35 | .bin-rate__text {
36 | font-size: 14px;
37 | vertical-align: middle;
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/src/styles/components/scrollbar.styl:
--------------------------------------------------------------------------------
1 | .bin-scrollbar {
2 | --b-scrollbar-margin: 2px;
3 | --b-scrollbar-index: 2;
4 | position: relative;
5 | overflow: hidden;
6 | height: 100%;
7 |
8 | &:active, &:focus, &:hover {
9 | > .bin-scrollbar__bar {
10 | opacity: 1;
11 | transition: opacity 0.3s ease-out;
12 | }
13 | }
14 | }
15 |
16 | .bin-scrollbar__wrap {
17 | overflow: auto;
18 | height: 100%;
19 | }
20 |
21 | // 默认隐藏原生滚动条宽度
22 | .bin-scrollbar__wrap--hidden-default {
23 | scrollbar-width: none;
24 | }
25 |
26 | .bin-scrollbar__wrap--hidden-default::-webkit-scrollbar {
27 | display: none;
28 | }
29 |
30 | .bin-scrollbar__bar {
31 | position: absolute;
32 | z-index: var(--b-scrollbar-index);
33 | right: var(--b-scrollbar-margin);
34 | bottom: var(--b-scrollbar-margin);
35 | opacity: 0;
36 | transition: opacity 0.12s ease-out;
37 |
38 | &.is-horizontal {
39 | height: var(--bin-scrollbar-width);
40 | left: var(--b-scrollbar-margin);
41 |
42 | > div {
43 | height: 100%;
44 | }
45 | }
46 |
47 | &.is-vertical {
48 | width: var(--bin-scrollbar-width);
49 | top: var(--b-scrollbar-margin);
50 |
51 | > div {
52 | width: 100%;
53 | }
54 | }
55 |
56 | &.always {
57 | opacity: 1;
58 | }
59 | }
60 |
61 | .bin-scrollbar__thumb {
62 | position: relative;
63 | display: block;
64 | width: 0;
65 | height: 0;
66 | cursor: pointer;
67 | border-radius: var(--bin-scrollbar-radius);
68 | background: var(--bin-scrollbar-color);
69 | transition: background var(--bin-animation-duration-base);
70 |
71 | &:hover {
72 | background: var(--bin-scrollbar-color-hover);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/styles/components/space.styl:
--------------------------------------------------------------------------------
1 | .bin-space {
2 | display: -webkit-inline-box;
3 | display: -ms-inline-flexbox;
4 | display: inline-flex
5 | }
6 | .bin-space--vertical {
7 | -webkit-box-orient: vertical;
8 | -webkit-box-direction: normal;
9 | -ms-flex-direction: column;
10 | flex-direction: column
11 | }
12 |
--------------------------------------------------------------------------------
/src/styles/components/split.styl:
--------------------------------------------------------------------------------
1 | .clear-fix:after {
2 | visibility: hidden;
3 | display: block;
4 | font-size: 0;
5 | content: " ";
6 | clear: both;
7 | height: 0;
8 | }
9 |
10 | .bin-splitter-container {
11 | height: 100%;
12 | position: relative;
13 | &.hide-line {
14 | .bin-splitter-pane-resizer {
15 | background-color: transparent;
16 | &:hover {
17 | background-color: var(--bin-border-color-base);
18 | }
19 | }
20 | }
21 | &.is-active {
22 | cursor: col-resize;
23 | user-select: none;
24 | .bin-splitter-pane-resizer {
25 | background-color: var(--bin-border-color-base);
26 | }
27 | }
28 | }
29 |
30 | .bin-splitter-pane.vertical.splitter-left {
31 | position: absolute;
32 | left: 0;
33 | height: 100%;
34 | }
35 |
36 | .bin-splitter-pane.vertical.splitter-right {
37 | position: absolute;
38 | right: 0;
39 | height: 100%;
40 | }
41 |
42 | .bin-splitter-pane.horizontal.splitter-left {
43 | position: absolute;
44 | top: 0;
45 | width: 100%;
46 | }
47 |
48 | .bin-splitter-pane.horizontal.splitter-right {
49 | position: absolute;
50 | bottom: 0;
51 | width: 100%;
52 | }
53 | .bin-splitter-pane-resizer {
54 | box-sizing: border-box;
55 | background-color: var(--bin-border-color-base);
56 | position: absolute;
57 | z-index: 1;
58 | background-clip: padding-box;
59 | }
60 |
61 | .bin-splitter-pane-resizer.horizontal {
62 | height: 11px;
63 | margin: -5px 0;
64 | border-top: 5px solid rgba(255, 255, 255, 0);
65 | border-bottom: 5px solid rgba(255, 255, 255, 0);
66 | cursor: n-resize;
67 | width: 100%;
68 | }
69 |
70 | .bin-splitter-pane-resizer.vertical {
71 | width: 11px;
72 | height: 100%;
73 | margin-left: -5px;
74 | border-left: 5px solid rgba(255, 255, 255, 0);
75 | border-right: 5px solid rgba(255, 255, 255, 0);
76 | cursor: e-resize;
77 | }
78 |
--------------------------------------------------------------------------------
/src/styles/components/upload.styl:
--------------------------------------------------------------------------------
1 | .bin-upload {
2 | input[type="file"] {
3 | display: none;
4 | }
5 | &-select {
6 | display: inline-block;
7 | }
8 | &-list {
9 | margin-top: 8px;
10 |
11 | &-file {
12 | padding: 4px;
13 | color: #515a6e;
14 | border-radius: 4px;
15 | line-height: 1.5em;
16 | font-size: 12px;
17 | transition: background-color var(--bin-animation-duration-base) ease-in-out;
18 | overflow: hidden;
19 | position: relative;
20 |
21 | & > span {
22 | cursor: pointer;
23 | transition: color var(--bin-animation-duration-base) ease-in-out;
24 | i {
25 | display: inline-block;
26 | vertical-align: baseline
27 | width: 14px;
28 | height: 14px;
29 | font-size: 16px;
30 | margin-right: 4px;
31 | color: #515a6e;
32 | text-align: center;
33 | }
34 | }
35 |
36 | &:hover {
37 | background: #f3f3f3;
38 | & > span {
39 | color: var(--bin-color-primary);
40 | i {
41 | color: #515a6e;
42 | }
43 | }
44 | .bin-upload-list-remove {
45 | opacity: 1;
46 | }
47 | }
48 | }
49 | &-remove {
50 | opacity: 0;
51 | font-size: 14px;
52 | cursor: pointer;
53 | float: right;
54 | margin-right: 4px;
55 | color: #999;
56 | transition: all var(--bin-animation-duration-base) ease;
57 | &:hover {
58 | color: #444;
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/styles/fonts/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/src/styles/fonts/iconfont.eot
--------------------------------------------------------------------------------
/src/styles/fonts/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/src/styles/fonts/iconfont.ttf
--------------------------------------------------------------------------------
/src/styles/fonts/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/src/styles/fonts/iconfont.woff
--------------------------------------------------------------------------------
/src/styles/fonts/iconfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangbin3162/bin-ui-next/544f55f06d067ce354d7af68379206074f5ec117/src/styles/fonts/iconfont.woff2
--------------------------------------------------------------------------------
/src/styles/scrollbar.styl:
--------------------------------------------------------------------------------
1 | // =================================
2 | // ==============scrollbar==========
3 | // =================================
4 | ::-webkit-scrollbar {
5 | width: var(--bin-scrollbar-width);
6 | height: var(--bin-scrollbar-width);
7 | }
8 |
9 | ::-webkit-scrollbar-track {
10 | background: var(--bin-scrollbar-track);
11 | }
12 |
13 | ::-webkit-scrollbar-thumb {
14 | background: var(--bin-scrollbar-color);
15 | border-radius: var(--bin-scrollbar-radius);
16 | transition: 0.2s;
17 | }
18 |
19 | ::-webkit-scrollbar-thumb:hover {
20 | background: var(--bin-scrollbar-color-hover);
21 | }
22 |
--------------------------------------------------------------------------------
/src/utils/aria.js:
--------------------------------------------------------------------------------
1 | export const EVENT_CODE = {
2 | tab: 'Tab',
3 | enter: 'Enter',
4 | space: 'Space',
5 | left: 'ArrowLeft', // 37
6 | up: 'ArrowUp', // 38
7 | right: 'ArrowRight', // 39
8 | down: 'ArrowDown', // 40
9 | esc: 'Escape',
10 | delete: 'Delete',
11 | backspace: 'Backspace',
12 | }
13 | /**
14 | * Trigger an event
15 | * mouseenter, mouseleave, mouseover, keyup, change, click, etc.
16 | * @param {HTMLElement} elm
17 | * @param {String} name
18 | * @param {*} opts
19 | */
20 | export const triggerEvent = function(elm, name, ...opts) {
21 | let eventName
22 | if (name.includes('mouse') || name.includes('click')) {
23 | eventName = 'MouseEvents'
24 | } else if (name.includes('key')) {
25 | eventName = 'KeyboardEvent'
26 | } else {
27 | eventName = 'HTMLEvents'
28 | }
29 | const evt = document.createEvent(eventName)
30 |
31 | evt.initEvent(name, ...opts)
32 | elm.dispatchEvent(evt)
33 | return elm
34 | }
35 |
--------------------------------------------------------------------------------
/src/utils/config.js:
--------------------------------------------------------------------------------
1 | let $ELEMENT = {}
2 |
3 | let transferIndex = 0
4 |
5 | function transferIncrease() {
6 | return ++transferIndex + $ELEMENT.zIndex
7 | }
8 |
9 | const setConfig = option => {
10 | $ELEMENT = option
11 | }
12 | const getConfig = key => {
13 | return $ELEMENT[key]
14 | }
15 |
16 | export { transferIncrease, getConfig, setConfig }
17 |
--------------------------------------------------------------------------------
/src/utils/constants.js:
--------------------------------------------------------------------------------
1 | export const UPDATE_MODEL_EVENT = 'update:modelValue'
2 |
3 | export const CHANGE_EVENT = 'change'
4 |
5 | export const VALIDATE_STATE_MAP = {
6 | validating: 'bin-icons b-icon-loading',
7 | info: 'bin-icons b-icon-info-circle',
8 | success: 'bin-icons b-icon-check-circle',
9 | waring: 'bin-icons b-icon-warning-circle',
10 | error: 'bin-icons b-icon-close-circle',
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/src/utils/create-loading-like-directive.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import { addClass, removeClass } from './dom'
3 |
4 | const relativeCls = 'g-relative'
5 |
6 | export default function createLoadingLikeDirective(Comp) {
7 | return {
8 | mounted(el, binding) {
9 | const app = createApp(Comp)
10 | const instance = app.mount(document.createElement('div'))
11 | const name = Comp.name
12 | if (!el[name]) {
13 | el[name] = {}
14 | }
15 | el[name].instance = instance
16 | const title = binding.arg
17 | if (typeof title !== 'undefined') {
18 | instance.setTitle(title)
19 | }
20 |
21 | if (binding.value) {
22 | append(el)
23 | }
24 | },
25 | updated(el, binding) {
26 | const title = binding.arg
27 | const name = Comp.name
28 | if (typeof title !== 'undefined') {
29 | el[name].instance.setTitle(title)
30 | }
31 | if (binding.value !== binding.oldValue) {
32 | binding.value ? append(el) : remove(el)
33 | }
34 | },
35 | }
36 |
37 | function append(el) {
38 | const name = Comp.name
39 | const style = getComputedStyle(el)
40 | if (['absolute', 'fixed', 'relative'].indexOf(style.position) === -1) {
41 | addClass(el, relativeCls)
42 | }
43 | el.appendChild(el[name].instance.$el)
44 | }
45 |
46 | function remove(el) {
47 | const name = Comp.name
48 | removeClass(el, relativeCls)
49 | el.removeChild(el[name].instance.$el)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/utils/isDef.js:
--------------------------------------------------------------------------------
1 | export function isKorean(text) {
2 | const reg = /([(\uAC00-\uD7AF)|(\u3130-\u318F)])+/gi
3 | return reg.test(text)
4 | }
5 |
--------------------------------------------------------------------------------
/src/utils/isServer.js:
--------------------------------------------------------------------------------
1 | export default typeof window === 'undefined'
2 |
--------------------------------------------------------------------------------
/src/utils/resize-event.js:
--------------------------------------------------------------------------------
1 | import ResizeObserver from 'resize-observer-polyfill'
2 | import isServer from './isServer'
3 |
4 | /* istanbul ignore next */
5 | const resizeHandler = function (entries) {
6 | for (const entry of entries) {
7 | const listeners = entry.target.__resizeListeners__ || []
8 | if (listeners.length) {
9 | listeners.forEach(fn => {
10 | fn()
11 | })
12 | }
13 | }
14 | }
15 |
16 | /* istanbul ignore next */
17 | export const addResizeListener = function (element, fn) {
18 | if (isServer || !element) return
19 | if (!element.__resizeListeners__) {
20 | element.__resizeListeners__ = []
21 | element.__ro__ = new ResizeObserver(resizeHandler)
22 | element.__ro__.observe(element)
23 | }
24 | element.__resizeListeners__.push(fn)
25 | }
26 |
27 | /* istanbul ignore next */
28 | export const removeResizeListener = function (element, fn) {
29 | if (!element || !element.__resizeListeners__) return
30 | element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1)
31 | if (!element.__resizeListeners__.length) {
32 | element.__ro__.disconnect()
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/utils/scroll-into-view.js:
--------------------------------------------------------------------------------
1 | import isServer from './isServer'
2 |
3 | export default function scrollIntoView(container, selected) {
4 | if (isServer) return
5 |
6 | if (!selected) {
7 | container.scrollTop = 0
8 | return
9 | }
10 |
11 | const offsetParents = []
12 | let pointer = selected.offsetParent
13 | while (
14 | pointer !== null &&
15 | container !== pointer &&
16 | container.contains(pointer)
17 | ) {
18 | offsetParents.push(pointer)
19 | pointer = pointer.offsetParent
20 | }
21 | const top =
22 | selected.offsetTop +
23 | offsetParents.reduce((prev, curr) => prev + curr.offsetTop, 0)
24 | const bottom = top + selected.offsetHeight
25 | const viewRectTop = container.scrollTop
26 | const viewRectBottom = viewRectTop + container.clientHeight
27 |
28 | if (top < viewRectTop) {
29 | container.scrollTop = top
30 | } else if (bottom > viewRectBottom) {
31 | container.scrollTop = bottom - container.clientHeight
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/utils/validator-size.js:
--------------------------------------------------------------------------------
1 | export const validSize = (val) => ['', 'large', 'default', 'small', 'mini'].includes(val)
2 |
--------------------------------------------------------------------------------
/src/utils/vnode.js:
--------------------------------------------------------------------------------
1 | import { Fragment, Text, Comment, createBlock, openBlock, createCommentVNode } from 'vue'
2 |
3 | const TEMPLATE = 'template'
4 |
5 | export const PatchFlags = {
6 | TEXT: 1,
7 | CLASS: 2,
8 | STYLE: 4,
9 | PROPS: 8,
10 | FULL_PROPS: 16,
11 | HYDRATE_EVENTS: 32,
12 | STABLE_FRAGMENT: 64,
13 | KEYED_FRAGMENT: 128,
14 | UNKEYED_FRAGMENT: 256,
15 | NEED_PATCH: 512,
16 | DYNAMIC_SLOTS: 1024,
17 | HOISTED: -1,
18 | BAIL: -2,
19 | }
20 |
21 | export const isFragment = (node) => node.type === Fragment
22 |
23 | export const isText = (node) => node.type === Text
24 |
25 | export const isComment = (node) => node.type === Comment
26 |
27 | export const isTemplate = (node) => node.type === TEMPLATE
28 |
29 | /**
30 | * get a valid child node (not fragment nor comment)
31 | * @param node {VNode} node to be searched
32 | * @param depth {number} depth to be searched
33 | */
34 | function getChildren(node, depth) {
35 | if (isComment(node)) return
36 | if (isFragment(node) || isTemplate(node)) {
37 | return depth > 0
38 | ? getFirstValidNode(node.children, depth - 1)
39 | : undefined
40 | }
41 | return node
42 | }
43 |
44 | /**
45 | * determine if the element is a valid element type rather than fragments and comment e.g. v-if
46 | * @param node {VNode} node to be tested
47 | */
48 | export const isValidElementNode = (node) =>
49 | !(isFragment(node) || isComment(node))
50 |
51 | export const getFirstValidNode = (nodes, maxDepth = 3) => {
52 | if (Array.isArray(nodes)) {
53 | return getChildren(nodes[0], maxDepth)
54 | } else {
55 | return getChildren(nodes, maxDepth)
56 | }
57 | }
58 |
59 | export function renderIf(condition, node, props, children, patchFlag, patchProps) {
60 | return (
61 | condition
62 | ? renderBlock(node, props, children, patchFlag, patchProps)
63 | : createCommentVNode('v-if', true)
64 | )
65 | }
66 |
67 | export function renderBlock(node, props, children, patchFlag, patchProps) {
68 | return (openBlock(), createBlock(node, props, children, patchFlag, patchProps))
69 | }
70 |
--------------------------------------------------------------------------------
]