├── pnpm-workspace.yaml ├── packages └── uni-ui │ ├── src │ ├── components │ │ ├── avatar-group │ │ │ ├── __tests__ │ │ │ │ ├── avatar.spec.d.ts │ │ │ │ ├── __snapshots__ │ │ │ │ │ └── avatar.spec.ts.snap │ │ │ │ └── avatar.spec.ts │ │ │ ├── index.scss │ │ │ ├── common.ts │ │ │ └── index.vue │ │ ├── form │ │ │ ├── index.scss │ │ │ ├── types.ts │ │ │ └── index.vue │ │ ├── config-provider │ │ │ ├── index.scss │ │ │ └── common.ts │ │ ├── checkbox-group │ │ │ ├── index.scss │ │ │ └── common.ts │ │ ├── common │ │ │ ├── create │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── props.ts │ │ │ ├── useVinContext.ts │ │ │ └── utils │ │ │ │ └── test │ │ │ │ └── event.ts │ │ ├── steps │ │ │ ├── index.scss │ │ │ ├── common.ts │ │ │ └── index.vue │ │ ├── form-item │ │ │ ├── types.ts │ │ │ └── common.ts │ │ ├── grid │ │ │ ├── index.scss │ │ │ ├── common.ts │ │ │ └── index.vue │ │ ├── tabbar │ │ │ ├── __test__ │ │ │ │ └── __snapshots__ │ │ │ │ │ └── index.spec.ts.snap │ │ │ ├── index.scss │ │ │ └── common.ts │ │ ├── overlay │ │ │ ├── index.scss │ │ │ ├── __tests__ │ │ │ │ └── __snapshots__ │ │ │ │ │ └── overlay.spec.ts.snap │ │ │ ├── common.ts │ │ │ └── index.vue │ │ ├── divider │ │ │ ├── __tests__ │ │ │ │ └── __snapshots__ │ │ │ │ │ └── divider.spec.ts.snap │ │ │ ├── common.ts │ │ │ ├── index.scss │ │ │ └── index.vue │ │ ├── tabpane │ │ │ ├── index.scss │ │ │ ├── common.ts │ │ │ └── index.vue │ │ ├── cell-group │ │ │ ├── test │ │ │ │ ├── __snapshots__ │ │ │ │ │ └── index.spec.ts.snap │ │ │ │ └── index.spec.ts │ │ │ ├── common.ts │ │ │ ├── index.scss │ │ │ └── index.vue │ │ ├── checkbox │ │ │ ├── __tests__ │ │ │ │ └── __snapshots__ │ │ │ │ │ └── checkbox.spec.ts.snap │ │ │ ├── index.scss │ │ │ └── common.ts │ │ ├── swiper │ │ │ ├── index.scss │ │ │ └── common.ts │ │ ├── radiogroup │ │ │ ├── index.scss │ │ │ ├── common.ts │ │ │ └── index.vue │ │ ├── row │ │ │ ├── __test__ │ │ │ │ └── index.spec.ts │ │ │ ├── common.ts │ │ │ ├── index.scss │ │ │ └── index.vue │ │ ├── switch │ │ │ ├── __tests__ │ │ │ │ └── __snapshots__ │ │ │ │ │ └── switch.spec.ts.snap │ │ │ ├── common.ts │ │ │ └── index.scss │ │ ├── col │ │ │ ├── common.ts │ │ │ ├── index.scss │ │ │ ├── __test__ │ │ │ │ ├── index.spec.ts │ │ │ │ └── __snapshots__ │ │ │ │ │ └── index.spec.ts.snap │ │ │ └── index.vue │ │ ├── button │ │ │ ├── __tests__ │ │ │ │ ├── __snapshots__ │ │ │ │ │ └── button.spec.ts.snap │ │ │ │ └── button.spec.ts │ │ │ └── common.ts │ │ ├── tag │ │ │ ├── __test__ │ │ │ │ ├── __snapshots__ │ │ │ │ │ └── tag.spec.ts.snap │ │ │ │ └── tag.spec.ts │ │ │ └── common.ts │ │ ├── backtop │ │ │ ├── index.scss │ │ │ └── common.ts │ │ ├── swipe │ │ │ ├── index.scss │ │ │ └── common.ts │ │ ├── list │ │ │ ├── index.scss │ │ │ ├── common.ts │ │ │ └── __tests__ │ │ │ │ └── list.spec.ts │ │ ├── comment-header │ │ │ └── common.ts │ │ ├── category │ │ │ ├── common.ts │ │ │ ├── index.scss │ │ │ └── index.vue │ │ ├── comment-bottom │ │ │ └── common.ts │ │ ├── uploader │ │ │ ├── __tests__ │ │ │ │ └── __snapshots__ │ │ │ │ │ └── index.spec.ts.snap │ │ │ └── type.ts │ │ ├── step │ │ │ └── common.ts │ │ ├── navbar │ │ │ ├── __test__ │ │ │ │ ├── __snapshots__ │ │ │ │ │ └── navbar.spec.ts.snap │ │ │ │ └── navbar.spec.ts │ │ │ └── common.ts │ │ ├── icon │ │ │ ├── __tests__ │ │ │ │ ├── __snapshots__ │ │ │ │ │ └── index.spec.ts.snap │ │ │ │ └── index.spec.ts │ │ │ ├── common.ts │ │ │ └── index.vue │ │ ├── notify │ │ │ ├── common.ts │ │ │ ├── index.scss │ │ │ └── __test__ │ │ │ │ └── notify.spec.ts │ │ ├── cell │ │ │ ├── common.ts │ │ │ ├── __tests__ │ │ │ │ └── __snapshots__ │ │ │ │ │ └── cell.spec.ts.snap │ │ │ └── index.scss │ │ ├── rate │ │ │ ├── index.scss │ │ │ └── common.ts │ │ ├── empty │ │ │ ├── index.scss │ │ │ ├── common.ts │ │ │ └── __tests__ │ │ │ │ └── index.spec.ts │ │ ├── badge │ │ │ ├── common.ts │ │ │ ├── index.scss │ │ │ ├── __test__ │ │ │ │ ├── __snapshots__ │ │ │ │ │ └── badge.spec.ts.snap │ │ │ │ └── badge.spec.ts │ │ │ └── index.vue │ │ ├── avatar │ │ │ ├── common.ts │ │ │ └── index.scss │ │ ├── cascader │ │ │ ├── types.ts │ │ │ └── common.ts │ │ ├── comment-images │ │ │ └── common.ts │ │ ├── searchbar │ │ │ ├── common.ts │ │ │ └── __tests__ │ │ │ │ └── __snapshots__ │ │ │ │ └── searchbar.spec.ts.snap │ │ ├── card │ │ │ └── common.ts │ │ ├── price │ │ │ ├── common.ts │ │ │ ├── index.scss │ │ │ └── __tests__ │ │ │ │ └── price.spec.ts │ │ ├── popup │ │ │ └── common.ts │ │ ├── input │ │ │ └── util.ts │ │ ├── radio │ │ │ ├── common.ts │ │ │ └── index.scss │ │ ├── grid-item │ │ │ └── common.ts │ │ ├── category-pane │ │ │ ├── common.ts │ │ │ └── index.scss │ │ ├── input-number │ │ │ ├── common.ts │ │ │ └── index.scss │ │ ├── textarea │ │ │ ├── index.scss │ │ │ └── common.ts │ │ ├── fixednav │ │ │ └── common.ts │ │ ├── tabbar-item │ │ │ └── common.ts │ │ ├── infiniteloading │ │ │ ├── common.ts │ │ │ └── index.scss │ │ ├── range │ │ │ └── common.ts │ │ ├── skeleton │ │ │ ├── __test__ │ │ │ │ └── __snapshots__ │ │ │ │ │ └── skeleton.spec.ts.snap │ │ │ ├── common.ts │ │ │ └── index.scss │ │ ├── dialog │ │ │ ├── common.ts │ │ │ ├── __tests__ │ │ │ │ └── index.spec.ts │ │ │ └── index.scss │ │ ├── action-sheet │ │ │ ├── __test__ │ │ │ │ └── __snapshots__ │ │ │ │ │ └── index.spec.ts.snap │ │ │ ├── common.ts │ │ │ └── index.scss │ │ ├── progress │ │ │ └── common.ts │ │ ├── calendar-item │ │ │ └── common.ts │ │ ├── tabs │ │ │ └── common.ts │ │ ├── calendar │ │ │ └── common.ts │ │ ├── comment │ │ │ └── __tests__ │ │ │ │ └── comment.spec.ts │ │ ├── noticebar │ │ │ └── common.ts │ │ ├── toast │ │ │ └── common.ts │ │ └── transition │ │ │ └── index.vue │ ├── styles │ │ ├── mixins │ │ │ ├── index.scss │ │ │ ├── text-ellipsis.scss │ │ │ └── make-animation.scss │ │ ├── font │ │ │ ├── iconfont.ttf │ │ │ ├── iconfont.woff │ │ │ └── iconfont.woff2 │ │ ├── extends │ │ │ ├── index.scss │ │ │ ├── theme │ │ │ │ ├── style.scss │ │ │ │ ├── dark.scss │ │ │ │ └── light.scss │ │ │ └── mixin.scss │ │ └── animation │ │ │ ├── index.scss │ │ │ ├── rotate.scss │ │ │ ├── fade.scss │ │ │ ├── ease.scss │ │ │ ├── zoom.scss │ │ │ └── drop.scss │ ├── shared │ │ ├── utils │ │ │ └── pxCheck.ts │ │ └── hooks │ │ │ ├── useRelation │ │ │ ├── useRelation.ts │ │ │ └── useInject.ts │ │ │ ├── useExpose.ts │ │ │ ├── index.ts │ │ │ ├── useRect │ │ │ └── index.ts │ │ │ ├── useRouter │ │ │ └── index.ts │ │ │ └── useTouch │ │ │ └── index.ts │ ├── locale │ │ ├── README.md │ │ └── index.ts │ └── resolver │ │ └── index.ts │ ├── vitest.config.ts │ ├── tsconfig.declaration.json │ ├── tsconfig.json │ ├── scripts │ └── build │ │ ├── const.js │ │ └── locale.js │ ├── LICENSE │ └── packs │ ├── npm │ └── LICENSE │ └── uni_modules │ └── LICENSE ├── .prettierrc.js ├── .husky ├── pre-commit └── commit-msg ├── commitlint.config.js ├── .prettierignore ├── docs ├── .vuepress │ ├── public │ │ ├── favicon.ico │ │ └── images │ │ │ ├── logo.png │ │ │ └── qrcode.jpg │ ├── styles │ │ ├── palette.styl │ │ └── index.scss │ ├── client.js │ ├── enhanceApp.js │ └── theme │ │ └── pathList.js ├── oss.config.js ├── package.json ├── guide │ ├── about.md │ ├── international.md │ └── theme.md ├── README.md └── components │ ├── divider.md │ ├── empty.md │ └── backtop.md ├── .eslintignore ├── .eslintrc.json ├── .npmrc ├── tsconfig.json ├── shims-vue.d.ts ├── example ├── src │ ├── main.ts │ ├── App.vue │ ├── hooks │ │ └── useTranslate.ts │ ├── pages │ │ └── components │ │ │ ├── divider.vue │ │ │ ├── textarea.vue │ │ │ └── list.vue │ └── styles │ │ └── demo.scss ├── oss.config.js ├── tsconfig.json ├── index.html ├── CHANGELOG.md ├── package.json └── vite.config.ts ├── .editorconfig ├── .stylelintrc ├── .changeset ├── config.json └── README.md ├── .gitignore ├── LICENSE ├── .workflow ├── pr-pipeline.yml ├── master-pipeline.yml └── branch-pipeline.yml └── .github └── workflows └── release.yml /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/** 3 | - docs 4 | - example 5 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/avatar-group/__tests__/avatar.spec.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('@vingogo/prettier-config'), 3 | }; 4 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/form/index.scss: -------------------------------------------------------------------------------- 1 | .vin-form { 2 | display: block; 3 | } 4 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | }; 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | dts 3 | docs/.vuepress/.temp 4 | docs/.vuepress/.cache 5 | docs/.vuepress/dist 6 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx commitlint --edit $1 5 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/mixins/index.scss: -------------------------------------------------------------------------------- 1 | @import 'make-animation.scss'; 2 | @import 'text-ellipsis.scss'; 3 | -------------------------------------------------------------------------------- /docs/.vuepress/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vingogo/vin-ui/HEAD/docs/.vuepress/public/favicon.ico -------------------------------------------------------------------------------- /packages/uni-ui/src/components/config-provider/index.scss: -------------------------------------------------------------------------------- 1 | /* stylelint-disable */ 2 | .vin-configprovider { 3 | } 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | locale 3 | font 4 | scripts 5 | build 6 | **/__tests__/**.ts 7 | *.json 8 | lib 9 | dts 10 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vingogo/eslint-config-vue", 3 | "rules": { 4 | "no-console": ["off"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /docs/.vuepress/public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vingogo/vin-ui/HEAD/docs/.vuepress/public/images/logo.png -------------------------------------------------------------------------------- /docs/.vuepress/public/images/qrcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vingogo/vin-ui/HEAD/docs/.vuepress/public/images/qrcode.jpg -------------------------------------------------------------------------------- /packages/uni-ui/src/components/checkbox-group/index.scss: -------------------------------------------------------------------------------- 1 | .vin-checkboxgroup { 2 | display: flex; 3 | flex-wrap: wrap; 4 | } 5 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/font/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vingogo/vin-ui/HEAD/packages/uni-ui/src/styles/font/iconfont.ttf -------------------------------------------------------------------------------- /docs/.vuepress/styles/palette.styl: -------------------------------------------------------------------------------- 1 | // 浅色模式 2 | .theme-mode-light 3 | --c-brand: red 4 | 5 | // 深色模式 6 | .theme-mode-dark 7 | --c-brand: red -------------------------------------------------------------------------------- /packages/uni-ui/src/components/common/create/index.ts: -------------------------------------------------------------------------------- 1 | import { createComponent } from './component'; 2 | 3 | export { createComponent }; 4 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/font/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vingogo/vin-ui/HEAD/packages/uni-ui/src/styles/font/iconfont.woff -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/font/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vingogo/vin-ui/HEAD/packages/uni-ui/src/styles/font/iconfont.woff2 -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | prefer-workspace-packages=true 2 | link-workspace-packages=true 3 | save-workspace-protocol=false 4 | auto-install-peers=false 5 | shamefully-hoist=true 6 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/common/index.ts: -------------------------------------------------------------------------------- 1 | export { default as commonProps } from './props'; 2 | export { default as useVinContext } from './useVinContext'; 3 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/steps/index.scss: -------------------------------------------------------------------------------- 1 | .vin-steps { 2 | display: flex; 3 | } 4 | .vin-steps-vertical { 5 | flex-flow: column; 6 | height: 100%; 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["node", "vite/client", "@dcloudio/types"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue'; 3 | 4 | const component: DefineComponent; 5 | export default component; 6 | } 7 | -------------------------------------------------------------------------------- /packages/uni-ui/src/shared/utils/pxCheck.ts: -------------------------------------------------------------------------------- 1 | export const pxCheck = (value: string | number): string => { 2 | return Number.isNaN(Number(value)) ? String(value) : `${value}px`; 3 | }; 4 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/extends/index.scss: -------------------------------------------------------------------------------- 1 | @import './var'; 2 | @import './theme/style'; 3 | @import './mixin'; 4 | @import './color'; 5 | @import './shadow'; 6 | @import './text'; 7 | @import './border'; 8 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/avatar-group/__tests__/__snapshots__/avatar.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`size props 1`] = `""`; 4 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/animation/index.scss: -------------------------------------------------------------------------------- 1 | // Animation 2 | @import 'fade.scss'; 3 | @import 'zoom.scss'; 4 | @import 'ease.scss'; 5 | @import 'drop.scss'; 6 | @import 'rotate.scss'; 7 | @import 'icon.scss'; 8 | -------------------------------------------------------------------------------- /docs/.vuepress/styles/index.scss: -------------------------------------------------------------------------------- 1 | html.dark, 2 | :root { 3 | // brand colors 4 | --c-brand: #f87d09; 5 | --c-brand-light: #f87d09; 6 | 7 | .sidebar::-webkit-scrollbar { 8 | width: 3px; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /example/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createSSRApp } from 'vue'; 2 | import App from './App.vue'; 3 | 4 | export function createApp() { 5 | const app = createSSRApp(App); 6 | 7 | return { 8 | app, 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /docs/.vuepress/client.js: -------------------------------------------------------------------------------- 1 | import { defineClientConfig } from '@vuepress/client'; 2 | import Layout from './theme/layouts/Layout.vue'; 3 | 4 | export default defineClientConfig({ 5 | layouts: { 6 | Layout, 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /docs/oss.config.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-var-requires 2 | const dotenv = require('dotenv'); 3 | 4 | dotenv.config(); 5 | 6 | module.exports = { 7 | bucket: 'vingogo', 8 | region: 'oss-cn-guangzhou', 9 | }; 10 | -------------------------------------------------------------------------------- /example/oss.config.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-var-requires 2 | const dotenv = require('dotenv'); 3 | 4 | dotenv.config(); 5 | 6 | module.exports = { 7 | bucket: 'vingogo', 8 | region: 'oss-cn-guangzhou', 9 | }; 10 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/animation/rotate.scss: -------------------------------------------------------------------------------- 1 | @keyframes rotation { 2 | 0% { 3 | -webkit-transform: rotate(0deg); 4 | } 5 | 100% { 6 | -webkit-transform: rotate(360deg); 7 | } 8 | } 9 | 10 | @include make-animation(vinRotate); 11 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/form-item/types.ts: -------------------------------------------------------------------------------- 1 | export class FormItemRule { 2 | regex?: RegExp; 3 | 4 | required?: boolean; 5 | 6 | message!: string; 7 | 8 | validator?: (value: any) => boolean | string | Promise; 9 | } 10 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/form/types.ts: -------------------------------------------------------------------------------- 1 | import { FormItemRule } from '../form-item/types'; 2 | 3 | export type FormRule = { 4 | prop: string; 5 | rules: FormItemRule[]; 6 | }; 7 | export type ErrorMessage = { 8 | prop: string; 9 | message: string; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/grid/index.scss: -------------------------------------------------------------------------------- 1 | .vin-grid { 2 | display: flex; 3 | flex-wrap: wrap; 4 | width: 100%; 5 | border: 0 solid $grid-border-color; 6 | 7 | &--border { 8 | border-top-width: 1px; 9 | border-left-width: 1px; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/tabbar/__test__/__snapshots__/index.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should render fixed element when using bottom prop 1`] = `""`; 4 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/overlay/index.scss: -------------------------------------------------------------------------------- 1 | .vin-overlay { 2 | position: fixed; 3 | top: 0; 4 | left: 0; 5 | width: 100%; 6 | height: 100%; 7 | background: $overlay-bg-color; 8 | } 9 | 10 | .vin-overflow-hidden { 11 | overflow: hidden !important; 12 | } 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | end_of_line = lf 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/divider/__tests__/__snapshots__/divider.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`slot: html should contain customer text 1`] = `"customer text"`; 4 | -------------------------------------------------------------------------------- /docs/.vuepress/enhanceApp.js: -------------------------------------------------------------------------------- 1 | export default ({ router }) => { 2 | router.beforeEach((to, from, next) => { 3 | if (typeof _hmt !== 'undefined') { 4 | if (to.path) { 5 | _hmt.push(['_trackPageview', to.fullPath]); 6 | } 7 | } 8 | 9 | next(); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/overlay/__tests__/__snapshots__/overlay.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`slots test 1`] = `"这里是正文"`; 4 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/tabpane/index.scss: -------------------------------------------------------------------------------- 1 | .vin-tabpane { 2 | display: block; 3 | flex-shrink: 0; 4 | box-sizing: border-box; 5 | width: 100%; 6 | padding: 24px 20px; 7 | overflow: auto; 8 | background-color: #fff; 9 | &.active { 10 | // overflow: visible; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/cell-group/test/__snapshots__/index.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should render title、desc slot correctly 1`] = ` 4 | "Custom TitleCustom Desc 5 | " 6 | `; 7 | -------------------------------------------------------------------------------- /example/src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/animation/fade.scss: -------------------------------------------------------------------------------- 1 | @keyframes vinFadeIn { 2 | from { 3 | opacity: 0; 4 | } 5 | 6 | to { 7 | opacity: 1; 8 | } 9 | } 10 | 11 | @keyframes vinFadeOut { 12 | from { 13 | opacity: 1; 14 | } 15 | 16 | to { 17 | opacity: 0; 18 | } 19 | } 20 | @include make-animation(vinFade); 21 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/checkbox/__tests__/__snapshots__/checkbox.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`basic usage 1`] = ` 4 | " 5 | 6 | " 7 | `; 8 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@vingogo/stylelint-config"], 3 | "ignoreFiles": ["**/*.js", "**/*.jsx", "**/*.tsx", "**/*.ts", "**/*.md"], 4 | "defaultSeverity": "warning", 5 | "rules": { 6 | "selector-pseudo-class-no-unknown": [ 7 | true, 8 | { 9 | "ignorePseudoClasses": ["deep"] 10 | } 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/uni-ui/src/shared/hooks/useRelation/useRelation.ts: -------------------------------------------------------------------------------- 1 | import { getCurrentInstance } from 'vue'; 2 | import type { ComponentPublicInstance } from 'vue'; 3 | 4 | export function useExtend(apis: T) { 5 | const instance = getCurrentInstance(); 6 | if (instance) { 7 | Object.assign(instance.proxy as ComponentPublicInstance, apis); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/uni-ui/src/shared/hooks/useExpose.ts: -------------------------------------------------------------------------------- 1 | import { getCurrentInstance } from 'vue'; 2 | import type { ComponentPublicInstance } from 'vue'; 3 | 4 | export function useExpose(apis: Record) { 5 | const instance = getCurrentInstance(); 6 | if (instance) { 7 | Object.assign(instance.proxy as ComponentPublicInstance, apis); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/cell-group/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const cellGroupProps = { 5 | ...commonProps, 6 | title: { type: String, default: '' }, 7 | desc: { type: String, default: '' }, 8 | }; 9 | 10 | export type CellGroupProps = ExtractPropTypes; 11 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/swiper/index.scss: -------------------------------------------------------------------------------- 1 | .vin-swiper { 2 | position: relative; 3 | z-index: 1; 4 | display: flex; 5 | box-sizing: content-box; 6 | overflow: hidden; 7 | cursor: grab; 8 | transition-property: transform; 9 | user-select: none; 10 | 11 | &__wrapper { 12 | position: relative; 13 | } 14 | } 15 | 16 | .vin-swiper-item { 17 | height: 100%; 18 | } 19 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/radiogroup/index.scss: -------------------------------------------------------------------------------- 1 | .vin-radiogroup { 2 | display: inline-block; 3 | .vin-radio { 4 | margin-bottom: 5px; 5 | } 6 | &--horizontal { 7 | .vin-radio { 8 | display: inline-flex; 9 | margin-right: 10px; 10 | &--round { 11 | .vin-radio__label { 12 | margin: 0 6px; 13 | } 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/row/__test__/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils'; 2 | import Row from '../index.vue'; 3 | 4 | test('should add "vin-row-flex-nowrap" class when wrap prop is false', () => { 5 | const wrapper = mount(Row, { 6 | props: { 7 | wrap: 'nowrap', 8 | }, 9 | }); 10 | expect(wrapper.classes()).toContain('vin-row-flex-nowrap'); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/uni-ui/src/shared/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { default as useRect } from './useRect'; 2 | export { useInject } from './useRelation/useInject'; 3 | export { useProvide } from './useRelation/useProvide'; 4 | export { useExtend } from './useRelation/useRelation'; 5 | export { default as useRouter } from './useRouter'; 6 | export { useTouch } from './useTouch'; 7 | export { useExpose } from './useExpose'; 8 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/config-provider/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const configProviderProps = { 5 | ...commonProps, 6 | theme: { type: String, default: '' }, 7 | themeVars: { type: Object, default: {} }, 8 | }; 9 | 10 | export type ConfigProviderProps = ExtractPropTypes; 11 | -------------------------------------------------------------------------------- /packages/uni-ui/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config'; 2 | 3 | import vue from '@vitejs/plugin-vue'; 4 | import uni from '@dcloudio/vite-plugin-uni'; 5 | 6 | export default defineConfig({ 7 | plugins: [ 8 | uni(), 9 | vue({ 10 | include: [/\.vue$/, /\.md$/], 11 | }), 12 | ], 13 | test: { 14 | globals: true, 15 | environment: 'jsdom', 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/switch/__tests__/__snapshots__/switch.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`render ok 1`] = ` 4 | " 5 | 6 | 7 | 8 | 9 | 10 | " 11 | `; 12 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", 3 | "changelog": [ 4 | "@changesets/changelog-github", 5 | { 6 | "repo": "vingogo/vin-ui" 7 | } 8 | ], 9 | "commit": false, 10 | "fixed": [], 11 | "linked": [], 12 | "access": "restricted", 13 | "baseBranch": "main", 14 | "updateInternalDependencies": "patch", 15 | "ignore": [] 16 | } 17 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/cell-group/test/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils'; 2 | import CellGroup from '../index.vue'; 3 | 4 | test('should render title、desc slot correctly', () => { 5 | const wrapper = mount(CellGroup, { 6 | slots: { 7 | title: () => 'Custom Title', 8 | desc: () => 'Custom Desc', 9 | }, 10 | }); 11 | expect(wrapper.html()).toMatchSnapshot(); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/form/index.vue: -------------------------------------------------------------------------------- 1 | 8 | 13 | 14 | 17 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/col/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const colProps = { 5 | ...commonProps, 6 | span: { 7 | type: [String, Number], 8 | default: '24', 9 | }, 10 | offset: { 11 | type: [String, Number], 12 | default: '0', 13 | }, 14 | }; 15 | 16 | export type ColProps = ExtractPropTypes; 17 | -------------------------------------------------------------------------------- /packages/uni-ui/src/locale/README.md: -------------------------------------------------------------------------------- 1 | ### VinUI 语言包 2 | 3 | 目前支持的语言: 4 | 5 | | 语言 | 文件名 | 版本 | 6 | | -------- | ------ | -------- | 7 | | 英语 | en-US | `v0.1.0` | 8 | | 简体中文 | zh-CN | `v0.1.0` | 9 | | 繁體中文 | zh-TW | `v0.1.0` | 10 | 11 | ## 常见问题 12 | 13 | ### 找不到所需的语言包? 14 | 15 | 如果上方列表中没有你需要的语言,欢迎给我们提 Pull Request 来增加新的语言包。 16 | 17 | ### 业务代码如何实现国际化? 18 | 19 | 可以使用 [vue-i18n](https://github.com/kazupon/vue-i18n) 来实现。 20 | -------------------------------------------------------------------------------- /packages/uni-ui/src/resolver/index.ts: -------------------------------------------------------------------------------- 1 | export default function VinUIResolver() { 2 | return (name: string) => { 3 | if (name.match(/^(Vin[A-Z]|vin-[a-z])/)) { 4 | const cName = name 5 | .slice(3) 6 | .replace(/([a-z])([A-Z])/, '$1-$2') 7 | .toLowerCase(); 8 | return { 9 | name, 10 | from: `@vingogo/uni-ui/lib/components/${cName}/index.vue`, 11 | }; 12 | } 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/animation/ease.scss: -------------------------------------------------------------------------------- 1 | @keyframes vinEaseIn { 2 | 0% { 3 | transform: scale(0.9); 4 | opacity: 0; 5 | } 6 | 100% { 7 | transform: scale(1); 8 | opacity: 1; 9 | } 10 | } 11 | 12 | @keyframes vinEaseOut { 13 | 0% { 14 | transform: scale(1); 15 | opacity: 1; 16 | } 17 | 100% { 18 | transform: scale(0.9); 19 | opacity: 0; 20 | } 21 | } 22 | 23 | @include make-animation(vinEase); 24 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/avatar-group/index.scss: -------------------------------------------------------------------------------- 1 | .vin-avatar-group { 2 | position: relative; 3 | display: inline-block; 4 | flex: 0 0 auto; // 防止被压缩 5 | background-repeat: no-repeat; 6 | background-position: center center; 7 | background-size: 100% 100%; 8 | 9 | .vin-avatar, 10 | ::v-deep .vin-avatar { 11 | border: 1px solid #fff; 12 | 13 | &:not(:first-of-type) { 14 | margin-left: -8px; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /docs/.vuepress/theme/pathList.js: -------------------------------------------------------------------------------- 1 | import config from '../../../config.json'; 2 | 3 | export default config.list.reduce((prev, next) => { 4 | return prev.concat( 5 | next.components.map(({ name }) => { 6 | return { 7 | parentPath: `/components/${name.replace(/\B([A-Z])/g, '-$1').toLocaleLowerCase()}.html`, 8 | childrenPath: `pages/components/${name.toLowerCase().replace('-', '')}`, 9 | }; 10 | }), 11 | ); 12 | }, []); 13 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/checkbox-group/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const checkboxGroupProps = { 5 | ...commonProps, 6 | modelValue: { 7 | type: Array, 8 | default: () => [], 9 | }, 10 | disabled: { 11 | type: Boolean, 12 | default: false, 13 | }, 14 | }; 15 | 16 | export type CheckboxGroupProps = ExtractPropTypes; 17 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/common/props.ts: -------------------------------------------------------------------------------- 1 | import type { CSSProperties, PropType, ExtractPropTypes } from 'vue'; 2 | 3 | const commonProps = { 4 | customClass: { 5 | type: [String, Array], 6 | default: '', 7 | }, 8 | customStyle: { 9 | type: [String, Object] as PropType, 10 | default: '', 11 | }, 12 | }; 13 | 14 | export type CommonProps = ExtractPropTypes; 15 | 16 | export default commonProps; 17 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/animation/zoom.scss: -------------------------------------------------------------------------------- 1 | @keyframes vinZoomIn { 2 | from { 3 | transform: scale3d(0.3, 0.3, 0.3); 4 | opacity: 0; 5 | } 6 | 7 | 50% { 8 | opacity: 1; 9 | } 10 | } 11 | 12 | @keyframes vinZoomOut { 13 | from { 14 | opacity: 1; 15 | } 16 | 17 | 50% { 18 | transform: scale3d(0.3, 0.3, 0.3); 19 | opacity: 0; 20 | } 21 | 22 | to { 23 | opacity: 0; 24 | } 25 | } 26 | @include make-animation(vinZoom); 27 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/animation/drop.scss: -------------------------------------------------------------------------------- 1 | @keyframes vinDropIn { 2 | 0% { 3 | transform: scaleY(0.8); 4 | opacity: 0; 5 | } 6 | 100% { 7 | transform: scaleY(1); 8 | opacity: 1; 9 | } 10 | } 11 | 12 | @keyframes vinDropOut { 13 | 0% { 14 | transform: scaleY(1); 15 | opacity: 1; 16 | } 17 | 100% { 18 | transform: scaleY(0.8); 19 | opacity: 0; 20 | } 21 | } 22 | 23 | // select、dropdown 24 | @include make-animation(vinDrop); 25 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue", "src/**/*.tsx"], 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "paths": { 7 | "@/*": ["src/*"] 8 | }, 9 | "types": ["@dcloudio/types"], 10 | "jsx": "preserve" 11 | }, 12 | "vueCompilerOptions": { 13 | "experimentalRuntimeMode": "runtime-uni-app", 14 | "nativeTags": ["block", "component", "template", "slot"] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/button/__tests__/__snapshots__/button.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should change icon class prefix when using icon-class-prefix prop 1`] = ` 4 | "" 10 | `; 11 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/tag/__test__/__snapshots__/tag.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should hide tag when the show prop is false 1`] = ` 4 | " 5 | 6 | " 7 | `; 8 | 9 | exports[`should render textColor correctly 1`] = ` 10 | " 11 | 12 | " 13 | `; 14 | -------------------------------------------------------------------------------- /packages/uni-ui/tsconfig.declaration.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "compilerOptions": { 4 | "moduleResolution": "node", 5 | "declaration": true, 6 | "declarationDir": "./dts/types", 7 | "emitDeclarationOnly": true 8 | }, 9 | "include": ["./src/**/*.d.ts", "./src/**/*.ts", "./src/**/*.vue"], 10 | "exclude": [ 11 | "node_modules", 12 | "**/__test__/**/*", 13 | "**/__tests__/**/*", 14 | "**/*/common.ts", 15 | "vitest.config.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | coverage 5 | lib 6 | dts 7 | 8 | # local env files 9 | .env 10 | .env.local 11 | .env.*.local 12 | 13 | # Log files 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | 18 | # Editor directories and files 19 | .project 20 | .idea 21 | .vscode 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw* 27 | .hbuilderx 28 | **/*-sfc.ts 29 | .cache 30 | .temp 31 | 32 | unpackage/ 33 | wxcomponents 34 | packages/uni-ui/uni_modules 35 | 36 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/backtop/index.scss: -------------------------------------------------------------------------------- 1 | .vin-backtop { 2 | position: fixed; 3 | display: none; 4 | &.show { 5 | display: flex; 6 | align-items: center; 7 | justify-content: center; 8 | width: 40px; 9 | height: 40px; 10 | background: $white; 11 | border: 1px solid $backtop-border-color; 12 | border-radius: 50%; 13 | } 14 | &.show :active { 15 | background: rgba(0, 0, 0, 0.1); 16 | } 17 | &-main { 18 | transition: all 0.2s ease-in-out; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/swipe/index.scss: -------------------------------------------------------------------------------- 1 | .vin-swipe { 2 | position: relative; 3 | display: block; 4 | transition: all 0.3s cubic-bezier(0.19, 1, 0.22, 1); 5 | &__left, 6 | &__right { 7 | position: absolute; 8 | top: 0; 9 | height: 100%; 10 | } 11 | &__left { 12 | left: 0; 13 | transform: translate3d(-100%, 0, 0); 14 | } 15 | &__right { 16 | right: 0; 17 | transform: translate3d(100%, 0, 0); 18 | } 19 | &__content { 20 | display: inherit; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/divider/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const dividerProps = { 5 | ...commonProps, 6 | contentPosition: { 7 | type: String, 8 | default: 'center', 9 | }, 10 | dashed: { 11 | type: Boolean, 12 | default: false, 13 | }, 14 | hairline: { 15 | type: Boolean, 16 | default: true, 17 | }, 18 | }; 19 | 20 | export type DividerProps = ExtractPropTypes; 21 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/steps/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const stepsProps = { 5 | ...commonProps, 6 | direction: { 7 | type: String, 8 | default: 'horizontal', 9 | }, 10 | current: { 11 | type: [String, Number], 12 | default: '0', 13 | }, 14 | progressDot: { 15 | type: Boolean, 16 | default: false, 17 | }, 18 | }; 19 | 20 | export type StepsProps = ExtractPropTypes; 21 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/tabpane/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const tabpaneProps = { 5 | ...commonProps, 6 | title: { 7 | type: [String, Number], 8 | default: '', 9 | }, 10 | paneKey: { 11 | type: [String, Number], 12 | default: '', 13 | }, 14 | disabled: { 15 | type: Boolean, 16 | default: false, 17 | }, 18 | }; 19 | 20 | export type TabpaneProps = ExtractPropTypes; 21 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/list/index.scss: -------------------------------------------------------------------------------- 1 | .vin-list { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | overflow: scroll; 6 | -webkit-overflow-scrolling: touch; 7 | &-phantom { 8 | position: absolute; 9 | top: 0; 10 | right: 0; 11 | left: 0; 12 | z-index: -1; 13 | } 14 | &-container { 15 | position: absolute; 16 | top: 0; 17 | right: 0; 18 | left: 0; 19 | } 20 | &-item { 21 | margin: $list-item-margin; 22 | overflow: hidden; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/col/index.scss: -------------------------------------------------------------------------------- 1 | .vin-col { 2 | float: left; 3 | box-sizing: border-box; 4 | word-break: break-all; 5 | 6 | &-gutter { 7 | &:last-child { 8 | padding-right: 0 !important; 9 | } 10 | &:first-child { 11 | padding-left: 0 !important; 12 | } 13 | } 14 | } 15 | 16 | @for $i from 1 through 24 { 17 | .vin-col-offset-#{$i} { 18 | margin-left: calc(100 / 24 * $i * 1%); 19 | } 20 | 21 | .vin-col-#{$i} { 22 | width: calc(100 / 24 * $i * 1%); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/radiogroup/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const radioGroupProps = { 5 | ...commonProps, 6 | modelValue: { 7 | type: [Number, String, Boolean], 8 | default: '', 9 | }, 10 | textPosition: { 11 | type: String, 12 | default: 'right', 13 | }, 14 | direction: { 15 | type: String, 16 | default: 'vertical', 17 | }, 18 | }; 19 | 20 | export type RadioGroupProps = ExtractPropTypes; 21 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/comment-header/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const commonHeaderProps = { 5 | ...commonProps, 6 | type: { 7 | type: String, 8 | default: 'default', // default,complex 9 | }, 10 | info: { 11 | type: Object, 12 | default: () => ({}), 13 | }, 14 | labels: { 15 | type: Function, 16 | default: () => '', 17 | }, 18 | }; 19 | 20 | export type CommonHeaderProps = ExtractPropTypes; 21 | -------------------------------------------------------------------------------- /packages/uni-ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "exclude": ["**/lib/**", "**/locale/**"], 4 | "include": ["**/*.ts", "**/*.d.ts", "**/*.vue", "**/*.tsx"], 5 | "compilerOptions": { 6 | "types": ["@dcloudio/types", "vitest/globals", "jest"], 7 | "jsx": "preserve" 8 | }, 9 | "vueCompilerOptions": { 10 | "experimentalRuntimeMode": "runtime-uni-app", 11 | "nativeTags": ["block", "component", "template", "slot"], 12 | // TODO: 构建暂不支持处理 template 中的 ts 类型 13 | "skipTemplateCodegen": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/mixins/text-ellipsis.scss: -------------------------------------------------------------------------------- 1 | @mixin text-ellipsis() { 2 | overflow: hidden; 3 | white-space: nowrap; 4 | text-overflow: ellipsis; 5 | } 6 | // 单行超长省略号 7 | @mixin oneline-ellipsis($width: 100%) { 8 | width: $width; 9 | overflow: hidden; 10 | white-space: nowrap; 11 | text-overflow: ellipsis; 12 | } 13 | // 多行超长省略号 14 | @mixin moreline-ellipsis($line: 2, $width: 100%) { 15 | display: -webkit-box; 16 | -webkit-box-orient: vertical; 17 | -webkit-line-clamp: $line; 18 | overflow: hidden; 19 | word-break: break-all; 20 | } 21 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/list/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const listProps = { 5 | ...commonProps, 6 | height: { 7 | type: [Number], 8 | default: 0, 9 | }, 10 | listData: { 11 | type: Array, 12 | default: () => { 13 | return []; 14 | }, 15 | }, 16 | containerHeight: { 17 | type: Number, 18 | default: uni?.getSystemInfoSync?.()?.windowHeight || 667, 19 | }, 20 | }; 21 | 22 | export type ListProps = ExtractPropTypes; 23 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/avatar-group/__tests__/avatar.spec.ts: -------------------------------------------------------------------------------- 1 | import { config, mount } from '@vue/test-utils'; 2 | import AvatarGroup from '../index.vue'; 3 | import Icon from '../../icon/index.vue'; 4 | 5 | beforeAll(() => { 6 | config.global.components = { 7 | Icon, 8 | }; 9 | }); 10 | 11 | afterAll(() => { 12 | config.global.components = {}; 13 | }); 14 | 15 | test('size props', async () => { 16 | const wrapper = mount(AvatarGroup, { 17 | props: { 18 | size: 'small', 19 | }, 20 | }); 21 | expect(wrapper.html()).toMatchSnapshot(); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/swipe/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const swipeProps = { 5 | ...commonProps, 6 | name: { 7 | type: String, 8 | default: '', 9 | }, 10 | disabled: { 11 | type: Boolean, 12 | default: false, 13 | }, 14 | touchMoveStopPropagation: { 15 | type: Boolean, 16 | default: false, 17 | }, 18 | touchMovePreventDefault: { 19 | type: Boolean, 20 | default: false, 21 | }, 22 | }; 23 | 24 | export type SwipeProps = ExtractPropTypes; 25 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/extends/theme/style.scss: -------------------------------------------------------------------------------- 1 | @import './light'; 2 | @import './dark'; 3 | 4 | // 多主题 5 | .theme-light { 6 | position: relative; 7 | z-index: 1; 8 | 9 | @include theme-light; 10 | } 11 | 12 | .theme-dark { 13 | position: relative; 14 | z-index: 1; 15 | 16 | @include theme-dark; 17 | } 18 | 19 | .theme-auto { 20 | position: relative; 21 | z-index: 1; 22 | 23 | @include theme-light; 24 | } 25 | 26 | @media (prefers-color-scheme: dark) { 27 | .theme-auto { 28 | position: relative; 29 | z-index: 1; 30 | 31 | @include theme-dark; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/category/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, PropType } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export type CategoryType = { 5 | catName?: string; 6 | [key: string]: any; 7 | }; 8 | 9 | export const categoryProps = { 10 | ...commonProps, 11 | // 分类模式 12 | type: { 13 | type: String, 14 | default: 'classify', 15 | }, 16 | 17 | // 左侧导航栏 18 | category: { 19 | type: Array as PropType, 20 | default: () => [], 21 | }, 22 | }; 23 | 24 | export type CategoryProps = ExtractPropTypes; 25 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/comment-bottom/common.ts: -------------------------------------------------------------------------------- 1 | import type { PropType, ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const commonBottomProps = { 5 | ...commonProps, 6 | type: { 7 | type: String, 8 | default: 'base', // simple,base,complex 9 | }, 10 | info: { 11 | type: Object, 12 | default: () => ({}), 13 | }, 14 | 15 | operation: { 16 | type: Array as PropType, 17 | default: ['replay', 'like', 'more'], 18 | }, 19 | }; 20 | 21 | export type CommonBottomProps = ExtractPropTypes; 22 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/uploader/__tests__/__snapshots__/index.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`render preview image 1`] = ` 4 | " 5 | 6 | 7 | " 8 | `; 9 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/col/__test__/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils'; 2 | import Col from '../index.vue'; 3 | import Row from '../../row/index.vue'; 4 | 5 | // 测试用例 6 | test('should render Col correctly and should render gutter correctly', async () => { 7 | const wrapper = mount({ 8 | components: { 9 | Row, 10 | Col, 11 | }, 12 | template: ` 13 | 14 | 8 15 | 8 16 | 8 17 | 18 | `, 19 | }); 20 | expect(wrapper.html()).toMatchSnapshot(); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/step/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const stepProps = { 5 | ...commonProps, 6 | title: { 7 | type: String, 8 | default: '', 9 | }, 10 | content: { 11 | type: String, 12 | default: '', 13 | }, 14 | icon: { 15 | type: String, 16 | default: null, 17 | }, 18 | iconColor: { 19 | type: String, 20 | default: '', 21 | }, 22 | size: { 23 | type: [String, Number], 24 | default: '12px', 25 | }, 26 | }; 27 | 28 | export type StepProps = ExtractPropTypes; 29 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/backtop/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const backtopProps = { 5 | ...commonProps, 6 | height: { 7 | type: String, 8 | default: '100vh', 9 | }, 10 | bottom: { 11 | type: Number, 12 | default: 20, 13 | }, 14 | right: { 15 | type: Number, 16 | default: 10, 17 | }, 18 | distance: { 19 | type: Number, 20 | default: 200, 21 | }, 22 | zIndex: { 23 | type: Number, 24 | default: 10, 25 | }, 26 | }; 27 | 28 | export type BacktopProps = ExtractPropTypes; 29 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/row/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const rowProps = { 5 | ...commonProps, 6 | type: { 7 | type: String, 8 | default: '', 9 | }, 10 | gutter: { 11 | type: [String, Number], 12 | default: '', 13 | }, 14 | justify: { 15 | type: String, 16 | default: 'start', 17 | }, 18 | align: { 19 | type: String, 20 | default: 'flex-start', 21 | }, 22 | wrap: { 23 | type: String, 24 | default: 'nowrap', 25 | }, 26 | }; 27 | 28 | export type RowProps = ExtractPropTypes; 29 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.1.0", 4 | "private": true, 5 | "license": "MIT", 6 | "scripts": { 7 | "dev": "vuepress dev .", 8 | "build": "vuepress build .", 9 | "deploy": "npm run build && static-upload start --prefix=docs --directory=.vuepress/dist" 10 | }, 11 | "devDependencies": { 12 | "vuepress": "2.0.0-beta.61", 13 | "@vuepress/client": "2.0.0-beta.61", 14 | "@vuepress/plugin-search": "2.0.0-beta.61", 15 | "@vuepress/theme-default": "2.0.0-beta.61", 16 | "vuepress-plugin-copy-code2": "2.0.0-beta.199", 17 | "vuepress-plugin-md-enhance": "2.0.0-beta.199" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/navbar/__test__/__snapshots__/navbar.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should render left slot correctly 1`] = `"Custom Left"`; 4 | 5 | exports[`should render left slot correctly 2`] = ` 6 | " 7 | Custom Right 8 | " 9 | `; 10 | 11 | exports[`should render title slot correctly 1`] = ` 12 | " 13 | 14 | 15 | " 16 | `; 17 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/tabbar/index.scss: -------------------------------------------------------------------------------- 1 | .vin-tabbar { 2 | display: flex; 3 | box-sizing: border-box; 4 | width: 100%; 5 | padding: 7px 0; 6 | background: $white; 7 | border: 0; 8 | border-top: $tabbar-border-top; 9 | border-bottom: $tabbar-border-bottom; 10 | box-shadow: $tabbar-box-shadow; 11 | 12 | &:last-child { 13 | border-right: 0; 14 | } 15 | 16 | &-bottom { 17 | position: fixed; 18 | bottom: 0; 19 | left: 0; 20 | z-index: 888; 21 | } 22 | 23 | &-safebottom { 24 | margin-bottom: constant(safe-area-inset-bottom); 25 | margin-bottom: env(safe-area-inset-bottom); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/uploader/type.ts: -------------------------------------------------------------------------------- 1 | export type SizeType = 'original' | 'compressed'; 2 | export type SourceType = 'album' | 'camera' | 'user' | 'environment'; 3 | export type FileItemStatus = 'ready' | 'uploading' | 'success' | 'error'; 4 | export type AcceptType = 'image' | 'media' | 'video' | 'all'; 5 | export type FileType = 'image' | 'video' | 'audio'; 6 | export type FileItem = { 7 | status: FileItemStatus; 8 | 9 | message: string; 10 | 11 | uid: string; 12 | 13 | name: string; 14 | 15 | url?: string; 16 | 17 | type?: FileType; 18 | 19 | path?: string; 20 | 21 | percentage: string | number; 22 | 23 | formData: any; 24 | }; 25 | -------------------------------------------------------------------------------- /docs/guide/about.md: -------------------------------------------------------------------------------- 1 | # 关于 2 | 3 | VIN 没有太多特殊的含义,截取的英文名的后 3 个字母,看起来也挺和谐,与 Vue 发音也有那么一堆堆接近,于是命名之... 4 | 5 | VIN 目前个人业务时间维护中,但希望更多志同道合的人参与进来,做一些有趣的事情,不只是 VinUI 哦~ 6 | 7 | ## 作者 8 | 9 | 英文名:Alvin,网名“橙子三个半”,目前在广州,某互联网公司仍在职员工。 10 | 11 | 关于 VIN,非 KPI 项目,业务时间用爱发电中。 12 | 13 | 主业以 React 技术栈,但仍不乏对 Vue 的喜爱,从 Vue 2 开始使用,也有过几个生产实际的项目经历。 14 | 15 | 如果有更多需要交流,可以加个微信,加时麻烦备注:VIN 16 | 17 |

18 | logo 19 |

20 | 21 | ## VinUI 22 | 23 | `VinUI` 目前发布的 npm 包名称为 `@vingogo/uni-ui`, `@vingogo/uni-ui` 会作为 VinUI 的 uniapp 版本 24 | 25 | 但是 VinUI 的目标不只是服务于 uniapp,目前正在规划一些其他的平台使用,敬请期待... 26 | -------------------------------------------------------------------------------- /packages/uni-ui/scripts/build/const.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require('path'); 2 | 3 | const packDirMap = { 4 | UNI: resolve(__dirname, `../../packs/uni_modules`), 5 | NPM: resolve(__dirname, `../../packs/npm`), 6 | }; 7 | 8 | const destMap = { 9 | UNI: resolve(__dirname, `../../uni_modules`), 10 | NPM: resolve(__dirname, `../../lib`), 11 | }; 12 | 13 | exports.TYPES_DIR = resolve(__dirname, `../../dts/types`); 14 | exports.PACK_DIR = packDirMap[process.env.MODE] || packDirMap['NPM']; 15 | exports.SRC_DIR = resolve(__dirname, `../../src`); 16 | exports.LIB_DIR = destMap[process.env.MODE] || destMap['NPM']; 17 | exports.UNI_DIR = resolve(__dirname, `../src/uni_modules`); 18 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/overlay/common.ts: -------------------------------------------------------------------------------- 1 | import type { CSSProperties, PropType } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const overlayProps = { 5 | ...commonProps, 6 | visible: { 7 | type: Boolean, 8 | default: false, 9 | }, 10 | zIndex: { 11 | type: [Number, String], 12 | default: 2000, 13 | }, 14 | duration: { 15 | type: [Number, String], 16 | default: 300, 17 | }, 18 | overlayClass: { 19 | type: String, 20 | default: '', 21 | }, 22 | overlayStyle: { 23 | type: Object as PropType, 24 | }, 25 | closeOnClickOverlay: { 26 | type: Boolean, 27 | default: true, 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/icon/__tests__/__snapshots__/index.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should render icon fabulous 1`] = `""`; 4 | 5 | exports[`should render icon fabulous color 1`] = `""`; 6 | 7 | exports[`should render icon fabulous size 1`] = `""`; 8 | 9 | exports[`should render icon image type 1`] = `""`; 10 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/icon/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, PropType } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const iconProps = { 5 | ...commonProps, 6 | name: { type: String, default: '' }, 7 | color: { type: String, default: '' }, 8 | size: { type: [String, Number], default: '' }, 9 | fontClassName: { 10 | type: String, 11 | default: 'vin-iconfont', 12 | }, 13 | classPrefix: { 14 | type: String, 15 | default: 'vin-icon', 16 | }, 17 | tag: { 18 | type: String as PropType, 19 | default: 'text', 20 | }, 21 | }; 22 | 23 | export type IconProps = ExtractPropTypes; 24 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/mixins/make-animation.scss: -------------------------------------------------------------------------------- 1 | @mixin make-animation( 2 | $keyframeName, 3 | $timingFun: $animation-timing-fun, 4 | $duration: $animation-duration 5 | ) { 6 | .#{$keyframeName}-enter-active, 7 | .#{$keyframeName}In, 8 | .#{$keyframeName}-leave-active, 9 | .#{$keyframeName}Out { 10 | animation-duration: $duration; 11 | animation-timing-function: $timingFun; 12 | animation-fill-mode: both; 13 | } 14 | 15 | .#{$keyframeName}-enter-active, 16 | .#{$keyframeName}In { 17 | animation-name: #{$keyframeName}In; 18 | } 19 | 20 | .#{$keyframeName}-leave-active, 21 | .#{$keyframeName}Out { 22 | animation-name: #{$keyframeName}Out; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/notify/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const notifyProps = { 5 | ...commonProps, 6 | id: String, 7 | type: { 8 | type: String, 9 | default: 'danger', 10 | }, 11 | message: { type: String, default: '' }, 12 | duration: { type: Number, default: 3000 }, 13 | color: { type: String, default: '' }, 14 | background: { type: String, default: '' }, 15 | visible: { 16 | type: Boolean, 17 | default: false, 18 | }, 19 | position: { 20 | type: String, 21 | default: 'top', 22 | }, 23 | }; 24 | 25 | export type NotifyProps = ExtractPropTypes; 26 | -------------------------------------------------------------------------------- /example/src/hooks/useTranslate.ts: -------------------------------------------------------------------------------- 1 | import Locale from '@vingogo/uni-ui/lib/locale'; 2 | 3 | export const { currentLang } = Locale; 4 | export const useTranslate = (object: Record) => { 5 | for (const [key, value] of Object.entries(object)) { 6 | Locale.merge(key, value); 7 | } 8 | }; 9 | 10 | export const translateChange = () => { 11 | let href = ''; 12 | const { location } = window.parent; 13 | const { currentLang } = Locale; 14 | if (currentLang.value === 'zh-CN') { 15 | href = location.href.replace('zh-CN', 'en-US'); 16 | Locale.use('en-US'); 17 | } else { 18 | href = location.href.replace('en-US', 'zh-CN'); 19 | Locale.use('zh-CN'); 20 | } 21 | location.href = href; 22 | }; 23 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/cell/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const cellProps = { 5 | ...commonProps, 6 | title: { type: String, default: '' }, 7 | subTitle: { type: String, default: '' }, 8 | desc: { type: String, default: '' }, 9 | descTextAlign: { 10 | type: String, 11 | default: 'right', 12 | }, 13 | isLink: { type: Boolean, default: false }, 14 | icon: { type: String, default: '' }, 15 | roundRadius: { 16 | type: [String, Number], 17 | default: '', 18 | }, 19 | to: { type: String, default: '' }, 20 | replace: { type: Boolean, default: false }, 21 | }; 22 | 23 | export type CellProps = ExtractPropTypes; 24 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: '/images/logo.png' 4 | lang: zh_CN 5 | title: Vin UI 使用文档 6 | description: 基于 Vue 3 的轻量、快速的多平台开发 UI 组件库 7 | tagline: 基于 Vue 3 的轻量、快速的多平台开发 UI 组件库 8 | meta: 9 | - name: keywords 10 | content: Vin, Vin UI, uni-app, Vite, 小程序, h5 多平台开发 UI 组件库 11 | actions: 12 | - text: 了解更多 13 | link: /guide/index.html 14 | type: primary 15 | features: 16 | - title: 小程序 17 | details: Vue 3 + TypeScript + uni-app, 一次开发, 多平台运行 18 | - title: UI 库 19 | details: 基于京东视觉规范的高质量、高可定制性的 UI 组件库 20 | - title: CLI 21 | details: 基于 uni-app 定制的简单易用、快速开发工具脚手架 22 | footer: MIT Licensed | Copyright © 2023-present Alvin 23 | --- 24 | 25 | # Vin UI 26 | 27 | Vin UI 项目主要针对开发中经常使用的组件库进行封装,基于 uni-app 提供多平台运行的能力,开发打包工具采用 Vite 。 28 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/col/__test__/__snapshots__/index.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should render Col correctly and should render gutter correctly 1`] = ` 4 | " 9 | 8 10 | 8 11 | 8 12 | " 13 | `; 14 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/rate/index.scss: -------------------------------------------------------------------------------- 1 | .vin-rate { 2 | display: flex; 3 | &-item { 4 | position: relative; 5 | display: flex; 6 | flex-shrink: 0; 7 | &:last-child { 8 | margin-right: 0; 9 | } 10 | 11 | &__icon { 12 | color: $rate-icon-color; 13 | cursor: pointer; 14 | 15 | &::before { 16 | position: relative; 17 | top: auto; 18 | left: auto; 19 | transform: none; 20 | } 21 | 22 | &--disabled { 23 | color: $rate-icon-void-color; 24 | } 25 | &--half { 26 | position: absolute; 27 | top: 0; 28 | left: 0; 29 | width: 50% !important; 30 | height: auto !important; 31 | overflow: hidden; 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/empty/index.scss: -------------------------------------------------------------------------------- 1 | .vin-empty { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | justify-content: center; 6 | box-sizing: border-box; 7 | padding: $empty-padding; 8 | 9 | &-image { 10 | width: $empty-image-size; 11 | height: $empty-image-size; 12 | 13 | .img { 14 | width: 100%; 15 | height: 100%; 16 | } 17 | 18 | // 兼容小程序标签和img-slot 19 | img, 20 | image { 21 | width: 100%; 22 | height: 100%; 23 | } 24 | } 25 | 26 | &-description { 27 | margin-top: $empty-description-margin-top; 28 | padding: $empty-description-padding; 29 | color: $empty-description-color; 30 | font-size: $empty-description-font-size; 31 | line-height: $empty-description-line-height; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/tabbar/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const tabbarProps = { 5 | ...commonProps, 6 | visible: { 7 | type: [Number, String], 8 | default: 0, 9 | }, 10 | bottom: { 11 | type: Boolean, 12 | default: false, 13 | }, 14 | type: { 15 | type: String, 16 | default: 'base', 17 | }, 18 | size: { 19 | type: String, 20 | default: '20px', 21 | }, 22 | unactiveColor: { 23 | type: String, 24 | default: '#000000', 25 | }, 26 | activeColor: { 27 | type: String, 28 | default: '', 29 | }, 30 | safeAreaInsetBottom: { 31 | type: Boolean, 32 | default: false, 33 | }, 34 | }; 35 | 36 | export type TabbarProps = ExtractPropTypes; 37 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/badge/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const badgeProps = { 5 | ...commonProps, 6 | value: { 7 | type: [String, Number], 8 | }, 9 | max: { 10 | type: Number, 11 | default: 10000, 12 | }, 13 | dot: { 14 | type: Boolean, 15 | default: false, 16 | }, 17 | hidden: { 18 | type: Boolean, 19 | default: false, 20 | }, 21 | top: { 22 | type: String, 23 | default: '0', 24 | }, 25 | right: { 26 | type: String, 27 | default: '0', 28 | }, 29 | zIndex: { 30 | type: Number, 31 | default: 9, 32 | }, 33 | color: { 34 | type: String, 35 | default: '', 36 | }, 37 | }; 38 | 39 | export type BadgeProps = ExtractPropTypes; 40 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/avatar/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const AVATAR_KEY = Symbol('avatarGroup'); 5 | 6 | export const avatarProps = { 7 | ...commonProps, 8 | size: { 9 | type: String, 10 | default: '', 11 | }, 12 | shape: { 13 | type: String, 14 | default: 'round', 15 | }, 16 | bgColor: { 17 | type: String, 18 | default: '#eee', 19 | }, 20 | color: { 21 | type: String, 22 | default: '#666', 23 | }, 24 | url: { 25 | type: String, 26 | default: '', 27 | }, 28 | alt: { 29 | type: String, 30 | default: '', 31 | }, 32 | icon: { 33 | type: String, 34 | default: '', 35 | }, 36 | }; 37 | 38 | export type AvatarProps = ExtractPropTypes; 39 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/cascader/types.ts: -------------------------------------------------------------------------------- 1 | export type CascaderConfig = { 2 | value?: string; 3 | text?: string; 4 | children?: string; 5 | }; 6 | 7 | export type CascaderOption = { 8 | text?: string; 9 | value?: number | string; 10 | disabled?: boolean; 11 | children?: CascaderOption[]; 12 | leaf?: boolean; 13 | level?: number; 14 | loading?: boolean; 15 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 16 | [key: PropertyKey]: any; 17 | }; 18 | 19 | export type CascaderPane = { 20 | nodes: CascaderOption[]; 21 | selectedNode: CascaderOption | null; 22 | }; 23 | 24 | export type CascaderValue = CascaderOption['value'][]; 25 | 26 | export type convertConfig = { 27 | topId?: string | number | null; 28 | idKey?: string; 29 | pidKey?: string; 30 | sortKey?: string; 31 | }; 32 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/tag/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, PropType } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export type TagType = 'primary' | 'success' | 'danger' | 'warning'; 5 | 6 | export const tagProps = { 7 | ...commonProps, 8 | color: { type: String, default: '' }, 9 | textColor: { type: String, default: '' }, 10 | type: { 11 | type: String as PropType, 12 | default: 'default', 13 | }, 14 | plain: { 15 | type: Boolean, 16 | default: false, 17 | }, 18 | round: { 19 | type: Boolean, 20 | default: false, 21 | }, 22 | mark: { 23 | type: Boolean, 24 | default: false, 25 | }, 26 | closeable: { 27 | type: Boolean, 28 | default: false, 29 | }, 30 | }; 31 | 32 | export type TagProps = ExtractPropTypes; 33 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/comment-images/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, PropType } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export interface VideosType { 5 | id: number | string; 6 | mainUrl: string; 7 | videoUrl: string; 8 | } 9 | 10 | export interface ImagesType { 11 | smallImgUrl: string; 12 | bigImgUrl: string; 13 | imgUrl: string; 14 | } 15 | 16 | export const commonImagesProps = { 17 | ...commonProps, 18 | type: { 19 | type: String, 20 | default: 'one', // one multi 21 | }, 22 | videos: { 23 | type: Array as PropType, 24 | default: () => [], 25 | }, 26 | images: { 27 | type: Array as PropType, 28 | default: () => [], 29 | }, 30 | }; 31 | 32 | export type CommonImagesProps = ExtractPropTypes; 33 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/searchbar/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const searchbarProps = { 5 | ...commonProps, 6 | modelValue: { 7 | type: [String, Number], 8 | default: '', 9 | }, 10 | maxLength: { 11 | type: [String, Number], 12 | default: '9999', 13 | }, 14 | inputType: { 15 | type: String, 16 | default: 'text', 17 | }, 18 | placeholder: { 19 | type: String, 20 | default: '', 21 | }, 22 | clearable: { 23 | type: Boolean, 24 | default: true, 25 | }, 26 | background: { 27 | type: String, 28 | default: '', 29 | }, 30 | inputBackground: { 31 | type: String, 32 | default: '', 33 | }, 34 | }; 35 | 36 | export type SearchbarProps = ExtractPropTypes; 37 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/card/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const cardProps = { 5 | ...commonProps, 6 | imgUrl: { 7 | type: String, 8 | default: '', 9 | }, 10 | title: { 11 | type: String, 12 | default: '', 13 | }, 14 | price: { 15 | type: String, 16 | default: '', 17 | }, 18 | vipPrice: { 19 | type: String, 20 | default: '', 21 | }, 22 | shopDesc: { 23 | type: String, 24 | default: '', 25 | }, 26 | delivery: { 27 | type: String, 28 | default: '', 29 | }, 30 | shopName: { 31 | type: String, 32 | default: '', 33 | }, 34 | isNeedPrice: { 35 | type: Boolean, 36 | default: true, 37 | }, 38 | }; 39 | 40 | export type CardProps = ExtractPropTypes; 41 | -------------------------------------------------------------------------------- /packages/uni-ui/src/shared/hooks/useRect/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | 获取元素的大小及其相对于视口的位置,等价于 Element.getBoundingClientRect。 3 | width 宽度 number 4 | height 高度 number 5 | top 顶部与视图窗口左上角的距离 number 6 | left 左侧与视图窗口左上角的距离 number 7 | right 右侧与视图窗口左上角的距离 number 8 | bottom 底部与视图窗口左上角的距离 number 9 | */ 10 | 11 | import { nextTick } from 'vue'; 12 | import type { ComponentInternalInstance } from 'vue'; 13 | 14 | export default (id: string, instance: ComponentInternalInstance): any => { 15 | return new Promise((resolve) => { 16 | nextTick(() => { 17 | uni 18 | .createSelectorQuery() 19 | // #ifndef MP-ALIPAY 20 | .in(instance) 21 | // #endif 22 | .select(`#${id}`) 23 | .boundingClientRect((res: any) => { 24 | resolve(res); 25 | }) 26 | .exec(); 27 | }); 28 | }); 29 | }; 30 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/navbar/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const navbarProps = { 5 | ...commonProps, 6 | leftShow: { type: Boolean, default: true }, // 左侧 是否显示返回icon 7 | title: { type: String, default: '' }, // 中间 文字标题 8 | titIcon: { type: String, default: '' }, // 中间 标题icon 9 | desc: { type: String, default: '' }, // 右侧 按钮文字 10 | fixed: { 11 | type: Boolean, 12 | default: false, 13 | }, 14 | safeAreaInsetTop: { 15 | type: Boolean, 16 | default: false, 17 | }, 18 | // 生成一个等高的占位元素 19 | placeholder: { 20 | type: Boolean, 21 | default: true, 22 | }, 23 | zIndex: { 24 | type: [Number, String], 25 | default: 10, 26 | }, 27 | }; 28 | 29 | export type NavbarProps = ExtractPropTypes; 30 | -------------------------------------------------------------------------------- /packages/uni-ui/src/shared/hooks/useRouter/index.ts: -------------------------------------------------------------------------------- 1 | export type NavigateToOptions = string | UniApp.NavigateToOptions; 2 | export type RedirectToOptions = string | UniApp.RedirectToOptions; 3 | 4 | export type RouterOptions = UniApp.NavigateToOptions | UniApp.RedirectToOptions; 5 | 6 | const useRouter = () => { 7 | const push = (options: NavigateToOptions) => { 8 | if (typeof options === 'string') { 9 | uni.navigateTo({ url: options }); 10 | return; 11 | } 12 | 13 | uni.navigateTo(options); 14 | }; 15 | const replace = (options: RedirectToOptions) => { 16 | if (typeof options === 'string') { 17 | uni.redirectTo({ url: options }); 18 | return; 19 | } 20 | 21 | uni.redirectTo(options); 22 | }; 23 | 24 | return { 25 | push, 26 | replace, 27 | }; 28 | }; 29 | 30 | export default useRouter; 31 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/avatar-group/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | 3 | export const AVATAR_KEY = Symbol('avatarGroup'); 4 | 5 | export const avatarGroupProps = { 6 | maxContent: { 7 | type: String, 8 | default: '', 9 | }, 10 | maxCount: { 11 | type: [Number, String], 12 | default: '', 13 | }, 14 | size: { 15 | type: String, 16 | default: '', 17 | }, 18 | shape: { 19 | type: String, 20 | default: '', 21 | }, 22 | maxBgColor: { 23 | type: String, 24 | default: '#eee', 25 | }, 26 | maxColor: { 27 | type: String, 28 | default: '#666', 29 | }, 30 | span: { 31 | type: String, 32 | default: '-8', 33 | }, 34 | zIndex: { 35 | type: String, 36 | default: 'left', 37 | }, 38 | }; 39 | 40 | export type AvatarGroupProps = ExtractPropTypes; 41 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/price/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const priceProps = { 5 | ...commonProps, 6 | price: { 7 | type: [Number, String], 8 | default: 0, 9 | }, 10 | needSymbol: { 11 | type: Boolean, 12 | default: true, 13 | }, 14 | symbol: { 15 | type: String, 16 | default: '¥', 17 | }, 18 | decimalDigits: { 19 | type: Number, 20 | default: 2, 21 | }, 22 | thousands: { 23 | type: Boolean, 24 | default: false, 25 | }, 26 | position: { 27 | type: String, 28 | default: 'before', 29 | }, 30 | size: { 31 | type: String, 32 | default: 'normal', 33 | }, 34 | strikeThrough: { 35 | type: Boolean, 36 | default: false, 37 | }, 38 | }; 39 | 40 | export type PriceProps = ExtractPropTypes; 41 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/popup/common.ts: -------------------------------------------------------------------------------- 1 | import { overlayProps } from '../overlay/common'; 2 | 3 | export const popupProps = { 4 | ...overlayProps, 5 | overlay: { 6 | type: Boolean, 7 | default: true, 8 | }, 9 | position: { 10 | type: String, 11 | default: 'center', 12 | }, 13 | transition: String, 14 | popClass: { 15 | type: String, 16 | default: '', 17 | }, 18 | closeable: { 19 | type: Boolean, 20 | default: false, 21 | }, 22 | closeIconPosition: { 23 | type: String, 24 | default: 'top-right', 25 | }, 26 | closeIcon: { 27 | type: String, 28 | default: 'close', 29 | }, 30 | destroyOnClose: { 31 | type: Boolean, 32 | default: true, 33 | }, 34 | round: { 35 | type: Boolean, 36 | default: false, 37 | }, 38 | safeAreaInsetBottom: { 39 | type: Boolean, 40 | default: false, 41 | }, 42 | }; 43 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/input/util.ts: -------------------------------------------------------------------------------- 1 | function trimExtraChar(value: string, char: string, regExp: RegExp) { 2 | const index = value.indexOf(char); 3 | 4 | if (index === -1) { 5 | return value; 6 | } 7 | 8 | if (char === '-' && index !== 0) { 9 | return value.slice(0, index); 10 | } 11 | 12 | return value.slice(0, index + 1) + value.slice(index).replace(regExp, ''); 13 | } 14 | 15 | export function formatNumber(value: string, allowDot = true, allowMinus = true) { 16 | let result = value; 17 | if (allowDot) { 18 | result = trimExtraChar(value, '.', /\./g); 19 | } else { 20 | result = value.split('.')[0]; 21 | } 22 | 23 | if (allowMinus) { 24 | result = trimExtraChar(result, '-', /-/g); 25 | } else { 26 | result = result.replace(/-/, ''); 27 | } 28 | const regExp = allowDot ? /[^-0-9.]/g : /[^-0-9]/g; 29 | 30 | return result.replace(regExp, ''); 31 | } 32 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/checkbox/index.scss: -------------------------------------------------------------------------------- 1 | .vin-checkbox { 2 | display: flex; 3 | align-items: center; 4 | margin-right: 20px; 5 | 6 | &--reverse { 7 | flex-direction: row-reverse; 8 | .vin-checkbox__label { 9 | margin-right: $checkbox-label-margin-left; 10 | margin-left: 0; 11 | } 12 | } 13 | &__label { 14 | margin-left: $checkbox-label-margin-left; 15 | color: $checkbox-label-color; 16 | font-size: $checkbox-label-font-size; 17 | &--disabled { 18 | color: $checkbox-label-disable-color; 19 | } 20 | } 21 | &__icon { 22 | color: $primary-color; 23 | font-size: $checkbox-icon-font-size; 24 | transition-duration: 0.3s; 25 | transition-property: color, border-color, background-color; 26 | } 27 | &__icon--unchecked { 28 | color: $checkbox-icon-disable-color; 29 | } 30 | &__icon--disable { 31 | color: $help-color; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/empty/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | type statusOptions = { 5 | [key: string]: string; 6 | }; 7 | 8 | /** 9 | * 内置图片地址 10 | */ 11 | export const defaultStatus: statusOptions = { 12 | empty: 'https://static-ftcms.jd.com/p/files/61a9e3183985005b3958672b.png', 13 | error: 'https://ftcms.jd.com/p/files/61a9e33ee7dcdbcc0ce62736.png', 14 | network: 'https://static-ftcms.jd.com/p/files/61a9e31de7dcdbcc0ce62734.png', 15 | }; 16 | 17 | export const emptyProps = { 18 | ...commonProps, 19 | image: { 20 | type: String, 21 | default: 'empty', // 默认empty 22 | }, 23 | imageSize: { 24 | type: [Number, String], // 图片大小,正方形 25 | default: '', 26 | }, 27 | description: { 28 | type: String, // 文字区 29 | default: '', 30 | }, 31 | }; 32 | 33 | export type EmptyProps = ExtractPropTypes; 34 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/radio/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const radioProps = { 5 | ...commonProps, 6 | disabled: { 7 | type: Boolean, 8 | default: false, 9 | }, 10 | iconSize: { 11 | type: [String, Number], 12 | default: '', 13 | }, 14 | iconName: { 15 | type: String, 16 | default: 'check-normal', 17 | }, 18 | iconActiveName: { 19 | type: String, 20 | default: 'check-checked', 21 | }, 22 | iconClassPrefix: { 23 | type: String, 24 | default: 'vin-icon', 25 | }, 26 | iconFontClassName: { 27 | type: String, 28 | default: 'vin-iconfont', 29 | }, 30 | label: { 31 | type: [String, Number], 32 | default: '', 33 | }, 34 | shape: { 35 | type: String, 36 | default: 'round', 37 | }, 38 | }; 39 | 40 | export type RadioProps = ExtractPropTypes; 41 | -------------------------------------------------------------------------------- /packages/uni-ui/scripts/build/locale.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require('path'); 2 | const { build } = require('vite'); 3 | const { SRC_DIR, LIB_DIR } = require('./const'); 4 | 5 | let input = { 6 | index: resolve(SRC_DIR, 'locale/index.ts'), 7 | }; 8 | 9 | ['zh-CN', 'zh-TW', 'en-US'].map((file) => { 10 | input[file] = resolve(SRC_DIR, `locale/lang/${file}.ts`); 11 | }); 12 | 13 | const buildLocale = () => 14 | build({ 15 | configFile: false, 16 | build: { 17 | target: 'es2015', 18 | minify: true, 19 | lib: { 20 | entry: '', 21 | name: 'index', 22 | formats: ['es'], 23 | }, 24 | rollupOptions: { 25 | external: ['vue', 'vue-i18n'], 26 | input, 27 | output: { 28 | dir: resolve(LIB_DIR, 'locale'), 29 | entryFileNames: '[name].js', 30 | }, 31 | }, 32 | emptyOutDir: false, 33 | }, 34 | }); 35 | 36 | module.exports = buildLocale; 37 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/grid-item/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, PropType } from 'vue'; 2 | import { commonProps } from '../common'; 3 | import type { RouterOptions } from '../../shared/hooks/useRouter'; 4 | 5 | export const gridItemProps = { 6 | ...commonProps, 7 | text: { 8 | type: String, 9 | }, 10 | icon: { 11 | type: String, 12 | }, 13 | iconSize: { 14 | type: [Number, String], 15 | }, 16 | iconColor: { 17 | type: String, 18 | }, 19 | iconClassPrefix: { 20 | type: String, 21 | }, 22 | iconFontClassName: { 23 | type: String, 24 | }, 25 | to: { 26 | type: [String, Object] as PropType, 27 | }, 28 | // #ifdef H5 29 | url: { 30 | type: String, 31 | default: '', 32 | }, 33 | // #endif 34 | replace: { 35 | type: Boolean, 36 | default: false, 37 | }, 38 | }; 39 | 40 | export type GridItemProps = ExtractPropTypes; 41 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/category-pane/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, PropType } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export type CategoryType = { 5 | catName?: string; 6 | [key: string]: any; 7 | }; 8 | 9 | export type ChildType = { 10 | catName?: string; 11 | catType?: number; 12 | [key: string]: any; 13 | }; 14 | export type CustomType = { 15 | catName?: string; 16 | [key: string]: any; 17 | }; 18 | 19 | export const categoryPaneProps = { 20 | ...commonProps, 21 | // 分类模式 22 | type: { 23 | type: String, 24 | default: 'classify', 25 | }, 26 | 27 | // 右侧导航数据 28 | categoryChild: { 29 | type: Array as PropType, 30 | default: () => [], 31 | }, 32 | 33 | // 模式传入自定义数据 34 | customCategory: { 35 | type: Array as PropType, 36 | default: () => [], 37 | }, 38 | }; 39 | 40 | export type CategoryPaneProps = ExtractPropTypes; 41 | -------------------------------------------------------------------------------- /packages/uni-ui/src/shared/hooks/useRelation/useInject.ts: -------------------------------------------------------------------------------- 1 | import { ref, inject, computed, onUnmounted, getCurrentInstance } from 'vue'; 2 | import type { InjectionKey, ComponentInternalInstance } from 'vue'; 3 | 4 | type ParentProvide = T & { 5 | add(child: ComponentInternalInstance): void; 6 | remove(child: ComponentInternalInstance): void; 7 | internalChildren: ComponentInternalInstance[]; 8 | }; 9 | 10 | export function useInject(key: InjectionKey>) { 11 | const parent = inject(key, null); 12 | 13 | if (parent) { 14 | const instance = getCurrentInstance()!; 15 | const { add, remove, internalChildren } = parent; 16 | 17 | add(instance); 18 | onUnmounted(() => remove(instance)); 19 | 20 | const index = computed(() => internalChildren.indexOf(instance)); 21 | 22 | return { 23 | parent, 24 | index, 25 | }; 26 | } 27 | 28 | return { 29 | parent: null, 30 | index: ref(-1), 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/badge/index.scss: -------------------------------------------------------------------------------- 1 | .vin-badge { 2 | position: relative; 3 | display: inline-block; 4 | 5 | .slot-icons { 6 | position: absolute; 7 | top: -20%; 8 | right: -20%; 9 | z-index: $badge-z-index; 10 | padding: $badge-padding; 11 | text-align: center; 12 | background: $badge-background-color; 13 | border-radius: $badge-border-radius; 14 | } 15 | 16 | .sup { 17 | position: absolute; 18 | padding: $badge-padding; 19 | color: $badge-color; 20 | font-weight: normal; 21 | font-size: $badge-font-size; 22 | text-align: center; 23 | background: $badge-background-color; 24 | border-radius: $badge-border-radius; 25 | } 26 | 27 | .vin-badge__content { 28 | transform: $badge-content-transform; 29 | } 30 | 31 | .is-dot { 32 | width: $badge-dot-width; 33 | height: $badge-dot-height; 34 | padding: $badge-dot-padding; 35 | border-radius: $badge-dot-border-radius; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/uni-ui/src/locale/index.ts: -------------------------------------------------------------------------------- 1 | import { ref, reactive } from 'vue'; 2 | import ZhCNLang from './lang/zh-CN'; 3 | import EnUSLang from './lang/en-US'; 4 | import { deepMerge } from '../shared/utils'; 5 | // 组件默认语言设置 6 | 7 | export type Lang = Record; 8 | const langs = reactive({ 9 | 'zh-CN': new ZhCNLang(), 10 | 'en-US': new EnUSLang(), 11 | }); 12 | export class Locale { 13 | static currentLang = ref('zh-CN'); 14 | 15 | static languages(): Lang { 16 | return langs[this.currentLang.value]; 17 | } 18 | 19 | static use(lang: string, Languages?: any) { 20 | if (Languages) { 21 | langs[lang] = new Languages(); 22 | } 23 | this.currentLang.value = lang; 24 | } 25 | 26 | static merge(lang: string, newLanguages: any) { 27 | if (newLanguages) { 28 | if (langs[lang]) { 29 | deepMerge(langs[lang], newLanguages); 30 | } else { 31 | this.use(lang, newLanguages); 32 | } 33 | } 34 | } 35 | } 36 | export default Locale; 37 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/checkbox/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const checkboxProps = { 5 | ...commonProps, 6 | modelValue: { 7 | type: Boolean, 8 | default: false, 9 | }, 10 | disabled: { 11 | type: Boolean, 12 | default: false, 13 | }, 14 | textPosition: { 15 | type: String, 16 | default: 'right', 17 | }, 18 | iconSize: { 19 | type: [String, Number], 20 | default: '', 21 | }, 22 | iconName: { 23 | type: String, 24 | default: 'check-normal', 25 | }, 26 | iconActiveName: { 27 | type: String, 28 | default: 'checked', 29 | }, 30 | iconClassPrefix: { 31 | type: String, 32 | default: 'vin-icon', 33 | }, 34 | iconFontClassName: { 35 | type: String, 36 | default: 'vin-iconfont', 37 | }, 38 | label: { 39 | type: String, 40 | default: '', 41 | }, 42 | }; 43 | 44 | export type CheckboxProps = ExtractPropTypes; 45 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/input-number/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const inputNumberProps = { 5 | ...commonProps, 6 | modelValue: { 7 | type: [Number, String], 8 | default: 0, 9 | }, 10 | inputWidth: { 11 | type: [Number, String], 12 | default: '', 13 | }, 14 | buttonSize: { 15 | type: [Number, String], 16 | default: '', 17 | }, 18 | min: { 19 | type: [Number, String], 20 | default: 1, 21 | }, 22 | max: { 23 | type: [Number, String], 24 | default: 9999, 25 | }, 26 | step: { 27 | type: [Number, String], 28 | default: 1, 29 | }, 30 | decimalPlaces: { 31 | type: [Number, String], 32 | default: 0, 33 | }, 34 | disabled: { 35 | type: Boolean, 36 | default: false, 37 | }, 38 | readonly: { 39 | type: Boolean, 40 | default: false, 41 | }, 42 | }; 43 | 44 | export type InputNumberProps = ExtractPropTypes; 45 | -------------------------------------------------------------------------------- /example/src/pages/components/divider.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 35 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/list/__tests__/list.spec.ts: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils'; 2 | import { nextTick } from 'vue'; 3 | import { mockScrollTop } from '../../../utils/test/unit'; 4 | import List from '../index.vue'; 5 | 6 | test('should render height', async () => { 7 | const wrapper = mount(List, { 8 | props: { 9 | height: 50, 10 | listData: new Array(100).fill(0), 11 | }, 12 | }); 13 | 14 | await nextTick(); 15 | 16 | const listItem = wrapper.findAll('.vin-list-item')[0]; 17 | expect((listItem.element as any).style.height).toEqual('50px'); 18 | }); 19 | 20 | test('should render height', async () => { 21 | const visibleCount = Math.ceil(667 / 50); 22 | const wrapper = mount(List, { 23 | props: { 24 | height: 50, 25 | listData: new Array(100).fill(0), 26 | }, 27 | }); 28 | 29 | await nextTick(); 30 | await mockScrollTop(100); 31 | 32 | const listItem = wrapper.findAll('.vin-list-item'); 33 | expect(listItem.length).toBe(visibleCount); 34 | }); 35 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/extends/mixin.scss: -------------------------------------------------------------------------------- 1 | @mixin bg-square { 2 | background: { 3 | position: 0 0, 20px 20px; 4 | color: #fff; 5 | image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%), 6 | linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%); 7 | size: 40px 40px; 8 | } 9 | } 10 | 11 | @mixin flex { 12 | position: relative; 13 | display: flex; 14 | align-items: center; 15 | } 16 | @mixin flex-bar { 17 | position: relative; 18 | display: flex; 19 | align-items: center; 20 | justify-content: space-between; 21 | } 22 | @mixin flex-center { 23 | display: flex; 24 | align-items: center; 25 | justify-content: center; 26 | } 27 | 28 | @mixin position-center { 29 | position: absolute !important; 30 | top: 0; 31 | right: 0; 32 | bottom: 0; 33 | left: 0; 34 | margin: auto; 35 | } 36 | 37 | @mixin blur { 38 | color: var(--vin-text-color); 39 | -webkit-backdrop-filter: blur(20px); 40 | backdrop-filter: blur(20px); 41 | } 42 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/textarea/index.scss: -------------------------------------------------------------------------------- 1 | .vin-textarea { 2 | position: relative; 3 | display: flex; 4 | box-sizing: border-box; 5 | width: 100%; 6 | padding: 10px 25px; 7 | font-size: $textarea-font; 8 | background: $white; 9 | 10 | &--disabled { 11 | .vin-textarea__textarea, 12 | .vin-textarea____limit { 13 | color: $textarea-disabled-color !important; 14 | cursor: not-allowed; 15 | } 16 | } 17 | &__limit { 18 | position: absolute; 19 | right: 15px; 20 | bottom: 12px; 21 | color: $textarea-limit-color; 22 | font-size: $textarea-font; 23 | } 24 | &__textarea { 25 | display: block; 26 | box-sizing: border-box; 27 | width: 100%; 28 | min-width: 0; 29 | margin: 0; 30 | padding: 0; 31 | color: $textarea-text-color; 32 | font-size: $textarea-font; 33 | text-align: left; 34 | background-color: transparent; 35 | border: 0; 36 | // min-height: $textarea-height; 37 | outline: none; 38 | resize: none; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/avatar-group/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 34 | 35 | 38 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/category/index.scss: -------------------------------------------------------------------------------- 1 | .vin-category { 2 | &__cateList { 3 | display: flex; 4 | background: $category-bg-color; 5 | } 6 | 7 | &__cateListLeft { 8 | background: $category-list-left-bg-color; 9 | } 10 | 11 | &__cateListItemChecked, 12 | &__cateListItem { 13 | display: flex; 14 | align-items: center; 15 | justify-content: center; 16 | width: 100px; 17 | height: 50px; 18 | color: $category-list-item-color; 19 | font-weight: normal; 20 | font-size: 13px; 21 | font-family: PingFangSC, -apple-system-font, Helvetica Neue, sans-serif; 22 | transition: all 0.3s; 23 | } 24 | &__cateListItemChecked { 25 | position: relative; 26 | font-weight: 500; 27 | background: $category-list-item-checked-color; 28 | transition: all 0.3s; 29 | &::before { 30 | position: absolute; 31 | left: 0; 32 | width: 5px; 33 | height: 18px; 34 | background: $category-list-item-checked-img-bg-color; 35 | content: ''; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/common/useVinContext.ts: -------------------------------------------------------------------------------- 1 | import { computed } from 'vue'; 2 | import { normalizeClass, stringifyStyle, normalizeStyle } from '../../shared/utils'; 3 | 4 | const classPrefix = 'vin'; 5 | 6 | const useVinContext = (props: any, { componentName }: { componentName: string }) => { 7 | const mainClass = computed(() => { 8 | const cls = normalizeClass([props.customClass, { [componentName]: true }]); 9 | 10 | return cls; 11 | }); 12 | 13 | const mainStyle = computed(() => { 14 | return stringifyStyle(normalizeStyle(props.customStyle)); 15 | }); 16 | 17 | const getMainClass = (cls: unknown) => { 18 | return normalizeClass([props.customClass, { [componentName]: true }, cls]); 19 | }; 20 | 21 | const getMainStyle = (style: unknown) => { 22 | return stringifyStyle(normalizeStyle([props.customStyle, style])); 23 | }; 24 | 25 | return { 26 | classPrefix, 27 | mainClass, 28 | mainStyle, 29 | getMainClass, 30 | getMainStyle, 31 | }; 32 | }; 33 | 34 | export default useVinContext; 35 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/textarea/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const textareaProps = { 5 | ...commonProps, 6 | modelValue: { 7 | type: [String], 8 | default: '', 9 | }, 10 | placeholder: { 11 | type: String, 12 | default: '', 13 | }, 14 | maxLength: { 15 | type: [String, Number], 16 | default: '', 17 | }, 18 | rows: { 19 | type: [String, Number], 20 | default: '', 21 | }, 22 | limitShow: { 23 | type: Boolean, 24 | default: false, 25 | }, 26 | autosize: { 27 | type: Boolean, 28 | default: false, 29 | }, 30 | textAlign: { 31 | type: String, 32 | default: '', 33 | }, 34 | readonly: { 35 | type: Boolean, 36 | default: false, 37 | }, 38 | disabled: { 39 | type: Boolean, 40 | default: false, 41 | }, 42 | autofocus: { 43 | type: Boolean, 44 | default: false, 45 | }, 46 | }; 47 | 48 | export type TextareaProps = ExtractPropTypes; 49 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/fixednav/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, PropType } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export interface navItem { 5 | id?: string; 6 | icon: string; 7 | text: string; 8 | num: number; 9 | } 10 | 11 | export const fixednavProps = { 12 | ...commonProps, 13 | visible: { 14 | type: Boolean, 15 | default: false, 16 | }, 17 | overlay: { 18 | type: Boolean, 19 | default: true, 20 | }, 21 | navList: { 22 | default: () => [], 23 | type: Array as PropType, 24 | }, 25 | activeText: { 26 | default: '', 27 | type: String, 28 | }, 29 | unActiveText: { 30 | default: '', 31 | type: String, 32 | }, 33 | position: { 34 | default: () => { 35 | return { 36 | top: 'auto', 37 | bottom: 'auto', 38 | }; 39 | }, 40 | type: Object, 41 | }, 42 | type: { 43 | default: 'right', 44 | type: String, 45 | }, 46 | }; 47 | 48 | export type FixednavProps = ExtractPropTypes; 49 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/tabbar-item/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const tabbarItemProps = { 5 | ...commonProps, 6 | tabTitle: { 7 | // 标签页的标题 8 | type: String, 9 | default: '', 10 | }, 11 | icon: { 12 | // 标签页显示的icon 13 | type: String, 14 | default: '', 15 | }, 16 | href: { 17 | // 标签页的跳转链接 18 | type: String, 19 | default: '', 20 | }, 21 | num: { 22 | // 页签右上角的数字角标 23 | type: String, 24 | default: '', 25 | }, 26 | activeImg: { 27 | type: String, 28 | default: '', 29 | }, 30 | img: { 31 | type: String, 32 | default: '', 33 | }, 34 | dot: { 35 | type: Boolean, 36 | default: false, 37 | }, 38 | classPrefix: { 39 | type: String, 40 | default: 'vin-icon', 41 | }, 42 | fontClassName: { 43 | type: String, 44 | default: 'vin-iconfont', 45 | }, 46 | to: [Object, String], 47 | }; 48 | 49 | export type TabbarItemProps = ExtractPropTypes; 50 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/infiniteloading/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const infiniteLoadingProps = { 5 | ...commonProps, 6 | hasMore: { 7 | type: Boolean, 8 | default: true, 9 | }, 10 | threshold: { 11 | type: Number, 12 | default: 200, 13 | }, 14 | upperThreshold: { 15 | type: Number, 16 | default: 40, 17 | }, 18 | pullIcon: { 19 | type: String, 20 | default: 'refresh', 21 | }, 22 | pullText: { 23 | type: String, 24 | default: '', 25 | }, 26 | loadIcon: { 27 | type: String, 28 | default: 'refresh', 29 | }, 30 | loadText: { 31 | type: String, 32 | default: '', 33 | }, 34 | loadMoreText: { 35 | type: String, 36 | default: '', 37 | }, 38 | containerId: { 39 | type: String, 40 | default: '', 41 | }, 42 | isOpenRefresh: { 43 | type: Boolean, 44 | default: false, 45 | }, 46 | }; 47 | 48 | export type InfiniteLoadingProps = ExtractPropTypes; 49 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/input-number/index.scss: -------------------------------------------------------------------------------- 1 | .vin-input-number { 2 | display: flex; 3 | align-items: center; 4 | 5 | &--disabled { 6 | input { 7 | color: $inputnumber-icon-void-color; 8 | } 9 | } 10 | 11 | &__icon { 12 | color: $inputnumber-icon-color; 13 | font-size: $inputnumber-icon-size; 14 | cursor: pointer; 15 | &--disabled { 16 | color: $inputnumber-icon-void-color; 17 | cursor: not-allowed; 18 | } 19 | } 20 | 21 | input, 22 | &__text--readonly { 23 | width: $inputnumber-input-width; 24 | height: 100%; 25 | margin: $inputnumber-input-margin; 26 | color: $inputnumber-input-font-color; 27 | font-size: $inputnumber-input-font-size; 28 | text-align: center; 29 | background-color: $inputnumber-input-background-color; 30 | border: $inputnumber-input-border; 31 | border-radius: $inputnumber-input-border-radius; 32 | outline: none; 33 | } 34 | input::-webkit-outer-spin-button, 35 | input::-webkit-inner-spin-button { 36 | appearance: none; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /docs/guide/international.md: -------------------------------------------------------------------------------- 1 | # 国际化 2 | 3 | ## 介绍 4 | 5 | `VinUI` 支持多语言,组件默认使用中文。具体可参照以下方式进行国际化设置 6 | 7 | ## 使用方法 8 | 9 | ### 多语言切换 10 | 11 | VinUI 通过 `Locale` 组件实现多语言支持,使用 `Locale.use` 方法可以切换当前使用的语言。 12 | 13 | ```js 14 | import { Locale } from '@vingogo/uni-ui'; 15 | 16 | // 引入英文语言包 17 | import enUS from '@vingogo/uni-ui/lib/locale/en-US'; 18 | Locale.use('en-US', enUS); 19 | ``` 20 | 21 | ### 覆盖语言包 22 | 23 | 通过 `Locale.merge` 方法可以实现文案的修改和扩展,示例如下: 24 | 25 | ```js 26 | import { Locale } from '@vingogo/uni-ui'; 27 | 28 | Locale.merge('zh-CN', { 29 | // 将全局 "确认" 修改为 "关闭" 30 | confirm: '关闭', 31 | // 修改某个组件内部语言 32 | shortpassword: { 33 | title: '请输入密码', // 将 "请输入密码" 修改为 "请输入卡密" 34 | }, 35 | }); 36 | ``` 37 | 38 | ### 目前支持的语言 39 | 40 | | 语言 | 文件名 | 版本 | 41 | | -------- | ------ | -------- | 42 | | 英语 | en-US | `v0.1.0` | 43 | | 简体中文 | zh-CN | `v0.1.0` | 44 | | 繁體中文 | zh-TW | `v0.1.0` | 45 | 46 | ## 常见问题 47 | 48 | ### 找不到所需的语言包? 49 | 50 | 如果上方列表中没有你需要的语言,欢迎给我们提 `Pull Request` 来增加新的语言包。 51 | 52 | ### 业务代码如何实现国际化? 53 | 54 | 可以使用 `vue-i18n` 来实现。 55 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/tabpane/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 34 | 35 | 38 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/form-item/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, PropType } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const formItemProps = { 5 | ...commonProps, 6 | required: { 7 | type: Boolean, 8 | default: false, 9 | }, 10 | prop: { 11 | type: String, 12 | default: '', 13 | }, 14 | label: { 15 | type: String, 16 | default: '', 17 | }, 18 | labelWidth: { 19 | type: [String, Number], 20 | default: '', 21 | }, 22 | labelAlign: { 23 | type: String, 24 | default: '', 25 | }, 26 | bodyAlign: { 27 | type: String, 28 | default: '', 29 | }, 30 | rules: { 31 | type: Array as PropType, 32 | default: () => { 33 | return []; 34 | }, 35 | }, 36 | showErrorMessage: { 37 | type: Boolean, 38 | default: true, 39 | }, 40 | showErrorLine: { 41 | type: Boolean, 42 | default: true, 43 | }, 44 | errorMessageAlign: { 45 | type: String, 46 | default: '', 47 | }, 48 | }; 49 | 50 | export type FormItemProps = ExtractPropTypes; 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Alvin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/cell-group/index.scss: -------------------------------------------------------------------------------- 1 | .vin-cell-group { 2 | display: block; 3 | 4 | &__title { 5 | display: inherit; 6 | margin-top: 30px; 7 | margin-bottom: 10px; 8 | padding: $cell-group-title-padding; 9 | color: $cell-group-title-color; 10 | font-size: $cell-group-title-font-size; 11 | line-height: $cell-group-title-line-height; 12 | } 13 | 14 | &__desc { 15 | display: inherit; 16 | margin-top: 10px; 17 | margin-bottom: 10px; 18 | padding: $cell-group-desc-padding; 19 | color: $cell-group-desc-color; 20 | font-size: $cell-group-desc-font-size; 21 | line-height: $cell-group-desc-line-height; 22 | } 23 | 24 | &__warp { 25 | display: inherit; 26 | margin: 10px 0; 27 | overflow: hidden; 28 | background-color: $cell-group-background-color; 29 | border-radius: $cell-border-radius; 30 | 31 | :deep(.vin-cell) { 32 | margin: 0; 33 | border-radius: 0; 34 | box-shadow: none; 35 | } 36 | } 37 | 38 | :deep(.vin-cell) { 39 | &::after { 40 | border-bottom: $cell-after-border-bottom; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/infiniteloading/index.scss: -------------------------------------------------------------------------------- 1 | .vin-infiniteloading { 2 | display: block; 3 | width: 100%; 4 | .vin-infinite-top { 5 | display: flex; 6 | align-items: center; 7 | justify-content: center; 8 | width: 100%; 9 | overflow: hidden; 10 | .top-box { 11 | display: flex; 12 | flex-direction: column; 13 | align-items: center; 14 | justify-content: center; 15 | width: 100%; 16 | 17 | .top-img { 18 | width: 28px; 19 | height: 24px; 20 | } 21 | .top-text { 22 | color: $text-color; 23 | font-size: 10px; 24 | } 25 | } 26 | } 27 | .vin-infinite-bottom { 28 | display: block; 29 | width: 100%; 30 | padding-top: 16px; 31 | color: $infiniteloading-bottom-color; 32 | font-size: $font-size-small; 33 | text-align: center; 34 | 35 | .bottom-box { 36 | .bottom-img { 37 | width: 28px; 38 | height: 24px; 39 | margin-right: 5px; 40 | } 41 | .bottom-text { 42 | color: $text-color; 43 | font-size: 10px; 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/uni-ui/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Alvin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/range/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, PropType } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export type SliderValue = number | number[]; 5 | 6 | export const rangeProps = { 7 | ...commonProps, 8 | range: { 9 | type: Boolean, 10 | default: false, 11 | }, 12 | disabled: Boolean, 13 | activeColor: String, 14 | inactiveColor: String, 15 | buttonColor: String, 16 | vertical: { 17 | type: Boolean, 18 | default: false, 19 | }, 20 | marks: { 21 | type: Object, 22 | default: {}, 23 | }, 24 | hiddenRange: { 25 | type: Boolean, 26 | default: false, 27 | }, 28 | hiddenTag: { 29 | type: Boolean, 30 | default: false, 31 | }, 32 | min: { 33 | type: [Number, String], 34 | default: 0, 35 | }, 36 | max: { 37 | type: [Number, String], 38 | default: 100, 39 | }, 40 | step: { 41 | type: [Number, String], 42 | default: 1, 43 | }, 44 | modelValue: { 45 | type: [Number, Array] as PropType, 46 | default: 0, 47 | }, 48 | }; 49 | 50 | export type RangeProps = ExtractPropTypes; 51 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/row/index.scss: -------------------------------------------------------------------------------- 1 | .vin-row { 2 | width: 100%; 3 | &::after { 4 | display: block; 5 | clear: both; 6 | height: 0; 7 | visibility: hidden; 8 | content: ''; 9 | } 10 | 11 | &-flex { 12 | display: flex; 13 | &::after { 14 | display: none; 15 | } 16 | .vin-col { 17 | float: none; 18 | } 19 | } 20 | &-justify-center { 21 | justify-content: center; 22 | } 23 | &-justify-end { 24 | justify-content: flex-end; 25 | } 26 | &-justify-space-between { 27 | align-items: center; 28 | justify-content: space-between; 29 | } 30 | &-justify-space-around { 31 | justify-content: space-around; 32 | } 33 | &-justify-space-evenly { 34 | justify-content: space-evenly; 35 | } 36 | &-align-flex-start { 37 | align-items: flex-start; 38 | } 39 | &-align-center { 40 | align-items: center; 41 | } 42 | &-align-flex-end { 43 | align-items: flex-end; 44 | } 45 | &-flex-wrap { 46 | flex-wrap: wrap; 47 | } 48 | &-flex-nowrap { 49 | flex-wrap: nowrap; 50 | } 51 | &-flex-reverse { 52 | flex-wrap: wrap-reverse; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /packages/uni-ui/packs/npm/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Alvin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/extends/theme/dark.scss: -------------------------------------------------------------------------------- 1 | // 核心主题样式文件 2 | @mixin theme-dark { 3 | // 背景色 4 | --vin-bg: #393939; 5 | --vin-bg-1: #333; 6 | --vin-bg-2: #2c2c2c; 7 | --vin-bg-3: #292929; 8 | --vin-bg-4: #222; 9 | 10 | // 文本色 11 | --vin-text-color: #fff; 12 | --vin-text-color-1: #d4d4d4; 13 | --vin-text-color-2: #919191; 14 | --vin-text-color-3: #6a6a6a; 15 | --vin-text-color-4: #474747; 16 | 17 | // 模糊 18 | --vin-blur: rgba(38, 38, 38, 0.98); 19 | --vin-blur-1: rgba(38, 38, 38, 0.75); 20 | --vin-blur-2: rgba(38, 38, 38, 0.25); 21 | --vin-blur-3: rgba(38, 38, 38, 0.05); 22 | 23 | // 边框 24 | --vin-border: rgba(119, 119, 119, 0.25); 25 | --vin-outline: rgba(255, 255, 255, 0.1); 26 | --vin-line: rgba(119, 119, 119, 0.25); 27 | 28 | // 透明与阴影 29 | --vin-shadow: 0 0.5em 1em rgba(0, 0, 0, 0.45); 30 | --vin-shadow-sm: 0 0.125em 0.25em rgba(0, 0, 0, 0.475); 31 | --vin-shadow-lg: 0 1em 3em rgba(0, 0, 0, 0.475); 32 | --vin-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.475); 33 | --vin-shadow-opacity: 0.55; 34 | --vin-shadow-opacity-sm: 0.175; 35 | --vin-shadow-opacity-lg: 0.75; 36 | --vin-bg-opacity: 0.1; 37 | } 38 | -------------------------------------------------------------------------------- /packages/uni-ui/packs/uni_modules/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Alvin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/cell-group/index.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 35 | 36 | 39 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/divider/index.scss: -------------------------------------------------------------------------------- 1 | .vin-divider { 2 | display: flex; 3 | align-items: center; 4 | margin: $divider-margin; 5 | color: $divider-text-color; 6 | font-size: $divider-text-font-size; 7 | 8 | &::before, 9 | &::after { 10 | flex: 1; 11 | height: $divider-line-height; 12 | border: $divider-line-height solid currentColor; 13 | border-width: $divider-line-height 0 0; 14 | content: ''; 15 | } 16 | 17 | &.vin-divider-center, 18 | &.vin-divider-left, 19 | &.vin-divider-right { 20 | &::before { 21 | margin-right: $divider-before-margin-right; 22 | } 23 | 24 | &::after { 25 | margin-left: $divider-after-margin-left; 26 | } 27 | } 28 | 29 | &.vin-divider-left { 30 | &::before { 31 | max-width: 10%; 32 | } 33 | } 34 | 35 | &.vin-divider-right { 36 | &::after { 37 | max-width: 10%; 38 | } 39 | } 40 | 41 | &.vin-divider-dashed { 42 | &::before, 43 | &::after { 44 | border-style: dashed; 45 | } 46 | } 47 | 48 | &.vin-divider-hairline { 49 | &::before, 50 | &::after { 51 | transform: scaleY(0.5); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /packages/uni-ui/src/styles/extends/theme/light.scss: -------------------------------------------------------------------------------- 1 | // 核心主题样式文件 2 | @mixin theme-light { 3 | // 背景色 4 | --vin-bg: #fff; 5 | --vin-bg-1: #f6f6f6; 6 | --vin-bg-2: #f1f1f1; 7 | --vin-bg-3: #e8e8e8; 8 | --vin-bg-4: #e0e0e0; 9 | 10 | // 文本色 11 | --vin-text-color: #303030; 12 | --vin-text-color-1: #525252; 13 | --vin-text-color-2: #777; 14 | --vin-text-color-3: #9e9e9e; 15 | --vin-text-color-4: #c6c6c6; 16 | 17 | // 模糊 18 | --vin-blur: rgba(255, 255, 255, 0.98); 19 | --vin-blur-1: rgba(255, 255, 255, 0.75); 20 | --vin-blur-2: rgba(255, 255, 255, 0.25); 21 | --vin-blur-3: rgba(255, 255, 255, 0.05); 22 | 23 | // 边框 24 | --vin-border: rgba(119, 119, 119, 0.25); 25 | --vin-outline: rgba(0, 0, 0, 0.1); 26 | --vin-line: rgba(119, 119, 119, 0.25); 27 | 28 | // 透明与阴影 29 | --vin-shadow: 0 0.5em 1em rgba(0, 0, 0, 0.15); 30 | --vin-shadow-sm: 0 0.125em 0.25em rgba(0, 0, 0, 0.075); 31 | --vin-shadow-lg: 0 1em 3em rgba(0, 0, 0, 0.175); 32 | --vin-shadow-inset: inset 0 0.1em 0.2em rgba(0, 0, 0, 0.075); 33 | --vin-shadow-opacity: 0.45; 34 | --vin-shadow-opacity-sm: 0.075; 35 | --vin-shadow-opacity-lg: 0.65; 36 | --vin-bg-opacity: 0.1; 37 | } 38 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/skeleton/__test__/__snapshots__/skeleton.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should change avatar shape when using avatarShape prop 1`] = ` 4 | " 5 | 6 | 7 | 8 | 9 | " 10 | `; 11 | 12 | exports[`should change avatar size when using avatarSize prop: 20px 1`] = `"20px"`; 13 | 14 | exports[`should change avatar size when using avatarSize prop: 20px 2`] = `"20px"`; 15 | 16 | exports[`should render default slot 1`] = ` 17 | " 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | " 28 | `; 29 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/dialog/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, PropType, VNode } from 'vue'; 2 | import { popupProps } from '../popup/common'; 3 | 4 | export const dialogProps = { 5 | ...popupProps, 6 | title: { 7 | type: String, 8 | default: '', 9 | }, 10 | content: { 11 | type: [String, Object] as PropType, 12 | default: '', 13 | }, 14 | closeOnClickOverlay: { 15 | type: Boolean, 16 | default: false, 17 | }, 18 | noFooter: { 19 | type: Boolean, 20 | default: false, 21 | }, 22 | noOkBtn: { 23 | type: Boolean, 24 | default: false, 25 | }, 26 | noCancelBtn: { 27 | type: Boolean, 28 | default: false, 29 | }, 30 | cancelText: { 31 | type: String, 32 | default: '', 33 | }, 34 | okText: { 35 | type: String, 36 | default: '', 37 | }, 38 | cancelAutoClose: { 39 | type: Boolean, 40 | default: true, 41 | }, 42 | textAlign: { 43 | type: String, 44 | default: 'center', 45 | }, 46 | footerDirection: { 47 | type: String, 48 | default: 'horizontal', // vertical 49 | }, 50 | }; 51 | 52 | export type DialogProps = ExtractPropTypes; 53 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/action-sheet/__test__/__snapshots__/index.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`should render sure actionsheet when use custom props 1`] = ` 4 | " 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 选项一 17 | 描述信息 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | " 27 | `; 28 | -------------------------------------------------------------------------------- /.workflow/pr-pipeline.yml: -------------------------------------------------------------------------------- 1 | version: '1.0' 2 | name: pr-pipeline 3 | displayName: PRPipeline 4 | stages: 5 | - stage: 6 | name: compile 7 | displayName: 编译 8 | steps: 9 | - step: build@nodejs 10 | name: build_nodejs 11 | displayName: Nodejs 构建 12 | # 支持8.16.2、10.17.0、12.16.1、14.16.0、15.12.0五个版本 13 | nodeVersion: 14.16.0 14 | # 构建命令:安装依赖 -> 清除上次打包产物残留 -> 执行构建 【请根据项目实际产出进行填写】 15 | commands: 16 | - npm install && rm -rf ./dist && npm run build 17 | # 非必填字段,开启后表示将构建产物暂存,但不会上传到制品库中,7天后自动清除 18 | artifacts: 19 | # 构建产物名字,作为产物的唯一标识可向下传递,支持自定义,默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址 20 | - name: BUILD_ARTIFACT 21 | # 构建产物获取路径,是指代码编译完毕之后构建物的所在路径 22 | path: 23 | - ./dist 24 | - step: publish@general_artifacts 25 | name: publish_general_artifacts 26 | displayName: 上传制品 27 | # 上游构建任务定义的产物名,默认BUILD_ARTIFACT 28 | dependArtifact: BUILD_ARTIFACT 29 | # 上传到制品库时的制品命名,默认output 30 | artifactName: output 31 | dependsOn: build_nodejs 32 | triggers: 33 | pr: 34 | branches: 35 | include: 36 | - master 37 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/action-sheet/common.ts: -------------------------------------------------------------------------------- 1 | import type { PropType, ExtractPropTypes } from 'vue'; 2 | import { popupProps } from '../popup/common'; 3 | 4 | export interface menuItems { 5 | disable: boolean; 6 | loading: boolean; 7 | color: string; 8 | name: string; 9 | subname: string; 10 | [x: string]: string | boolean; 11 | } 12 | 13 | export const actionSheetProps = { 14 | ...popupProps, 15 | cancelTxt: { 16 | type: String, 17 | default: '', 18 | }, 19 | optionTag: { 20 | type: String, 21 | default: 'name', 22 | }, 23 | optionSubTag: { 24 | type: String, 25 | default: 'subname', 26 | }, 27 | chooseTagValue: { 28 | type: String, 29 | default: '', 30 | }, 31 | title: { 32 | type: String, 33 | default: '', 34 | }, 35 | color: { 36 | type: String, 37 | default: '#ee0a24', 38 | }, 39 | description: { 40 | type: String, 41 | default: '', 42 | }, 43 | menuItems: { 44 | type: Array as PropType, 45 | default: () => [], 46 | }, 47 | closeAbled: { 48 | type: Boolean, 49 | default: true, 50 | }, 51 | }; 52 | 53 | export type ActionSheetProps = ExtractPropTypes; 54 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/cascader/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { popupProps } from '../popup/common'; 3 | 4 | export const cascaderProps = { 5 | ...popupProps, 6 | modelValue: Array, 7 | visible: Boolean, 8 | options: { 9 | type: Array, 10 | default: () => [], 11 | }, 12 | lazy: Boolean, 13 | lazyLoad: Function, 14 | valueKey: { 15 | type: String, 16 | default: 'value', 17 | }, 18 | textKey: { 19 | type: String, 20 | default: 'text', 21 | }, 22 | childrenKey: { 23 | type: String, 24 | default: 'children', 25 | }, 26 | convertConfig: Object, 27 | title: String, 28 | }; 29 | 30 | export const cascaderItemProps = { 31 | visible: Boolean, 32 | modelValue: Array, 33 | options: { 34 | type: Array, 35 | default: () => [], 36 | }, 37 | lazy: Boolean, 38 | lazyLoad: Function, 39 | valueKey: { 40 | type: String, 41 | default: 'value', 42 | }, 43 | textKey: { 44 | type: String, 45 | default: 'text', 46 | }, 47 | childrenKey: { 48 | type: String, 49 | default: 'children', 50 | }, 51 | convertConfig: Object, 52 | }; 53 | 54 | export type CascaderProps = ExtractPropTypes; 55 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/divider/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 36 | 37 | 40 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/progress/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const progressProps = { 5 | ...commonProps, 6 | percentage: { 7 | type: [Number, String], 8 | default: 0, 9 | required: true, 10 | }, 11 | size: { 12 | type: String, 13 | default: 'base', 14 | }, 15 | status: { 16 | type: String, 17 | default: 'text', 18 | }, 19 | strokeWidth: { 20 | type: [Number, String], 21 | default: '', 22 | }, 23 | textInside: { 24 | type: Boolean, 25 | default: false, 26 | }, 27 | showText: { 28 | type: Boolean, 29 | default: true, 30 | }, 31 | strokeColor: { 32 | type: String, 33 | default: '', 34 | }, 35 | textColor: { 36 | tyep: String, 37 | default: '', 38 | }, 39 | textBackground: { 40 | tyep: String, 41 | default: '', 42 | }, 43 | iconName: { 44 | type: String, 45 | default: 'checked', 46 | }, 47 | iconColor: { 48 | type: String, 49 | default: '#439422', 50 | }, 51 | isShowPercentage: { 52 | type: Boolean, 53 | default: true, 54 | }, 55 | }; 56 | 57 | export type ProgressProps = ExtractPropTypes; 58 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/switch/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const switchProps = { 5 | ...commonProps, 6 | modelValue: { 7 | type: [String, Number, Boolean], 8 | default: false, 9 | }, 10 | disable: { 11 | type: Boolean, 12 | default: false, 13 | }, 14 | loading: { 15 | type: Boolean, 16 | default: false, 17 | }, 18 | name: { 19 | type: String, 20 | default: 'loading', 21 | }, 22 | color: { 23 | type: String, 24 | default: '', 25 | }, 26 | size: { 27 | type: [String, Number], 28 | default: '12px', 29 | }, 30 | activeColor: { 31 | type: String, 32 | default: '', 33 | }, 34 | inactiveColor: { 35 | type: String, 36 | default: '', 37 | }, 38 | activeText: { 39 | type: String, 40 | default: '', 41 | }, 42 | inactiveText: { 43 | type: String, 44 | default: '', 45 | }, 46 | activeValue: { 47 | type: [String, Number, Boolean], 48 | default: true, 49 | }, 50 | inactiveValue: { 51 | type: [String, Number, Boolean], 52 | default: false, 53 | }, 54 | }; 55 | 56 | export type SwitchProps = ExtractPropTypes; 57 | -------------------------------------------------------------------------------- /example/src/pages/components/textarea.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /example/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @vingogo/example 2 | 3 | ## 0.2.0 4 | 5 | ### Minor Changes 6 | 7 | - [`818ca19`](https://github.com/vingogo/vin-ui/commit/818ca19f237171a7a83ea42a9721c626585480a6) Thanks [@Alvin-LM](https://github.com/Alvin-LM)! - chore: upgrade dependencies version 8 | 9 | - [`5361070`](https://github.com/vingogo/vin-ui/commit/536107017e3ac7440a67f2a18b138e9bbc33a35d) Thanks [@Alvin-LM](https://github.com/Alvin-LM)! - fix: replace unsupported tags 10 | 11 | ### Patch Changes 12 | 13 | - [`645562d`](https://github.com/vingogo/vin-ui/commit/645562d542396be2affcdef89acbc28d0927d066) Thanks [@Alvin-LM](https://github.com/Alvin-LM)! - fix: style render error 14 | 15 | - [`700e9b8`](https://github.com/vingogo/vin-ui/commit/700e9b8a5b98d18fc198c6adf47d981655a894bb) Thanks [@Alvin-LM](https://github.com/Alvin-LM)! - fix: input error 16 | 17 | - Updated dependencies [[`645562d`](https://github.com/vingogo/vin-ui/commit/645562d542396be2affcdef89acbc28d0927d066), [`700e9b8`](https://github.com/vingogo/vin-ui/commit/700e9b8a5b98d18fc198c6adf47d981655a894bb), [`1be2292`](https://github.com/vingogo/vin-ui/commit/1be2292891229f4c2d81744190da27ef03b78e41), [`5361070`](https://github.com/vingogo/vin-ui/commit/536107017e3ac7440a67f2a18b138e9bbc33a35d)]: 18 | - @vingogo/uni-ui@null 19 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/calendar-item/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import Utils from '../../shared/utils/date'; 3 | 4 | export const calendarItemProps = { 5 | type: { 6 | type: String, 7 | default: 'one', 8 | }, 9 | isAutoBackFill: { 10 | type: Boolean, 11 | default: false, 12 | }, 13 | poppable: { 14 | type: Boolean, 15 | default: true, 16 | }, 17 | showTitle: { 18 | type: Boolean, 19 | default: true, 20 | }, 21 | showSubTitle: { 22 | type: Boolean, 23 | default: true, 24 | }, 25 | showToday: { 26 | type: Boolean, 27 | default: true, 28 | }, 29 | title: { 30 | type: String, 31 | default: '', 32 | }, 33 | confirmText: { 34 | type: String, 35 | default: '', 36 | }, 37 | startText: { 38 | type: String, 39 | default: '', 40 | }, 41 | endText: { 42 | type: String, 43 | default: '', 44 | }, 45 | defaultValue: { 46 | type: [String, Array], 47 | default: null, 48 | }, 49 | startDate: { 50 | type: String, 51 | default: Utils.getDay(0), 52 | }, 53 | endDate: { 54 | type: String, 55 | default: Utils.getDay(365), 56 | }, 57 | }; 58 | 59 | export type CalendarItemProps = ExtractPropTypes; 60 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/empty/__tests__/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils'; 2 | import Empty from '../index.vue'; 3 | 4 | describe('Empty', () => { 5 | test('should be shown when passing image and description', () => { 6 | const wrapper = mount(Empty, { 7 | props: { 8 | image: 'empty', 9 | description: '这是文字描述', 10 | }, 11 | }); 12 | 13 | expect(wrapper.html()).toContain('img'); 14 | expect(wrapper.html()).toContain('这是文字描述'); 15 | }); 16 | 17 | test('should be shown when passing slot image', () => { 18 | const wrapper = mount(Empty, { 19 | slots: { 20 | image: '', 21 | }, 22 | }); 23 | 24 | expect(wrapper.html()).toContain('abc.png'); 25 | }); 26 | 27 | test('should be shown when passing slot description', () => { 28 | const wrapper = mount(Empty, { 29 | slots: { 30 | description: 'test', 31 | }, 32 | }); 33 | 34 | expect(wrapper.html()).toContain('test'); 35 | }); 36 | 37 | test('should be shown when passing slot defalut', () => { 38 | const wrapper = mount(Empty, { 39 | slots: { 40 | default: '加载失败,请刷新页面', 41 | }, 42 | }); 43 | 44 | expect(wrapper.html()).toContain('加载失败'); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/grid/common.ts: -------------------------------------------------------------------------------- 1 | import type { PropType, ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const GRID_KEY = Symbol('grid'); 5 | 6 | export type GridDirection = 'horizontal' | 'vertical'; 7 | 8 | export const gridProps = { 9 | ...commonProps, 10 | // 列数 11 | columnNum: { 12 | type: [Number, String], 13 | default: 4, 14 | }, 15 | // 图标大小 16 | iconSize: { 17 | type: [Number, String], 18 | default: 28, 19 | }, 20 | // 图标颜色 21 | iconColor: { 22 | type: String, 23 | }, 24 | // 是否显示边框 25 | border: { 26 | type: Boolean, 27 | default: true, 28 | }, 29 | // 格子之间间隔距离 30 | gutter: { 31 | type: [Number, String], 32 | default: 0, 33 | }, 34 | // 是否内容居中 35 | center: { 36 | type: Boolean, 37 | default: true, 38 | }, 39 | // 是否固定正方形 40 | square: { 41 | type: Boolean, 42 | default: false, 43 | }, 44 | // 内容与文字翻转 45 | reverse: { 46 | type: Boolean, 47 | default: false, 48 | }, 49 | // 内容排列方向 50 | direction: { 51 | type: String as PropType, 52 | }, 53 | // 是否开启点击反馈 54 | clickable: { 55 | type: Boolean, 56 | default: false, 57 | }, 58 | }; 59 | 60 | export type GridProps = ExtractPropTypes; 61 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/tabs/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, PropType } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export type TabsSize = 'large' | 'normal' | 'small'; 5 | 6 | export const tabsProps = { 7 | ...commonProps, 8 | modelValue: { 9 | type: [String, Number], 10 | default: 0, 11 | }, 12 | color: { 13 | type: String, 14 | default: '', 15 | }, 16 | direction: { 17 | type: String, 18 | default: 'horizontal', // vertical 19 | }, 20 | size: { 21 | type: String as PropType, 22 | default: 'normal', 23 | }, 24 | type: { 25 | type: String, 26 | default: 'line', // card、line、smile 27 | }, 28 | titleScroll: { 29 | type: Boolean, 30 | default: false, 31 | }, 32 | ellipsis: { 33 | type: Boolean, 34 | default: true, 35 | }, 36 | background: { 37 | type: String, 38 | default: '', 39 | }, 40 | animatedTime: { 41 | type: [Number, String], 42 | default: 300, 43 | }, 44 | titleGutter: { 45 | type: [Number, String], 46 | default: 0, 47 | }, 48 | customClass: { 49 | type: [String, Object], 50 | default: '', 51 | }, 52 | }; 53 | 54 | export type TabsProps = ExtractPropTypes; 55 | 56 | export const TAB_KEY = Symbol('tabs'); 57 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/grid/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 42 | 43 | 46 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/rate/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const rateProps = { 5 | ...commonProps, 6 | modelValue: { 7 | type: [String, Number], 8 | default: 0, 9 | }, 10 | count: { 11 | type: [String, Number], 12 | default: 5, 13 | }, 14 | iconSize: { 15 | type: [String, Number], 16 | default: 18, 17 | }, 18 | activeColor: { 19 | type: String, 20 | default: '', 21 | }, 22 | voidColor: { 23 | type: String, 24 | default: '', 25 | }, 26 | uncheckedIcon: { 27 | type: String, 28 | default: 'star-n', 29 | }, 30 | checkedIcon: { 31 | type: String, 32 | default: 'star-fill-n', 33 | }, 34 | fontClassName: { 35 | type: String, 36 | default: 'vin-iconfont', 37 | }, 38 | classPrefix: { 39 | type: String, 40 | default: 'vin-icon', 41 | }, 42 | allowHalf: { 43 | type: Boolean, 44 | default: false, 45 | }, 46 | readonly: { 47 | type: Boolean, 48 | default: false, 49 | }, 50 | disabled: { 51 | type: Boolean, 52 | default: false, 53 | }, 54 | spacing: { 55 | type: [String, Number], 56 | default: 14, 57 | }, 58 | }; 59 | 60 | export type RateProps = ExtractPropTypes; 61 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/skeleton/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, PropType } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export type avatarShapeType = 'round' | 'square'; 5 | 6 | export const skeletonProps = { 7 | ...commonProps, 8 | 9 | // 每行宽度 10 | width: { 11 | type: String, 12 | default: '100px', 13 | }, 14 | // 每行高度 15 | height: { 16 | type: String, 17 | default: '100px', 18 | }, 19 | // 是否显示动画 20 | animated: { 21 | type: Boolean, 22 | default: false, 23 | }, 24 | // 头像 25 | avatar: { 26 | type: Boolean, 27 | default: false, 28 | }, 29 | // 头像形状:正方形/圆形 30 | avatarShape: { 31 | type: String as PropType, 32 | default: 'round', 33 | }, 34 | // 头像大小 35 | avatarSize: { 36 | type: String, 37 | default: '50px', 38 | }, 39 | // 是否显示骨架屏 40 | loading: { 41 | type: Boolean, 42 | default: true, 43 | }, 44 | // 标题/段落 圆角风格 45 | round: { 46 | type: Boolean, 47 | default: false, 48 | }, 49 | 50 | // 显示段落行数 51 | row: { 52 | type: String, 53 | default: '1', 54 | }, 55 | 56 | // 是否显示段落标题 57 | title: { 58 | type: Boolean, 59 | default: true, 60 | }, 61 | }; 62 | 63 | export type SkeletonProps = ExtractPropTypes; 64 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/icon/__tests__/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { config, mount } from '@vue/test-utils'; 2 | import Icon from '../index.vue'; 3 | 4 | test('should render icon fabulous', async () => { 5 | const wrapper = mount(Icon, { 6 | props: { 7 | name: 'fabulous', 8 | }, 9 | }); 10 | 11 | expect(wrapper.html()).toMatchSnapshot(); 12 | }); 13 | test('should render icon image type', async () => { 14 | const wrapper = mount(Icon, { 15 | props: { 16 | name: 'https://cdn.vingogo.cn/logo.png', 17 | }, 18 | }); 19 | 20 | expect(wrapper.html()).toMatchSnapshot(); 21 | }); 22 | 23 | test('should render icon fabulous color', async () => { 24 | const wrapper = mount(Icon, { 25 | props: { 26 | name: 'fabulous', 27 | color: 'red', 28 | }, 29 | }); 30 | 31 | expect(wrapper.find('.vin-icon-fabulous').element.style.color).toEqual('red'); 32 | expect(wrapper.html()).toMatchSnapshot(); 33 | }); 34 | 35 | test('should render icon fabulous size', async () => { 36 | const wrapper = mount(Icon, { 37 | props: { 38 | name: 'fabulous', 39 | size: '24', 40 | }, 41 | }); 42 | 43 | expect(wrapper.find('.vin-icon-fabulous').element.style.fontSize).toEqual('24px'); 44 | expect(wrapper.html()).toMatchSnapshot(); 45 | }); 46 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/calendar/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import Utils from '../../shared/utils/date'; 3 | 4 | export const calendarProps = { 5 | type: { 6 | type: String, 7 | default: 'one', 8 | }, 9 | isAutoBackFill: { 10 | type: Boolean, 11 | default: false, 12 | }, 13 | poppable: { 14 | type: Boolean, 15 | default: true, 16 | }, 17 | showTitle: { 18 | type: Boolean, 19 | default: true, 20 | }, 21 | showSubTitle: { 22 | type: Boolean, 23 | default: true, 24 | }, 25 | visible: { 26 | type: Boolean, 27 | default: false, 28 | }, 29 | showToday: { 30 | type: Boolean, 31 | default: true, 32 | }, 33 | title: { 34 | type: String, 35 | default: '', 36 | }, 37 | confirmText: { 38 | type: String, 39 | default: '', 40 | }, 41 | startText: { 42 | type: String, 43 | default: '', 44 | }, 45 | endText: { 46 | type: String, 47 | default: '', 48 | }, 49 | defaultValue: { 50 | type: [String, Array], 51 | }, 52 | startDate: { 53 | type: String, 54 | default: Utils.getDay(0), 55 | }, 56 | endDate: { 57 | type: String, 58 | default: Utils.getDay(365), 59 | }, 60 | }; 61 | 62 | export type CalendarProps = ExtractPropTypes; 63 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/overlay/index.vue: -------------------------------------------------------------------------------- 1 | 12 | 44 | 47 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/swiper/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const swiperProps = { 5 | ...commonProps, 6 | list: { 7 | type: Array, 8 | default: () => [], 9 | }, 10 | width: { 11 | type: [Number, String], 12 | default: '100%', 13 | }, 14 | height: { 15 | type: [Number, String], 16 | default: 150, 17 | }, 18 | direction: { 19 | type: String, 20 | default: 'horizontal', // horizontal and vertical 21 | }, 22 | paginationVisible: { 23 | type: Boolean, 24 | default: false, 25 | }, 26 | paginationColor: { 27 | type: String, 28 | default: 'rgba(0, 0, 0, 0.3)', 29 | }, 30 | paginationActiveColor: { 31 | type: String, 32 | default: '#000', 33 | }, 34 | loop: { 35 | type: Boolean, 36 | default: true, 37 | }, 38 | duration: { 39 | type: [Number, String], 40 | default: 500, 41 | }, 42 | autoPlay: { 43 | type: [Number, String], 44 | default: 0, 45 | }, 46 | initPage: { 47 | type: [Number, String], 48 | default: 0, 49 | }, 50 | touchable: { 51 | type: Boolean, 52 | default: true, 53 | }, 54 | }; 55 | 56 | export const SWIPER_KEY = Symbol('swiper'); 57 | 58 | export type SwiperProps = ExtractPropTypes; 59 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/comment/__tests__/comment.spec.ts: -------------------------------------------------------------------------------- 1 | import { config, mount } from '@vue/test-utils'; 2 | import { nextTick, toRefs, reactive } from 'vue'; 3 | import VinIcon from '../../icon/index.vue'; 4 | import VinRate from '../../rate/index.vue'; 5 | import Comment from '../index.vue'; 6 | import CommentData from '../comment_data.json'; 7 | 8 | beforeAll(() => { 9 | config.global.components = { 10 | VinIcon, 11 | VinRate, 12 | }; 13 | }); 14 | 15 | afterAll(() => { 16 | config.global.components = {}; 17 | }); 18 | 19 | test('comment init render', async () => { 20 | const wrapper = mount(Comment, { 21 | props: { 22 | images: CommentData.Comment.images, 23 | videos: CommentData.Comment.videos, 24 | info: CommentData.Comment.info, 25 | }, 26 | }); 27 | await nextTick(); 28 | expect(wrapper.find('.vin-comment__main').exists()).toBeTruthy(); 29 | }); 30 | 31 | test('comment mutli images', async () => { 32 | const wrapper = mount(Comment, { 33 | props: { 34 | headerType: 'complex', 35 | imagesRows: 'multi', 36 | images: CommentData.Comment.images, 37 | videos: CommentData.Comment.videos, 38 | info: CommentData.Comment.info, 39 | }, 40 | }); 41 | await nextTick(); 42 | expect(wrapper.find('.vin-comment-images__mask').exists()).toBeTruthy(); 43 | }); 44 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/button/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, PropType } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export type ButtonType = 'default' | 'primary' | 'info' | 'success' | 'warning' | 'danger'; 5 | export type ButtonSize = 'large' | 'normal' | 'small' | 'mini'; 6 | export type ButtonShape = 'square' | 'round'; 7 | 8 | export const buttonProps = { 9 | ...commonProps, 10 | type: { 11 | type: String as PropType, 12 | default: 'default', 13 | }, 14 | size: { 15 | type: String as PropType, 16 | default: 'normal', 17 | }, 18 | shape: { 19 | type: String as PropType, 20 | default: 'round', 21 | }, 22 | color: String, 23 | plain: { 24 | type: Boolean, 25 | default: false, 26 | }, 27 | disabled: { 28 | type: Boolean, 29 | default: false, 30 | }, 31 | block: { 32 | type: Boolean, 33 | default: false, 34 | }, 35 | icon: { 36 | type: String, 37 | default: '', 38 | }, 39 | iconFontClassName: { 40 | type: String, 41 | default: 'vin-iconfont', 42 | }, 43 | iconClassPrefix: { 44 | type: String, 45 | default: 'vin-icon', 46 | }, 47 | loading: { 48 | type: Boolean, 49 | default: false, 50 | }, 51 | }; 52 | 53 | export type ButtonProps = ExtractPropTypes; 54 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/price/index.scss: -------------------------------------------------------------------------------- 1 | .vin-price { 2 | display: inline; 3 | color: $price-color; 4 | font-size: 0; 5 | &--strike { 6 | [class*='vin-price'] { 7 | text-decoration: line-through; 8 | } 9 | } 10 | &--symbol { 11 | display: inline-block; 12 | font-size: $font-size-3; 13 | } 14 | &--large { 15 | display: inline-block; 16 | font-size: $price-big-size; 17 | } 18 | &--point { 19 | display: inline-block; 20 | font-size: $price-big-size; 21 | } 22 | &--decimal-large { 23 | display: inline-block; 24 | font-size: $price-decimal-big-size; 25 | } 26 | &--symbol-large { 27 | display: inline-block; 28 | font-size: $price-symbol-big-size; 29 | } 30 | &--normal { 31 | display: inline-block; 32 | font-size: $price-medium-size; 33 | } 34 | &--decimal-normal { 35 | display: inline-block; 36 | font-size: $price-decimal-medium-size; 37 | } 38 | &--symbol-normal { 39 | display: inline-block; 40 | font-size: $price-symbol-medium-size; 41 | } 42 | &--small { 43 | display: inline-block; 44 | font-size: $price-small-size; 45 | } 46 | &--decimal-small { 47 | display: inline-block; 48 | font-size: $price-decimal-small-size; 49 | } 50 | &--symbol-small { 51 | display: inline-block; 52 | font-size: $price-symbol-small-size; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/avatar/index.scss: -------------------------------------------------------------------------------- 1 | .vin-avatar { 2 | position: relative; 3 | display: inline-block; 4 | flex: 0 0 auto; // 防止被压缩 5 | text-align: center; 6 | background-repeat: no-repeat; 7 | background-position: center center; 8 | background-size: 100% 100%; 9 | 10 | img { 11 | width: 100%; 12 | height: 100%; 13 | } 14 | 15 | .icon { 16 | position: absolute; 17 | top: 50%; 18 | left: 50%; 19 | background-size: 100% 100%; 20 | transform: translate(-50%, -50%); 21 | } 22 | 23 | .vin-icon__img { 24 | width: 100%; 25 | height: 100%; 26 | } 27 | 28 | .text { 29 | display: inline-block; 30 | width: 100%; 31 | height: 100%; 32 | overflow: hidden; 33 | text-align: center; 34 | } 35 | } 36 | 37 | .vin-avatar-large { 38 | width: $avatar-large-width; 39 | height: $avatar-large-height; 40 | line-height: $avatar-large-height; 41 | } 42 | 43 | .vin-avatar-small { 44 | width: $avatar-small-width; 45 | height: $avatar-small-height; 46 | line-height: $avatar-small-height; 47 | } 48 | 49 | .vin-avatar-normal { 50 | width: $avatar-normal-width; 51 | height: $avatar-normal-height; 52 | line-height: $avatar-normal-height; 53 | } 54 | 55 | .vin-avatar-round { 56 | overflow: hidden; 57 | border-radius: 50%; 58 | } 59 | 60 | .vin-avatar-square { 61 | border-radius: $avatar-square; 62 | } 63 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/notify/index.scss: -------------------------------------------------------------------------------- 1 | .vin-popup-top { 2 | position: fixed; 3 | top: 0; 4 | left: 0; 5 | z-index: 9999; 6 | display: flex; 7 | width: 100%; 8 | overflow-y: auto; 9 | transition: transform 0.3s; 10 | } 11 | .vin-popup-bottom { 12 | position: fixed; 13 | bottom: 0; 14 | left: 0; 15 | z-index: 9999; 16 | width: 100%; 17 | overflow-y: auto; 18 | transition: transform 0.3s; 19 | } 20 | 21 | .vin-fade-enter-active { 22 | transition: opacity 1s; 23 | } 24 | 25 | .vin-fade-leave-active { 26 | transition: opacity 1s; 27 | } 28 | 29 | .vin-fade-enter-from, 30 | .vin-fade-leave-to { 31 | opacity: 0; 32 | } 33 | .vin-notify { 34 | box-sizing: border-box; 35 | width: 100%; 36 | height: $notify-height; 37 | padding: $notify-padding; 38 | color: $notify-text-color; 39 | font-size: $notify-font-size; 40 | line-height: $notify-line-height; 41 | white-space: pre-wrap; 42 | text-align: center; 43 | word-wrap: break-word; 44 | &--base { 45 | background: $notify-base-background-color; 46 | } 47 | &--primary { 48 | background: $notify-primary-background-color; 49 | } 50 | 51 | &--success { 52 | background: $notify-success-background-color; 53 | } 54 | 55 | &--danger { 56 | background: $notify-danger-background-color; 57 | } 58 | 59 | &--warning { 60 | background: $notify-warning-background-color; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vingogo/example", 3 | "version": "0.2.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vin dev", 7 | "build": "vin build", 8 | "type-check": "vue-tsc --noEmit", 9 | "deploy": "npm run build && static-upload start --prefix=ui --directory=dist/build/h5" 10 | }, 11 | "dependencies": { 12 | "@dcloudio/uni-app": "^3.0.0-3081220230817001", 13 | "@dcloudio/uni-app-plus": "^3.0.0-3081220230817001", 14 | "@dcloudio/uni-components": "^3.0.0-3081220230817001", 15 | "@dcloudio/uni-h5": "^3.0.0-3081220230817001", 16 | "@dcloudio/uni-mp-alipay": "^3.0.0-3081220230817001", 17 | "@dcloudio/uni-mp-baidu": "^3.0.0-3081220230817001", 18 | "@dcloudio/uni-mp-kuaishou": "^3.0.0-3081220230817001", 19 | "@dcloudio/uni-mp-lark": "^3.0.0-3081220230817001", 20 | "@dcloudio/uni-mp-qq": "^3.0.0-3081220230817001", 21 | "@dcloudio/uni-mp-toutiao": "^3.0.0-3081220230817001", 22 | "@dcloudio/uni-mp-weixin": "^3.0.0-3081220230817001", 23 | "@vingogo/uni-ui": "workspace:^", 24 | "vue": "^3.2.33" 25 | }, 26 | "devDependencies": { 27 | "@dcloudio/types": "^3.2.11", 28 | "@dcloudio/vite-plugin-uni": "^3.0.0-3081220230817001", 29 | "@uni-helper/vite-plugin-uni-components": "^0.0.6", 30 | "@vingogo/vin-cli": "^0.6.0", 31 | "sass": "^1.52.1", 32 | "typescript": "^4.6.3", 33 | "vite": "^4.0.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/radiogroup/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 46 | 49 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/noticebar/common.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const noticebarProps = { 5 | ...commonProps, 6 | // 滚动方向 across 横向 vertical 纵向 7 | direction: { 8 | type: String, 9 | default: 'across', 10 | }, 11 | list: { 12 | type: Array, 13 | default: () => { 14 | return []; 15 | }, 16 | }, 17 | standTime: { 18 | type: Number, 19 | default: 1000, 20 | }, 21 | complexAm: { 22 | type: Boolean, 23 | default: false, 24 | }, 25 | height: { 26 | type: Number, 27 | default: 40, 28 | }, 29 | text: { 30 | type: String, 31 | default: '', 32 | }, 33 | closeMode: { 34 | type: Boolean, 35 | default: false, 36 | }, 37 | wrapable: { 38 | type: Boolean, 39 | default: false, 40 | }, 41 | leftIcon: { type: String, default: '' }, 42 | rightIcon: { type: String, default: '' }, 43 | color: { 44 | type: String, 45 | default: '#F9911B', 46 | }, 47 | background: { 48 | type: String, 49 | default: '', 50 | }, 51 | delay: { 52 | type: [String, Number], 53 | default: 1, 54 | }, 55 | scrollable: { 56 | type: Boolean, 57 | default: null, 58 | }, 59 | speed: { 60 | type: Number, 61 | default: 50, 62 | }, 63 | }; 64 | 65 | export type NoticebarProps = ExtractPropTypes; 66 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/badge/__test__/__snapshots__/badge.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`should change dot position when using offset prop: -2px 1`] = `""`; 4 | 5 | exports[`should change dot position when using offset prop: 4px 1`] = `""`; 6 | 7 | exports[`should render content slot correctly 1`] = ` 8 | " 9 | Custom Content 10 | " 11 | `; 12 | 13 | exports[`should render nothing when content is empty string 1`] = ` 14 | " 15 | 16 | 17 | " 18 | `; 19 | 20 | exports[`should render nothing when content is undefined 1`] = ` 21 | " 22 | 23 | 24 | " 25 | `; 26 | 27 | exports[`should render nothing when content is zero 1`] = ` 28 | " 29 | 30 | 0 31 | " 32 | `; 33 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/dialog/__tests__/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { config, mount } from '@vue/test-utils'; 2 | import DialogTemplate from '../index.vue'; 3 | import Icon from '../../icon/index.vue'; 4 | import Popup from '../../popup/index.vue'; 5 | import Button from '../../button/index.vue'; 6 | import OverLay from '../../overlay/index.vue'; 7 | 8 | beforeAll(() => { 9 | config.global.components = { 10 | [Icon.name]: Icon, 11 | [Popup.name]: Popup, 12 | [Button.name]: Button, 13 | [OverLay.name]: OverLay, 14 | }; 15 | }); 16 | 17 | beforeEach(() => { 18 | // create teleport target 19 | const el = document.createElement('div'); 20 | el.id = 'app'; 21 | document.body.appendChild(el); 22 | }); 23 | 24 | afterEach(() => { 25 | // clean up 26 | document.body.outerHTML = ''; 27 | }); 28 | 29 | test('should render dialog template', async () => { 30 | const wrapper = mount(DialogTemplate, { 31 | props: { 32 | title: 't1', 33 | content: 'c1', 34 | }, 35 | }); 36 | 37 | const overLay = wrapper.getComponent(OverLay); 38 | expect(await overLay.find('.vin-dialog__content')); 39 | }); 40 | 41 | // test('should render dialog methods', async () => { 42 | // Dialog({ 43 | // title: '基础弹框', 44 | // content: '支持函数调用和组件调用两种方式。', 45 | // onCancel, 46 | // onOk 47 | // }); 48 | // const overLay = wrapper.getComponent(OverLay); 49 | // expect(await overLay.find('.vin-dialog__content')) 50 | // }); 51 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/dialog/index.scss: -------------------------------------------------------------------------------- 1 | .vin-dialog { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | box-sizing: border-box; 6 | width: $dialog-width; 7 | min-height: 156px; 8 | padding: 28px 24px 16px 24px; 9 | 10 | &__header { 11 | display: block; 12 | height: 20px; 13 | color: rgba(38, 38, 38, 1); 14 | font-size: 16px; 15 | text-align: center; 16 | @include oneline-ellipsis(); 17 | } 18 | &__content { 19 | flex: 1; 20 | width: 100%; 21 | max-height: 268px; 22 | margin: 20px 0; 23 | overflow: auto; 24 | color: $text-color; 25 | font-size: 12px; 26 | line-height: 16px; 27 | white-space: pre-wrap; 28 | word-wrap: break-word; 29 | word-break: break-all; 30 | } 31 | &__footer { 32 | display: flex; 33 | align-items: center; 34 | justify-content: space-around; 35 | width: 100%; 36 | 37 | &.vertical { 38 | flex-direction: column; 39 | 40 | .vin-button { 41 | min-width: 100%; 42 | margin: 0; 43 | &.vin-dialog__footer-cancel { 44 | border: 0; 45 | } 46 | &.vin-dialog__footer-ok { 47 | margin-top: 10px; 48 | } 49 | } 50 | } 51 | 52 | .vin-button { 53 | min-width: 100px; 54 | } 55 | 56 | &-cancel { 57 | margin-right: 20px; 58 | } 59 | &-ok { 60 | max-width: 128px; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/row/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 47 | 48 | 51 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/badge/__test__/badge.spec.ts: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils'; 2 | import Badge from '../index.vue'; 3 | 4 | test('should render nothing when content is empty string', () => { 5 | const wrapper = mount(Badge, { 6 | props: { 7 | value: '', 8 | }, 9 | }); 10 | 11 | expect(wrapper.html()).toMatchSnapshot(); 12 | }); 13 | 14 | test('should render nothing when content is undefined', () => { 15 | const wrapper = mount(Badge, { 16 | props: { 17 | value: undefined, 18 | }, 19 | }); 20 | 21 | expect(wrapper.html()).toMatchSnapshot(); 22 | }); 23 | 24 | test('should render nothing when content is zero', () => { 25 | const wrapper = mount(Badge, { 26 | props: { 27 | value: 0, 28 | }, 29 | }); 30 | 31 | expect(wrapper.html()).toMatchSnapshot(); 32 | }); 33 | 34 | test('should render content slot correctly', () => { 35 | const wrapper = mount(Badge, { 36 | slots: { 37 | default: () => 'Custom Content', 38 | }, 39 | }); 40 | 41 | expect(wrapper.html()).toMatchSnapshot(); 42 | }); 43 | 44 | test('should change dot position when using offset prop', () => { 45 | const wrapper = mount(Badge, { 46 | props: { 47 | top: '4', 48 | right: '-2', 49 | }, 50 | }); 51 | 52 | const badge: any = wrapper.find('.vin-badge'); 53 | expect(badge.element.style.top).toMatchSnapshot('4px'); 54 | expect(badge.element.style.right).toMatchSnapshot('-2px'); 55 | }); 56 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/navbar/__test__/navbar.spec.ts: -------------------------------------------------------------------------------- 1 | import { mount, config } from '@vue/test-utils'; 2 | import NavBar from '../index.vue'; 3 | 4 | import VinIcon from '../../icon/index.vue'; 5 | 6 | beforeAll(() => { 7 | config.global.components = { 8 | VinIcon, 9 | }; 10 | }); 11 | 12 | afterAll(() => { 13 | config.global.components = {}; 14 | }); 15 | 16 | test('should render left slot correctly', () => { 17 | const wrapper = mount(NavBar, { 18 | slots: { 19 | left: () => 'Custom Left', 20 | }, 21 | }); 22 | 23 | expect(wrapper.find('.vin-navbar__left').html()).toMatchSnapshot(); 24 | }); 25 | 26 | test('should render left slot correctly', () => { 27 | const wrapper = mount(NavBar, { 28 | slots: { 29 | right: () => 'Custom Right', 30 | }, 31 | }); 32 | 33 | expect(wrapper.find('.vin-navbar__right').html()).toMatchSnapshot(); 34 | }); 35 | 36 | test('should render title slot correctly', () => { 37 | const wrapper = mount(NavBar, { 38 | slots: { 39 | title: () => 'Custom Title', 40 | }, 41 | }); 42 | 43 | expect(wrapper.find('.vin-navbar__title').html()).toMatchSnapshot(); 44 | }); 45 | 46 | test('should emit click-right event when clicking right text', () => { 47 | const wrapper = mount(NavBar, { 48 | props: { 49 | desc: 'right', 50 | }, 51 | }); 52 | 53 | wrapper.find('.right_text').trigger('click'); 54 | expect(wrapper.emitted('on-click-right')).toBeTruthy(); 55 | }); 56 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/col/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 49 | 50 | 53 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/skeleton/index.scss: -------------------------------------------------------------------------------- 1 | .vin-skeleton { 2 | position: relative; 3 | display: inline-block; 4 | overflow: hidden; 5 | vertical-align: middle; 6 | .content { 7 | display: flex; 8 | 9 | .content-line { 10 | display: flex; 11 | flex-direction: column; 12 | .title { 13 | width: 30%; 14 | height: 15px; 15 | background: #efefef; 16 | } 17 | } 18 | } 19 | 20 | &__block { 21 | &, 22 | &--round { 23 | width: 100%; 24 | height: 100%; 25 | margin-top: 10px; 26 | background: rgb(239, 239, 239); 27 | 28 | &:last-child { 29 | width: 70% !important; 30 | } 31 | } 32 | 33 | &--round { 34 | border-radius: 10px; 35 | } 36 | } 37 | 38 | &__avatar { 39 | margin-right: 20px; 40 | background: rgb(239, 239, 239); 41 | } 42 | 43 | &-animation { 44 | position: absolute; 45 | top: 0; 46 | left: 0; 47 | z-index: 1; 48 | width: 100%; 49 | height: 100%; 50 | background: linear-gradient( 51 | 90deg, 52 | hsla(0, 0%, 100%, 0), 53 | hsla(0, 0%, 100%, 0.5) 50%, 54 | hsla(0, 0%, 100%, 0) 80% 55 | ); 56 | background-repeat: no-repeat; 57 | animation: backpos 2s ease-in-out 0s infinite; 58 | } 59 | 60 | @keyframes backpos { 61 | 0% { 62 | background-position-x: -500px; 63 | } 64 | to { 65 | background-position-x: calc(500px + 100%); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/searchbar/__tests__/__snapshots__/searchbar.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`basic usage 1`] = ` 4 | " 5 | 6 | 7 | 8 | 9 |
10 | 11 |
12 | 13 |
14 | 15 |
" 16 | `; 17 | 18 | exports[`slot test 1`] = ` 19 | " 20 | 21 | 22 | 23 | 24 |
25 | 26 |
27 | 28 |
29 | 30 |
" 31 | `; 32 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/action-sheet/index.scss: -------------------------------------------------------------------------------- 1 | .vin-action-sheet { 2 | display: block; 3 | .vin-action-sheet__title { 4 | display: block; 5 | margin: 0; 6 | padding: 10px; 7 | color: $title-color; 8 | font-size: $font-size-base; 9 | text-align: center; 10 | background-color: $white; 11 | border-bottom: 1px solid $actionsheet-light-color; 12 | } 13 | .vin-action-sheet__menu { 14 | display: block; 15 | margin: 0; 16 | padding: 0; 17 | list-style: none; 18 | } 19 | 20 | .vin-action-sheet__cancel, 21 | .vin-action-sheet__item { 22 | display: block; 23 | padding: 10px; 24 | color: $actionsheet-item-font-color; 25 | font-size: $actionsheet-item-font-size; 26 | line-height: $actionsheet-item-line-height; 27 | text-align: center; 28 | background-color: #fff; 29 | border-bottom: $actionsheet-item-border-bottom; 30 | cursor: pointer; 31 | } 32 | 33 | .vin-action-sheet__desc { 34 | color: #999; 35 | font-size: $actionsheet-item-font-size; 36 | cursor: default; 37 | } 38 | 39 | .vin-action-sheet__subdesc { 40 | display: block; 41 | color: #999; 42 | font-size: $actionsheet-item-subdesc-font-size; 43 | } 44 | 45 | .vin-action-sheet__item--disabled { 46 | color: #e1e1e1 !important; 47 | cursor: not-allowed; 48 | } 49 | .vin-action-sheet__item--loading { 50 | cursor: default; 51 | } 52 | 53 | .vin-action-sheet__cancel { 54 | margin-top: 5px; 55 | border-top: $actionsheet-item-cancel-border-top; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/badge/index.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 56 | 57 | 60 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/category/index.vue: -------------------------------------------------------------------------------- 1 | 23 | 55 | 56 | 59 | -------------------------------------------------------------------------------- /.workflow/master-pipeline.yml: -------------------------------------------------------------------------------- 1 | version: '1.0' 2 | name: master-pipeline 3 | displayName: MasterPipeline 4 | stages: 5 | - stage: 6 | name: compile 7 | displayName: 编译 8 | steps: 9 | - step: build@nodejs 10 | name: build_nodejs 11 | displayName: Nodejs 构建 12 | # 支持8.16.2、10.17.0、12.16.1、14.16.0、15.12.0五个版本 13 | nodeVersion: 14.16.0 14 | # 构建命令:安装依赖 -> 清除上次打包产物残留 -> 执行构建 【请根据项目实际产出进行填写】 15 | commands: 16 | - npm install && rm -rf ./dist && npm run build 17 | # 非必填字段,开启后表示将构建产物暂存,但不会上传到制品库中,7天后自动清除 18 | artifacts: 19 | # 构建产物名字,作为产物的唯一标识可向下传递,支持自定义,默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址 20 | - name: BUILD_ARTIFACT 21 | # 构建产物获取路径,是指代码编译完毕之后构建物的所在路径 22 | path: 23 | - ./dist 24 | - step: publish@general_artifacts 25 | name: publish_general_artifacts 26 | displayName: 上传制品 27 | # 上游构建任务定义的产物名,默认BUILD_ARTIFACT 28 | dependArtifact: BUILD_ARTIFACT 29 | # 上传到制品库时的制品命名,默认output 30 | artifactName: output 31 | dependsOn: build_nodejs 32 | - stage: 33 | name: release 34 | displayName: 发布 35 | steps: 36 | - step: publish@release_artifacts 37 | name: publish_release_artifacts 38 | displayName: '发布' 39 | # 上游上传制品任务的产出 40 | dependArtifact: output 41 | # 发布制品版本号 42 | version: '1.0.0.0' 43 | # 是否开启版本号自增,默认开启 44 | autoIncrement: true 45 | triggers: 46 | push: 47 | branches: 48 | include: 49 | - master 50 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/toast/common.ts: -------------------------------------------------------------------------------- 1 | import type { CSSProperties, ExtractPropTypes, PropType } from 'vue'; 2 | import { commonProps } from '../common'; 3 | 4 | export const toastProps = { 5 | ...commonProps, 6 | id: String, 7 | msg: String, 8 | duration: { 9 | type: Number, 10 | default: 2000, 11 | }, 12 | title: { 13 | type: String, 14 | default: '', 15 | }, 16 | center: { 17 | type: Boolean, 18 | default: true, 19 | }, 20 | bottom: { 21 | type: String, 22 | default: '30px', 23 | }, 24 | textAlignCenter: { 25 | type: Boolean, 26 | default: true, 27 | }, 28 | bgColor: { 29 | type: String, 30 | default: '', 31 | }, 32 | size: { 33 | type: [String, Number], 34 | default: 'base', 35 | }, 36 | icon: String, 37 | iconSize: { 38 | type: String, 39 | default: '20', 40 | }, 41 | cover: { 42 | type: Boolean, 43 | default: false, 44 | }, 45 | coverColor: { 46 | type: String, 47 | default: '', 48 | }, 49 | loadingRotate: { 50 | type: Boolean, 51 | default: true, 52 | }, 53 | onClose: Function, 54 | unmount: Function, 55 | closeOnClickOverlay: { 56 | type: Boolean, 57 | default: false, 58 | }, 59 | visible: { 60 | type: Boolean, 61 | default: false, 62 | }, 63 | type: { 64 | type: String, 65 | default: 'text', 66 | }, 67 | toastStyle: { 68 | type: Object as PropType, 69 | default: () => ({}), 70 | }, 71 | toastClass: String, 72 | }; 73 | 74 | export type ToastProps = ExtractPropTypes; 75 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/tag/__test__/tag.spec.ts: -------------------------------------------------------------------------------- 1 | import { mount, config } from '@vue/test-utils'; 2 | import Tag from '../index.vue'; 3 | 4 | import VinIcon from '../../icon/index.vue'; 5 | 6 | beforeAll(() => { 7 | config.global.components = { 8 | VinIcon, 9 | }; 10 | }); 11 | 12 | afterAll(() => { 13 | config.global.components = {}; 14 | }); 15 | 16 | test('should emit close event when clicking the close icon', () => { 17 | const wrapper = mount(Tag, { 18 | props: { 19 | closeable: true, 20 | }, 21 | }); 22 | 23 | wrapper.find('.vin-tag--close').trigger('click'); 24 | expect(wrapper.emitted('close')!.length).toEqual(1); 25 | }); 26 | 27 | test('should hide tag when the show prop is false', () => { 28 | const wrapper = mount(Tag, { 29 | props: { 30 | show: false, 31 | }, 32 | }); 33 | expect(wrapper.html()).toMatchSnapshot(); 34 | }); 35 | 36 | test('should not trigger click event when clicking the close icon', () => { 37 | const onClick = jest.fn(); 38 | const wrapper = mount(Tag, { 39 | props: { 40 | onClick, 41 | closeable: true, 42 | }, 43 | }); 44 | 45 | wrapper.find('.vin-tag--close').trigger('click'); 46 | expect(onClick).toHaveBeenCalledTimes(0); 47 | 48 | wrapper.trigger('click'); 49 | expect(onClick).toHaveBeenCalledTimes(1); 50 | }); 51 | 52 | test('should render textColor correctly', () => { 53 | const wrapper = mount(Tag, { 54 | props: { 55 | plain: true, 56 | color: 'red', 57 | textColor: 'blue', 58 | }, 59 | }); 60 | 61 | expect(wrapper.html()).toMatchSnapshot(); 62 | }); 63 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/steps/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 56 | 57 | 60 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/cell/__tests__/__snapshots__/cell.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`prop desc-text-align left 1`] = ` 4 | " 5 | 6 | 7 | 张三 8 | 9 | " 10 | `; 11 | 12 | exports[`prop isLink 1`] = ` 13 | " 14 | 15 | 16 | 17 | " 18 | `; 19 | 20 | exports[`prop title desc subtitle 1`] = ` 21 | " 22 | 23 | 24 | 标题1 25 | 副标题1 26 | 27 | 描述1 28 | 29 | " 30 | `; 31 | 32 | exports[`slot default test 1`] = `"Custom Content"`; 33 | 34 | exports[`slot link、icon test 1`] = ` 35 | " 36 | Custom Icon 37 | 38 | 标题1 39 | 副标题1 40 | 41 | 描述1Custom Link 42 | " 43 | `; 44 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/switch/index.scss: -------------------------------------------------------------------------------- 1 | .vin-switch { 2 | display: inline-flex; 3 | flex: 0 0 auto; // 防止被压缩 4 | align-items: center; 5 | background-color: $primary-color; 6 | background-repeat: no-repeat; 7 | background-position: center center; 8 | background-size: 100% 100%; 9 | border-radius: $switch-border-radius; 10 | cursor: pointer; 11 | &.switch-close { 12 | background-color: $switch-close-bg-color; 13 | .close-line { 14 | background: $switch-close-cline-bg-color; 15 | border-radius: 2px; 16 | } 17 | } 18 | .switch-button { 19 | display: flex; 20 | align-items: center; 21 | justify-content: center; 22 | background: $white; 23 | border-radius: 50%; 24 | transition: transform 0.3s; 25 | .vin-switch-label { 26 | color: $white; 27 | font-size: $font-size-1; 28 | &.open { 29 | transform: translateX(-16px); 30 | } 31 | &.close { 32 | transform: translateX(16px); 33 | } 34 | } 35 | } 36 | &.vin-switch-disable { 37 | opacity: 0.6; 38 | } 39 | &.vin-switch-base { 40 | width: $switch-width; 41 | height: $switch-height; 42 | line-height: $switch-line-height; 43 | .switch-button { 44 | width: $switch-inside-height; 45 | height: $switch-inside-width; 46 | transform: $switch-inside-close-transform; 47 | } 48 | &.switch-open { 49 | .switch-button { 50 | transform: $switch-inside-open-transform; 51 | } 52 | } 53 | &.switch-close { 54 | .close-line { 55 | width: 8px; 56 | height: 2px; 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/notify/__test__/notify.spec.ts: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils'; 2 | import Notify from '../index.vue'; 3 | 4 | describe('Notify', () => { 5 | test('base notify', () => { 6 | const wrapper = mount(Notify); 7 | const rate = wrapper.find('.vin-notify'); 8 | expect(rate.exists()).toBe(true); 9 | }); 10 | test('base notify message', async () => { 11 | const wrapper = mount(Notify, { 12 | props: { 13 | message: '测试文案', 14 | }, 15 | }); 16 | expect(wrapper.html()).toContain('测试文案'); 17 | }); 18 | test('should be displayed after setting the type', async () => { 19 | const wrapper = mount(Notify, { 20 | props: { 21 | type: 'warning', 22 | }, 23 | }); 24 | const notify = wrapper.findAll('.vin-notify--warning'); 25 | expect(notify.length).toBe(1); 26 | }); 27 | 28 | test('should be displayed after setting the color and background', async () => { 29 | const wrapper = mount(Notify, { 30 | props: { 31 | color: 'rgb(173, 0, 0)', 32 | background: 'rgb(255, 225, 225)', 33 | }, 34 | }); 35 | const notify = wrapper.find('.vin-notify'); 36 | expect((notify.element as HTMLElement).style.color).toBe('rgb(173, 0, 0)'); 37 | expect((notify.element as HTMLElement).style.background).toBe('rgb(255, 225, 225)'); 38 | }); 39 | 40 | test('should be displayed after setting the color and class-name', () => { 41 | const wrapper = mount(Notify, { 42 | props: { customClass: 'xxx' }, 43 | }); 44 | const rate = wrapper.findAll('.xxx'); 45 | expect(rate.length).toBe(1); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /example/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import uni from '@dcloudio/vite-plugin-uni'; 3 | import path from 'path'; 4 | import UniHelperComponents from '@uni-helper/vite-plugin-uni-components'; 5 | 6 | export default defineConfig({ 7 | root: process.cwd(), 8 | base: '/ui/', 9 | plugins: [ 10 | UniHelperComponents({ 11 | resolvers: [ 12 | (name) => { 13 | if (name.match(/^(Vin[A-Z]|vin-[a-z])/)) { 14 | const cName = name 15 | .slice(3) 16 | .replace(/([a-z])([A-Z])/, '$1-$2') 17 | .toLowerCase(); 18 | return { 19 | name, 20 | from: `@vingogo/uni-ui/lib/components/${cName}/index.vue`, 21 | }; 22 | } 23 | }, 24 | (name) => { 25 | if (name.match(/^(App[A-Z]|app-[a-z])/)) { 26 | const cName = name 27 | .slice(3) 28 | .replace(/([a-z])([A-Z])/, '$1-$2') 29 | .toLowerCase(); 30 | return { 31 | name, 32 | from: `@/components/${cName}.vue`, 33 | }; 34 | } 35 | }, 36 | ], 37 | dts: 'src/components.d.ts', 38 | directoryAsNamespace: true, 39 | }), 40 | uni(), 41 | ], 42 | css: { 43 | preprocessorOptions: { 44 | scss: { 45 | // eslint-disable-next-line 46 | additionalData: "@import '@vingogo/uni-ui/lib/styles/variables.scss';", 47 | }, 48 | }, 49 | }, 50 | resolve: { 51 | alias: { 52 | '@': path.resolve(__dirname, './src'), 53 | }, 54 | preserveSymlinks: true, 55 | }, 56 | }); 57 | -------------------------------------------------------------------------------- /docs/components/divider.md: -------------------------------------------------------------------------------- 1 | # Divider 分割线 2 | 3 | ### 介绍 4 | 5 | 用于将内容分隔为多个区域。 6 | 7 | ### 基础用法 8 | 9 | 默认渲染一条水平分割线。 10 | 11 | ```html 12 | 17 | ``` 18 | 19 | ### 展示文本 20 | 21 | 通过插槽在可以分割线中间插入内容。 22 | 23 | ```html 24 | 29 | ``` 30 | 31 | ### 内容位置 32 | 33 | 通过 content-position 指定内容所在位置。 34 | 35 | ```html 36 | 44 | ``` 45 | 46 | ### 虚线 47 | 48 | 添加 dashed 属性使分割线渲染为虚线。 49 | 50 | ```html 51 | 56 | ``` 57 | 58 | ### 自定义样式 59 | 60 | 可以直接通过 style 属性设置分割线的样式。 61 | 62 | ```html 63 | 70 | ``` 71 | 72 | ## API 73 | 74 | ### Props 75 | 76 | | 参数 | 说明 | 类型 | 默认值 | 77 | | ---------------- | ----------------------------- | ------- | ------ | 78 | | dashed | 是否使用虚线 | Boolean | false | 79 | | hairline | 是否使用 0.5px 线 | Boolean | true | 80 | | content-position | 内容位置,可选值为 left right | String | center | 81 | 82 | ### Slots 83 | 84 | | 名称 | 说明 | 85 | | ------- | ---- | 86 | | default | 内容 | 87 | -------------------------------------------------------------------------------- /docs/guide/theme.md: -------------------------------------------------------------------------------- 1 | # 定制主题 2 | 3 | ## 介绍 4 | 5 | `VinUI` 支持灵活的样式定制,满足多种视觉业务和品牌需求,包括但不限于全局主色调和特定组件视觉定制的支持。 6 | 7 | ### 使用 SASS 变量 进行主题配置 8 | 9 | #### 1. 新建自定义变量 SCSS 文件 10 | 11 | 在本地项目中新建一个 SCSS 文件 `custom_theme.scss` 进行自定义。 12 | 13 | ```scss 14 | $primary-color: #478ef2; 15 | $primary-color-end: #496af2; 16 | ``` 17 | 18 | #### 2. 修改本地项目 webpack 或者 vite 的配置文件 19 | 20 | 修改 `vite` 或者 `webpack` 配置文件中 `sass-loader` 的配置。如下示例: 21 | 22 | **vite** 23 | 24 | ```js 25 | // https://vitejs.dev/config/ 26 | export default defineConfig({ 27 | //... 28 | css: { 29 | preprocessorOptions: { 30 | scss: { 31 | additionalData: `@import '@/assets/custom_theme.scss';@import '@vingogo/uni-ui/lib/styles/variables.scss';`, 32 | }, 33 | }, 34 | }, 35 | }); 36 | ``` 37 | 38 | **webpack** 39 | 40 | ```js 41 | { 42 | test: /\.(sa|sc)ss$/, 43 | use: [ 44 | { 45 | loader: 'sass-loader', 46 | options: { 47 | // 注意:在 sass-loader 不同版本,这个选项名是 是不一样的,具体可参考 sass-loader对应的版本文档 48 | data: `@import '@/assets/custom_theme.scss';@import '@vingogo/uni-ui/lib/styles/variables.scss';`, 49 | } 50 | } 51 | ] 52 | } 53 | ``` 54 | 55 | **vue-cli3.x** 56 | 57 | ```js 58 | module.exports = { 59 | css: { 60 | loaderOptions: { 61 | scss: { 62 | // 注意:在 sass-loader 不同版本,这个选项名是 是不一样的,具体可参考 sass-loader对应的版本文档 63 | prependData: `@import '@/assets/custom_theme.scss';@import '@vingogo/uni-ui/lib/styles/variables.scss';`, 64 | }, 65 | }, 66 | }, 67 | }; 68 | ``` 69 | 70 | 注意:其中 `@/assets/custom_theme.scss` 对应自定义样式变量文件路径,需要替换成实际项目中文件路径。 71 | 72 | ## FAQ 73 | 74 | 1. 样式不生效? 75 | 76 | 参考[默认主题 FAQ 部分的回答](./official-theme.html#faq) 77 | -------------------------------------------------------------------------------- /example/src/styles/demo.scss: -------------------------------------------------------------------------------- 1 | .demo { 2 | -webkit-box-sizing: border-box; 3 | box-sizing: border-box; 4 | min-height: 100vh; 5 | padding: 15px 17px 15px; 6 | overflow-x: hidden; 7 | overflow-y: auto; 8 | background: $help-color; 9 | 10 | .h2 { 11 | display: flex; 12 | margin-top: 30px; 13 | margin-bottom: 10px; 14 | color: #303030; 15 | font-weight: bold; 16 | font-size: 16px; 17 | 18 | &::before { 19 | width: 5px; 20 | margin-right: 10px; 21 | background-color: $primary-color; 22 | border-radius: 4px; 23 | content: ' '; 24 | } 25 | } 26 | 27 | &.full { 28 | min-height: 100vh; 29 | padding: 15px 0 0; 30 | 31 | .h2 { 32 | margin-left: 10px; 33 | } 34 | } 35 | } 36 | 37 | .bg-w { 38 | background-color: $white; 39 | } 40 | 41 | .demo-title { 42 | display: flex; 43 | color: #303030; 44 | font-weight: bold; 45 | 46 | &::before { 47 | width: 5px; 48 | margin-right: 10px; 49 | background-color: $primary-color; 50 | border-radius: 4px; 51 | content: ' '; 52 | } 53 | 54 | &.heading-2 { 55 | padding-top: 15px; 56 | padding-bottom: 10px; 57 | font-size: 16px; 58 | } 59 | } 60 | 61 | .paragraph { 62 | margin: 0 0 20px; 63 | line-height: 1.8; 64 | } 65 | 66 | .code { 67 | position: relative; 68 | z-index: 1; 69 | display: inline-block; 70 | padding: 0 5px; 71 | color: $primary-color; 72 | font-size: 90%; 73 | font-family: Monaco, Menlo, Consolas, 'Courier New', -apple-system-font, Helvetica Neue, 74 | sans-serif; 75 | line-height: 1.6; 76 | vertical-align: baseline; 77 | background-color: $white; 78 | border-radius: 3px; 79 | } 80 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | release: 10 | name: Release 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout Repo 14 | uses: actions/checkout@v3 15 | with: 16 | # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits 17 | fetch-depth: 0 18 | 19 | - uses: pnpm/action-setup@v2.2.4 20 | with: 21 | version: latest 22 | 23 | - name: Setup Node.js 16.x 24 | uses: actions/setup-node@v3 25 | with: 26 | node-version: 16.x 27 | 28 | - name: Get pnpm store directory 29 | id: pnpm-cache 30 | shell: bash 31 | run: | 32 | echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT 33 | 34 | - uses: actions/cache@v3 35 | name: Setup pnpm cache 36 | with: 37 | path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} 38 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 39 | restore-keys: | 40 | ${{ runner.os }}-pnpm-store- 41 | 42 | - name: Install Dependencies 43 | run: pnpm install 44 | 45 | - name: Create Release Pull Request or Publish to npm 46 | id: changesets 47 | uses: changesets/action@v1 48 | with: 49 | version: pnpm ci:version 50 | commit: 'chore: update versions' 51 | title: 'chore: update versions' 52 | publish: pnpm ci:publish 53 | env: 54 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 55 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 56 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/category-pane/index.scss: -------------------------------------------------------------------------------- 1 | .vin-category-pane { 2 | &__cateListRight { 3 | padding-left: 15px; 4 | background: $category-bg-color; 5 | } 6 | &__childTitle { 7 | margin-top: 15px; 8 | margin-bottom: 15px; 9 | color: $category-pane-title-color; 10 | font-weight: 500; 11 | font-size: 13px; 12 | font-family: PingFangSC, -apple-system-font, Helvetica Neue, sans-serif; 13 | } 14 | 15 | &__childItemList { 16 | display: flex; 17 | flex-wrap: wrap; 18 | } 19 | &__childItem { 20 | margin-right: 10px; 21 | } 22 | 23 | &__childImg { 24 | width: 75px; 25 | height: 75px; 26 | border-radius: 5px; 27 | } 28 | 29 | &__skuName { 30 | display: flex; 31 | align-items: center; 32 | justify-content: center; 33 | width: 75px; 34 | height: 40px; 35 | margin-top: 15px; 36 | margin-right: 10px; 37 | margin-left: 15px; 38 | color: $category-pane-gray-color; 39 | font-weight: normal; 40 | font-size: 12px; 41 | font-family: PingFangSC, -apple-system-font, Helvetica Neue, sans-serif; 42 | border: 1px solid $category-pane-border-color; 43 | border-radius: 5px; 44 | 45 | &:nth-child(3n) { 46 | margin-right: 0; 47 | } 48 | &:nth-child(n + 4) { 49 | margin-top: 15px; 50 | } 51 | } 52 | 53 | &__skuImg { 54 | margin-top: 10px; 55 | margin-bottom: 10px; 56 | color: $category-pane-gray-color; 57 | font-weight: normal; 58 | font-size: 12px; 59 | font-family: PingFangSC, -apple-system-font, Helvetica Neue, sans-serif; 60 | text-align: center; 61 | } 62 | 63 | &__selfItemList { 64 | display: flex; 65 | flex-wrap: wrap; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /docs/components/empty.md: -------------------------------------------------------------------------------- 1 | # Empty 空状态 2 | 3 | ### 介绍 4 | 5 | 空状态时的占位提示 6 | 7 | ### 基础用法 8 | 9 | ```html 10 | 13 | ``` 14 | 15 | ### 图片类型,内置 3 个 16 | 17 | ```html 18 | 23 | ``` 24 | 25 | ### 自定义图片 26 | 27 | ```html 28 | 35 | ``` 36 | 37 | ### 底部内容 38 | 39 | ```html 40 | 47 | ``` 48 | 49 | ## API 50 | 51 | ### Props 52 | 53 | | 参数 | 说明 | 类型 | 默认值 | 54 | | ----------- | --------------------------------------------------------- | ---------------- | ------ | 55 | | image | 图片类型,可选值为 error network search,支持传入图片 URL | String | empty | 56 | | image-size | 图片大小,Number 类型单位为 px | Number \| String | - | 57 | | description | 图片下方的描述文字 | String | 无内容 | 58 | 59 | ### Slots 60 | 61 | | 事件名 | 说明 | 62 | | ----------- | -------------- | 63 | | default | 自定义底部内容 | 64 | | image | 自定义图片 | 65 | | description | 自定义描述文字 | 66 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/button/__tests__/button.spec.ts: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils'; 2 | import { nextTick } from 'vue'; 3 | import Button from '../index.vue'; 4 | 5 | describe('../index.vue', () => { 6 | test('emit click event', () => { 7 | const wrapper = mount(Button); 8 | 9 | wrapper.trigger('click'); 10 | expect(wrapper.emitted('click')!.length).toEqual(1); 11 | }); 12 | 13 | test('slot test', async () => { 14 | const wrapper = mount(Button, { 15 | slots: { 16 | default: '按钮测试', 17 | }, 18 | }); 19 | expect(wrapper.html()).toContain('按钮测试'); 20 | }); 21 | test('should emit click event', () => { 22 | const wrapper = mount(Button); 23 | 24 | wrapper.trigger('click'); 25 | expect(wrapper.emitted('click')).toHaveLength(1); 26 | }); 27 | 28 | test('should not allow click when set disabled props', async () => { 29 | const wrapper = mount(Button, { 30 | props: { 31 | disabled: true, 32 | }, 33 | }); 34 | wrapper.trigger('click'); 35 | await nextTick(); 36 | expect(wrapper.emitted('click')).toBeFalsy(); 37 | }); 38 | test('should not emit click event when loading', () => { 39 | const wrapper = mount(Button, { 40 | props: { 41 | loading: true, 42 | }, 43 | }); 44 | 45 | wrapper.trigger('click'); 46 | expect(wrapper.emitted('click')).toBeFalsy(); 47 | }); 48 | test('should change icon class prefix when using icon-class-prefix prop', () => { 49 | const wrapper = mount(Button, { 50 | props: { 51 | icon: 'star-fill', 52 | iconClassPrefix: 'my-icon', 53 | }, 54 | }); 55 | 56 | expect(wrapper.html()).toMatchSnapshot(); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /docs/components/backtop.md: -------------------------------------------------------------------------------- 1 | # BackTop 返回顶部 2 | 3 | ### 介绍 4 | 5 | 提供较长的页面快捷返回顶部功能。 6 | 7 | ### 基本用法 8 | 9 | ```html 10 | 11 | 20 | 21 | ``` 22 | 23 | ### 设置出现位置 24 | 25 | ```html 26 | 27 | ``` 28 | 29 | ### 自定义样式 30 | 31 | ```html 32 | 自定义内容 33 | ``` 34 | 35 | ### click 事件 36 | 37 | ```html 38 | 39 | ``` 40 | 41 | ```html 42 | 55 | ``` 56 | 57 | ### API 58 | 59 | ### Prop 60 | 61 | | 字段 | 说明 | 类型 | 默认值 | 62 | | -------- | ---------------------- | ------ | ------- | 63 | | height | 滚动区域的高度 | String | `100vh` | 64 | | bottom | 距离页面底部距离 | Number | `20` | 65 | | right | 距离页面右侧距离 | Number | `10` | 66 | | distance | 页面垂直滚动多高后出现 | Number | `200` | 67 | | z-index | 设置组件页面层级 | Number | `10` | 68 | 69 | ### Event 70 | 71 | | 名称 | 说明 | 回调参数 | 72 | | ----- | ------------------ | ----------------- | 73 | | click | 按钮点击时触发事件 | event: MouseEvent | 74 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/transition/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 53 | 54 | 57 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/price/__tests__/price.spec.ts: -------------------------------------------------------------------------------- 1 | import { config, mount } from '@vue/test-utils'; 2 | import Price from '../index.vue'; 3 | 4 | afterAll(() => { 5 | config.global.components = {}; 6 | }); 7 | 8 | test('base price', () => { 9 | const wrapper = mount(Price, { 10 | props: { 11 | price: '199.99', 12 | }, 13 | }); 14 | const price: any = wrapper.find('.vin-price'); 15 | expect(price.text()).toBe('¥199.99'); 16 | }); 17 | 18 | test('decimalDigits price', () => { 19 | const wrapper = mount(Price, { 20 | props: { 21 | price: '299.95', 22 | decimalDigits: 1, 23 | }, 24 | }); 25 | const price: any = wrapper.find('.vin-price'); 26 | expect(price.text()).toBe('¥299.9'); 27 | }); 28 | 29 | test('default needSymbol props', () => { 30 | const wrapper = mount(Price); 31 | const price: any = wrapper.find('.vin-price'); 32 | expect(price.find('.vin-price--symbol').text()).toBe('¥'); 33 | }); 34 | test('needSymbol props', () => { 35 | const wrapper = mount(Price, { 36 | props: { 37 | needSymbol: false, 38 | }, 39 | }); 40 | const price: any = wrapper.find('.vin-price'); 41 | expect(price.find('.vin-price--symbol').exists()).toBe(false); 42 | }); 43 | test('symbol props', () => { 44 | const wrapper = mount(Price, { 45 | props: { 46 | symbol: '$', 47 | }, 48 | }); 49 | const price: any = wrapper.find('.vin-price'); 50 | expect(price.find('.vin-price--symbol').text()).toBe('$'); 51 | }); 52 | 53 | test('size props', () => { 54 | const wrapper = mount(Price, { 55 | props: { 56 | size: 'small', 57 | }, 58 | }); 59 | const price: any = wrapper.find('.vin-price'); 60 | expect(price.html()).toContain('vin-price--small'); 61 | }); 62 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/common/utils/test/event.ts: -------------------------------------------------------------------------------- 1 | function getTouch(el: HTMLElement | Window, x: number, y: number) { 2 | return { 3 | identifier: Date.now(), 4 | target: el, 5 | pageX: x, 6 | pageY: y, 7 | clientX: x, 8 | clientY: y, 9 | radiusX: 2.5, 10 | radiusY: 2.5, 11 | rotationAngle: 10, 12 | force: 0.5, 13 | }; 14 | } 15 | 16 | // Trigger pointer/touch event 17 | export function trigger(wrapper: any, eventName: string, x = 0, y = 0, options: any = {}) { 18 | const el = 'element' in wrapper ? wrapper.element : wrapper; 19 | const touchList = options.touchList || [getTouch(el, x, y)]; 20 | 21 | if (options.x || options.y) { 22 | touchList.push(getTouch(el, options.x, options.y)); 23 | } 24 | 25 | const event = document.createEvent('CustomEvent'); 26 | event.initCustomEvent(eventName, true, true, {}); 27 | 28 | Object.assign(event, { 29 | clientX: x, 30 | clientY: y, 31 | touches: touchList, 32 | targetTouches: touchList, 33 | changedTouches: touchList, 34 | }); 35 | 36 | el.dispatchEvent(event); 37 | } 38 | 39 | // simulate drag gesture 40 | export function triggerDrag(el: any, relativeX = 0, relativeY = 0): void { 41 | let x = relativeX; 42 | let y = relativeY; 43 | let startX = 0; 44 | let startY = 0; 45 | if (relativeX < 0) { 46 | startX = Math.abs(relativeX); 47 | x = 0; 48 | } 49 | if (relativeY < 0) { 50 | startY = Math.abs(relativeY); 51 | y = 0; 52 | } 53 | trigger(el, 'touchstart', startX, startY); 54 | trigger(el, 'touchmove', x / 4, y / 4); 55 | trigger(el, 'touchmove', x / 3, y / 3); 56 | trigger(el, 'touchmove', x / 2, y / 2); 57 | trigger(el, 'touchmove', x, y); 58 | trigger(el, 'touchend', x, y); 59 | } 60 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/icon/index.vue: -------------------------------------------------------------------------------- 1 | 8 | 57 | 58 | 61 | -------------------------------------------------------------------------------- /.workflow/branch-pipeline.yml: -------------------------------------------------------------------------------- 1 | version: '1.0' 2 | name: branch-pipeline 3 | displayName: BranchPipeline 4 | triggers: 5 | trigger: auto 6 | push: 7 | branches: 8 | precise: 9 | - main 10 | stages: 11 | - name: compile 12 | displayName: 编译 13 | strategy: naturally 14 | trigger: auto 15 | steps: 16 | - step: build@nodejs 17 | name: build_nodejs 18 | displayName: Nodejs 构建 19 | nodeVersion: 14.16.0 20 | commands: 21 | - npm install -g pnpm@8.6.1 22 | - pnpm install 23 | - '' 24 | - if [ -d "docs/.vuepress/dist" ]; then 25 | - ' rm -rf docs/.vuepress/dist' 26 | - fi 27 | - '' 28 | - echo '🚀 开始构建...' 29 | - '' 30 | - 'npm run build:docs # > /dev/null 2>&1' 31 | - '' 32 | - if [ $? -ne 0 ]; then 33 | - ' echo "❌ 构建失败。请使用 npm run build:docs 命令构建以查看详情"' 34 | - ' exit' 35 | - fi 36 | - '' 37 | - echo '🎉 构建成功!' 38 | - '' 39 | - echo '开始将生成的静态网站推送至 gt-pages 分支' 40 | - '' 41 | - cd docs/.vuepress/dist && git init && git checkout --orphan gt-pages \ 42 | - '&& git add . && git commit -m "pushed by deploy.sh" \' 43 | - '&& git remote add origin git@gitee.com:vingogo/vin-ui.git \' 44 | - '&& git push origin gt-pages --force && rm -rf .git' 45 | - '' 46 | - if [ $? -ne 0 ]; then 47 | - ' echo "❌ 抱歉,推送失败了"' 48 | - ' exit' 49 | - fi 50 | - '' 51 | - echo '🎉 推送成功!' 52 | artifacts: 53 | - name: BUILD_ARTIFACT 54 | path: 55 | - ./docs/.vuepress/dist 56 | caches: [] 57 | strategy: {} 58 | -------------------------------------------------------------------------------- /packages/uni-ui/src/shared/hooks/useTouch/index.ts: -------------------------------------------------------------------------------- 1 | import { ref } from 'vue'; 2 | 3 | const MIN_DISTANCE = 10; 4 | 5 | type Direction = '' | 'vertical' | 'horizontal'; 6 | 7 | function getDirection(x: number, y: number) { 8 | if (x > y && x > MIN_DISTANCE) { 9 | return 'horizontal'; 10 | } 11 | if (y > x && y > MIN_DISTANCE) { 12 | return 'vertical'; 13 | } 14 | return ''; 15 | } 16 | 17 | export function useTouch() { 18 | const startX = ref(0); 19 | const startY = ref(0); 20 | const deltaX = ref(0); 21 | const deltaY = ref(0); 22 | const offsetX = ref(0); 23 | const offsetY = ref(0); 24 | const direction = ref(''); 25 | 26 | const isVertical = () => direction.value === 'vertical'; 27 | const isHorizontal = () => direction.value === 'horizontal'; 28 | 29 | const reset = () => { 30 | deltaX.value = 0; 31 | deltaY.value = 0; 32 | offsetX.value = 0; 33 | offsetY.value = 0; 34 | direction.value = ''; 35 | }; 36 | 37 | const start = ((event: TouchEvent) => { 38 | reset(); 39 | startX.value = event.touches[0].clientX; 40 | startY.value = event.touches[0].clientY; 41 | }) as EventListener; 42 | 43 | const move = ((event: TouchEvent) => { 44 | const touch = event.touches[0]; 45 | deltaX.value = touch.clientX - startX.value; 46 | deltaY.value = touch.clientY - startY.value; 47 | offsetX.value = Math.abs(deltaX.value); 48 | offsetY.value = Math.abs(deltaY.value); 49 | 50 | if (!direction.value) { 51 | direction.value = getDirection(offsetX.value, offsetY.value); 52 | } 53 | }) as EventListener; 54 | 55 | return { 56 | move, 57 | start, 58 | reset, 59 | startX, 60 | startY, 61 | deltaX, 62 | deltaY, 63 | offsetX, 64 | offsetY, 65 | direction, 66 | isVertical, 67 | isHorizontal, 68 | }; 69 | } 70 | -------------------------------------------------------------------------------- /example/src/pages/components/list.vue: -------------------------------------------------------------------------------- 1 | 15 | 55 | 72 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/cell/index.scss: -------------------------------------------------------------------------------- 1 | .vin-cell { 2 | position: relative; 3 | display: flex; 4 | align-items: center; 5 | box-sizing: border-box; 6 | width: 100%; 7 | margin: 10px 0; 8 | padding: $cell-padding; 9 | color: $cell-color; 10 | font-size: $cell-title-font; 11 | line-height: $cell-line-height; 12 | background: $white; 13 | border-radius: $cell-border-radius; 14 | box-shadow: 0 1px 7px 0 rgba(237, 238, 241, 1); 15 | 16 | &:last-child { 17 | &::after { 18 | border: 0 !important; 19 | } 20 | } 21 | 22 | &::after { 23 | position: absolute; 24 | right: $cell-after-right; 25 | bottom: 0; 26 | left: 16px; 27 | box-sizing: border-box; 28 | transform: scaleY(0.5); 29 | content: ' '; 30 | pointer-events: none; 31 | } 32 | 33 | &:active::before { 34 | opacity: 0.1; 35 | } 36 | 37 | &--clickable { 38 | cursor: pointer; 39 | 40 | &::before { 41 | position: absolute; 42 | top: 50%; 43 | left: 50%; 44 | width: 100%; 45 | height: 100%; 46 | background-color: $black; 47 | border: inherit; 48 | border-color: $black; 49 | border-radius: inherit; 50 | transform: translate(-50%, -50%); 51 | opacity: 0; 52 | content: ' '; 53 | } 54 | } 55 | 56 | .vin-cell__icon, 57 | ::v-deep .vin-cell__icon { 58 | display: flex; 59 | flex-direction: row; 60 | align-items: center; 61 | margin: $cell-default-icon-margin; 62 | } 63 | 64 | &__title { 65 | display: flex; 66 | flex: 1; 67 | flex-direction: column; 68 | 69 | &-desc { 70 | font-size: $cell-title-desc-font; 71 | } 72 | } 73 | 74 | &__value { 75 | display: inline-block; 76 | color: $cell-desc-color; 77 | font-size: $cell-desc-font; 78 | text-align: right; 79 | } 80 | 81 | &__link { 82 | color: #979797; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /packages/uni-ui/src/components/radio/index.scss: -------------------------------------------------------------------------------- 1 | .vin-radio { 2 | display: flex; 3 | flex-shrink: 0; 4 | align-items: center; 5 | 6 | &:last-child { 7 | margin-right: 0 !important; 8 | margin-bottom: 0 !important; 9 | } 10 | 11 | &--reverse { 12 | .vin-radio__label { 13 | margin-right: $radio-label-margin-left; 14 | margin-left: 0; 15 | } 16 | } 17 | 18 | &__button { 19 | display: inline-flex; 20 | align-items: center; 21 | box-sizing: border-box; 22 | padding: $radio-button-padding; 23 | color: $radio-label-font-color; 24 | font-size: $radio-button-font-size; 25 | background: #f6f7f9; 26 | border-radius: $radio-button-border-radius; 27 | &--active { 28 | position: relative; 29 | overflow: hidden; 30 | color: $radio-label-font-active-color; 31 | background: transparent; 32 | border: 1px solid $radio-label-button-border-color; 33 | 34 | &::after { 35 | position: absolute; 36 | width: 100%; 37 | height: 100%; 38 | background-color: $radio-label-button-background; 39 | opacity: 0.05; 40 | content: ''; 41 | inset: 0; 42 | } 43 | } 44 | &--disabled { 45 | color: $radio-label-disable-color; 46 | border: none; 47 | } 48 | } 49 | 50 | &__label { 51 | margin-left: $radio-label-margin-left; 52 | color: $radio-label-font-color; 53 | font-size: $radio-label-font-size; 54 | &--disabled { 55 | color: $radio-label-disable-color; 56 | } 57 | } 58 | 59 | &__icon { 60 | color: $radio-label-font-active-color; 61 | font-size: $radio-icon-font-size; 62 | transition-duration: 0.3s; 63 | transition-property: color, border-color, background-color; 64 | } 65 | &__icon--unchecked { 66 | color: $radio-icon-disable-color; 67 | } 68 | &__icon--disable { 69 | color: $help-color; 70 | } 71 | } 72 | --------------------------------------------------------------------------------