├── .nvmrc ├── docs ├── README.md ├── src │ ├── vite-env.d.ts │ ├── pages │ │ ├── notFound.vue │ │ ├── home.vue │ │ └── docs.vue │ ├── shims-vue.d.ts │ ├── assets │ │ └── vue.svg │ ├── main.ts │ ├── router │ │ ├── index.ts │ │ └── routers.ts │ └── components │ │ └── ComponentDemos.tsx ├── tsconfig.node.json ├── index.html ├── build │ ├── vite-plugin-md-transform-demo.ts │ └── mdTransformVueSrs.ts ├── vite.config.ts ├── package.json └── tsconfig.json ├── packages ├── components │ ├── row │ │ ├── README.md │ │ ├── index.ts │ │ ├── demos │ │ │ ├── respond.demo.vue │ │ │ ├── row.page.md │ │ │ ├── basic.demo.vue │ │ │ └── gutter.demo.vue │ │ └── src │ │ │ └── types.ts │ ├── descriptions │ │ ├── index.ts │ │ └── src │ │ │ ├── descriptions.tsx │ │ │ └── types.ts │ ├── form-item │ │ ├── README.md │ │ └── index.ts │ ├── card │ │ ├── demos │ │ │ └── card.page.md │ │ ├── index.ts │ │ └── src │ │ │ ├── types.ts │ │ │ └── card.tsx │ ├── dropdown │ │ ├── demos │ │ │ ├── dropdown.page.md │ │ │ ├── trigger.demo.vue │ │ │ └── basic.demo.vue │ │ ├── index.ts │ │ └── src │ │ │ └── dropdownMenu.tsx │ ├── README.md │ ├── image │ │ ├── demos │ │ │ ├── image.page.md │ │ │ └── basic.demo.vue │ │ ├── index.ts │ │ └── src │ │ │ └── types.ts │ ├── upload │ │ ├── demos │ │ │ ├── upload.page.md │ │ │ └── basic.demo.vue │ │ └── index.ts │ ├── radio │ │ ├── demos │ │ │ ├── basic.demo.vue │ │ │ ├── radio.page.md │ │ │ ├── disabled.demo.vue │ │ │ └── options.demo.vue │ │ ├── index.ts │ │ └── src │ │ │ └── types.ts │ ├── pagination │ │ ├── demos │ │ │ ├── pagination.page.md │ │ │ └── basic.demo.vue │ │ ├── index.ts │ │ └── src │ │ │ └── types.ts │ ├── slot │ │ └── index.ts │ ├── date-picker │ │ ├── demos │ │ │ ├── datePicker.page.md │ │ │ └── basic.demo.vue │ │ ├── index.ts │ │ └── src │ │ │ ├── icons.tsx │ │ │ └── arrowIcon.tsx │ ├── time-picker │ │ ├── demos │ │ │ ├── time-picker.page.md │ │ │ └── basic.demo.vue │ │ ├── index.ts │ │ └── src │ │ │ └── types.ts │ ├── color-picker │ │ ├── demos │ │ │ ├── color-picker.page.md │ │ │ └── basic.demo.vue │ │ ├── index.ts │ │ └── src │ │ │ └── types.ts │ ├── divider │ │ ├── demos │ │ │ ├── basic.demo.vue │ │ │ ├── divider.page.md │ │ │ ├── vertical.demo.vue │ │ │ └── title.demo.vue │ │ ├── index.ts │ │ └── src │ │ │ ├── types.ts │ │ │ └── divider.tsx │ ├── message │ │ ├── index.ts │ │ ├── demos │ │ │ ├── timing.demo.vue │ │ │ ├── close.demo.vue │ │ │ ├── basic.demo.vue │ │ │ ├── type.demo.vue │ │ │ └── message.page.md │ │ └── src │ │ │ └── instance.ts │ ├── ellipsis │ │ ├── demos │ │ │ ├── basic.demo.vue │ │ │ ├── max.demo.vue │ │ │ ├── custom.demo.vue │ │ │ └── ellipsis.page.md │ │ ├── index.ts │ │ └── src │ │ │ └── types.ts │ ├── flex │ │ ├── demos │ │ │ ├── flex.page.md │ │ │ ├── gap.demo.vue │ │ │ ├── items.demo.vue │ │ │ └── basic.demo.vue │ │ └── index.ts │ ├── back-top │ │ ├── demos │ │ │ ├── basic.demo.vue │ │ │ ├── position.demo.vue │ │ │ ├── back-top.page.md │ │ │ └── target.demo.vue │ │ ├── index.ts │ │ └── src │ │ │ └── types.ts │ ├── col │ │ └── index.ts │ ├── switch │ │ ├── demos │ │ │ ├── size.demo.vue │ │ │ ├── basic.demo.vue │ │ │ ├── disabled.demo.vue │ │ │ ├── loading.demo.vue │ │ │ ├── text.demo.vue │ │ │ ├── customValue.demo.vue │ │ │ └── switch.page.md │ │ ├── index.ts │ │ └── src │ │ │ └── types.ts │ ├── form │ │ ├── index.ts │ │ └── src │ │ │ └── types.ts │ ├── menu │ │ ├── index.ts │ │ └── src │ │ │ ├── utils.ts │ │ │ └── types.ts │ ├── button │ │ ├── demos │ │ │ ├── disabled.demo.vue │ │ │ ├── loading.demo.vue │ │ │ ├── group.demo.vue │ │ │ ├── button.page.md │ │ │ └── basic.demo.vue │ │ └── index.ts │ ├── input │ │ ├── index.ts │ │ └── demos │ │ │ ├── size.demo.vue │ │ │ ├── disabled.demo.vue │ │ │ ├── formatter.demo.vue │ │ │ ├── textarea.demo.vue │ │ │ ├── compact.demo.vue │ │ │ └── basic.demo.vue │ ├── space │ │ ├── index.ts │ │ └── demos │ │ │ ├── vertical.demo.vue │ │ │ ├── size.demo.vue │ │ │ ├── basic.demo.vue │ │ │ ├── space.page.md │ │ │ └── justify.demo.vue │ ├── pop-confirm │ │ ├── demos │ │ │ ├── basic.demo.vue │ │ │ ├── async.demo.vue │ │ │ ├── trigger.demo.vue │ │ │ └── pop-confirm.page.md │ │ └── index.ts │ ├── drawer │ │ ├── index.ts │ │ ├── demos │ │ │ ├── basic.demo.vue │ │ │ ├── drawer.page.md │ │ │ └── position.demo.vue │ │ └── src │ │ │ └── types.ts │ ├── overlay │ │ ├── index.ts │ │ └── src │ │ │ └── types.ts │ ├── tooltip │ │ ├── index.ts │ │ ├── demos │ │ │ ├── basic.demo.vue │ │ │ └── tooltip.page.md │ │ └── src │ │ │ └── types.ts │ ├── checkbox │ │ ├── index.ts │ │ └── demos │ │ │ ├── basic.demo.vue │ │ │ └── checkbox.page.md │ ├── package.json │ ├── tabs │ │ ├── index.ts │ │ └── demos │ │ │ ├── centered.demo.vue │ │ │ ├── trigger.demo.vue │ │ │ ├── card.demo.vue │ │ │ ├── basic.demo.vue │ │ │ ├── vertical.demo.vue │ │ │ └── tabs.page.md │ ├── badge │ │ ├── index.ts │ │ ├── demos │ │ │ ├── zero.demo.vue │ │ │ ├── offset.demo.vue │ │ │ ├── type.demo.vue │ │ │ ├── badge.page.md │ │ │ ├── basic.demo.vue │ │ │ └── max.demo.vue │ │ └── src │ │ │ └── types.ts │ ├── scrollbar │ │ ├── index.ts │ │ └── demos │ │ │ ├── x.demo.vue │ │ │ ├── trigger.demo.vue │ │ │ ├── basic.demo.vue │ │ │ └── scrollbar.page.md │ ├── expand-transition │ │ ├── src │ │ │ └── types.ts │ │ └── index.ts │ ├── modal │ │ ├── index.ts │ │ ├── demos │ │ │ ├── basic.demo.vue │ │ │ └── function.demo.vue │ │ └── src │ │ │ └── function-method.tsx │ ├── number │ │ ├── index.ts │ │ ├── demos │ │ │ ├── number.page.md │ │ │ ├── gap.demo.vue │ │ │ ├── basic.demo.vue │ │ │ └── class.demo.vue │ │ └── src │ │ │ └── types.ts │ ├── popper │ │ ├── index.ts │ │ └── demos │ │ │ └── popper.page.md │ ├── select │ │ ├── index.ts │ │ └── demos │ │ │ └── select.page.md │ ├── slider │ │ ├── index.ts │ │ └── demos │ │ │ ├── basic.demo.vue │ │ │ └── slider.page.md │ ├── button-group │ │ ├── index.ts │ │ └── src │ │ │ ├── types.ts │ │ │ └── buttonGroup.tsx │ ├── layout │ │ ├── src │ │ │ ├── footer.tsx │ │ │ ├── types.ts │ │ │ ├── header.tsx │ │ │ ├── content.tsx │ │ │ ├── layout.tsx │ │ │ └── sidebar.tsx │ │ ├── demos │ │ │ └── layout.page.md │ │ └── index.ts │ ├── checkbox-group │ │ └── index.ts │ ├── radio-group │ │ ├── index.ts │ │ └── src │ │ │ ├── types.ts │ │ │ └── radioGroup.tsx │ ├── image-preview │ │ ├── index.ts │ │ └── src │ │ │ └── types.ts │ └── index.ts ├── yy-ui │ ├── defaults.ts │ ├── index.ts │ ├── package.json │ ├── makeInstaller.ts │ └── README.md ├── theme │ ├── README.md │ ├── src │ │ ├── mixins │ │ │ ├── config.scss │ │ │ ├── function.scss │ │ │ ├── mixins.scss │ │ │ └── set-color-level.scss │ │ ├── checkbox-group.scss │ │ ├── image.scss │ │ ├── overlay.scss │ │ ├── number.scss │ │ ├── ellipsis.scss │ │ ├── pop-confirm.scss │ │ ├── common │ │ │ └── var.scss │ │ ├── row.scss │ │ ├── card.scss │ │ ├── space.scss │ │ ├── back-top.scss │ │ ├── dropdown.scss │ │ ├── flex.scss │ │ ├── popper.scss │ │ ├── index.scss │ │ └── image-preview.scss │ └── package.json ├── utils │ ├── README.md │ ├── src │ │ ├── array.ts │ │ ├── event.ts │ │ ├── typescript.ts │ │ ├── common.ts │ │ ├── withInstall.ts │ │ ├── style.ts │ │ ├── scroll.ts │ │ └── createNamespace.ts │ ├── __tests__ │ │ └── utils.test.js │ ├── index.ts │ └── package.json ├── stylelint-config │ ├── index.js │ ├── README.md │ ├── __tests__ │ │ └── stylelint-config.test.js │ └── package.json ├── tokens │ ├── README.md │ ├── src │ │ ├── layout.ts │ │ ├── config.ts │ │ ├── row.ts │ │ ├── image-preview.ts │ │ ├── tooltip.ts │ │ ├── menu.ts │ │ ├── checkbox-group.ts │ │ ├── types.ts │ │ ├── form-item.ts │ │ ├── button-group.ts │ │ ├── form.ts │ │ └── radio-group.ts │ ├── index.ts │ └── package.json ├── eslint-config │ ├── README.md │ ├── __tests__ │ │ └── eslint-config.test.js │ ├── package.json │ └── index.js ├── hooks │ ├── src │ │ ├── useExpose.ts │ │ ├── useCreateId.ts │ │ ├── useCreateIndex.ts │ │ ├── useClickOutside.ts │ │ ├── useGlobalConfig.ts │ │ ├── useScrollParent.ts │ │ ├── useMouseInOut.ts │ │ ├── useResizeObserver.ts │ │ ├── useLazyRender.ts │ │ ├── useMergePropOrContext.ts │ │ └── useEventListener.ts │ ├── package.json │ └── index.ts └── tsconfig.type.json ├── .eslintignore ├── .prettierignore ├── .stylelintignore ├── .stylelintrc ├── scripts ├── bin.js ├── lib │ ├── utils │ │ └── path.js │ └── cli.js └── package.json ├── .gitignore ├── .eslintrc.json ├── tsconfig.json ├── .prettierrc.js ├── lerna.json ├── tsconfig.web.json ├── tsconfig.base.json ├── package.json └── README.md /.nvmrc: -------------------------------------------------------------------------------- 1 | v18.13.0 2 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # nimble-ui库的文档 -------------------------------------------------------------------------------- /packages/components/row/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/components/descriptions/index.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/components/form-item/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist/* 3 | yy/* -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | yy 4 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | *.d.ts -------------------------------------------------------------------------------- /packages/components/card/demos/card.page.md: -------------------------------------------------------------------------------- 1 | # 卡片 card -------------------------------------------------------------------------------- /docs/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@nimble-ui/stylelint-config"] 3 | } 4 | -------------------------------------------------------------------------------- /scripts/bin.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import "./lib/cli.js"; 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | docs/.vitepress/cache/ 3 | dist/ 4 | yy/ 5 | build/lib/ -------------------------------------------------------------------------------- /docs/src/pages/notFound.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["@nimble-ui/eslint-config"] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { "path": "./tsconfig.web.json" } 4 | ] 5 | } -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | endOfLine: "auto", 3 | printWidth: 120, 4 | tabWidth: 2, 5 | semi: true, 6 | bracketSpacing: true, 7 | }; 8 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "node_modules/lerna/schemas/lerna-schema.json", 3 | "useWorkspaces": true, 4 | "version": "0.1.0", 5 | "npmClient": "yarn" 6 | } 7 | -------------------------------------------------------------------------------- /packages/yy-ui/defaults.ts: -------------------------------------------------------------------------------- 1 | import { makeInstaller } from "./makeInstaller"; 2 | import Components from "./components"; 3 | 4 | export default makeInstaller([...Components]); 5 | -------------------------------------------------------------------------------- /packages/components/dropdown/demos/dropdown.page.md: -------------------------------------------------------------------------------- 1 | # 下拉菜单 Dropdown 2 | 3 | 将动作或菜单折叠到下拉菜单中。 4 | 5 | ## 代码演示 6 | ```demo 7 | basic.vue 8 | position.vue 9 | trigger.vue 10 | ``` -------------------------------------------------------------------------------- /packages/theme/README.md: -------------------------------------------------------------------------------- 1 | # `theme` 2 | 3 | > TODO: description 4 | 5 | ## Usage 6 | 7 | ``` 8 | const theme = require('theme'); 9 | 10 | // TODO: DEMONSTRATE API 11 | ``` 12 | -------------------------------------------------------------------------------- /packages/utils/README.md: -------------------------------------------------------------------------------- 1 | # `utils` 2 | 3 | > TODO: description 4 | 5 | ## Usage 6 | 7 | ``` 8 | const utils = require('utils'); 9 | 10 | // TODO: DEMONSTRATE API 11 | ``` 12 | -------------------------------------------------------------------------------- /packages/stylelint-config/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["stylelint-config-standard", "stylelint-config-standard-scss"], 3 | rules: { 4 | indentation: 2, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /packages/tokens/README.md: -------------------------------------------------------------------------------- 1 | # `tokens` 2 | 3 | > TODO: description 4 | 5 | ## Usage 6 | 7 | ``` 8 | const tokens = require('tokens'); 9 | 10 | // TODO: DEMONSTRATE API 11 | ``` 12 | -------------------------------------------------------------------------------- /packages/utils/src/array.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 把目标转成数组 3 | * @param item 目标 4 | * @returns {Array} 5 | */ 6 | export const toArray = (item: T | T[]): T[] => (Array.isArray(item) ? item : [item]); 7 | -------------------------------------------------------------------------------- /packages/components/README.md: -------------------------------------------------------------------------------- 1 | # `components` 2 | 3 | > TODO: description 4 | 5 | ## Usage 6 | 7 | ``` 8 | const components = require('components'); 9 | 10 | // TODO: DEMONSTRATE API 11 | ``` 12 | -------------------------------------------------------------------------------- /packages/theme/src/mixins/config.scss: -------------------------------------------------------------------------------- 1 | $namespace: 'y' !default; 2 | $common-separator: '-' !default; 3 | $element-separator: '__' !default; 4 | $modifier-separator: '--' !default; 5 | $state-prefix: 'is-' !default; -------------------------------------------------------------------------------- /packages/eslint-config/README.md: -------------------------------------------------------------------------------- 1 | # `eslint-config` 2 | 3 | > TODO: description 4 | 5 | ## Usage 6 | 7 | ``` 8 | const eslintConfig = require('eslint-config'); 9 | 10 | // TODO: DEMONSTRATE API 11 | ``` 12 | -------------------------------------------------------------------------------- /packages/components/image/demos/image.page.md: -------------------------------------------------------------------------------- 1 | # 图像 Image 2 | 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | ``` 8 | ## API 9 | 10 | ### Image Props 11 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 12 | | --- | --- | --- | --- | --- | -------------------------------------------------------------------------------- /packages/stylelint-config/README.md: -------------------------------------------------------------------------------- 1 | # `stylelint-config` 2 | 3 | > TODO: description 4 | 5 | ## Usage 6 | 7 | ``` 8 | const stylelintConfig = require('stylelint-config'); 9 | 10 | // TODO: DEMONSTRATE API 11 | ``` 12 | -------------------------------------------------------------------------------- /packages/components/upload/demos/upload.page.md: -------------------------------------------------------------------------------- 1 | # 上传 Upload 2 | 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | ``` 8 | ## API 9 | 10 | ### Upload Props 11 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 12 | | --- | --- | --- | --- | --- | 13 | -------------------------------------------------------------------------------- /packages/utils/__tests__/utils.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('..'); 4 | const assert = require('assert').strict; 5 | 6 | assert.strictEqual(utils(), 'Hello from utils'); 7 | console.info("utils tests passed"); 8 | -------------------------------------------------------------------------------- /packages/components/radio/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 最简单的用法 6 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /packages/components/pagination/demos/pagination.page.md: -------------------------------------------------------------------------------- 1 | # 分页 Pagination 2 | 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | ``` 8 | ## API 9 | 10 | ### Pagination Props 11 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 12 | | --- | --- | --- | --- | --- | 13 | -------------------------------------------------------------------------------- /packages/components/slot/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _onlyChild, { type OnlyChildEventFn } from "./src/only-child"; 3 | 4 | export const YOnlyChild = withInstall(_onlyChild); 5 | export { OnlyChildEventFn }; 6 | -------------------------------------------------------------------------------- /packages/tokens/src/layout.ts: -------------------------------------------------------------------------------- 1 | import type { InjectionKey } from "vue"; 2 | 3 | interface LayoutContext { 4 | setSider: (has: boolean) => void; 5 | } 6 | 7 | export const layoutContextKey: InjectionKey = Symbol("layoutContextKey"); 8 | -------------------------------------------------------------------------------- /packages/components/date-picker/demos/datePicker.page.md: -------------------------------------------------------------------------------- 1 | # 日期选择框 DatePicker 2 | 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | ``` 8 | ## API 9 | 10 | ### DatePicker Props 11 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 12 | | --- | --- | --- | --- | --- | 13 | -------------------------------------------------------------------------------- /packages/components/time-picker/demos/time-picker.page.md: -------------------------------------------------------------------------------- 1 | # 时间选择器 TimePicker 2 | 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | ``` 8 | ## API 9 | 10 | ### TimePicker Props 11 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 12 | | --- | --- | --- | --- | --- | 13 | -------------------------------------------------------------------------------- /packages/components/color-picker/demos/color-picker.page.md: -------------------------------------------------------------------------------- 1 | # 颜色选择器 ColorPicker 2 | 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | ``` 8 | ## API 9 | 10 | ### ColorPicker Props 11 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 12 | | --- | --- | --- | --- | --- | 13 | -------------------------------------------------------------------------------- /packages/components/radio/demos/radio.page.md: -------------------------------------------------------------------------------- 1 | # 单选框 Radio 2 | 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | disabled.vue 8 | options.vue 9 | ``` 10 | ## API 11 | 12 | ### Radio Props 13 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 14 | | --- | --- | --- | --- | --- | 15 | -------------------------------------------------------------------------------- /packages/tokens/src/config.ts: -------------------------------------------------------------------------------- 1 | import { InjectionKey } from "vue"; 2 | 3 | export interface GlobalConfigContext { 4 | // 初始zIndex 5 | zIndex?: number; 6 | } 7 | 8 | export const globalConfigContextKey: InjectionKey = Symbol("CONFIG_CONTEXT_KEY"); 9 | -------------------------------------------------------------------------------- /packages/components/divider/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 对不同段落的文本进行分割。 6 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /packages/eslint-config/__tests__/eslint-config.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const eslintConfig = require('..'); 4 | const assert = require('assert').strict; 5 | 6 | assert.strictEqual(eslintConfig(), 'Hello from eslintConfig'); 7 | console.info("eslintConfig tests passed"); 8 | -------------------------------------------------------------------------------- /packages/components/message/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstallFunction } from "@nimble-ui/utils"; 2 | import _message from "./src/function-method"; 3 | 4 | export * from "./src/types"; 5 | export const YMessage = withInstallFunction(_message, "$message"); 6 | export default YMessage; 7 | -------------------------------------------------------------------------------- /packages/hooks/src/useExpose.ts: -------------------------------------------------------------------------------- 1 | import { getCurrentInstance } from "vue"; 2 | 3 | export function useExpose>(obj: T) { 4 | const instance = getCurrentInstance(); 5 | if (instance && instance.proxy) { 6 | Object.assign(instance.proxy, obj); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/components/ellipsis/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 带弹出提示基本的单行省略。 6 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /packages/components/flex/demos/flex.page.md: -------------------------------------------------------------------------------- 1 | 2 | # 弹性布局 Flex 3 | 4 | 5 | ## 代码演示 6 | ```demo 7 | basic.vue 8 | align.vue 9 | gap.vue 10 | items.vue 11 | ``` 12 | ## API 13 | 14 | ### Flex Props 15 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 16 | | --- | --- | --- | --- | --- | 17 | -------------------------------------------------------------------------------- /packages/stylelint-config/__tests__/stylelint-config.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const stylelintConfig = require('..'); 4 | const assert = require('assert').strict; 5 | 6 | assert.strictEqual(stylelintConfig(), 'Hello from stylelintConfig'); 7 | console.info("stylelintConfig tests passed"); 8 | -------------------------------------------------------------------------------- /packages/theme/src/checkbox-group.scss: -------------------------------------------------------------------------------- 1 | @use "./mixins/mixins.scss" as *; 2 | @use "./mixins/function.scss" as *; 3 | 4 | @include b(checkbox-group) { 5 | display: flex; 6 | flex-flow: row wrap; 7 | 8 | @include when(horizontal) { 9 | flex-direction: column; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/components/back-top/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 如果为listenTo为undefined会监听距离最近的一个可滚动的祖先节点 6 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /scripts/lib/utils/path.js: -------------------------------------------------------------------------------- 1 | import { resolve } from "path"; 2 | import { fileURLToPath } from "url"; 3 | 4 | export const projRoot = resolve(fileURLToPath(import.meta.url), "..", "..", "..", ".."); 5 | export const pkgRoot = resolve(projRoot, "packages"); 6 | export const comRoot = resolve(pkgRoot, "components"); 7 | -------------------------------------------------------------------------------- /packages/components/radio/demos/disabled.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 禁用 4 | 5 | 禁用单选框 6 | 7 | 8 | 14 | -------------------------------------------------------------------------------- /packages/yy-ui/index.ts: -------------------------------------------------------------------------------- 1 | import installer from "./defaults"; 2 | export * from "@nimble-ui/components"; 3 | import { useTheme } from "@nimble-ui/hooks"; 4 | export * from "@nimble-ui/hooks"; 5 | 6 | export { useTheme }; 7 | 8 | useTheme(); 9 | export const install = installer.install; 10 | export default installer; 11 | -------------------------------------------------------------------------------- /docs/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true, 8 | "lib": ["ES2020", "DOM"] 9 | }, 10 | "include": ["vite.config.ts", "build/**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/components/back-top/demos/position.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 改变位置 4 | 5 | 可以通过改变 `bottom`、`right` 属性 6 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /packages/theme/src/image.scss: -------------------------------------------------------------------------------- 1 | @use "./mixins/mixins.scss" as *; 2 | @use "./mixins/function.scss" as *; 3 | 4 | @include b(image) { 5 | display: inline-block; 6 | max-width: 100%; 7 | max-height: 100%; 8 | 9 | @include e(img) { 10 | width: 100%; 11 | height: auto; 12 | vertical-align: middle; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/utils/src/event.ts: -------------------------------------------------------------------------------- 1 | export function startComposing({ target }: Event) { 2 | (target as any).composing = true; 3 | } 4 | 5 | export function endComposing({ target }: Event) { 6 | if ((target as any).composing) { 7 | (target as any).composing = false; 8 | target?.dispatchEvent(new Event("input")); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/components/col/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import col from "./src/col"; 3 | 4 | export * from "./src/types"; 5 | export const YCol = withInstall(col); 6 | export default YCol; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YCol: typeof YCol; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/row/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import row from "./src/row"; 3 | 4 | export * from "./src/types"; 5 | export const YRow = withInstall(row); 6 | export default YRow; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YRow: typeof YRow; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/switch/demos/size.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 大小 4 | 5 | 可以通过设置size改变大小 6 | 7 | 8 | 15 | -------------------------------------------------------------------------------- /packages/components/form/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import form from "./src/form"; 3 | 4 | export * from "./src/types"; 5 | export const YForm = withInstall(form); 6 | export default YForm; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YForm: typeof YForm; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/tokens/src/row.ts: -------------------------------------------------------------------------------- 1 | import type { Ref, InjectionKey } from "vue"; 2 | import type { Fun } from "@nimble-ui/utils"; 3 | 4 | interface RowContext { 5 | gutter: number; 6 | details: any; 7 | span: number | Fun | undefined; 8 | } 9 | 10 | export const rowContextKey: InjectionKey> = Symbol("rowContextKey"); 11 | -------------------------------------------------------------------------------- /packages/components/card/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _card from "./src/card"; 3 | 4 | export * from "./src/types"; 5 | export const YCard = withInstall(_card); 6 | export default YCard; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YCard: typeof YCard; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/menu/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _menu from "./src/menu"; 3 | 4 | export * from "./src/types"; 5 | export const YMenu = withInstall(_menu); 6 | export default YMenu; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YMenu: typeof YMenu; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/tokens/src/image-preview.ts: -------------------------------------------------------------------------------- 1 | import type { InjectionKey } from "vue"; 2 | 3 | interface ImagePreviewContext { 4 | isGroup?: boolean; 5 | toggle: (bool: boolean) => void; 6 | setPreviewSrc: (src: string) => void; 7 | } 8 | 9 | export const imagePreviewContextKey: InjectionKey = Symbol("imagePreviewContext"); 10 | -------------------------------------------------------------------------------- /packages/components/button/demos/disabled.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 禁用 4 | 5 | 按钮可以被禁用。 6 | 7 | 8 | 14 | -------------------------------------------------------------------------------- /packages/components/input/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _input from "./src/input"; 3 | 4 | export * from "./src/types"; 5 | export const YInput = withInstall(_input); 6 | export default YInput; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YInput: typeof YInput; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/space/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _space from "./src/space"; 3 | 4 | export * from "./src/types"; 5 | export const YSpace = withInstall(_space); 6 | export default YSpace; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YSpace: typeof YSpace; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/image/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 最简单的用法。 6 | 7 | 8 | 14 | -------------------------------------------------------------------------------- /packages/components/pop-confirm/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 最简单的用法,支持确认标题和描述。 6 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /docs/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/ban-types */ 2 | declare module "*.vue" { 3 | import type { App, DefineComponent } from "vue"; 4 | const component: DefineComponent<{}, {}, any> & { 5 | install(app: App): void; 6 | }; 7 | export default component; 8 | } 9 | 10 | declare module "*.md" { 11 | export default any; 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/button/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import button from "./src/button"; 3 | 4 | export * from "./src/types"; 5 | export const YButton = withInstall(button); 6 | export default YButton; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YButton: typeof YButton; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/drawer/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _drawer from "./src/drawer"; 3 | 4 | export * from "./src/types"; 5 | export const YDrawer = withInstall(_drawer); 6 | export default YDrawer; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YDrawer: typeof YDrawer; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/space/demos/vertical.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 垂直间距 4 | 5 | 相邻组件垂直间距。 6 | 7 | 8 | 15 | -------------------------------------------------------------------------------- /packages/components/switch/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 最简单的用法。 6 | 7 | 8 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /packages/components/switch/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _switch from "./src/switch"; 3 | 4 | export * from "./src/types"; 5 | export const YSwitch = withInstall(_switch); 6 | export default YSwitch; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YSwitch: typeof YSwitch; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/divider/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _divider from "./src/divider"; 3 | 4 | export * from "./src/types"; 5 | export const YDivider = withInstall(_divider); 6 | export default YDivider; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YDivider: typeof YDivider; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/overlay/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _overlay from "./src/overlay"; 3 | 4 | export * from "./src/types"; 5 | export const YOverlay = withInstall(_overlay); 6 | export default YOverlay; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YOverlay: typeof YOverlay; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/tooltip/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _tooltip from "./src/tooltip"; 3 | 4 | export * from "./src/types"; 5 | export const YTooltip = withInstall(_tooltip); 6 | export default YTooltip; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YTooltip: typeof YTooltip; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/checkbox/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import checkbox from "./src/checkbox"; 3 | 4 | export * from "./src/types"; 5 | export const YCheckbox = withInstall(checkbox); 6 | export default YCheckbox; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YCheckbox: typeof YCheckbox; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/dropdown/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _dropdown from "./src/dropdown"; 3 | 4 | export * from "./src/types"; 5 | export const YDropdown = withInstall(_dropdown); 6 | export default YDropdown; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YDropdown: typeof YDropdown; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/flex/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _flex from "./src/flex"; 3 | 4 | export * from "./src/types"; 5 | export const YFlex = withInstall(_flex); 6 | export default YFlex; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YFlex: typeof YFlex; 11 | "y-flex": typeof YFlex; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/components/form-item/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import formItem from "./src/formItem"; 3 | 4 | export * from "./src/types"; 5 | export const YFormItem = withInstall(formItem); 6 | export default YFormItem; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YFormItem: typeof YFormItem; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nimble-ui/components", 3 | "version": "0.1.0", 4 | "description": "基于 Vue3 + ts 开发组件", 5 | "author": "陈羽云 <897908015@qq.com>", 6 | "main": "index.ts", 7 | "module": "index.ts", 8 | "peerDependencies": { 9 | "vue": "^3.2.0" 10 | }, 11 | "dependencies": { 12 | "stylelint-order": "^6.0.3" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/components/tabs/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _tabs from "./src/tabs"; 3 | 4 | export * from "./src/types"; 5 | export const YTabs = withInstall(_tabs); 6 | export default YTabs; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YTabs: typeof YTabs; 11 | "y-tabs": typeof YTabs; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/utils/src/typescript.ts: -------------------------------------------------------------------------------- 1 | export type Nullable = T | null; 2 | export type Awaitable = Promise | T; 3 | export type Mutable = { -readonly [P in keyof T]: T[P] }; 4 | export type ObjectTypes = { [key: string | number]: T }; 5 | export type ContainFunction any> = T | ReturnType; 6 | export type Fun = (...args: any[]) => T; 7 | -------------------------------------------------------------------------------- /packages/components/badge/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _badge from "./src/badge"; 3 | 4 | export * from "./src/types"; 5 | export const YBadge = withInstall(_badge); 6 | export default YBadge; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YBadge: typeof YBadge; 11 | "y-badge": typeof YBadge; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/components/image/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _image from "./src/image"; 3 | 4 | export * from "./src/types"; 5 | export const YImage = withInstall(_image); 6 | export default YImage; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YImage: typeof YImage; 11 | "y-image": typeof YImage; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/components/radio/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _radio from "./src/radio"; 3 | 4 | export * from "./src/types"; 5 | export const YRadio = withInstall(_radio); 6 | export default YRadio; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YRadio: typeof YRadio; 11 | "y-radio": typeof YRadio; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/components/scrollbar/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _scrollbar from "./src/scrollbar"; 3 | 4 | export * from "./src/types"; 5 | export const YScrollbar = withInstall(_scrollbar); 6 | export default YScrollbar; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YScrollbar: typeof YScrollbar; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/tooltip/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 最简单的用法。 6 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /packages/components/ellipsis/demos/max.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 最大行数 4 | 5 | 最大显示多少行,多出的隐藏 6 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /packages/components/expand-transition/src/types.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes, PropType } from "vue"; 2 | 3 | const expandTransitionProps = () => ({ 4 | appear: Boolean, 5 | mode: String as PropType<"in-out" | "out-in" | "default">, 6 | }); 7 | 8 | export default expandTransitionProps; 9 | 10 | export type ExpandTransitionProps = ExtractPropTypes>; 11 | -------------------------------------------------------------------------------- /packages/components/modal/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _modal from "./src/modal"; 3 | 4 | export * from "./src/types"; 5 | export * from "./src/function-method"; 6 | export const YModal = withInstall(_modal); 7 | export default YModal; 8 | 9 | declare module "vue" { 10 | export interface GlobalComponents { 11 | YModal: typeof YModal; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/components/number/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _number from "./src/number"; 3 | 4 | export * from "./src/types"; 5 | export const YNumber = withInstall(_number); 6 | export default YNumber; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YNumber: typeof YNumber; 11 | "y-number": typeof YNumber; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/components/popper/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _popper from "./src/popper"; 3 | 4 | export * from "./src/types"; 5 | export const YPopper = withInstall(_popper); 6 | export default YPopper; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YPopper: typeof YPopper; 11 | "y-popper": typeof YPopper; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/components/select/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _select from "./src/select"; 3 | 4 | export * from "./src/types"; 5 | export const YSelect = withInstall(_select); 6 | export default YSelect; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YSelect: typeof YSelect; 11 | "y-select": typeof YSelect; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/components/slider/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _slider from "./src/slider"; 3 | 4 | export * from "./src/types"; 5 | export const YSlider = withInstall(_slider); 6 | export default YSlider; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YSlider: typeof YSlider; 11 | "y-slider": typeof YSlider; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/components/upload/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _upload from "./src/upload"; 3 | 4 | export * from "./src/types"; 5 | export const YUpload = withInstall(_upload); 6 | export default YUpload; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YUpload: typeof YUpload; 11 | "y-upload": typeof YUpload; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /scripts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nimble-ui/cli", 3 | "version": "0.1.0", 4 | "description": "> TODO: description", 5 | "author": "陈羽云 <897908015@qq.com>", 6 | "homepage": "", 7 | "license": "ISC", 8 | "type": "module", 9 | "main": "lib/index.js", 10 | "bin": { 11 | "yy-cli": "./bin.js" 12 | }, 13 | "dependencies": { 14 | "commander": "^11.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/components/button-group/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import buttonGroup from "./src/buttonGroup"; 3 | 4 | export * from "./src/types"; 5 | export const YButtonGroup = withInstall(buttonGroup); 6 | export default YButtonGroup; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YButtonGroup: typeof YButtonGroup; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/layout/src/footer.tsx: -------------------------------------------------------------------------------- 1 | import { createNamespace } from "@nimble-ui/utils"; 2 | import { defineComponent } from "vue"; 3 | 4 | export default defineComponent({ 5 | name: "YFooter", 6 | setup(props, ctx) { 7 | const bem = createNamespace("layout-footer"); 8 | return () => { 9 | return
{ctx.slots.default?.()}
; 10 | }; 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /packages/components/switch/demos/disabled.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 禁用状态 4 | 5 | 设置`disabled`属性,接受一个`Boolean`,设置`true`即可禁用。 6 | 7 | 8 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /packages/components/switch/demos/loading.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 加载状态 4 | 5 | 设置`loading`属性,接受一个`Boolean`,设置true即加载中状态。 6 | 7 | 8 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /packages/components/back-top/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _backTop from "./src/backTop"; 3 | 4 | export * from "./src/types"; 5 | export const YBackTop = withInstall(_backTop); 6 | export default YBackTop; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YBackTop: typeof YBackTop; 11 | "y-back-top": typeof YBackTop; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/components/input/demos/size.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 三种大小 4 | 5 | 可以通过设置属性size改变大小。 6 | 7 | 8 | 15 | -------------------------------------------------------------------------------- /packages/components/checkbox-group/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import checkboxGroup from "./src/checkboxGroup"; 3 | 4 | export * from "./src/types"; 5 | export const YCheckboxGroup = withInstall(checkboxGroup); 6 | export default YCheckboxGroup; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YCheckboxGroup: typeof YCheckboxGroup; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/ellipsis/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _ellipsis from "./src/ellipsis"; 3 | 4 | export * from "./src/types"; 5 | export const YEllipsis = withInstall(_ellipsis); 6 | export default YEllipsis; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YEllipsis: typeof YEllipsis; 11 | "y-ellipsis": typeof YEllipsis; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Nimble UI 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/components/layout/src/types.ts: -------------------------------------------------------------------------------- 1 | import { mergeCommonProp } from "@nimble-ui/utils"; 2 | import { ExtractPropTypes } from "vue"; 3 | 4 | const layoutProps = mergeCommonProp({ 5 | /** 6 | * @description 组件内部是否有边栏 7 | */ 8 | hasSidebar: { 9 | type: Boolean, 10 | }, 11 | }); 12 | 13 | export default layoutProps; 14 | 15 | export type LayoutProps = ExtractPropTypes>; 16 | -------------------------------------------------------------------------------- /packages/components/select/demos/select.page.md: -------------------------------------------------------------------------------- 1 | # 选择器 Select 2 | 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | ``` 8 | ## API 9 | 10 | ### Select Props 11 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 12 | | --- | --- | --- | --- | --- | 13 | | name | `number\|string` | - | 唯一标识,给form收集数据 | - | 14 | | options | `Array` | - | 配置项 | - | 15 | | disabled | `boolean` | - | 禁用 | - | 16 | | modelValue | `number\|string` | - | 绑定的值 | - | 17 | -------------------------------------------------------------------------------- /packages/theme/src/overlay.scss: -------------------------------------------------------------------------------- 1 | @use "./mixins/mixins.scss" as *; 2 | @use "./mixins/function.scss" as *; 3 | @use "./mixins/config.scss" as *; 4 | 5 | @include b(overlay) { 6 | --y-overlay-background: rgb(0 0 0 / 30%); 7 | 8 | position: fixed; 9 | top: 0; 10 | left: 0; 11 | z-index: auto; 12 | width: 100%; 13 | height: 100%; 14 | background: var(--y-overlay-background); 15 | pointer-events: all; 16 | } -------------------------------------------------------------------------------- /packages/components/ellipsis/demos/custom.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 定制 Tooltip 内容 4 | 5 | 通过tooltip插槽定制提升内容。 6 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /packages/components/divider/demos/divider.page.md: -------------------------------------------------------------------------------- 1 | # 分割线 Divider 2 | 区隔内容的分割线。 3 | 4 | ```demo 5 | basic.vue 6 | title.vue 7 | vertical.vue 8 | ``` 9 | ## API 10 | 11 | ### Divider Props 12 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 13 | | --- | --- | --- | --- | --- | 14 | | direction | `"left"` \| `"center"` \| `"right"` | `'center'` | 标题的位置 | | 15 | | dashed | `boolean` | `false` | 是否使用虚线分割 | | 16 | | vertical | `boolean` | `false` | 是否垂直分隔 | | 17 | -------------------------------------------------------------------------------- /packages/components/pagination/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _pagination from "./src/pagination"; 3 | 4 | export * from "./src/types"; 5 | export const YPagination = withInstall(_pagination); 6 | export default YPagination; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YPagination: typeof YPagination; 11 | "y-pagination": typeof YPagination; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/hooks/src/useCreateId.ts: -------------------------------------------------------------------------------- 1 | import { getCurrentInstance, computed } from "vue"; 2 | 3 | const count = Math.floor(Math.random() * 10000); 4 | let current = 0; 5 | 6 | export function useCreateId() { 7 | const instance = getCurrentInstance(); 8 | 9 | return { 10 | id: computed(() => { 11 | return (instance?.props.id ?? `y-id-${count}-${instance?.uid || current++}`) as string; 12 | }), 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /packages/components/date-picker/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _datePicker from "./src/datePicker"; 3 | 4 | export * from "./src/types"; 5 | export const YDatePicker = withInstall(_datePicker); 6 | export default YDatePicker; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YDatePicker: typeof YDatePicker; 11 | "y-date-picker": typeof YDatePicker; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/components/expand-transition/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _expandTransition from "./src/expandTransition"; 3 | 4 | export * from "./src/types"; 5 | export const YExpandTransition = withInstall(_expandTransition); 6 | export default YExpandTransition; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YExpandTransition: typeof YExpandTransition; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/components/pop-confirm/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _popConfirm from "./src/popConfirm"; 3 | 4 | export * from "./src/types"; 5 | export const YPopConfirm = withInstall(_popConfirm); 6 | export default YPopConfirm; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YPopConfirm: typeof YPopConfirm; 11 | "y-pop-confirm": typeof YPopConfirm; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/components/radio-group/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _radioGroup from "./src/radioGroup"; 3 | 4 | export * from "./src/types"; 5 | export const YRadioGroup = withInstall(_radioGroup); 6 | export default YRadioGroup; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YRadioGroup: typeof YRadioGroup; 11 | "y-radio-group": typeof YRadioGroup; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/components/time-picker/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _timePicker from "./src/timePicker"; 3 | 4 | export * from "./src/types"; 5 | export const YTimePicker = withInstall(_timePicker); 6 | export default YTimePicker; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YTimePicker: typeof YTimePicker; 11 | "y-time-picker": typeof YTimePicker; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/build/vite-plugin-md-transform-demo.ts: -------------------------------------------------------------------------------- 1 | import { Plugin } from "vite"; 2 | import { mdTransformVueSrs } from "./mdTransformVueSrs"; 3 | 4 | const fileRegex = /\.(md|vue)$/; 5 | 6 | export function markedTransformDemo(): Plugin { 7 | return { 8 | name: "vite-plugin-md-transform-demo", 9 | transform(code, id) { 10 | if (fileRegex.test(id)) { 11 | return mdTransformVueSrs(id); 12 | } 13 | }, 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /docs/src/pages/home.vue: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /packages/components/color-picker/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _colorPicker from "./src/colorPicker"; 3 | 4 | export * from "./src/types"; 5 | export const YColorPicker = withInstall(_colorPicker); 6 | export default YColorPicker; 7 | 8 | declare module "vue" { 9 | export interface GlobalComponents { 10 | YColorPicker: typeof YColorPicker; 11 | "y-color-picker": typeof YColorPicker; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/components/divider/demos/vertical.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 垂直分割线 4 | 5 | 使用 ```vertical``` 设置为行内的垂直分割线。 6 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /packages/components/image-preview/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _imagePreview from "./src/imagePreview"; 3 | 4 | export * from "./src/types"; 5 | export * from "./src/function-method"; 6 | export const YImagePreview = withInstall(_imagePreview); 7 | export default YImagePreview; 8 | 9 | declare module "vue" { 10 | export interface GlobalComponents { 11 | YImagePreview: typeof YImagePreview; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/tokens/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./src/row"; 2 | export * from "./src/form"; 3 | export * from "./src/form-item"; 4 | export * from "./src/config"; 5 | export * from "./src/button-group"; 6 | export * from "./src/checkbox-group"; 7 | export * from "./src/tooltip"; 8 | export * from "./src/image-preview"; 9 | export * from "./src/menu"; 10 | export * from "./src/radio-group"; 11 | export * from "./src/layout"; 12 | 13 | export * from "./src/types"; 14 | -------------------------------------------------------------------------------- /packages/components/color-picker/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 最简单的使用方法。 6 | 7 | 8 | 11 | 12 | 21 | -------------------------------------------------------------------------------- /packages/components/divider/demos/title.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 带文字的分割线 4 | 5 | 分割线中带有文字,可以用 ```direction``` 指定文字位置。 6 | 7 | 8 | 17 | -------------------------------------------------------------------------------- /packages/yy-ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nimble-ui/vue", 3 | "version": "0.1.0", 4 | "description": "基于vue3开发的组件库", 5 | "author": "陈羽云 <897908015@qq.com>", 6 | "license": "MIT", 7 | "main": "index.ts", 8 | "publishConfig": { 9 | "registry": "https://registry.npm.taobao.org" 10 | }, 11 | "scripts": { 12 | "test": "node ./__tests__/yy.test.js" 13 | }, 14 | "dependencies": { 15 | "@nimble-ui/components": "^0.1.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/components/switch/demos/text.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 文字和图标 4 | 5 | 带有文字和图标。 6 | 7 | 8 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /packages/components/tooltip/demos/tooltip.page.md: -------------------------------------------------------------------------------- 1 | # 文字提示 Tooltip 2 | 简单的文字提示气泡框。 3 | 4 | ```demo 5 | basic.vue 6 | location.vue 7 | ``` 8 | ## API 9 | 10 | ### Tooltip Props 11 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 12 | | --- | --- | --- | --- | --- | 13 | | lineClamp | `number` | `0` | 最大行数 | | 14 | | maxWidth | `string \| number` | - | 最大宽度 | | 15 | 16 | ### Tooltip Slots 17 | | 名称 | 参数 | 说明 | 18 | | --- | --- | --- | 19 | | default | - | 文本省略的内容 | 20 | | tooltip | - | 提示的的内容 | 21 | -------------------------------------------------------------------------------- /tsconfig.web.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "composite": true, 5 | "jsx": "preserve", 6 | "lib": ["ES2018", "DOM", "DOM.Iterable"], 7 | "skipLibCheck": true 8 | }, 9 | "include": ["packages"], 10 | "exclude": [ 11 | "node_modules", 12 | "**/dist", 13 | "**/__tests__/**/*", 14 | "**/gulpfile.ts", 15 | "**/test-helper", 16 | "packages/test-utils", 17 | "**/*.md" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /docs/build/mdTransformVueSrs.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import { mdToPage } from "./mdToPage"; 3 | import { vueToDemo } from "./vueToDemo"; 4 | 5 | export function mdTransformVueSrs(path: string) { 6 | if (path.endsWith(".md")) { 7 | const code = fs.readFileSync(path, { encoding: "utf-8" }); 8 | return mdToPage(code); 9 | } else if (path.endsWith(".demo.vue")) { 10 | const code = fs.readFileSync(path, "utf-8"); 11 | return vueToDemo(code); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./src/common"; 2 | export * from "./src/withInstall"; 3 | export * from "./src/type"; 4 | export * from "./src/createNamespace"; 5 | export * from "./src/generate"; 6 | export * from "./src/props"; 7 | export * from "./src/object"; 8 | export * from "./src/event"; 9 | export * from "./src/array"; 10 | export * from "./src/scroll"; 11 | export * from "./src/style"; 12 | export * from "./src/dom"; 13 | 14 | export * from "./src/typescript"; 15 | -------------------------------------------------------------------------------- /packages/components/message/demos/timing.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 自定义显示时长 4 | 5 | 自定义时长 10s,是以毫秒文单位 6 | 7 | 8 | 11 | 12 | 22 | -------------------------------------------------------------------------------- /packages/components/upload/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 最简单的用法。 6 | 7 | 8 | 11 | 12 | 18 | -------------------------------------------------------------------------------- /packages/components/descriptions/src/descriptions.tsx: -------------------------------------------------------------------------------- 1 | import { createNamespace } from "@nimble-ui/utils"; 2 | import { defineComponent } from "vue"; 3 | 4 | import descriptionsProps from "./types"; 5 | 6 | export default defineComponent({ 7 | name: "YDescriptions", 8 | props: descriptionsProps(), 9 | setup(props, ctx) { 10 | const bem = createNamespace("descriptions"); 11 | 12 | return () => { 13 | return
; 14 | }; 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /packages/components/ellipsis/demos/ellipsis.page.md: -------------------------------------------------------------------------------- 1 | # 文本省略 Ellipsis 2 | 文本溢出隐藏 3 | 4 | ```demo 5 | basic.vue 6 | max.vue 7 | custom.vue 8 | ``` 9 | ## API 10 | 11 | ### Ellipsis Props 12 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 13 | | --- | --- | --- | --- | --- | 14 | | lineClamp | `number` | `0` | 最大行数 | | 15 | | maxWidth | `string \| number` | - | 最大宽度 | | 16 | 17 | ### Ellipsis Slots 18 | | 名称 | 参数 | 说明 | 19 | | --- | --- | --- | 20 | | default | - | 文本省略的内容 | 21 | | tooltip | - | 提示的的内容 | 22 | -------------------------------------------------------------------------------- /scripts/lib/cli.js: -------------------------------------------------------------------------------- 1 | import { Command } from "commander"; 2 | 3 | const program = new Command(); 4 | 5 | program 6 | .command("component ") 7 | .description("创建组件") 8 | .option("-f, --force, 是否覆盖已有的") 9 | .option("-n, --CNName , 中文名") 10 | .action(async (name, options) => { 11 | const { createComponent } = await import("./commands/create-component.js"); 12 | return createComponent(name, options); 13 | }); 14 | 15 | program.parse(process.argv); 16 | -------------------------------------------------------------------------------- /packages/tsconfig.type.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "baseUrl": ".", 6 | "declaration": true, 7 | "emitDeclarationOnly": true, 8 | "declarationDir": "../dist/types", 9 | "jsx": "preserve", 10 | "paths": { 11 | "@nimble-ui/*": ["../packages/*"], 12 | } 13 | }, 14 | "exclude": ["node_module"], 15 | "include": ["components/**/*", "hooks/**/*", "tokens/**/*", "utils/**/*", "yy-ui/**/*"] 16 | } -------------------------------------------------------------------------------- /docs/src/assets/vue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/components/drawer/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 基础抽屉,点击触发按钮抽屉从右滑出,点击遮罩区关闭。 6 | 7 | 8 | 12 | 13 | 21 | -------------------------------------------------------------------------------- /packages/components/layout/demos/layout.page.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 布局 Layout 4 | 协助进行页面级整体布局。 5 | 6 | ## 代码演示 7 | ```demo 8 | basic.vue 9 | ``` 10 | 11 | ## API 12 | 13 | ### Layout Props 14 | 15 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 16 | | --- | --- | --- | --- | --- | 17 | 18 | 19 | ### Layout Events 20 | | 事件名 | 说明 | 类型 | 21 | | --- | --- | --- | 22 | | click | 点击按钮事件 | `(e: Event) => void`| 23 | 24 | ### Layout Slots 25 | | 名称 | 参数 | 说明 | 26 | | --- | --- | --- | 27 | | default | - | 按钮的内容 | 28 | -------------------------------------------------------------------------------- /packages/components/number/demos/number.page.md: -------------------------------------------------------------------------------- 1 | # 数字动画 Number 2 | 3 | 4 | ## 代码演示 5 | ```demo 6 | gap.vue 7 | ``` 8 | ## API 9 | 10 | ### Number Props 11 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 12 | | --- | --- | --- | --- | --- | 13 | | count | `string \| number` | - | 标记数量 | - | 14 | | max | `string \| number` | - | 展示封顶的数字值 | - | 15 | | numberClass | `string \| Array \| Object` | - | 数字的类名 | - | 16 | | numberStyle | `string \| Array \| Object` | - | 数字的样式 | - | 17 | | gap | `string \| number ` | - | 数字间的间隙 | - | 18 | -------------------------------------------------------------------------------- /packages/tokens/src/tooltip.ts: -------------------------------------------------------------------------------- 1 | import type { InjectionKey, Ref } from "vue"; 2 | 3 | type RefSetter = (el: T) => void; 4 | 5 | export type RectInfo = { 6 | width: number; 7 | height: number; 8 | }; 9 | interface TooltipContext { 10 | triggerRef: Ref; 11 | contentRef: Ref; 12 | setRef: RefSetter; 13 | rectInfo: RectInfo; 14 | } 15 | 16 | export const tooltipContextKey: InjectionKey = Symbol("tooltipContextKey"); 17 | -------------------------------------------------------------------------------- /packages/tokens/src/menu.ts: -------------------------------------------------------------------------------- 1 | import type { ComputedRef, InjectionKey } from "vue"; 2 | 3 | type KeyType = string | number | symbol | undefined; 4 | interface MenuContext { 5 | onItemClick: (site: number[], item: any, key?: KeyType) => void; 6 | onSubClick: (site: number[], item: any, isAllOpen?: boolean) => void; 7 | selectSite: Array; 8 | activeSite: Array; 9 | activeKey: ComputedRef; 10 | } 11 | 12 | export const menuContextKey: InjectionKey = Symbol("menuContextKey"); 13 | -------------------------------------------------------------------------------- /docs/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import vue from "@vitejs/plugin-vue"; 3 | import vueJsx from "@vitejs/plugin-vue-jsx"; 4 | import { markedTransformDemo } from "./build/vite-plugin-md-transform-demo"; 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | base: "./", 9 | plugins: [ 10 | markedTransformDemo(), 11 | vue({ 12 | include: [/\.vue$/, /\.md$/], 13 | }), 14 | vueJsx(), 15 | ], 16 | server: { 17 | host: "0.0.0.0", 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /packages/components/scrollbar/demos/x.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 横向滚动 4 | 5 | 通过 ```xScroll``` 属性设置,会显示横向滚动条。 6 | 7 | 8 | 18 | -------------------------------------------------------------------------------- /packages/components/checkbox/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 通过 v-model 绑定复选框的勾选状态。 6 | 7 | 8 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /packages/components/image-preview/src/types.ts: -------------------------------------------------------------------------------- 1 | import { mergeCommonProp } from "@nimble-ui/utils"; 2 | import { ExtractPropTypes } from "vue"; 3 | 4 | const imagePreviewProps = mergeCommonProp({ 5 | isGroup: { 6 | type: Boolean, 7 | }, 8 | }); 9 | 10 | export default imagePreviewProps; 11 | 12 | export type imagePreviewExpose = { 13 | toggle: (bool: boolean) => void; 14 | setPreviewSrc: (src: string) => void; 15 | }; 16 | 17 | export type ImagePreviewProps = ExtractPropTypes>; 18 | -------------------------------------------------------------------------------- /packages/hooks/src/useCreateIndex.ts: -------------------------------------------------------------------------------- 1 | import { computed, ref } from "vue"; 2 | import { useGlobalConfig } from "./useGlobalConfig"; 3 | 4 | const zIndex = ref(0); 5 | 6 | export function useCreateIndex() { 7 | const initZIndex = useGlobalConfig("zIndex", 2000); 8 | const currentZIndex = computed(() => initZIndex.value + zIndex.value); 9 | const nextZIndex = () => { 10 | zIndex.value++; 11 | return currentZIndex.value; 12 | }; 13 | 14 | return { 15 | currentZIndex, 16 | nextZIndex, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /packages/tokens/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nimble-ui/tokens", 3 | "version": "0.1.0", 4 | "description": "> TODO: description", 5 | "author": "陈羽云 <897908015@qq.com>", 6 | "license": "MIT", 7 | "main": "index.ts", 8 | "module": "index.ts", 9 | "publishConfig": { 10 | "registry": "https://registry.npm.taobao.org" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git@toscode.gitee.com:fast_dev/yy-ui.git" 15 | }, 16 | "dependencies": { 17 | "stylelint-order": "^6.0.3" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/theme/src/number.scss: -------------------------------------------------------------------------------- 1 | @use "./mixins/mixins.scss" as *; 2 | 3 | @include b(number) { 4 | overflow: hidden; 5 | 6 | @include e(scroll){ 7 | height: 20px; 8 | } 9 | 10 | @include e(only) { 11 | display: inline-block; 12 | position: relative; 13 | white-space: nowrap; 14 | text-align: center; 15 | 16 | @include m(unit) { 17 | display: inline-block; 18 | position: absolute; 19 | 20 | @include when(current) { 21 | position: relative; 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/tokens/src/checkbox-group.ts: -------------------------------------------------------------------------------- 1 | import type { InjectionKey, Ref } from "vue"; 2 | import type { ProvideContext } from "./types"; 3 | import type { CheckboxGroupProps } from "@nimble-ui/components/checkbox-group"; 4 | 5 | type CheckboxGroupContext = ProvideContext<{ 6 | props: CheckboxGroupProps; 7 | model: Ref | undefined>; 8 | change: (checked: boolean, uid?: number) => void; 9 | }>; 10 | 11 | export const checkboxGroupContextKey: InjectionKey = Symbol("checkboxGroupContextKey"); 12 | -------------------------------------------------------------------------------- /packages/components/scrollbar/demos/trigger.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 触发方式 4 | 5 | 通过 ```trigger``` 属性设置滚动条的时机。 6 | 7 | 8 | 13 | 14 | 19 | -------------------------------------------------------------------------------- /packages/tokens/src/types.ts: -------------------------------------------------------------------------------- 1 | import { ComponentInternalInstance, ComponentPublicInstance } from "vue"; 2 | 3 | export type TriggerEventType = "onBlur" | "onChange" | "onSubmit" | "onFocus"; 4 | 5 | export type ChildrenType = { 6 | public: ComponentPublicInstance; 7 | internal: ComponentInternalInstance; 8 | }; 9 | 10 | export type ProvideContext = T & { 11 | children: ChildrenType[]; 12 | link: (child: ComponentInternalInstance | null) => void; 13 | unlink: (child: ComponentInternalInstance | null) => void; 14 | }; 15 | -------------------------------------------------------------------------------- /packages/components/card/src/types.ts: -------------------------------------------------------------------------------- 1 | import { mergeCommonProp } from "@nimble-ui/utils"; 2 | import { ExtractPropTypes, PropType, StyleValue } from "vue"; 3 | 4 | const cardProps = mergeCommonProp({ 5 | contentClass: { 6 | type: [String, Array, Object], 7 | }, 8 | contentStyle: { 9 | type: [String, Array, Object] as PropType, 10 | }, 11 | }); 12 | 13 | export default cardProps; 14 | 15 | // 给组件ref智能提示 16 | // export type cardExpose = {}; 17 | 18 | export type CardProps = ExtractPropTypes>; 19 | -------------------------------------------------------------------------------- /packages/components/button/demos/loading.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 加载中 4 | 5 | 按钮添加加载状态。 6 | 7 | 8 | 11 | 12 | 24 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist", 4 | "target": "es2018", 5 | "module": "esnext", 6 | "baseUrl": ".", 7 | "sourceMap": false, 8 | "moduleResolution": "node", 9 | "allowJs": false, 10 | "strict": true, 11 | "noUnusedLocals": true, 12 | "resolveJsonModule": true, 13 | "allowSyntheticDefaultImports": true, 14 | "esModuleInterop": true, 15 | "removeComments": false, 16 | "rootDir": ".", 17 | "paths": { 18 | "@nimble-ui/*": ["packages/*"] 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/hooks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nimble-ui/hooks", 3 | "version": "0.1.0", 4 | "description": "> TODO: description", 5 | "author": "陈羽云 <897908015@qq.com>", 6 | "license": "MIT", 7 | "main": "index.ts", 8 | "module": "index.ts", 9 | "publishConfig": { 10 | "registry": "https://registry.npm.taobao.org" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git@toscode.gitee.com:fast_dev/yy-ui.git" 15 | }, 16 | "dependencies": { 17 | "@nimble-ui/tokens": "^0.1.0", 18 | "stylelint-order": "^6.0.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/components/button/demos/group.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 按钮组 4 | 5 | 把几个按钮结合成按钮组。 6 | 7 | 8 | 22 | -------------------------------------------------------------------------------- /packages/components/descriptions/src/types.ts: -------------------------------------------------------------------------------- 1 | import { mergeCommonProp } from "@nimble-ui/utils"; 2 | import { ExtractPropTypes } from "vue"; 3 | 4 | const descriptionsProps = mergeCommonProp({ 5 | /** 6 | * @description 总列数 7 | */ 8 | column: { 9 | type: Number, 10 | default: 0, 11 | }, 12 | /** 13 | * @description 分隔符 14 | */ 15 | separator: { 16 | type: String, 17 | default: ":", 18 | }, 19 | }); 20 | 21 | export default descriptionsProps; 22 | 23 | export type DescriptionsProps = ExtractPropTypes>; 24 | -------------------------------------------------------------------------------- /packages/components/modal/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 创建第一个对话框 6 | 7 | 8 | 16 | 17 | 25 | -------------------------------------------------------------------------------- /packages/components/date-picker/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 最简单的使用方法。 6 | 7 | 8 | 17 | 18 | 26 | -------------------------------------------------------------------------------- /packages/components/switch/demos/customValue.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 自定义选中的值 4 | 5 | 使用 `checked-value` 和 `unchecked-value` 制定选中的值。 6 | 7 | 8 | 11 | 12 | 21 | -------------------------------------------------------------------------------- /packages/components/layout/src/header.tsx: -------------------------------------------------------------------------------- 1 | import { createNamespace } from "@nimble-ui/utils"; 2 | import { defineComponent } from "vue"; 3 | 4 | export default defineComponent({ 5 | name: "YHeader", 6 | props: { 7 | /** 8 | * @description 是否显示边框 9 | */ 10 | bordered: Boolean, 11 | /** 12 | * @description 是否固定头部 13 | */ 14 | fixed: Boolean, 15 | }, 16 | setup(props, ctx) { 17 | const bem = createNamespace("layout-header"); 18 | 19 | return () => { 20 | return
{ctx.slots.default?.()}
; 21 | }; 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /docs/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import router from "./router"; 3 | import YYUi from "@nimble-ui/vue"; 4 | import "@nimble-ui/theme/src/index.scss"; 5 | import "highlight.js/styles/atom-one-dark.css"; 6 | 7 | import App from "./App.vue"; 8 | import ComponentDemo from "./components/ComponentDemo.vue"; 9 | import ComponentDemos from "./components/ComponentDemos"; 10 | 11 | createApp(App) 12 | .use(YYUi) 13 | .use(router) 14 | .use((app) => { 15 | app.component("ComponentDemo", ComponentDemo); 16 | app.component("ComponentDemos", ComponentDemos); 17 | }) 18 | .mount("#app"); 19 | -------------------------------------------------------------------------------- /packages/components/scrollbar/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 设置滚动条高度,若不设置则根据父容器高度自适应。 6 | 7 | 8 | 13 | 14 | 23 | -------------------------------------------------------------------------------- /packages/tokens/src/form-item.ts: -------------------------------------------------------------------------------- 1 | import type { InjectionKey, ComputedRef } from "vue"; 2 | import type { ProvideContext, TriggerEventType } from "./types"; 3 | 4 | export interface FormItemState { 5 | status: "failed" | "passed" | "init"; 6 | message: string; 7 | focus: boolean; 8 | } 9 | 10 | type FormItemContext = ProvideContext<{ 11 | state: FormItemState; 12 | propsRef: ComputedRef<{ details?: any }>; 13 | events: (type: TriggerEventType, value: string | number | boolean) => void; 14 | }>; 15 | 16 | export const formItemContextKey: InjectionKey = Symbol("formItemContext"); 17 | -------------------------------------------------------------------------------- /packages/components/flex/demos/gap.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 设置间隙 4 | 5 | 使用 gap 设置元素之间的间距 6 | 7 | 8 | 16 | 22 | -------------------------------------------------------------------------------- /packages/components/layout/src/content.tsx: -------------------------------------------------------------------------------- 1 | import { createNamespace } from "@nimble-ui/utils"; 2 | import YScrollbar from "@nimble-ui/components/scrollbar"; 3 | import { defineComponent } from "vue"; 4 | 5 | export default defineComponent({ 6 | name: "YContent", 7 | inheritAttrs: false, 8 | setup(props, ctx) { 9 | const bem = createNamespace("layout-content"); 10 | return () => { 11 | return ( 12 | 13 | {ctx.slots.default?.()} 14 | 15 | ); 16 | }; 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /packages/components/pagination/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 简单使用 6 | 7 | 8 | 13 | 14 | 23 | -------------------------------------------------------------------------------- /packages/components/space/demos/size.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 自定义尺寸 4 | 5 | 自定义间距大小。 6 | 7 | 8 | 16 | 17 | 23 | -------------------------------------------------------------------------------- /packages/utils/src/common.ts: -------------------------------------------------------------------------------- 1 | export const isBrowser = typeof document !== "undefined" && typeof window !== "undefined"; 2 | 3 | // canvas合成海报,解决画布模糊的问题 4 | export function getRatio(context: any): number { 5 | if (!context) { 6 | return 1; 7 | } 8 | // 获取画布的宽高比 9 | const backingStore = 10 | context.backingStorePixelRatio || 11 | context.webkitBackingStorePixelRatio || 12 | context.mozBackingStorePixelRatio || 13 | context.msBackingStorePixelRatio || 14 | context.oBackingStorePixelRatio || 15 | context.backingStorePixelRatio || 16 | 1; 17 | return (window.devicePixelRatio || 1) / backingStore; 18 | } 19 | -------------------------------------------------------------------------------- /packages/components/input/demos/disabled.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 输入框禁用 4 | 5 | 设置属性disabled为true。 6 | 7 | 8 | 16 | 17 | 25 | -------------------------------------------------------------------------------- /packages/components/space/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 相邻组件水平间距。 6 | 7 | 8 | 21 | -------------------------------------------------------------------------------- /packages/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./src/useExpose"; 2 | export * from "./src/useTheme"; 3 | export * from "./src/useRelation"; 4 | export * from "./src/useCreateId"; 5 | export * from "./src/useEventListener"; 6 | export * from "./src/useLazyRender"; 7 | export * from "./src/useResizeObserver"; 8 | export * from "./src/useGlobalConfig"; 9 | export * from "./src/useCreateIndex"; 10 | export * from "./src/useScrollParent"; 11 | export * from "./src/useMouseMove"; 12 | export * from "./src/useMergePropOrContext"; 13 | export * from "./src/useComputePosition"; 14 | export * from "./src/useClickOutside"; 15 | export * from "./src/useMouseInOut"; 16 | -------------------------------------------------------------------------------- /packages/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nimble-ui/utils", 3 | "version": "0.1.0", 4 | "description": "> TODO: description", 5 | "author": "陈羽云 <897908015@qq.com>", 6 | "homepage": "", 7 | "license": "ISC", 8 | "main": "index.ts", 9 | "module": "index.ts", 10 | "directories": { 11 | "lib": "lib", 12 | "test": "__tests__" 13 | }, 14 | "files": [ 15 | "lib" 16 | ], 17 | "publishConfig": { 18 | "registry": "https://registry.npm.taobao.org" 19 | }, 20 | "scripts": { 21 | "test": "node ./__tests__/utils.test.js" 22 | }, 23 | "dependencies": { 24 | "stylelint-order": "^6.0.3" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/components/message/demos/close.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 手动关闭 4 | 5 | 把 `duration` 设置为零不会自动关闭,要手动调用close方法 6 | 7 | 8 | 14 | 15 | 29 | -------------------------------------------------------------------------------- /packages/theme/src/ellipsis.scss: -------------------------------------------------------------------------------- 1 | @use "./mixins/mixins.scss" as *; 2 | @use "./mixins/function.scss" as *; 3 | @use "./mixins/config.scss" as *; 4 | @use "./mixins//utils.scss" as*; 5 | @use "./common/transition.scss"; 6 | 7 | @include b(ellipsis) { 8 | color: var(--y-color-text); 9 | font-size: var(--y-font-size); 10 | 11 | @include e(title) { 12 | overflow: hidden; 13 | 14 | &:not(.is-line-clamp) { 15 | @include utils-ellipsis 16 | } 17 | 18 | @include when(line-clamp) { 19 | display: -webkit-inline-box; 20 | -moz-box-orient: vertical; 21 | -webkit-box-orient: vertical; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/components/input/demos/formatter.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 格式化 4 | 5 | 在formatter的格式化显示值,parser格式化v-model绑定的值 6 | 7 | 8 | 17 | 18 | 25 | -------------------------------------------------------------------------------- /packages/components/tabs/demos/centered.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 居中 4 | 5 | 标签居中展示。 6 | 7 | 8 | 11 | 12 | 30 | -------------------------------------------------------------------------------- /packages/theme/src/pop-confirm.scss: -------------------------------------------------------------------------------- 1 | @use "./mixins/mixins.scss" as *; 2 | @use "./common/var.scss" as *; 3 | 4 | @include b(pop-confirm) { 5 | --y-pop-confirm-content-bg-color: var(--y-color-bg-elevated); 6 | --y-pop-confirm-text-color: var(--y-color-text); 7 | 8 | background-color: var(--y-pop-confirm-content-bg-color); 9 | box-shadow: $box-shadow-secondary; 10 | color: var(--y-pop-confirm-text-color); 11 | 12 | @include e(message) { 13 | margin-bottom: 8px; 14 | 15 | @include m(text-title) { 16 | font-weight: 600; 17 | } 18 | 19 | @include m(text-description) { 20 | margin-top: 4px; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /docs/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory } from "vue-router"; 2 | 3 | import componentRouters from "./routers"; 4 | const router = createRouter({ 5 | history: createWebHashHistory(), 6 | routes: [ 7 | { 8 | path: "/", 9 | redirect: "/home", 10 | }, 11 | { 12 | path: "/home", 13 | component: () => import("../pages/home.vue"), 14 | }, 15 | { 16 | path: "/component/", 17 | name: "componentLayout", 18 | component: () => import("../components/ComponentLayout.vue"), 19 | children: [...componentRouters], 20 | }, 21 | ], 22 | }); 23 | 24 | export default router; 25 | -------------------------------------------------------------------------------- /packages/components/slider/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 从堆叠到水平排列。 6 | 7 | 8 | 11 | 31 | -------------------------------------------------------------------------------- /packages/components/time-picker/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 从堆叠到水平排列。 6 | 7 | 8 | 13 | 14 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /packages/theme/src/common/var.scss: -------------------------------------------------------------------------------- 1 | @use "../mixins/set-color-level.scss" as *; 2 | @use "../mixins/config.scss" as *; 3 | 4 | $box-shadow-secondary: 0 6px 16px 0 rgb(0 0 0 / 8%), 5 | 0 3px 6px -4px rgb(0 0 0 / 12%), 6 | 0 9px 28px 8px rgb(0 0 0 / 5%); 7 | $xs: 576px !default; 8 | $sm: 576px !default; 9 | $md: 768px !default; 10 | $lg: 992px !default; 11 | $xl: 1200px !default; 12 | $xxl: 1600px !default; 13 | $breakpoints: ( 14 | 'xs': '(max-width: #{$sm})', 15 | 'sm': '(min-width: #{$sm})', 16 | 'md': '(min-width: #{$md})', 17 | 'lg': '(min-width: #{$lg})', 18 | 'xl': '(min-width: #{$xl})', 19 | 'xxl': '(min-width: #{$xxl})', 20 | ) !default; 21 | -------------------------------------------------------------------------------- /packages/components/number/demos/gap.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 数字间的间隙 4 | 5 | 使用属性`gap`修改数字间的间隙 6 | 7 | 8 | 18 | 19 | 27 | -------------------------------------------------------------------------------- /packages/components/overlay/src/types.ts: -------------------------------------------------------------------------------- 1 | import { CSSProperties, ExtractPropTypes, PropType } from "vue"; 2 | import { mergeCommonProp } from "@nimble-ui/utils"; 3 | 4 | const overlayProps = mergeCommonProp({ 5 | show: Boolean, 6 | zIndex: [Number, String], 7 | duration: [Number, String], 8 | lockScroll: { 9 | type: Boolean, 10 | default: true, 11 | customStyle: Object as PropType, 12 | }, 13 | /** 14 | * @description 禁止穿梭 15 | */ 16 | disabled: { 17 | type: Boolean, 18 | }, 19 | }); 20 | 21 | export default overlayProps; 22 | 23 | export type OverlayProps = ExtractPropTypes>; 24 | -------------------------------------------------------------------------------- /packages/components/pop-confirm/demos/async.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 异步关闭 4 | 5 | 可以通过属性 `beforeConfirm` 传入函数 6 | 7 | 8 | 13 | 14 | 24 | -------------------------------------------------------------------------------- /packages/components/number/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 简单使用 6 | 7 | 8 | 18 | 19 | 27 | -------------------------------------------------------------------------------- /packages/components/message/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 从顶部出现,3s 后自动消失。 6 | 7 | 8 | 14 | 15 | 27 | -------------------------------------------------------------------------------- /packages/components/ellipsis/src/types.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes, PropType } from "vue"; 2 | import { mergeCommonProp } from "@nimble-ui/utils"; 3 | 4 | const ellipsisProps = mergeCommonProp({ 5 | /** 6 | * @description 最大行数 7 | */ 8 | lineClamp: { 9 | type: Number, 10 | default: 0, 11 | }, 12 | /** 13 | * @description 最大宽度 14 | */ 15 | maxWidth: { 16 | type: [String, Number], 17 | }, 18 | /** 19 | * @description 展开的触发方式 20 | */ 21 | trigger: { 22 | type: String as PropType<"click">, 23 | }, 24 | }); 25 | 26 | export default ellipsisProps; 27 | 28 | export type EllipsisProps = ExtractPropTypes>; 29 | -------------------------------------------------------------------------------- /packages/components/back-top/demos/back-top.page.md: -------------------------------------------------------------------------------- 1 | # 回到顶部 BackTop 2 | 3 | ## 代码演示 4 | ```demo 5 | basic.vue 6 | position.vue 7 | target.vue 8 | ``` 9 | ## API 10 | 11 | ### BackTop Props 12 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 13 | | --- | --- | --- | --- | --- | 14 | | bottom | `string \| number` | `40` | 距离页面底部的高度 | | 15 | | right | `string \| number` | `40` | 距离页面右侧的宽度 | | 16 | | listenTo | `string \| HTMLElement` | - | 监听滚动的元素,如果为 undefined 会监听距离最近的一个可滚动的祖先节点 | | 17 | | mount | `string \| HTMLElement` | `'body'` | 渲染的容器节点 | | 18 | | scrollTop | `number` | `180` | 滚动时触发显示回到顶部的高度 | | 19 | 20 | ### BackTop Slots 21 | | 名称 | 参数 | 说明 | 22 | | --- | --- | --- | 23 | | default | - | 回到顶部的内容 | 24 | -------------------------------------------------------------------------------- /packages/components/tabs/demos/trigger.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 触发方式 4 | 5 | 可以使用 trigger='hover' 触发标签页的改变。 6 | 7 | 8 | 11 | 12 | 30 | -------------------------------------------------------------------------------- /packages/components/divider/src/types.ts: -------------------------------------------------------------------------------- 1 | import { mergeCommonProp } from "@nimble-ui/utils"; 2 | import { ExtractPropTypes, PropType } from "vue"; 3 | 4 | const dividerProps = mergeCommonProp({ 5 | /** 6 | * @description 标题的位置 7 | */ 8 | direction: { 9 | type: String as PropType<"left" | "center" | "right">, 10 | default: "center", 11 | }, 12 | /** 13 | * @description 是否使用虚线分割 14 | */ 15 | dashed: { 16 | type: Boolean, 17 | }, 18 | /** 19 | * @description 是否垂直分隔 20 | */ 21 | vertical: { 22 | type: Boolean, 23 | }, 24 | }); 25 | 26 | export default dividerProps; 27 | 28 | export type DividerProps = ExtractPropTypes>; 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "private": true, 4 | "workspaces": [ 5 | "packages/*", 6 | "docs", 7 | "build", 8 | "scripts" 9 | ], 10 | "scripts": { 11 | "theme:prod": "lerna run --scope @nimble-ui/theme build", 12 | "theme:dev": "lerna run --scope @nimble-ui/theme dev", 13 | "docs:dev": "lerna run --scope @nimble-ui/docs dev", 14 | "docs:build": "lerna run --scope @nimble-ui/docs build", 15 | "build": "lerna run --scope @nimble-ui/build build", 16 | "component": "npx yy-cli component" 17 | }, 18 | "devDependencies": { 19 | "eslint": "^8.33.0", 20 | "lerna": "^6.1.0", 21 | "vue": "^3.2.45", 22 | "stylelint": "15.6.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/utils/src/withInstall.ts: -------------------------------------------------------------------------------- 1 | import { App } from "vue"; 2 | 3 | export type WithInstall = T & { 4 | install(app: App): void; 5 | }; 6 | 7 | export function withInstall(component: T) { 8 | (component as Record).install = (app: App) => { 9 | const { name } = component as unknown as { name: string }; 10 | app.component(name, component as any); 11 | }; 12 | 13 | return component as WithInstall; 14 | } 15 | 16 | export function withInstallFunction(component: T, name: string) { 17 | (component as Record).install = (app: App) => { 18 | app.config.globalProperties[name] = component; 19 | }; 20 | 21 | return component as WithInstall; 22 | } 23 | -------------------------------------------------------------------------------- /packages/components/radio-group/src/types.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes, PropType } from "vue"; 2 | import { radioCommonProps } from "@nimble-ui/tokens"; 3 | import { mergeCommonProp } from "@nimble-ui/utils"; 4 | import { RadioProps } from "@nimble-ui/components/radio"; 5 | 6 | const radioGroupProps = mergeCommonProp({ 7 | ...radioCommonProps, 8 | /** 9 | * @description radio列表配置 10 | */ 11 | options: { 12 | type: Array as PropType, 13 | }, 14 | /** 15 | * @description 是否竖直排列 16 | */ 17 | vertical: { 18 | type: Boolean, 19 | }, 20 | }); 21 | 22 | export default radioGroupProps; 23 | 24 | export type RadioGroupProps = ExtractPropTypes>; 25 | -------------------------------------------------------------------------------- /packages/components/row/demos/respond.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 响应式布局 4 | 5 | 响应式布局 6 | 7 | 8 | 26 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nimble-ui/docs", 3 | "version": "0.1.0", 4 | "author": "陈羽云 <897908015@qq.com>", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "vue-router": "4.2.4", 13 | "vue": "^3.2.0" 14 | }, 15 | "devDependencies": { 16 | "@types/node": "^20.5.0", 17 | "@vitejs/plugin-vue": "^4.2.3", 18 | "@vitejs/plugin-vue-jsx": "^3.0.1", 19 | "highlight.js": "^11.8.0", 20 | "marked": "^7.0.3", 21 | "sass": "^1.66.0", 22 | "typescript": "^5.0.2", 23 | "vite": "^4.4.5", 24 | "vue-tsc": "^1.8.5", 25 | "fast-glob": "^3.3.1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/components/flex/demos/items.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 设置间隙 4 | 5 | 使用 gap 设置元素之间的间距 6 | 7 | 8 | 11 | 35 | -------------------------------------------------------------------------------- /packages/components/message/demos/type.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 提示类型 4 | 5 | 包括成功、失败、警告。 6 | 7 | 8 | 15 | 16 | 31 | -------------------------------------------------------------------------------- /packages/components/modal/demos/function.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 函数调用方式 4 | 5 | 可以使用函数方式创建 6 | 7 | 8 | 13 | 14 | 32 | -------------------------------------------------------------------------------- /packages/components/badge/demos/zero.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # 是否显示 0 5 | 6 | 通过设置属性`show-zero`来显示。 7 | 8 | 9 | 19 | 20 | 25 | 26 | 34 | -------------------------------------------------------------------------------- /packages/tokens/src/button-group.ts: -------------------------------------------------------------------------------- 1 | import type { InjectionKey, ComputedRef } from "vue"; 2 | import type { Fun } from "@nimble-ui/utils"; 3 | 4 | export type ButtonTypes = "default" | "primary" | "success" | "warning" | "info" | "error" | "dashed"; 5 | 6 | export type ButtonShape = "default" | "circle" | "round"; 7 | export type ButtonSize = "large" | "default" | "small"; 8 | 9 | type ButtonGroupContext = { 10 | type?: ButtonTypes | Fun; 11 | shape?: ButtonShape | Fun; 12 | disabled?: boolean | Fun; 13 | size?: ButtonSize | Fun; 14 | details: any; 15 | }; 16 | 17 | export const buttonGroupContextKey: InjectionKey> = Symbol("buttonGroupContextKey"); 18 | -------------------------------------------------------------------------------- /packages/components/badge/demos/offset.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # 自定义位置偏移 5 | 6 | 设置状态点的位置偏移,格式为 `[left, top]`,表示状态点距默认位置左侧、上方的偏移量。 7 | 8 | 9 | 16 | 17 | 23 | 24 | 32 | -------------------------------------------------------------------------------- /packages/components/layout/src/layout.tsx: -------------------------------------------------------------------------------- 1 | import { defineComponent, provide, ref } from "vue"; 2 | import { createNamespace } from "@nimble-ui/utils"; 3 | 4 | import { layoutContextKey } from "@nimble-ui/tokens"; 5 | 6 | import layoutProps from "./types"; 7 | 8 | export default defineComponent({ 9 | name: "YLayout", 10 | props: layoutProps(), 11 | setup(props, ctx) { 12 | const bem = createNamespace("layout"); 13 | 14 | const hasSider = ref(false); 15 | provide(layoutContextKey, { 16 | setSider(has) { 17 | hasSider.value = has; 18 | }, 19 | }); 20 | 21 | return () => { 22 | return
{ctx.slots.default?.()}
; 23 | }; 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /packages/components/tabs/demos/card.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 页签的基本样式 4 | 5 | 可以通过改变type属性,可选line、card、radio、bar 6 | 7 | 8 | 11 | 12 | 35 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "preserve", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /docs/src/router/routers.ts: -------------------------------------------------------------------------------- 1 | import { RouteRecordRaw } from "vue-router"; 2 | 3 | const modules = import.meta.glob("../../../packages/components/**/*.page.md"); 4 | 5 | const keys = Object.keys(modules); 6 | 7 | function camelCase(s: string) { 8 | const shouldConvert = !(s.indexOf("-") === -1 && s.indexOf("_") === -1 && s.indexOf(".") === -1); 9 | return shouldConvert ? s.replace(/[-_.]+([^-_.])/g, (...args) => args[1].toUpperCase()) : s; 10 | } 11 | 12 | export default keys.map((key) => { 13 | const list = key.split("/"); 14 | const len = list.length; 15 | const name = camelCase(list[len - 1].split(".")[0]); 16 | const route = { 17 | name, 18 | path: `${name}`, 19 | component: modules[key], 20 | }; 21 | return route as unknown as RouteRecordRaw; 22 | }); 23 | -------------------------------------------------------------------------------- /packages/components/row/demos/row.page.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 栅格 Grid 4 | 通过基础的 24 分栏,迅速简便地创建布局。 5 | 6 | ## 代码演示 7 | ```demo 8 | basic.vue 9 | gutter.vue 10 | respond.vue 11 | ``` 12 | 13 | ## API 14 | 15 | ### Row Props 16 | 17 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 18 | | --- | --- | --- | --- | --- | 19 | | gutter | `number` \| `array` | `0` | 栅格间隔 | | 20 | | align | `'top'` \| `'middle'` \| `'bottom'` | `'top'` | flex 布局下的垂直排列方式 | | 21 | | justify | `'start'` \| `'end'` \| `'center'` \| `'space-around'` \| `'space-between'` \| `'space-evenly'` | `'start'` | flex 布局下的水平排列方式 | | 22 | | tag | `'string'` | `'div'` | 自定义元素标签 | | 23 | 24 | ### Col Props 25 | 26 | 27 | ### Row Slots 28 | | 名称 | 参数 | 说明 | 29 | | --- | --- | --- | 30 | | default | - | 自定义默认内容 | 31 | 32 | ### Col Props 33 | -------------------------------------------------------------------------------- /packages/components/badge/demos/type.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # 类型 5 | 6 | 有`success`、`error`、`warning`、`info`类型。 7 | 8 | 9 | 25 | 26 | 34 | -------------------------------------------------------------------------------- /packages/theme/src/row.scss: -------------------------------------------------------------------------------- 1 | @use 'mixins/mixins' as *; 2 | 3 | @include b(row) { 4 | display: flex; 5 | flex-wrap: wrap; 6 | position: relative; 7 | box-sizing: border-box; 8 | 9 | @include when(justify-center) { 10 | justify-content: center; 11 | } 12 | 13 | @include when(justify-end) { 14 | justify-content: flex-end; 15 | } 16 | 17 | @include when(justify-space-between) { 18 | justify-content: space-between; 19 | } 20 | 21 | @include when(justify-space-around) { 22 | justify-content: space-around; 23 | } 24 | 25 | @include when(justify-space-evenly) { 26 | justify-content: space-evenly; 27 | } 28 | 29 | @include when(align-middle) { 30 | align-items: center; 31 | } 32 | 33 | @include when(align-bottom) { 34 | align-items: flex-end; 35 | } 36 | } -------------------------------------------------------------------------------- /packages/components/divider/src/divider.tsx: -------------------------------------------------------------------------------- 1 | import { createNamespace } from "@nimble-ui/utils"; 2 | import { computed, defineComponent } from "vue"; 3 | 4 | import dividerProps from "./types"; 5 | 6 | export default defineComponent({ 7 | name: "YDivider", 8 | props: dividerProps(), 9 | setup(props, ctx) { 10 | const bem = createNamespace("divider"); 11 | 12 | const dividerCls = computed(() => { 13 | const { direction, dashed, vertical } = props; 14 | return [bem.b(), bem.is(direction), bem.is("dashed", dashed), bem.is("vertical", vertical)]; 15 | }); 16 | 17 | return () => { 18 | const children = props.vertical ? null : ctx.slots.default?.(); 19 | return
{children &&
{children}
}
; 20 | }; 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /packages/components/pop-confirm/demos/trigger.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 条件触发 4 | 5 | 可以判断是否需要弹出 6 | 7 | 8 | 21 | 22 | 32 | -------------------------------------------------------------------------------- /docs/src/pages/docs.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /packages/tokens/src/form.ts: -------------------------------------------------------------------------------- 1 | import type { InjectionKey } from "vue"; 2 | import type { ProvideContext, TriggerEventType } from "./types"; 3 | import { FormProps } from "@nimble-ui/components"; 4 | 5 | export interface Rule { 6 | required?: boolean; 7 | pattern?: RegExp; 8 | trigger?: TriggerEventType | TriggerEventType[]; 9 | formatter?: (value: any, rule: Rule, details: any) => any; 10 | message?: string | ((value: any, rule: Rule, details: any) => string); 11 | validator?: (value: any, rule: Rule, details: any) => boolean | string | Promise; 12 | } 13 | 14 | export type Rules = Rule | Array | ((details: any) => Rule | Array); 15 | 16 | type FormContext = ProvideContext<{ props: FormProps }>; 17 | 18 | export const formContextKey: InjectionKey = Symbol("formContextKey"); 19 | -------------------------------------------------------------------------------- /packages/components/tabs/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 默认选中第一项。 6 | 7 | 8 | 11 | 12 | 36 | -------------------------------------------------------------------------------- /packages/hooks/src/useClickOutside.ts: -------------------------------------------------------------------------------- 1 | import { isArray } from "@nimble-ui/utils"; 2 | import { Ref, onMounted, onUnmounted, unref } from "vue"; 3 | 4 | type TargetType = Ref; 5 | export const useClickOutside = (element: TargetType | TargetType[], callback: (e: MouseEvent) => void) => { 6 | const handler = (e: MouseEvent) => { 7 | if (isArray(element)) { 8 | if (!element.some((el) => unref(el)?.contains(e.target as Element))) { 9 | callback(e); 10 | } 11 | return; 12 | } 13 | 14 | if (!unref(element)?.contains(e.target as Element)) { 15 | callback(e); 16 | } 17 | }; 18 | onMounted(() => { 19 | document.addEventListener("click", handler); 20 | }); 21 | onUnmounted(() => { 22 | document.removeEventListener("click", handler); 23 | }); 24 | }; 25 | -------------------------------------------------------------------------------- /packages/components/badge/demos/badge.page.md: -------------------------------------------------------------------------------- 1 | # 标记 Badge 2 | 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | type.vue 8 | zero.vue 9 | max.vue 10 | offset.vue 11 | ``` 12 | ## API 13 | 14 | ### Badge Props 15 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 16 | | ---- | ---- | ------ | ---- | ---- | 17 | | color | `string` | - | 自定义小圆点的颜色 | - | 18 | | count | `string \| number` | - | 标记数量 | - | 19 | | dot | `boolean` | `false` | 不展示数字,只有一个小红点 | - | 20 | | offset | `[number, number]` | - | 设置状态点的位置偏移 | - | 21 | | max | `number` | - | 展示的最大值 | - | 22 | | showZero | `boolean` | `false` | 为 0 时是否显示 | - | 23 | | hide | `boolean` | `false` | 是否隐藏 | - | 24 | | type | `'success' \| 'error' \| 'warning' \| 'info'` | `'error'` | 类型 | - | 25 | 26 | ### Scrollbar Slots 27 | | 名称 | 参数 | 说明 | 28 | | ------- | ---- | ------------ | 29 | | default | - | 内容 | 30 | -------------------------------------------------------------------------------- /packages/components/space/demos/space.page.md: -------------------------------------------------------------------------------- 1 | # 间距 Space 2 | 3 | 设置组件之间的间距。 4 | 5 | ```demo 6 | basic.vue 7 | vertical.vue 8 | justify.vue 9 | size.vue 10 | ``` 11 | 12 | ## API 13 | 14 | ### Space Props 15 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 16 | | --- | --- | --- | --- | --- | 17 | | align | `'start'` \| `'end'` \| `'center'` \| `'baseline'` | - | 对齐方式 | | 18 | | justify | `'start'` \| `'end'` \| `'center'` \| `'space-around'` \| `'space-between'` \| `'space-evenly'` | `'start'` | 水平排列方式 | | 19 | | size | `number` \| `[number, number]` | `8` | 间距大小 | | 20 | | vertical | `boolean` | `false` | 是否垂直布局 | | 21 | | wrap | `boolean` | `true` | 是否超出换行 | | 22 | | split | `string` \| `VNode` | - | 间隔符 | | 23 | | inline | `boolean` | `false` | 是否为行内元素 | | 24 | 25 | ### Space Slots 26 | | 名称 | 参数 | 说明 | 27 | | --- | --- | --- | 28 | | default | - | 间距的内容 | -------------------------------------------------------------------------------- /packages/utils/src/style.ts: -------------------------------------------------------------------------------- 1 | export const classNameToArray = (cls = "") => cls.split(" ").filter((item) => !!item.trim()); 2 | 3 | export const hasClass = (el: Element, cls: string): boolean => { 4 | if (!el || !cls) return false; 5 | if (cls.includes(" ")) throw new Error("className不应该包含空格。"); 6 | return el.classList.contains(cls); 7 | }; 8 | 9 | export const addClass = (el: Element, cls: string) => { 10 | if (!el || !cls.trim()) return; 11 | el.classList.add(...classNameToArray(cls)); 12 | }; 13 | 14 | export const removeClass = (el: Element, cls: string) => { 15 | if (!el || !cls.trim()) return; 16 | el.classList.remove(...classNameToArray(cls)); 17 | }; 18 | 19 | export const getComputedStyleKey = (el: HTMLElement, key: keyof CSSStyleDeclaration) => { 20 | return document.defaultView?.getComputedStyle(el, null)[key]; 21 | }; 22 | -------------------------------------------------------------------------------- /packages/yy-ui/makeInstaller.ts: -------------------------------------------------------------------------------- 1 | import type { App, Plugin } from "vue"; 2 | 3 | import { globalConfigContextKey, GlobalConfigContext } from "@nimble-ui/tokens"; 4 | import { useTheme } from "@nimble-ui/hooks"; 5 | import type { Opts } from "@nimble-ui/hooks"; 6 | 7 | export interface OptionsProps extends GlobalConfigContext { 8 | theme?: Opts; 9 | // 是否暗黑主题 10 | isDark?: boolean; 11 | } 12 | 13 | export const makeInstaller = (components: Plugin[] = []) => { 14 | const install = (app: App, options: OptionsProps = {}): void => { 15 | components.forEach((c) => app.use(c)); 16 | const { theme, isDark, ...other } = options; 17 | // 设置主题颜色 18 | useTheme(theme, isDark ? "dark" : "light"); 19 | // 公共参数 20 | app.provide(globalConfigContextKey, other); 21 | }; 22 | 23 | return { 24 | install, 25 | }; 26 | }; 27 | -------------------------------------------------------------------------------- /packages/components/date-picker/src/icons.tsx: -------------------------------------------------------------------------------- 1 | export const dateIcon = ( 2 | 3 | 7 | 8 | ); 9 | -------------------------------------------------------------------------------- /packages/components/layout/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@nimble-ui/utils"; 2 | import _layout from "./src/layout"; 3 | import _header from "./src/header"; 4 | import _sidebar from "./src/sidebar"; 5 | import _content from "./src/content"; 6 | import _footer from "./src/footer"; 7 | 8 | export * from "./src/types"; 9 | export const YLayout = withInstall(_layout); 10 | export const YHeader = withInstall(_header); 11 | export const YSidebar = withInstall(_sidebar); 12 | export const YContent = withInstall(_content); 13 | export const YFooter = withInstall(_footer); 14 | export default YLayout; 15 | 16 | declare module "vue" { 17 | export interface GlobalComponents { 18 | YLayout: typeof YLayout; 19 | YHeader: typeof YHeader; 20 | YSidebar: typeof YSidebar; 21 | YContent: typeof YContent; 22 | YFooter: typeof YFooter; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/components/drawer/demos/drawer.page.md: -------------------------------------------------------------------------------- 1 | # 抽屉 Drawer 2 | 屏幕边缘滑出的浮层面板。 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | position.vue 8 | ``` 9 | 10 | ## API 11 | 12 | ### Drawer Props 13 | 14 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 15 | | --- | --- | --- | --- | --- | 16 | | attr-type | `'button'` \| `'submit'`\| `'reset'` \| `'button'` | 按钮的 DOM 的 `type` 属性 | | 17 | | block | `boolean` | `false` | 按钮是否显示为块级 | | 18 | | bordered | `boolean` | `true` | 按钮是否显示 border | | 19 | | circle | `boolean` | `false` | 按钮是否为圆形 | | 20 | | dashed | `boolean` | `false` | 按钮边框是否为虚线 | | 21 | | disabled | `boolean` | `false` | 按钮是否禁用 | | 22 | | keyboard | `boolean` | `true` | 是否支持键盘操作 | | 23 | | loading | `boolean` | `false` | 按钮是否显示加载状态 | | 24 | | round | `boolean` | `false` | 按钮是否显示圆角 | | 25 | | size | `'tiny'` \| `'small'` \| `'medium'` \| `'large'` \| `'medium'` | 按钮的尺寸 | | 26 | -------------------------------------------------------------------------------- /packages/components/radio/src/types.ts: -------------------------------------------------------------------------------- 1 | import { radioCommonProps } from "@nimble-ui/tokens"; 2 | import { mergeCommonProp } from "@nimble-ui/utils"; 3 | import { ExtractPropTypes, PropType, VNodeChild } from "vue"; 4 | 5 | const radioProps = mergeCommonProp({ 6 | ...radioCommonProps, 7 | /** 8 | * @description 标签 9 | */ 10 | label: { 11 | type: [Object, Function, String] as PropType VNodeChild)>, 12 | }, 13 | /** 14 | * @description 选中的值 15 | */ 16 | value: { 17 | type: [String, Number, Boolean] as PropType, 18 | default: true, 19 | }, 20 | hide: { 21 | type: [Boolean, Function] as PropType<((details: any) => boolean) | boolean>, 22 | }, 23 | }); 24 | 25 | export default radioProps; 26 | 27 | export type RadioProps = Partial>>; 28 | -------------------------------------------------------------------------------- /packages/theme/src/mixins/function.scss: -------------------------------------------------------------------------------- 1 | @use "./config.scss" as *; 2 | 3 | // 获取变量名 4 | @function join-var-name($list) { 5 | $name: '--' + $namespace; 6 | 7 | @each $item in $list { 8 | @if $item != '' { 9 | $name: $name + '-' + $item; 10 | } 11 | } 12 | 13 | @return $name; 14 | } 15 | 16 | @function get-css-var-name($args...) { 17 | @return joinVarName($args); 18 | } 19 | 20 | @function get-css-var($args...) { 21 | @return var(#{join-var-name($args)}); 22 | } 23 | 24 | // bem规范 25 | @function bem($block, $element: '', $modifier: '') { 26 | $name: config.$namespace + config.$common-separator + $block; 27 | 28 | @if $element != '' { 29 | $name: $name + config.$element-separator + $element; 30 | } 31 | 32 | @if $modifier != '' { 33 | $name: $name + config.$modifier-separator + $modifier; 34 | } 35 | 36 | @return $name; 37 | } 38 | -------------------------------------------------------------------------------- /packages/hooks/src/useGlobalConfig.ts: -------------------------------------------------------------------------------- 1 | import { ComputedRef, computed, inject, reactive } from "vue"; 2 | import { GlobalConfigContext, globalConfigContextKey } from "@nimble-ui/tokens"; 3 | 4 | const globalConfig = reactive({}); 5 | 6 | export function useGlobalConfig( 7 | key: K, 8 | defaultValue?: D 9 | ): ComputedRef | D>; 10 | export function useGlobalConfig(): GlobalConfigContext; 11 | export function useGlobalConfig( 12 | key?: K, 13 | defaultValue?: D 14 | ) { 15 | const config = inject(globalConfigContextKey, globalConfig); 16 | 17 | if (key) { 18 | return computed(() => config?.zIndex ?? defaultValue); 19 | } else { 20 | return config; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/components/menu/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { h, type Slots } from "vue"; 2 | import { pick, keysOf } from "@nimble-ui/utils"; 3 | import YSubMenu from "./subMenu"; 4 | import YMenuItem from "./menuItem"; 5 | 6 | import { MenuItems, MenuProps } from "./types"; 7 | import { subMenuProps, menuItemProps } from "./props"; 8 | 9 | type Props = MenuProps & { nodeIndent?: number; site: number[]; item?: MenuItems; slots: Slots }; 10 | 11 | export function itemRenderer(item: MenuItems | undefined, menuProps: Props) { 12 | if (!item) return null; 13 | 14 | const { childrenField } = menuProps; 15 | 16 | if (item[childrenField]) { 17 | return h(YSubMenu, { 18 | ...pick(menuProps, keysOf(subMenuProps())), 19 | item, 20 | }); 21 | } else { 22 | return h(YMenuItem, { 23 | ...pick(menuProps, keysOf(menuItemProps())), 24 | item, 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

nimble-ui

3 |

一个 Vue 3 组件库

4 |

比较完整,主题可调,组件灵活,使用 TypeScript 开发

5 | 6 | ### 使用 TypeScript 7 | 8 | @nimble-ui/vue 全量使用 TypeScript 编写,和你的 TypeScript 项目无缝衔接。 9 | 10 | ### npm 11 | 12 | 使用 npm 安装。 13 | 14 | ```bash 15 | npm i @nimble-ui/vue --save 16 | yarn add @nimble-ui/vue --save 17 | ``` 18 | 19 | ### 使用 20 | 21 | ```ts 22 | import YYUi from "@nimble-ui/vue"; 23 | import "@nimble-ui/vue/index.css"; 24 | 25 | createApp(App).use(YYUi, { 26 | isDark: true, // 开启暗黑主题 27 | theme: { 28 | primary: "#1677ff" // 修改主色调 29 | // ... 30 | } 31 | }) 32 | ``` 33 | 34 | ### 其他方式切换主题方式 35 | 36 | ```ts 37 | import { useTheme } from "@nimble-ui/vue" 38 | 39 | /** 40 | * 第一个参数改颜色、字体大小等等 41 | * 第二个参数切换主题:dark:暗黑主题 light:正常主题 42 | */ 43 | useTheme({ 44 | primary: "#1677ff", 45 | //... 46 | }, 'dark') 47 | ``` -------------------------------------------------------------------------------- /packages/components/message/demos/message.page.md: -------------------------------------------------------------------------------- 1 | # 消息提示 Message 2 | 常用于主动操作后的反馈提示。 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | timing.vue 8 | type.vue 9 | close.vue 10 | ``` 11 | 12 | ## API 13 | 14 | ### Button Props 15 | 16 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 17 | | --- | --- | --- | --- | --- | 18 | | attr-type | `'button'` \| `'submit'`\| `'reset'` \| `'button'` | 按钮的 DOM 的 `type` 属性 | | 19 | | block | `boolean` | `false` | 按钮是否显示为块级 | | 20 | | bordered | `boolean` | `true` | 按钮是否显示 border | | 21 | | circle | `boolean` | `false` | 按钮是否为圆形 | | 22 | | dashed | `boolean` | `false` | 按钮边框是否为虚线 | | 23 | | disabled | `boolean` | `false` | 按钮是否禁用 | | 24 | | keyboard | `boolean` | `true` | 是否支持键盘操作 | | 25 | | loading | `boolean` | `false` | 按钮是否显示加载状态 | | 26 | | round | `boolean` | `false` | 按钮是否显示圆角 | | 27 | | size | `'tiny'` \| `'small'` \| `'medium'` \| `'large'` \| `'medium'` | 按钮的尺寸 | | 28 | -------------------------------------------------------------------------------- /packages/yy-ui/README.md: -------------------------------------------------------------------------------- 1 |

@nimble-ui/vue

2 |

一个 Vue 3 组件库

3 |

比较完整,主题可调,组件灵活,使用 TypeScript 开发

4 | 5 | ### 使用 TypeScript 6 | 7 | @nimble-ui/vue 全量使用 TypeScript 编写,和你的 TypeScript 项目无缝衔接。 8 | 9 | ### npm 10 | 11 | 使用 npm 安装。 12 | 13 | ```bash 14 | npm i @nimble-ui/vue --save 15 | yarn i @nimble-ui/vue --save 16 | ``` 17 | 18 | ### 使用 19 | 20 | ```ts 21 | import YYUi from "@nimble-ui/vue"; 22 | import "@nimble-ui/vue/index.css"; 23 | 24 | createApp(App).use(YYUi, { 25 | isDark: true, // 开启暗黑主题 26 | theme: { 27 | primary: "#1677ff" // 修改主色调 28 | // ... 29 | } 30 | }) 31 | ``` 32 | 33 | ### 其他方式切换主题方式 34 | 35 | ```ts 36 | import { useTheme } from "@nimble-ui/vue" 37 | 38 | /** 39 | * 第一个参数改颜色、字体大小等等 40 | * 第二个参数切换主题:dark:暗黑主题 light:正常主题 41 | */ 42 | useTheme({ 43 | primary: "#1677ff", 44 | //... 45 | }, 'dark') 46 | ``` -------------------------------------------------------------------------------- /packages/components/drawer/demos/position.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 自定义位置 4 | 5 | 自定义位置,点击触发按钮抽屉从相应的位置滑出,点击遮罩区关闭。 6 | 7 | 8 | 17 | 18 | 29 | -------------------------------------------------------------------------------- /packages/components/dropdown/demos/trigger.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # 基础用法 5 | 下拉菜单的基础用法。 6 | 7 | 8 | 13 | 14 | 46 | -------------------------------------------------------------------------------- /packages/components/number/src/types.ts: -------------------------------------------------------------------------------- 1 | import { mergeCommonProp } from "@nimble-ui/utils"; 2 | import type { ExtractPropTypes, PropType, StyleValue } from "vue"; 3 | 4 | const numberProps = mergeCommonProp({ 5 | /** 6 | * @description 标记数量 7 | */ 8 | count: { 9 | type: [Number, String], 10 | }, 11 | /** 12 | * @description 展示封顶的数字值 13 | */ 14 | max: { 15 | type: [String, Number], 16 | }, 17 | /** 18 | * @description 数字的类名 19 | */ 20 | numberClass: { 21 | type: [String, Array, Object], 22 | }, 23 | /** 24 | * @description 数字的样式 25 | */ 26 | numberStyle: { 27 | type: [String, Array, Object] as PropType, 28 | }, 29 | /** 30 | * @description 数字间的间隙 31 | */ 32 | gap: { 33 | type: [Number, String], 34 | }, 35 | }); 36 | 37 | export default numberProps; 38 | 39 | export type NumberProps = ExtractPropTypes>; 40 | -------------------------------------------------------------------------------- /packages/components/radio/demos/options.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 最简单的用法 6 | 7 | 8 | 11 | 12 | 39 | -------------------------------------------------------------------------------- /packages/components/slider/demos/slider.page.md: -------------------------------------------------------------------------------- 1 | # 滑动输入条 Slider 2 | 滑动型输入器,展示当前值和可选范围。 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | ``` 8 | ## API 9 | 10 | ### Slider Props 11 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 12 | | --- | --- | --- | --- | --- | 13 | | modelValue/v-mode| `number\|number[]` | - | 选中项绑定值 | | 14 | | min | `number` | `0` | 最小值 | | 15 | | max | `number` | `100` | 最大值 | | 16 | | step | `number` | `1` | 步长 | | 17 | | vertical | `boolean` | `false` | 垂直模式 | | 18 | | marks | `{ [key: number]: VNodeChild \| (() => VNodeChild) }` | - | slider上的标记 | | 19 | | formatTooltip | `(value: number) => VNodeChild` | - | 格式化tooltip | | 20 | | showTooltip | `boolean` | `false` | 是否一直显示tooltip | | 21 | 22 | ### Slider Events 23 | | 事件名 | 说明 | 类型 | 24 | | --- | --- | --- | 25 | | change | 滑动时触发事件 | `(value: number\| number[]) => void`| 26 | 27 | ### Slider Slots 28 | | 名称 | 参数 | 说明 | 29 | | --- | --- | --- | 30 | | thumb | - | 滑块按钮的内容 | 31 | -------------------------------------------------------------------------------- /packages/components/tabs/demos/vertical.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 居中 4 | 5 | 标签居中展示。 6 | 7 | 8 | 15 | 16 | 39 | -------------------------------------------------------------------------------- /packages/components/tooltip/src/types.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes, PropType } from "vue"; 2 | import { mergeCommonProp } from "@nimble-ui/utils"; 3 | 4 | import { contentProps, type PlacementType } from "./props"; 5 | 6 | export type TriggerType = "hover" | "click" | "focus" | "contextmenu"; 7 | 8 | const tooltipProps = mergeCommonProp({ 9 | ...contentProps(), 10 | trigger: { 11 | type: String as PropType, 12 | }, 13 | /*** 14 | * @description Tooltip 组件是否禁用 15 | */ 16 | disabled: { 17 | type: [Boolean, Function] as PropType boolean)>, 18 | }, 19 | /** 20 | * @description 控制显示隐藏 21 | */ 22 | modelValue: { 23 | type: Boolean as PropType, 24 | default: undefined, 25 | }, 26 | }); 27 | 28 | export { PlacementType }; 29 | export default tooltipProps; 30 | export type TooltipProps = ExtractPropTypes>; 31 | -------------------------------------------------------------------------------- /packages/stylelint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nimble-ui/stylelint-config", 3 | "version": "0.1.0", 4 | "description": "> TODO: description", 5 | "author": "陈羽云 <897908015@qq.com>", 6 | "homepage": "", 7 | "license": "ISC", 8 | "main": "index.js", 9 | "directories": { 10 | "lib": "lib", 11 | "test": "__tests__" 12 | }, 13 | "files": [ 14 | "lib" 15 | ], 16 | "publishConfig": { 17 | "registry": "https://registry.npm.taobao.org" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git@gitee.com:fast_dev/yy-ui.git" 22 | }, 23 | "scripts": { 24 | "test": "node ./__tests__/stylelint-config.test.js" 25 | }, 26 | "dependencies": { 27 | "stylelint": "^15.6.0", 28 | "stylelint-scss": "4.6.0", 29 | "stylelint-config-standard": "^33.0.0", 30 | "stylelint-config-standard-scss": "^9.0.0", 31 | "postcss": "^8.4.23", 32 | "postcss-scss": "^4.0.6" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/components/badge/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # 基础用法 5 | 6 | 最简单的用法 7 | 8 | 9 | 25 | 26 | 34 | 35 | 43 | -------------------------------------------------------------------------------- /packages/components/message/src/instance.ts: -------------------------------------------------------------------------------- 1 | import { shallowReactive } from "vue"; 2 | import { MessageInstance } from "./types"; 3 | 4 | export const instances = shallowReactive([]); 5 | 6 | export const getInstance = (id: string) => { 7 | const index = instances.findIndex((instance) => instance.id === id); 8 | const current = instances[index]; 9 | let prev: MessageInstance | undefined; 10 | if (index > 0) { 11 | prev = instances[index - 1]; 12 | } 13 | return { current, prev }; 14 | }; 15 | 16 | export const getLastOffset = (id: string): number => { 17 | const { prev } = getInstance(id); 18 | if (!prev) return 0; 19 | const exposed = prev.vm.exposed; 20 | if (!exposed) return 0; 21 | return exposed.bottom.value; 22 | }; 23 | 24 | export const getOffsetOrSpace = (id: string, offset: number) => { 25 | const index = instances.findIndex((instance) => instance.id === id); 26 | return index > 0 ? 16 : offset; 27 | }; 28 | -------------------------------------------------------------------------------- /packages/theme/src/card.scss: -------------------------------------------------------------------------------- 1 | @use "./mixins/mixins.scss" as *; 2 | @use "./mixins/function.scss" as *; 3 | 4 | @include b(card) { 5 | --y-card-text-color: var(--y-color-text); 6 | --y-card-font-size: var(--y-font-size); 7 | --y-card-head-font-size: var(--y-font-size-xl); 8 | --y-card-bg-color: var(--y-color-bg-container); 9 | --y-card-border-color: var(--y-color-border-secondary); 10 | } 11 | 12 | @include b(card) { 13 | display: flex; 14 | flex-direction: column; 15 | font-size: var(--y-card-font-size); 16 | border-radius: 4px; 17 | border: 1px solid var(--y-card-border-color); 18 | background-color: var(--y-card-bg-color); 19 | 20 | @include e('header') { 21 | padding: 15px 20px; 22 | display: flex; 23 | align-items: center; 24 | font-size: var(--y-card-head-font-size); 25 | border-bottom: 1px solid var(--y-card-border-color); 26 | } 27 | 28 | @include e(content) { 29 | padding: 10px 20px; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/utils/src/scroll.ts: -------------------------------------------------------------------------------- 1 | type ScrollElement = HTMLElement | Window; 2 | 3 | const overflowScrollReg = /scroll|auto|overlay/i; 4 | 5 | const overflowKeys = { 6 | undefined: "overflow", 7 | true: "overflowY", 8 | false: "overflowX", 9 | } as const; 10 | 11 | const ELEMENT_NODE_TYPE = 1; 12 | function isElement(node: Element) { 13 | return node.tagName !== "HTML" && node.tagName !== "BODY" && node.nodeType === ELEMENT_NODE_TYPE; 14 | } 15 | 16 | export function getScrollParent(el: Element, isVertical?: boolean, root: ScrollElement | undefined = window) { 17 | let node = el; 18 | 19 | const key = overflowKeys[String(isVertical) as keyof typeof overflowKeys]; 20 | 21 | while (node && node !== root && isElement(node)) { 22 | const overflow = window.getComputedStyle(node)[key]; 23 | if (overflowScrollReg.test(overflow)) { 24 | return node; 25 | } 26 | node = node.parentNode as Element; 27 | } 28 | 29 | return root; 30 | } 31 | -------------------------------------------------------------------------------- /packages/hooks/src/useScrollParent.ts: -------------------------------------------------------------------------------- 1 | import { Ref, isRef, onMounted, ref, unref, watch } from "vue"; 2 | import { getScrollParent, isString } from "@nimble-ui/utils"; 3 | import { useEventListener } from "./useEventListener"; 4 | 5 | type ScrollElement = HTMLElement | Window; 6 | export function useScrollParent( 7 | el: Ref, 8 | handle: (e: Event) => void, 9 | root?: ScrollElement | undefined 10 | ) { 11 | const scrollParent = ref(); 12 | 13 | useEventListener("scroll", handle, { 14 | target: scrollParent, 15 | }); 16 | 17 | function init() { 18 | const warp = unref(el); 19 | const scroll = isString(warp) ? document.querySelector(warp) : warp; 20 | if (scroll) { 21 | scrollParent.value = getScrollParent(scroll, undefined, root); 22 | } 23 | } 24 | 25 | onMounted(init); 26 | if (isRef(el)) { 27 | watch(el, () => init()); 28 | } 29 | 30 | return scrollParent; 31 | } 32 | -------------------------------------------------------------------------------- /packages/components/dropdown/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # 基础用法 5 | 下拉菜单的基础用法。 6 | 7 | 8 | 13 | 14 | 34 | -------------------------------------------------------------------------------- /packages/components/input/demos/textarea.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 多文本框 4 | 5 | 设置属性type为textarea。 6 | 7 | 8 | 26 | 27 | 37 | -------------------------------------------------------------------------------- /packages/theme/src/space.scss: -------------------------------------------------------------------------------- 1 | @use "./mixins/mixins.scss" as *; 2 | @use "./mixins/config.scss" as *; 3 | 4 | @include b(space) { 5 | display: flex; 6 | justify-content: flex-start; 7 | 8 | @include when(inline) { 9 | display: inline-flex; 10 | } 11 | 12 | @include when(wrap) { 13 | flex-flow: wrap; 14 | } 15 | 16 | @include when(vertical) { 17 | flex-direction: column; 18 | } 19 | 20 | @include when(compact) { 21 | .#{$b + $element-separator + 'item'} { 22 | &:not(.is-last) { 23 | border-start-end-radius: 0; 24 | border-end-end-radius: 0; 25 | margin-inline-end: -1px; 26 | } 27 | 28 | &:not(.is-first) { 29 | border-start-start-radius: 0; 30 | border-end-start-radius: 0; 31 | } 32 | 33 | &:hover { 34 | z-index: 10; 35 | } 36 | 37 | &.is-focus { 38 | z-index: 10; 39 | box-shadow: none; 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/components/color-picker/src/types.ts: -------------------------------------------------------------------------------- 1 | import { mergeCommonProp } from "@nimble-ui/utils"; 2 | import type { ExtractPropTypes, PropType } from "vue"; 3 | 4 | const colorPickerProps = mergeCommonProp({ 5 | /** 6 | * @description 颜色选择器的触发模式 7 | */ 8 | trigger: { 9 | type: String as PropType<"hover" | "click">, 10 | }, 11 | /** 12 | * @description 颜色格式 13 | */ 14 | format: { 15 | type: String as PropType<"rgb" | "hex" | "hsb">, 16 | }, 17 | modelValue: { 18 | type: String, 19 | default: "#1677ff", 20 | }, 21 | /** 22 | * @description 弹框的方向 23 | */ 24 | placement: { 25 | type: String as PropType<"bottom-start" | "bottom-end">, 26 | default: "bottom-start", 27 | }, 28 | /** 29 | * @description 禁用颜色选择器 30 | */ 31 | disabled: { 32 | type: Boolean, 33 | }, 34 | }); 35 | 36 | export default colorPickerProps; 37 | 38 | export type ColorPickerProps = ExtractPropTypes>; 39 | -------------------------------------------------------------------------------- /packages/components/input/demos/compact.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 组合布局 4 | 5 | 组合布局。 6 | 7 | 8 | 26 | 27 | 35 | -------------------------------------------------------------------------------- /packages/components/checkbox/demos/checkbox.page.md: -------------------------------------------------------------------------------- 1 | # 复选框 Checkbox 2 | 在一组可选项中进行多项选择时 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | ``` 8 | 9 | ## API 10 | 11 | ### Checkbox Props 12 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 13 | | --- | --- | --- | --- | --- | 14 | | modelValue \| v-model | `string` \| `boolean` \| `number` | - | 选中时绑定的值 | | 15 | | name | `string` | - | 标识符,作为提交表单时的标识符 | | 16 | | labelPosition | `'left'` \| `'right'` | `'right'` | 文本位置 | | 17 | | shape | `'square'` \| `'round'` | `'square'` | 形状 | | 18 | | disabled | `boolean` | `false` | 是否禁用 | | 19 | | label | `string` | - | 标签说明 | | 20 | | value | `string` \| `number` | - | 选中时的值 | | 21 | 22 | 23 | ### Checkbox Events 24 | | 事件名 | 说明 | 类型 | 25 | | --- | --- | --- | 26 | | update:modelValue | 选项组的值改变时的回调 | `(value: string \| number \| boolean) => void`| 27 | | change | 当绑定值变化时触发的事件 | `(value: string \| number \| boolean) => void` | 28 | 29 | ### Checkbox Slots 30 | | 名称 | 参数 | 说明 | 31 | | --- | --- | --- | 32 | | default | - | 自定义默认内容 | -------------------------------------------------------------------------------- /packages/hooks/src/useMouseInOut.ts: -------------------------------------------------------------------------------- 1 | import { ComponentPublicInstance, Ref, onBeforeMount, onMounted, ref } from "vue"; 2 | 3 | export function useMouseInOut(el: Ref) { 4 | const isEnter = ref(false); 5 | 6 | function enter() { 7 | isEnter.value = true; 8 | } 9 | 10 | function leave() { 11 | isEnter.value = false; 12 | } 13 | 14 | onMounted(() => { 15 | const { value } = el; 16 | const node = value instanceof HTMLElement ? value : value?.$el; 17 | if (node) { 18 | node.addEventListener("mouseenter", enter); 19 | node.addEventListener("mouseleave", leave); 20 | } 21 | }); 22 | 23 | onBeforeMount(() => { 24 | const { value } = el; 25 | const node = value instanceof HTMLElement ? value : value?.$el; 26 | if (node) { 27 | node.removeEventListener("mouseenter", enter); 28 | node.removeEventListener("mouseleave", leave); 29 | } 30 | }); 31 | 32 | return { isEnter }; 33 | } 34 | -------------------------------------------------------------------------------- /packages/components/back-top/src/types.ts: -------------------------------------------------------------------------------- 1 | import { mergeCommonProp } from "@nimble-ui/utils"; 2 | import { ExtractPropTypes, PropType } from "vue"; 3 | 4 | const backTopProps = mergeCommonProp({ 5 | /** 6 | * @description 距离页面底部的高度 7 | */ 8 | bottom: { 9 | type: [Number, String], 10 | default: 40, 11 | }, 12 | /** 13 | * @description 距离页面右侧的宽度 14 | */ 15 | right: { 16 | type: [Number, String], 17 | default: 40, 18 | }, 19 | /** 20 | * @description 监听滚动的元素,如果为 undefined 会监听距离最近的一个可滚动的祖先节点 21 | */ 22 | listenTo: { 23 | type: [String, Object] as PropType, 24 | }, 25 | /** 26 | * @description 渲染的容器节点 27 | */ 28 | mount: { 29 | type: [String, Object] as PropType, 30 | default: "body", 31 | }, 32 | scrollTop: { 33 | type: Number, 34 | default: 180, 35 | }, 36 | }); 37 | 38 | export default backTopProps; 39 | 40 | export type BackTopProps = ExtractPropTypes>; 41 | -------------------------------------------------------------------------------- /packages/components/flex/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 最简单的用法。 6 | 7 | 8 | 29 | 38 | -------------------------------------------------------------------------------- /packages/components/layout/src/sidebar.tsx: -------------------------------------------------------------------------------- 1 | import { createNamespace } from "@nimble-ui/utils"; 2 | import { defineComponent, inject } from "vue"; 3 | import { layoutContextKey } from "@nimble-ui/tokens"; 4 | import { YScrollbar } from "@nimble-ui/components/scrollbar"; 5 | 6 | export default defineComponent({ 7 | name: "YSidebar", 8 | props: { 9 | /** 10 | * @description 边栏是否折叠 11 | */ 12 | collapsed: Boolean, 13 | }, 14 | setup(props, ctx) { 15 | const bem = createNamespace("layout-sidebar"); 16 | 17 | const layoutContext = inject(layoutContextKey, undefined); 18 | layoutContext?.setSider(true); 19 | 20 | return () => { 21 | return ( 22 | 30 | ); 31 | }; 32 | }, 33 | }); 34 | -------------------------------------------------------------------------------- /packages/theme/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nimble-ui/theme", 3 | "version": "0.1.0", 4 | "description": "组件样式和主题", 5 | "author": "陈羽云 <897908015@qq.com>", 6 | "homepage": "", 7 | "license": "MIT", 8 | "main": "dist/index.css", 9 | "directories": { 10 | "lib": "lib", 11 | "test": "__tests__" 12 | }, 13 | "style": "index.css", 14 | "scripts": { 15 | "build": "cross-env NODE_ENV=prod gulp --require @esbuild-kit/cjs-loader", 16 | "dev": "cross-env NODE_ENV=dev gulp --require @esbuild-kit/cjs-loader" 17 | }, 18 | "devDependencies": { 19 | "@types/node": "^18.11.18" 20 | }, 21 | "dependencies": { 22 | "@esbuild-kit/cjs-loader": "^2.4.1", 23 | "chalk": "^5.2.0", 24 | "consola": "^2.15.3", 25 | "cross-env": "^7.0.3", 26 | "gulp": "^4.0.2", 27 | "gulp-autoprefixer": "^8.0.0", 28 | "gulp-clean-css": "^4.3.0", 29 | "gulp-rename": "^2.0.0", 30 | "gulp-sass": "^5.1.0", 31 | "sass": "^1.57.1", 32 | "stylelint-order": "^6.0.3" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/components/badge/demos/max.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # 最大值 5 | 6 | 通过设置属性`max`来控制 7 | 8 | 9 | 25 | 26 | 35 | 36 | 44 | -------------------------------------------------------------------------------- /packages/components/switch/demos/switch.page.md: -------------------------------------------------------------------------------- 1 | # 开关 Switch 2 | 开关选择器。 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | text.vue 8 | disabled.vue 9 | loading.vue 10 | customValue.vue 11 | size.vue 12 | ``` 13 | 14 | ## API 15 | 16 | ### Switch Props 17 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 18 | | --- | --- | --- | --- | --- | 19 | | modelValue \| v-model | `string \| number \| boolean` | `false` | 开关选中状态 | | 20 | | disabled | `boolean` | `false` | 是否禁用 | | 21 | | loading | `boolean` | `false` | 是否加载 | | 22 | | checkedValue | `string \| number \| boolean` | `true` | 打开时对应的值 | | 23 | | uncheckedValue | `string \| number \| boolean` | `false` | 关闭时对应的值 | | 24 | | checkedText | `string` | - | 打开时的文字描述 | | 25 | | uncheckedText | `string` | - | 关闭时的文字描述 | | 26 | 27 | ### Switch Events 28 | | 事件名 | 说明 | 类型 | 29 | | --- | --- | --- | 30 | | change | 状态发生变化时的回调函数 | `(val: boolean \| string \| number) => void` | 31 | 32 | ### Switch Slots 33 | | 名称 | 参数 | 说明 | 34 | | --- | --- | --- | 35 | | checked | - | 打开时的文字描述 | 36 | | unchecked | - | 关闭时的文字描述 | 37 | -------------------------------------------------------------------------------- /packages/components/input/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 最简单的用法。 6 | 7 | 8 | 22 | 23 | 33 | -------------------------------------------------------------------------------- /packages/components/tabs/demos/tabs.page.md: -------------------------------------------------------------------------------- 1 | # 标签页 Tabs 2 | 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | card.vue 8 | centered.vue 9 | trigger.vue 10 | vertical.vue 11 | scroll.vue 12 | ``` 13 | ## API 14 | 15 | ### Tabs Props 16 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 17 | | --- | --- | --- | --- | --- | 18 | | modelValue | `string \| number` | - | 绑定值,tabs参数中的 idField值,默认是id | | 19 | | items | `Array` | - | 配置选项卡内容 | | 20 | | labelField | `string` | `'label'` | 选项 label 的字段名 | | 21 | | keyField | `string` | `'id'` | 选项 key 的字段名,默认是id | | 22 | | trigger | `'click' \| 'hover'` | `'click'` | 触发的方式 | | 23 | | renderTabBar | `function` | - | 替换默认TabBar | | 24 | | centered | `Boolean` | `false` | 标签居中展示 | | 25 | | type | `'line' \| 'card' \| 'radio' \| "bar"` | `'line'` | 页签的基本样式 | | 26 | | tabPosition | `'left' \| 'top' \| 'right' \| "bottom"` | `'top'` | 页签位置 | | 27 | 28 | ### Switch Events 29 | | 事件名 | 说明 | 类型 | 30 | | --- | --- | --- | 31 | | change | 改变时触发 | `(val: string \| number) => void` | 32 | | click | tab 被选中时触发 | `(item: object, e: Event) => void` | -------------------------------------------------------------------------------- /packages/components/time-picker/src/types.ts: -------------------------------------------------------------------------------- 1 | import { mergeCommonProp } from "@nimble-ui/utils"; 2 | import { ExtractPropTypes, PropType } from "vue"; 3 | 4 | const timePickerProps = mergeCommonProp({ 5 | modelValue: { 6 | type: [String, Number], 7 | }, 8 | /** 9 | * @description 展示的时间格式 10 | */ 11 | format: { 12 | type: String, 13 | default: "hh:mm:ss", 14 | }, 15 | /** 16 | * @description 是否可以清除 17 | */ 18 | allowClear: { 19 | type: Boolean, 20 | }, 21 | /** 22 | * @description 选择框的占位符 23 | */ 24 | placeholder: { 25 | type: String, 26 | }, 27 | /** 28 | * @description 确认的回调函数 29 | */ 30 | onConfirm: { 31 | type: Function as PropType<(data: { h?: number; m?: number; s?: number; value: string | number }) => void>, 32 | }, 33 | "onUpdate:modelValue": { 34 | type: Function as PropType<(value: string | number) => void>, 35 | }, 36 | }); 37 | 38 | export default timePickerProps; 39 | 40 | export type TimePickerProps = ExtractPropTypes>; 41 | -------------------------------------------------------------------------------- /packages/components/menu/src/types.ts: -------------------------------------------------------------------------------- 1 | import { mergeCommonProp } from "@nimble-ui/utils"; 2 | import { ExtractPropTypes, PropType, VNodeChild } from "vue"; 3 | import { subMenu, commonProps, type MenuItems } from "./props"; 4 | 5 | export { MenuItems }; 6 | const menuProps = mergeCommonProp({ 7 | ...subMenu, 8 | ...commonProps, 9 | /** 10 | * @description 菜单的数据 11 | */ 12 | items: { 13 | type: Array as PropType, 14 | }, 15 | /** 16 | * @description 是否使用手风琴模式 17 | */ 18 | accordion: Boolean as PropType, 19 | /** 20 | * @description 菜单是否折叠 21 | */ 22 | collapsed: Boolean as PropType, 23 | /** 24 | * @description 批量处理菜单标签渲染 25 | */ 26 | renderLabel: { 27 | type: Function as PropType<(item: MenuItems) => VNodeChild>, 28 | }, 29 | /** 30 | * @description 选中菜单的Key 31 | */ 32 | modelValue: { 33 | type: [String, Number, Symbol], 34 | }, 35 | }); 36 | 37 | export default menuProps; 38 | 39 | export type MenuProps = ExtractPropTypes>; 40 | -------------------------------------------------------------------------------- /packages/components/number/demos/class.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # 修改样式、类名 5 | 6 | 使用属性`number-class`、`number-style`修改数字间的间隙 7 | 8 | 9 | 19 | 20 | 28 | 29 | 43 | -------------------------------------------------------------------------------- /packages/theme/src/back-top.scss: -------------------------------------------------------------------------------- 1 | @use "./mixins/mixins.scss" as *; 2 | @use "./common/transition.scss" as *; 3 | 4 | @include b(back-top) { 5 | --y-back-top-width: 44px; 6 | --y-back-top-height: 44px; 7 | --y-back-top-border-radius: 22px; 8 | --y-back-top-box-shadow: 0 2px 8px 0px rgb(0 0 0 / 12%); 9 | --y-back-top-text-color: var(--y-color-text); 10 | --y-back-top-bg-color: var(--y-color-bg-container); 11 | --y-back-top-border-color: var(--y-color-border-secondary); 12 | } 13 | 14 | @include b(back-top) { 15 | position: fixed; 16 | right: 40px; 17 | bottom: 40px; 18 | display: flex; 19 | align-items: center; 20 | justify-content: center; 21 | cursor: pointer; 22 | overflow: hidden; 23 | border-radius: var(--y-back-top-border-radius); 24 | color: var(--y-back-top-text-color); 25 | height: var(--y-back-top-height); 26 | min-width: var(--y-back-top-width); 27 | box-shadow: var(--y-back-top-box-shadow); 28 | background-color: var(--y-back-top-bg-color); 29 | border: 1px solid var(--y-back-top-border-color); 30 | } 31 | -------------------------------------------------------------------------------- /packages/theme/src/mixins/mixins.scss: -------------------------------------------------------------------------------- 1 | @use "./config.scss" as *; 2 | @use "../common/var.scss" as *; 3 | 4 | // BEM 5 | @mixin b($block) { 6 | $b: $namespace + $common-separator + $block !global; 7 | 8 | .#{$b} { 9 | @content; 10 | } 11 | } 12 | 13 | @mixin e($element) { 14 | $e: $element !global; 15 | $be: $b + $element-separator + $element !global; 16 | 17 | @at-root { 18 | #{'.' + $be} { 19 | @content; 20 | } 21 | } 22 | } 23 | 24 | @mixin m($modifier) { 25 | $m: $modifier !global; 26 | $selector: &; 27 | $bem: $selector + $modifier-separator + $modifier !global; 28 | 29 | @at-root { 30 | #{$bem} { 31 | @content; 32 | } 33 | } 34 | } 35 | 36 | @mixin when($state) { 37 | @at-root { 38 | &.#{$state-prefix + $state} { 39 | @content; 40 | } 41 | } 42 | } 43 | 44 | @mixin res($key, $map: $breakpoints) { 45 | @if map-has-key($map, $key) { 46 | @media only screen and #{unquote(map-get($map, $key))} { 47 | @content; 48 | } 49 | } @else { 50 | @warn "没找到: `#{$map}`"; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/components/row/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 从堆叠到水平排列。 6 | 7 | 8 | 30 | -------------------------------------------------------------------------------- /packages/theme/src/dropdown.scss: -------------------------------------------------------------------------------- 1 | @use "./mixins/mixins.scss" as *; 2 | @use "./mixins/function.scss" as *; 3 | @use "./mixins/config.scss" as *; 4 | @use "./common/var.scss" as *; 5 | 6 | @include b(dropdown) { 7 | padding: 0; 8 | background-color: transparent; 9 | color: var(--y-pop-confirm-text-color); 10 | 11 | @include e(title) { 12 | position: relative; 13 | display: inline-flex; 14 | color: var(--y-color-text); 15 | font-size: var(--y-font-size); 16 | } 17 | } 18 | 19 | @include b(dropdown-menu) { 20 | --y-dropdown-bg-color: var(--y-color-bg-elevated); 21 | --y-hover-text-color: var(--y-color-primary); 22 | --y-hover-bg-color: var(--y-color-primary-3); 23 | 24 | box-shadow: $box-shadow-secondary; 25 | background-color: var(--y-dropdown-bg-color); 26 | border-radius: 3px; 27 | max-height: 240px; 28 | } 29 | 30 | @include b(dropdown-option) { 31 | padding: 5px 12px;list-style: none; 32 | cursor: pointer; 33 | 34 | &:hover { 35 | color: var(--y-hover-text-color); 36 | background-color: var(--y-hover-bg-color); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/components/button-group/src/types.ts: -------------------------------------------------------------------------------- 1 | import { PropType, ExtractPropTypes } from "vue"; 2 | import type { VNodeChild } from "vue"; 3 | import type { ButtonShape, ButtonTypes, ButtonSize } from "@nimble-ui/tokens"; 4 | 5 | import { mergeFunctionProp, mergeCommonProp, Fun } from "@nimble-ui/utils"; 6 | 7 | const buttonGroupProps = mergeCommonProp({ 8 | /** 9 | * @description 按钮组的显示内容 10 | */ 11 | content: { 12 | type: [Function, String, Object] as PropType>, 13 | }, 14 | /** 15 | * @description 按钮类型 16 | */ 17 | type: mergeFunctionProp(String, "default"), 18 | /** 19 | * @description 按钮的形状 20 | */ 21 | shape: mergeFunctionProp(String, "default"), 22 | /** 23 | * @description 禁用按钮 24 | */ 25 | disabled: mergeFunctionProp(Boolean), 26 | /** 27 | * @description 按钮的尺寸 28 | */ 29 | size: mergeFunctionProp(String), 30 | }); 31 | 32 | export default buttonGroupProps; 33 | export type ButtonGroupProps = ExtractPropTypes>; 34 | -------------------------------------------------------------------------------- /packages/eslint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nimble-ui/eslint-config", 3 | "version": "0.1.0", 4 | "description": "eslint配置文件", 5 | "author": "陈羽云 <897908015@qq.com>", 6 | "homepage": "", 7 | "license": "ISC", 8 | "main": "index.js", 9 | "directories": { 10 | "lib": "lib", 11 | "test": "__tests__" 12 | }, 13 | "files": [ 14 | "index.js" 15 | ], 16 | "peerDependencies": { 17 | "eslint": "^8.0.0" 18 | }, 19 | "dependencies": { 20 | "@typescript-eslint/eslint-plugin": "^5.30.0", 21 | "@typescript-eslint/parser": "^5.30.0", 22 | "eslint-config-prettier": "^8.5.0", 23 | "eslint-define-config": "^1.5.1", 24 | "eslint-plugin-eslint-comments": "^3.2.0", 25 | "eslint-plugin-jsonc": "^2.3.0", 26 | "eslint-plugin-markdown": "^3.0.0", 27 | "eslint-plugin-prettier": "^4.1.0", 28 | "eslint-plugin-vue": "^9.1.1", 29 | "jsonc-eslint-parser": "^2.1.0", 30 | "prettier": "^2.7.1", 31 | "stylelint-order": "^6.0.3", 32 | "typescript": "^4.7.4" 33 | }, 34 | "devDependencies": { 35 | "eslint": "^8.18.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/components/date-picker/src/arrowIcon.tsx: -------------------------------------------------------------------------------- 1 | import { defineComponent } from "vue"; 2 | import YFlex from "@nimble-ui/components/flex"; 3 | import { createNamespace } from "@nimble-ui/utils"; 4 | 5 | export default defineComponent({ 6 | name: "DateArrowIcon", 7 | props: { 8 | reverse: { 9 | type: Boolean, 10 | }, 11 | }, 12 | emits: ["month", "year"], 13 | setup(props, ctx) { 14 | const bem = createNamespace("date-arrow"); 15 | 16 | const onClickMonth = () => ctx.emit("month"); 17 | const onClickYear = () => ctx.emit("year"); 18 | 19 | return () => { 20 | const { reverse } = props; 21 | return ( 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ); 30 | }; 31 | }, 32 | }); 33 | -------------------------------------------------------------------------------- /packages/components/button-group/src/buttonGroup.tsx: -------------------------------------------------------------------------------- 1 | import { computed, defineComponent, provide } from "vue"; 2 | import buttonGroupProps from "./types"; 3 | import { createNamespace, isFunction } from "@nimble-ui/utils"; 4 | import { buttonGroupContextKey } from "@nimble-ui/tokens"; 5 | 6 | export default defineComponent({ 7 | name: "YButtonGroup", 8 | props: buttonGroupProps(), 9 | setup(props, ctx) { 10 | const bem = createNamespace("button-group"); 11 | const buttonGroupCls = computed(() => { 12 | return [bem.b()]; 13 | }); 14 | 15 | const buttonGroupContext = computed(() => { 16 | const { type, shape, disabled, details, size } = props; 17 | return { type, shape, disabled, details, size }; 18 | }); 19 | provide(buttonGroupContextKey, buttonGroupContext); 20 | 21 | return () => { 22 | const { content, details } = props; 23 | return ( 24 |
25 | {isFunction(content) ? content(details) : content || ctx.slots.default?.({ details })} 26 |
27 | ); 28 | }; 29 | }, 30 | }); 31 | -------------------------------------------------------------------------------- /packages/theme/src/flex.scss: -------------------------------------------------------------------------------- 1 | @use "./mixins/mixins.scss" as *; 2 | @use "sass:list"; 3 | 4 | @include b(flex) { 5 | display: flex; 6 | 7 | @include when(vertical) { 8 | flex-direction: column; 9 | } 10 | 11 | @include when(wrap) { 12 | flex-wrap: wrap; 13 | } 14 | 15 | @each $type in (flex-start, center, flex-end, space-between, space-around, space-evenly) { 16 | @include when(#{'justify-' + $type}) { 17 | justify-content: $type; 18 | } 19 | } 20 | 21 | @each $align in (flex-start, center, flex-end) { 22 | @include when(#{'align-' + $align}) { 23 | align-items: $align; 24 | } 25 | } 26 | 27 | @each $gap in ((small, 8px), (middle, 16px), (large, 24px)) { 28 | $value: list.nth($gap, 2); 29 | 30 | @include when(#{'gap-' + list.nth($gap, 1)}) { 31 | gap: $value; 32 | } 33 | } 34 | 35 | @include when(row-reverse) { 36 | flex-direction: row-reverse; 37 | } 38 | 39 | @include when(column-reverse) { 40 | flex-direction: column-reverse; 41 | } 42 | 43 | @include when(inline) { 44 | display: inline-block; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/theme/src/popper.scss: -------------------------------------------------------------------------------- 1 | @use "./mixins/mixins.scss" as *; 2 | @use "./mixins/config.scss" as *; 3 | @use "./mixins/utils.scss" as *; 4 | 5 | @include b(popper) { 6 | @include e(content) { 7 | position: absolute; 8 | top: 0; 9 | left: 0; 10 | 11 | @include m('arrow') { 12 | position: absolute; 13 | 14 | @include when(bottom) { 15 | bottom: 1px; 16 | transform: translateY(100%); 17 | 18 | @include utils-arrow-fill(7px, 'top'); 19 | } 20 | 21 | @include when(top) { 22 | top: 1px; 23 | transform: translateY(-100%); 24 | 25 | @include utils-arrow-fill(7px, 'bottom'); 26 | } 27 | 28 | @include when(right) { 29 | right: 1px; 30 | transform: translateX(100%); 31 | 32 | @include utils-arrow-fill(7px, 'left'); 33 | } 34 | 35 | @include when(left) { 36 | left: 1px; 37 | transform: translateX(-100%); 38 | 39 | @include utils-arrow-fill(7px, 'right'); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/components/space/demos/justify.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 对齐 4 | 5 | 设置不同的对齐模式。 6 | 7 | 8 | 33 | -------------------------------------------------------------------------------- /packages/hooks/src/useResizeObserver.ts: -------------------------------------------------------------------------------- 1 | import { Ref, onBeforeUnmount, watch } from "vue"; 2 | 3 | export function useResizeObserver(target: Ref, callback: ResizeObserverCallback) { 4 | let observer: ResizeObserver | undefined = new ResizeObserver(callback); 5 | 6 | const stopWatch = watch(target, (el) => { 7 | observer?.disconnect(); 8 | if (el) { 9 | observer?.observe(el); 10 | } 11 | }); 12 | 13 | onBeforeUnmount(() => { 14 | observer?.disconnect(); 15 | observer = undefined; 16 | stopWatch(); 17 | }); 18 | } 19 | 20 | export function useMutationObserver(target: Ref, callback: MutationCallback) { 21 | let observer: MutationObserver | undefined = new MutationObserver(callback); 22 | 23 | const stopWatch = watch(target, (el) => { 24 | observer?.disconnect(); 25 | if (el) { 26 | observer?.observe(el, { attributes: true, childList: true, subtree: true }); 27 | } 28 | }); 29 | 30 | onBeforeUnmount(() => { 31 | observer?.disconnect(); 32 | observer = undefined; 33 | stopWatch(); 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /packages/utils/src/createNamespace.ts: -------------------------------------------------------------------------------- 1 | import { isString } from "./type"; 2 | 3 | export class BEM { 4 | private block = ""; 5 | constructor(name: string) { 6 | this.block = `y-${name}`; 7 | } 8 | b(name?: T, state = true) { 9 | return name ? (state ? `${this.block}-${name}` : undefined) : this.block; 10 | } 11 | 12 | e(element: string) { 13 | const e = `${this.block}__${element}`; 14 | return e; 15 | } 16 | 17 | m(modifier: string | string[], element?: string) { 18 | if (isString(modifier)) { 19 | modifier = [modifier]; 20 | } 21 | 22 | return modifier.map((m) => { 23 | if (element) { 24 | return `${this.block}__${element}--${m}`; 25 | } 26 | return m ? `${this.block}--${m}` : undefined; 27 | }); 28 | } 29 | 30 | is(name: T | undefined, state = true) { 31 | return name && state ? `is-${name}` : undefined; 32 | } 33 | 34 | name(name: string) { 35 | return name ? `y-${name}` : undefined; 36 | } 37 | } 38 | 39 | export function createNamespace(name: string) { 40 | return new BEM(name); 41 | } 42 | -------------------------------------------------------------------------------- /packages/hooks/src/useLazyRender.ts: -------------------------------------------------------------------------------- 1 | import { ref, watch, WatchSource } from "vue"; 2 | 3 | type OptionsType = { 4 | isTransition?: boolean; 5 | destroyOnClose?: boolean; 6 | watchCallback?: (val: boolean | undefined) => void; 7 | }; 8 | 9 | export function useLazyRender(show: WatchSource, options: OptionsType = {}) { 10 | const rendered = ref(false); 11 | 12 | watch( 13 | show, 14 | (value) => { 15 | const { destroyOnClose, isTransition, watchCallback } = options; 16 | if (value) { 17 | rendered.value = value; 18 | } 19 | 20 | // 判断close是否要全部销毁子元素,如果有动画,要在外面等待动画执行完成再调用 destroy方法 21 | if (value == false && destroyOnClose && !isTransition) { 22 | rendered.value = false; 23 | } 24 | watchCallback?.(value); 25 | }, 26 | { immediate: true } 27 | ); 28 | 29 | const destroy = () => { 30 | if (options.destroyOnClose) { 31 | rendered.value = false; 32 | } 33 | }; 34 | 35 | const lazyRender = (render: () => JSX.Element) => () => rendered.value ? render() : null; 36 | return { 37 | destroy, 38 | lazyRender, 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /packages/components/back-top/demos/target.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 指定监听目标 4 | 5 | 可以通过改变 `listen-to` 属性指定监听元素 6 | 7 | 8 | 28 | 29 | 33 | -------------------------------------------------------------------------------- /packages/theme/src/index.scss: -------------------------------------------------------------------------------- 1 | @use "./common/var.scss"; 2 | @use "./common/transition.scss"; 3 | @use "./button.scss"; 4 | @use "./col.scss"; 5 | @use "./row.scss"; 6 | @use "./button-group.scss"; 7 | @use "./input.scss"; 8 | @use "./form-item.scss"; 9 | @use "./checkbox.scss"; 10 | @use "./checkbox-group.scss"; 11 | @use "./switch.scss"; 12 | @use "./tooltip.scss"; 13 | @use "./dropdown.scss"; 14 | @use "./overlay.scss"; 15 | @use "./drawer.scss"; 16 | @use "./message.scss"; 17 | @use "./modal.scss"; 18 | @use "./ellipsis.scss"; 19 | @use "./image.scss"; 20 | @use "./image-preview.scss"; 21 | @use "./layout.scss"; 22 | @use "./menu.scss"; 23 | @use "./card.scss"; 24 | @use "./scrollbar.scss"; 25 | @use "./space.scss"; 26 | @use "./divider.scss"; 27 | @use "./back-top.scss"; 28 | @use "./tabs.scss"; 29 | @use "./flex.scss"; 30 | @use "./radio.scss"; 31 | @use "./pop-confirm.scss"; 32 | @use "./upload.scss"; 33 | @use "./color-picker.scss"; 34 | @use "./select.scss"; 35 | @use "./slider.scss"; 36 | @use "./date-picker.scss"; 37 | @use "./number.scss"; 38 | @use "./badge.scss"; 39 | @use "./popper.scss"; 40 | @use "./pagination.scss"; 41 | @use "./time-picker.scss"; 42 | -------------------------------------------------------------------------------- /packages/components/button/demos/button.page.md: -------------------------------------------------------------------------------- 1 | # 按钮 Button 2 | 按钮用于开始一个即时操作。 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | disabled.vue 8 | group.vue 9 | loading.vue 10 | ``` 11 | 12 | ## API 13 | 14 | ### Button Props 15 | 16 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 17 | | --- | --- | --- | --- | --- | 18 | | attr-type | `'button'` \| `'submit'`\| `'reset'` | `'button'` | 按钮的 DOM 的 `type` 属性 | | 19 | | block | `boolean` | `false` | 按钮是否显示为块级 | | 20 | | bordered | `boolean` | `true` | 按钮是否显示 border | | 21 | | circle | `boolean` | `false` | 按钮是否为圆形 | | 22 | | dashed | `boolean` | `false` | 按钮边框是否为虚线 | | 23 | | disabled | `boolean` | `false` | 按钮是否禁用 | | 24 | | keyboard | `boolean` | `true` | 是否支持键盘操作 | | 25 | | loading | `boolean` | `false` | 按钮是否显示加载状态 | | 26 | | round | `boolean` | `false` | 按钮是否显示圆角 | | 27 | | content | `(details) => VNodeChild` \| `string` | - |按钮的显示内容 | | 28 | | size | `'small'` \| `'medium'` \| `'large'` | `'medium'` |按钮的尺寸 | | 29 | 30 | ### Button Events 31 | | 事件名 | 说明 | 类型 | 32 | | --- | --- | --- | 33 | | click | 点击按钮事件 | `(e: Event) => void`| 34 | 35 | ### Button Slots 36 | | 名称 | 参数 | 说明 | 37 | | --- | --- | --- | 38 | | default | - | 按钮的内容 | 39 | -------------------------------------------------------------------------------- /packages/components/pop-confirm/demos/pop-confirm.page.md: -------------------------------------------------------------------------------- 1 | # 气泡确认框 PopConfirm 2 | 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | trigger.vue 8 | async.vue 9 | ``` 10 | ## API 11 | 12 | ### PopConfirm Props 13 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 14 | | --- | --- | --- | --- | --- | 15 | | cancelText | `string` | - | 取消按钮文字 | | 16 | | disabled | `boolean` | - | 阻止点击PopConfirm子元素时弹出确认框 | | 17 | | icon | `VNodeChild \| (() => VNodeChild)` | - | 自定义弹出气泡 Icon 图标| | 18 | | okText | `string` | - | 确认按钮文字 | 19 | | okType | `string` | `'primary'` | 确认按钮类型 | | 20 | | hideCancel | `boolean` | - | 是否隐藏取消按钮 | | 21 | | title | `VNodeChild \| (() => VNodeChild)` | - | 确认框标题 | | 22 | | description | `VNodeChild \| (() => VNodeChild)` | - | 确认内容的详细描述 | | 23 | | beforeConfirm | `(done: (cancel?: boolean) => void) => void` | - | 确认前执行的函数,回调函数内执行 done 参数方法的时候才是真正关闭对话框的时候。 | | 24 | 25 | ### PopConfirm Events 26 | | 事件名 | 说明 | 类型 | 27 | | --- | --- | --- | 28 | | cancel | 点击取消的回调 | `() => void`| 29 | | confirm | 点击确认的回调 | `() => void`| 30 | 31 | ### PopConfirm Slots 32 | | 名称 | 参数 | 说明 | 33 | | --- | --- | --- | 34 | | default | - | Tooltip 触发 & 引用的元素 | 35 | | title | - | 确认框标题 | 36 | | description | - | 确认内容的详细描述 | -------------------------------------------------------------------------------- /packages/components/dropdown/src/dropdownMenu.tsx: -------------------------------------------------------------------------------- 1 | import { createNamespace } from "@nimble-ui/utils"; 2 | import YScrollbar from "@nimble-ui/components/scrollbar"; 3 | import { defineComponent, ref } from "vue"; 4 | 5 | import YDropdownOption from "./dropdownOption"; 6 | import { dropdownMenuProps } from "./types"; 7 | 8 | export default defineComponent({ 9 | name: "YDropdownMenu", 10 | props: dropdownMenuProps, 11 | setup(props) { 12 | const domEl = ref(); 13 | const bem = createNamespace("dropdown-menu"); 14 | 15 | const renderOption = () => { 16 | const { childrenKey, labelField, keyField } = props; 17 | 18 | return props.options?.map((item) => ( 19 | 27 | )); 28 | }; 29 | 30 | return () => { 31 | return ( 32 |
33 | {renderOption()} 34 |
35 | ); 36 | }; 37 | }, 38 | }); 39 | -------------------------------------------------------------------------------- /packages/eslint-config/index.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require("eslint-define-config"); 2 | 3 | module.exports = defineConfig({ 4 | env: { 5 | es6: true, 6 | browser: true, 7 | node: true, 8 | jest: true, 9 | }, 10 | plugins: ["@typescript-eslint"], 11 | 12 | extends: [ 13 | "plugin:jsonc/recommended-with-jsonc", 14 | "plugin:markdown/recommended", 15 | "plugin:vue/vue3-recommended", 16 | "plugin:@typescript-eslint/recommended", 17 | "prettier", 18 | "plugin:prettier/recommended", 19 | ], 20 | 21 | rules: { 22 | "prettier/prettier": "error", 23 | "@typescript-eslint/no-var-requires": "off", 24 | "@typescript-eslint/no-explicit-any": "off", 25 | "vue/require-default-prop": "off", 26 | }, 27 | 28 | overrides: [ 29 | { 30 | files: ["*.vue"], 31 | parser: require.resolve("vue-eslint-parser"), 32 | parserOptions: { 33 | parser: "@typescript-eslint/parser", 34 | ecmaVersion: "latest", 35 | sourceType: "module", 36 | extraFileExtensions: [".vue"], 37 | }, 38 | }, 39 | { 40 | files: ["*.json", "*.json5", "*.jsonc"], 41 | parser: "jsonc-eslint-parser", 42 | }, 43 | ], 44 | }); 45 | -------------------------------------------------------------------------------- /packages/components/row/demos/gutter.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 区块间隔 4 | 5 | 栅格常常需要和间隔进行配合,你可以使用 Row 的 gutter 属性,默认值为0。 6 | 7 | 8 | 29 | -------------------------------------------------------------------------------- /packages/components/button/demos/basic.demo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 基础用法 4 | 5 | 使用 type、plain、round 和 circle 来定义按钮的样式。 6 | 7 | 8 | 31 | -------------------------------------------------------------------------------- /packages/components/row/src/types.ts: -------------------------------------------------------------------------------- 1 | import { PropType, ExtractPropTypes } from "vue"; 2 | import { mergeCommonProp, mergeFunctionProp } from "@nimble-ui/utils"; 3 | 4 | export type RowAlign = "top" | "middle" | "bottom"; 5 | export type RowJustify = "start" | "center" | "end" | "space-around" | "space-between" | "space-evenly"; 6 | 7 | export const rowUniqueProp = { 8 | /** 9 | * @description 栅格间隔 10 | */ 11 | gutter: { 12 | type: [Number, Array] as PropType, 13 | default: 0, 14 | }, 15 | /** 16 | * @description 自定义元素标签 17 | */ 18 | tag: String as PropType, 19 | /** 20 | * @description flex 布局下的垂直排列方式 21 | */ 22 | align: { 23 | type: String as PropType, 24 | default: "top", 25 | }, 26 | /** 27 | * @description flex 布局下的水平排列方式 28 | */ 29 | justify: { 30 | type: String as PropType, 31 | default: "start", 32 | }, 33 | /** 34 | * @description 栅格占据的列数 35 | */ 36 | span: mergeFunctionProp(Number), 37 | } as const; 38 | 39 | const rowProps = mergeCommonProp(rowUniqueProp); 40 | 41 | export default rowProps; 42 | export type RowProps = ExtractPropTypes>; 43 | -------------------------------------------------------------------------------- /packages/components/badge/src/types.ts: -------------------------------------------------------------------------------- 1 | import { mergeCommonProp } from "@nimble-ui/utils"; 2 | import { ExtractPropTypes, PropType } from "vue"; 3 | 4 | const badgeProps = mergeCommonProp({ 5 | /** 6 | * @description 自定义小圆点的颜色 7 | */ 8 | color: { 9 | type: String, 10 | }, 11 | /** 12 | * @description 标记数量 13 | */ 14 | count: { 15 | type: [String, Number], 16 | }, 17 | /** 18 | * @description 不展示数字,只有一个小红点 19 | */ 20 | dot: { 21 | type: Boolean, 22 | }, 23 | /** 24 | * @description 设置状态点的位置偏移 25 | */ 26 | offset: { 27 | type: Array as unknown as PropType<[number, number]>, 28 | }, 29 | /** 30 | * @description 展示的最大值 31 | */ 32 | max: { 33 | type: Number, 34 | }, 35 | /** 36 | * @description 为 0 时是否显示 37 | */ 38 | showZero: { 39 | type: Boolean, 40 | }, 41 | /** 42 | * @description 是否隐藏 43 | */ 44 | hide: { 45 | type: Boolean, 46 | }, 47 | /** 48 | * @description 类型 49 | */ 50 | type: { 51 | type: String as PropType<"success" | "error" | "warning" | "info">, 52 | default: "error", 53 | }, 54 | }); 55 | 56 | export default badgeProps; 57 | 58 | export type BadgeProps = ExtractPropTypes>; 59 | -------------------------------------------------------------------------------- /packages/components/pagination/src/types.ts: -------------------------------------------------------------------------------- 1 | import { mergeCommonProp } from "@nimble-ui/utils"; 2 | import { ExtractPropTypes, PropType } from "vue"; 3 | 4 | const paginationProps = mergeCommonProp({ 5 | /** 6 | * @description 绑定当前页码 7 | */ 8 | modelValue: { 9 | type: Number, 10 | default: 1, 11 | }, 12 | /** 13 | * @description 数据总数 14 | */ 15 | total: { 16 | type: Number, 17 | default: 0, 18 | }, 19 | /** 20 | * @description 每页条数 21 | */ 22 | pageSize: { 23 | type: Number, 24 | default: 10, 25 | }, 26 | /** 27 | * @description 大小 28 | */ 29 | size: { 30 | type: String as PropType<"default" | "small">, 31 | }, 32 | /** 33 | * @description 由于分页长度,如果传入的是偶数加一变成奇数, 34 | */ 35 | pageSlot: { 36 | type: Number, 37 | default: 9, 38 | }, 39 | /** 40 | * @description 页码或 pageSize 改变的回调,参数是改变后的页码及每页条数 41 | */ 42 | onChange: { 43 | type: Function as PropType<(page: number, pageSize: number) => void>, 44 | }, 45 | "onUpdate:modelValue": { 46 | type: Function as PropType<(page: number) => void>, 47 | }, 48 | }); 49 | 50 | export default paginationProps; 51 | 52 | export type PaginationProps = ExtractPropTypes>; 53 | -------------------------------------------------------------------------------- /packages/tokens/src/radio-group.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, InjectionKey, PropType, Ref } from "vue"; 2 | import type { ContainFunction } from "@nimble-ui/utils"; 3 | 4 | export const radioCommonProps = { 5 | /** 6 | * @description 单选按钮 radio 元素的 name 属性。 7 | */ 8 | name: String, 9 | /** 10 | * @description 绑定值 11 | */ 12 | modelValue: { 13 | type: [String, Number, Boolean] as PropType, 14 | default: undefined, 15 | }, 16 | /** 17 | * @@description 禁用状态 18 | */ 19 | disabled: { 20 | type: [Boolean, Function] as PropType boolean>>, 21 | default: undefined, 22 | }, 23 | /** 24 | * @description 大小 25 | */ 26 | size: { 27 | type: String as PropType<"small" | "medium" | "large">, 28 | }, 29 | /** 30 | * @description 标签的位置 31 | */ 32 | labelPosition: { 33 | type: String as PropType<"start" | "end">, 34 | }, 35 | } as const; 36 | 37 | type radioGroupContext = { 38 | propsRef: Ref>; 39 | onChange: (value: string | number | boolean) => void; 40 | }; 41 | 42 | export const radioGroupContextKey: InjectionKey = Symbol("radioGroupContextKey"); 43 | -------------------------------------------------------------------------------- /packages/components/drawer/src/types.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes, PropType } from "vue"; 2 | import { mergeCommonProp } from "@nimble-ui/utils"; 3 | 4 | export type DrawerDirection = "right" | "left" | "top" | "bottom"; 5 | 6 | type DoneFn = (cancel?: boolean) => void; 7 | type BeforeCloseFn = (done: DoneFn) => void; 8 | 9 | const drawerProps = mergeCommonProp({ 10 | /** 11 | * @description 是否显示 12 | */ 13 | modelValue: { 14 | type: Boolean, 15 | }, 16 | /** 17 | * @description 打开的方向 18 | */ 19 | direction: { 20 | type: String as PropType, 21 | default: "right", 22 | }, 23 | /** 24 | * @description 窗体的大小 25 | */ 26 | size: { 27 | type: [String, Number], 28 | default: "30%", 29 | }, 30 | /** 31 | * @description 关闭前的回调 32 | */ 33 | beforeClose: { 34 | type: Function as PropType, 35 | }, 36 | /** 37 | * @description 是否需要遮罩层 38 | */ 39 | modal: { 40 | type: Boolean, 41 | default: true, 42 | }, 43 | /** 44 | * @description 是否在关闭之后将子元素全部销毁 45 | */ 46 | destroyOnClose: { 47 | type: Boolean, 48 | }, 49 | }); 50 | 51 | export default drawerProps; 52 | 53 | export type DrawerProps = ExtractPropTypes>; 54 | -------------------------------------------------------------------------------- /packages/theme/src/mixins/set-color-level.scss: -------------------------------------------------------------------------------- 1 | @use 'sass:math'; 2 | @use "./config.scss" as *; 3 | 4 | @mixin set-color-level ($type, $number, $color) { 5 | $name: --#{$namespace}-color-#{$type}-#{$number}; 6 | 7 | $valueRed: --#{$namespace}-#{$type}-red; 8 | $valueGreen: --#{$namespace}-#{$type}-green; 9 | $valueBlue: --#{$namespace}-#{$type}-blue; 10 | 11 | $value: math.div($number, 10); 12 | $valueLight: 1 - $value; 13 | 14 | $red: --#{$namespace}-#{$color}-red; 15 | $green: --#{$namespace}-#{$color}-green; 16 | $blue: --#{$namespace}-#{$color}-blue; 17 | 18 | @if ($number == 0) { 19 | --#{$namespace}-color-#{$type}: rgb(var(#{$valueRed}), var(#{$valueGreen}), var(#{$valueBlue})); 20 | } @else { 21 | #{$name}: rgb( 22 | calc(var($valueRed) * $valueLight + var($red) * $value), 23 | calc(var($valueGreen) * $valueLight + var($green) * $value), 24 | calc(var($valueBlue) * $valueLight + var($blue) * $value) 25 | ) 26 | } 27 | }; 28 | 29 | @mixin set-color-transparency($type, $opacity) { 30 | $name: --#{$namespace}-text-color-#{$type}; 31 | $red: --#{$namespace}-neutral-red; 32 | $green: --#{$namespace}-neutral-green; 33 | $blue: --#{$namespace}-neutral-blue; 34 | 35 | #{$name}: rgba(var($red), var($green), var($blue), $opacity); 36 | } 37 | -------------------------------------------------------------------------------- /packages/components/image/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes, ImgHTMLAttributes, PropType } from "vue"; 2 | import { mergeCommonProp } from "@nimble-ui/utils"; 3 | 4 | const imageProps = mergeCommonProp({ 5 | /** 6 | * @description 图片来源 7 | */ 8 | src: { 9 | type: String, 10 | }, 11 | /** 12 | * @description 预览图片的图片地址 13 | */ 14 | previewSrc: { 15 | type: String, 16 | }, 17 | /** 18 | * @description 是否禁用单击图像预览 19 | */ 20 | previewDisabled: { 21 | type: Boolean, 22 | }, 23 | /** 24 | * @description 是否让图片进入视口再加载 25 | */ 26 | lazy: { 27 | type: Boolean, 28 | }, 29 | /** 30 | * @description 图片高度 31 | */ 32 | height: { 33 | type: [String, Number], 34 | }, 35 | /** 36 | * @description 图片宽度 37 | */ 38 | width: { 39 | type: [String, Number], 40 | }, 41 | /** 42 | * @description 图片在容器内的的适应类型 43 | */ 44 | objectFit: { 45 | type: String as PropType<"fill" | "contain" | "cover" | "none" | "scale-down">, 46 | default: "fill", 47 | }, 48 | /** 49 | * @description 组件中img元素的属性 50 | */ 51 | imgProps: { 52 | type: Object as PropType, 53 | }, 54 | }); 55 | 56 | export default imageProps; 57 | 58 | export type ImageProps = ExtractPropTypes>; 59 | -------------------------------------------------------------------------------- /packages/components/card/src/card.tsx: -------------------------------------------------------------------------------- 1 | import { createNamespace } from "@nimble-ui/utils"; 2 | import { defineComponent } from "vue"; 3 | 4 | import cardProps from "./types"; 5 | 6 | export default defineComponent({ 7 | name: "YCard", 8 | props: cardProps(), 9 | setup(props, ctx) { 10 | const bem = createNamespace("card"); 11 | 12 | return () => { 13 | const { contentClass, contentStyle } = props; 14 | return ( 15 |
16 | {ctx.slots.header ? ( 17 |
{ctx.slots.header()}
18 | ) : ctx.slots.headerLeft || ctx.slots.headerCenter || ctx.slots.headerRight ? ( 19 |
20 |
{ctx.slots.headerLeft?.()}
21 |
{ctx.slots.headerCenter?.()}
22 |
{ctx.slots.headerRight?.()}
23 |
24 | ) : null} 25 |
26 | {ctx.slots.default?.()} 27 |
28 |
{ctx.slots.footer?.()}
29 |
30 | ); 31 | }; 32 | }, 33 | }); 34 | -------------------------------------------------------------------------------- /packages/components/form/src/types.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes, ComponentPublicInstance, PropType } from "vue"; 2 | import { mergeCommonProp, mergeFunctionProp } from "@nimble-ui/utils"; 3 | import { TriggerEventType, Rules } from "@nimble-ui/tokens"; 4 | 5 | const formProps = mergeCommonProp({ 6 | /** 7 | * @description 是否在提交表单且校验不通过时滚动至错误的表单项 8 | */ 9 | scrollToError: { 10 | type: Boolean, 11 | default: false, 12 | }, 13 | /** 14 | * @description 表单校验触发时机 15 | */ 16 | validateTrigger: { 17 | type: [String, Array] as PropType, 18 | }, 19 | /** 20 | * @description 是否为禁用状态 21 | */ 22 | disabled: mergeFunctionProp(Boolean), 23 | /** 24 | * @description 表单校验规则 25 | */ 26 | rules: { 27 | type: Object as PropType<{ [key: string]: Rules }>, 28 | }, 29 | }); 30 | 31 | export default formProps; 32 | 33 | export type FormExpose = { 34 | submit: () => void; 35 | getValues: () => Record; 36 | validate: (name?: string | string[] | undefined) => Promise; 37 | resetValidation: (name?: string | string[] | undefined) => void; 38 | }; 39 | 40 | export type FormProps = ExtractPropTypes>; 41 | export type FormInstance = ComponentPublicInstance; 42 | -------------------------------------------------------------------------------- /packages/components/scrollbar/demos/scrollbar.page.md: -------------------------------------------------------------------------------- 1 | # 滚动条 Scrollbar 2 | 用于替换浏览器原生滚动条。 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | x.vue 8 | trigger.vue 9 | ``` 10 | 11 | ## API 12 | 13 | ### Scrollbar Props 14 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 15 | | --- | --- | --- | --- | --- | 16 | | tag | `string` | `'div'` | 视图的元素标签 | | 17 | | native | `boolean` | `false` | 是否使用原生滚动条样式 | | 18 | | contentClass | `array \|object \|string` | - | 视图的自定义类名 | | 19 | | contentStyle | `array \|object \|string` | - | 视图的自定义样式 | | 20 | | xScroll | `boolean` | `false` | 是否可以横向滚动 | | 21 | | trigger | `'hover' \| 'hide' \| 'none'` | `'none'` | 显示滚动条的时机,'none' 表示一直显示 | | 22 | | size | `number` | `5` | 滚动条大小 | | 23 | 24 | ### Scrollbar Events 25 | | 事件名 | 说明 | 类型 | 26 | | --- | --- | --- | 27 | | scroll | 当触发滚动事件时,返回滚动的距离 | `({ scrollLeft: number, scrollTop: number, scroll: number }) => void`| 28 | 29 | ### Scrollbar Slots 30 | | 名称 | 参数 | 说明 | 31 | | --- | --- | --- | 32 | | default | - | 滚动条的内容 | 33 | 34 | ### Scrollbar Methods 35 | | 名称 | 说明 | 类型 | 36 | | --- | --- | --- | 37 | | scrollTo | 滚动到特定坐标 | `(options: ScrollToOptions) => void \| (x: number, y: number) => void` | 38 | | setScrollTop | 设置滚动条到顶部的距离 | `(value: number) => void` | 39 | | setScrollLeft | 设置滚动条到左边的距离 | `(value: number) => void` | 40 | | update | 手动更新滚动条状态 | `() => void` | 41 | -------------------------------------------------------------------------------- /packages/components/switch/src/types.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes, PropType } from "vue"; 2 | import { mergeCommonProp } from "@nimble-ui/utils"; 3 | 4 | const switchProps = mergeCommonProp({ 5 | /** 6 | * @description 开关选中状态 7 | */ 8 | modelValue: { 9 | type: [String, Number, Boolean], 10 | default: undefined, 11 | }, 12 | /** 13 | * @description 打开时对应的值 14 | */ 15 | checkedValue: { 16 | type: [String, Number, Boolean], 17 | default: true, 18 | }, 19 | /** 20 | * @description 关闭时对应的值 21 | */ 22 | uncheckedValue: { 23 | type: [String, Number, Boolean], 24 | default: false, 25 | }, 26 | /** 27 | * @description 是否禁用 28 | */ 29 | disabled: { 30 | type: Boolean, 31 | }, 32 | /** 33 | * @description 打开时的文字描述 34 | */ 35 | checkedText: { 36 | type: String, 37 | }, 38 | /** 39 | * @description 关闭时的文字描述 40 | */ 41 | uncheckedText: { 42 | type: String, 43 | }, 44 | /** 45 | * @description 是否加载 46 | */ 47 | loading: { 48 | type: Boolean, 49 | }, 50 | /** 51 | * @description 开关大小 52 | */ 53 | size: { 54 | type: String as PropType<"small" | "medium" | "large">, 55 | }, 56 | }); 57 | 58 | export default switchProps; 59 | export type SwitchProps = ExtractPropTypes>; 60 | -------------------------------------------------------------------------------- /packages/hooks/src/useMergePropOrContext.ts: -------------------------------------------------------------------------------- 1 | import { computed, isRef, Ref } from "vue"; 2 | import { isFunction, type ObjectTypes, type Fun } from "@nimble-ui/utils"; 3 | 4 | export function useMergePropOrContext }>( 5 | props: T, 6 | context: Ref | K | undefined, 7 | callback?: (value: T[D], contextValue: K[D], key: D) => T[D] 8 | ) { 9 | const keys = Object.keys(props) as (keyof T)[]; 10 | const length = keys.length; 11 | 12 | return computed(() => { 13 | let index = -1; 14 | const result = {} as { [P in keyof T]?: Exclude> }; 15 | const ctx = isRef(context) ? context.value : context; 16 | const details = props.details ?? ctx?.details; 17 | 18 | while (props != null && ++index < length) { 19 | const key = keys[index]; 20 | 21 | const val = props[key]; 22 | const ctxVal = ctx?.[key]; 23 | const ctxValue = isRef(ctxVal) ? ctxVal.value : ctxVal; 24 | 25 | if (callback) { 26 | result[key] = callback(val, ctxValue, key); 27 | } else { 28 | const value: unknown = val ?? ctxValue; 29 | 30 | const _value = isFunction(value) ? value(details, props.uuId) : value; 31 | result[key] = _value; 32 | } 33 | } 34 | return result; 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /packages/components/popper/demos/popper.page.md: -------------------------------------------------------------------------------- 1 | # 提示 Popper 2 | 3 | 4 | ## 代码演示 5 | ```demo 6 | basic.vue 7 | ``` 8 | ## API 9 | 10 | ### Popper Props 11 | | 名称 | 类型 | 默认值 | 说明 | 版本 | 12 | | --- | --- | --- | --- | --- | 13 | | placement | `"top"\|"right"\|"bottom"\|"left""top-start"\|"top-end"\|"right-start \|"right-end"\|"bottom-start"\|"bottom-end"\|"left-start"\|"left-end"` | `"bottom"` | 弹出位置 | - | 14 | | trigger | `"hover"\|"click"\|"focus"\|"contextmenu"` | `"click"` | 触发方式 | - | 15 | | disabled | `boolean \| (details: any) => boolean` | `false` | 是否禁用 | - | 16 | | modelValue | `boolean` | - | 控制显示隐藏 | - | 17 | | appendTo | `string \| HTMLElement` | `'body'` | 渲染在哪里 | - | 18 | | teleported | `boolean` | - | 是否禁止穿梭功能 | - | 19 | | transition | `string` | - | 过度动画名称 | - | 20 | | contentClass | `Array \| Object \| String` | - | 提示内容的class | - | 21 | | contentStyle | `Array \| Object \| String` | - | 提示内容的style | - | 22 | 23 | ### Popper Events 24 | | 事件名 | 说明 | 类型 | 25 | | ------- | -------------- | ------------ | 26 | | update:modelValue | 显示状态改变的回调函数 | `(value: boolean) => void` | 27 | 28 | ### Popper Slots 29 | | 名称 | 参数 | 说明 | 30 | | ----------- | ---- | ------------------------- | 31 | | default | - | Tooltip 触发 & 引用的元素 | 32 | | title | - | 确认框标题 | 33 | | description | - | 确认内容的详细描述 | -------------------------------------------------------------------------------- /packages/components/radio-group/src/radioGroup.tsx: -------------------------------------------------------------------------------- 1 | import { computed, defineComponent, provide } from "vue"; 2 | import { createNamespace } from "@nimble-ui/utils"; 3 | import { radioGroupContextKey } from "@nimble-ui/tokens"; 4 | import { YRadio } from "@nimble-ui/components/radio"; 5 | 6 | import radioGroupProps from "./types"; 7 | 8 | export default defineComponent({ 9 | name: "YRadioGroup", 10 | props: radioGroupProps(), 11 | emits: ["update:modelValue", "change"], 12 | setup(props, ctx) { 13 | const bem = createNamespace("radio-group"); 14 | 15 | const model = computed({ 16 | get: () => props.modelValue, 17 | set: (val) => { 18 | ctx.emit("update:modelValue", val); 19 | }, 20 | }); 21 | 22 | const onChange = (value: string | number | boolean) => { 23 | model.value = value; 24 | ctx.emit("change", value); 25 | }; 26 | 27 | const propsRef = computed(() => ({ ...props })); 28 | 29 | provide(radioGroupContextKey, { 30 | onChange, 31 | propsRef, 32 | }); 33 | 34 | return () => { 35 | const { options, vertical } = props; 36 | return ( 37 |
38 | {options ? options.map((item, index) => ) : ctx.slots.default?.()} 39 |
40 | ); 41 | }; 42 | }, 43 | }); 44 | -------------------------------------------------------------------------------- /packages/theme/src/image-preview.scss: -------------------------------------------------------------------------------- 1 | @use "./mixins/mixins.scss" as *; 2 | @use "./mixins/function.scss" as *; 3 | 4 | @include b(image-preview) { 5 | --y-image-preview-toolbar-bg-color: var(--y-color-bg-spotlight); 6 | } 7 | 8 | @include b(image-preview) { 9 | position: fixed; 10 | left: 0; 11 | top: 0; 12 | width: 100vw; 13 | height: 100vh; 14 | display: flex; 15 | 16 | @include e('wrapper') { 17 | position: absolute; 18 | left: 0; 19 | top: 0; 20 | width: 100vw; 21 | height: 100vh; 22 | display: flex; 23 | pointer-events: none; 24 | z-index: 2; 25 | 26 | .img { 27 | user-select: none; 28 | pointer-events: all; 29 | margin: auto; 30 | max-height: calc(100vh - 32px); 31 | max-width: calc(100vw - 32px); 32 | transition: transform .3s cubic-bezier(.4, 0, .2, 1) 33 | } 34 | } 35 | 36 | @include e('toolbar') { 37 | position: absolute; 38 | left: 50%; 39 | transform: translateX(-50%); 40 | border-radius: 999px; 41 | height: 48px; 42 | bottom: 40px; 43 | padding: 0 12px; 44 | color: #fff; 45 | display: flex; 46 | align-items: center; 47 | background: var(--y-image-preview-toolbar-bg-color); 48 | 49 | @include m(icon) { 50 | margin: 0 6px; 51 | width: 25px; 52 | height: 25px; 53 | cursor: pointer; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/components/modal/src/function-method.tsx: -------------------------------------------------------------------------------- 1 | import { AppContext, createVNode, ref, render } from "vue"; 2 | import ModalConstructor from "./modal"; 3 | 4 | import type { ModalProps, ModalAction } from "./types"; 5 | 6 | function createModal( 7 | options: Partial void; onConfirm: () => void }>, 8 | context?: AppContext | null 9 | ) { 10 | const container = document.createElement("div"); 11 | 12 | const onDestroy = () => { 13 | render(null, container); 14 | }; 15 | 16 | const vNode = createVNode({ 17 | setup() { 18 | const modelValue = ref(true); 19 | const onShow = (val: boolean) => (modelValue.value = val); 20 | return () => ( 21 | 27 | ); 28 | }, 29 | }); 30 | if (context) vNode.appContext = context; 31 | render(vNode, container); 32 | } 33 | 34 | export function showModal(options: Partial): Promise { 35 | return new Promise((resolve) => { 36 | createModal({ 37 | ...options, 38 | onClose: (type: string) => { 39 | resolve(type as ModalAction); 40 | }, 41 | onConfirm() { 42 | resolve("confirm"); 43 | }, 44 | }); 45 | }); 46 | } 47 | -------------------------------------------------------------------------------- /packages/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./row"; 2 | export * from "./col"; 3 | export * from "./button"; 4 | export * from "./button-group"; 5 | export * from "./input"; 6 | export * from "./form"; 7 | export * from "./form-item"; 8 | export * from "./checkbox"; 9 | export * from "./checkbox-group"; 10 | export * from "./switch"; 11 | export * from "./tooltip"; 12 | export * from "./dropdown"; 13 | export * from "./overlay"; 14 | export * from "./drawer"; 15 | export * from "./message"; 16 | export * from "./modal"; 17 | export * from "./ellipsis"; 18 | export * from "./image"; 19 | export * from "./image-preview"; 20 | export * from "./layout"; 21 | export * from "./menu"; 22 | export * from "./expand-transition"; 23 | export * from "./card"; 24 | export * from "./card"; 25 | export * from "./scrollbar"; 26 | export * from "./space"; 27 | export * from "./divider"; 28 | export * from "./back-top"; 29 | export * from "./tabs"; 30 | export * from "./flex"; 31 | export * from "./radio"; 32 | export * from "./radio-group"; 33 | export * from "./pop-confirm"; 34 | export * from "./upload"; 35 | export * from "./color-picker"; 36 | export * from "./select"; 37 | export * from "./slider"; 38 | export * from "./date-picker"; 39 | export * from "./number"; 40 | export * from "./badge"; 41 | export * from "./popper"; 42 | export * from "./slot"; 43 | export * from "./pagination"; 44 | export * from "./time-picker"; 45 | -------------------------------------------------------------------------------- /packages/hooks/src/useEventListener.ts: -------------------------------------------------------------------------------- 1 | import { onMounted, onUnmounted, Ref, unref, onDeactivated, isRef, watch } from "vue"; 2 | 3 | type TargetRef = EventTarget | Ref; 4 | type Options = { 5 | target?: TargetRef; 6 | capture?: boolean; 7 | passive?: boolean; 8 | }; 9 | 10 | export function useEventListener( 11 | type: K, 12 | listener: (event: DocumentEventMap[K]) => void, 13 | options: Options = {} 14 | ) { 15 | const { target = document, passive = false, capture = false } = options; 16 | 17 | let attached: boolean; 18 | const add = (target?: TargetRef) => { 19 | const element = unref(target); 20 | 21 | if (element && !attached) { 22 | element.addEventListener(type, listener as any, { 23 | capture, 24 | passive, 25 | }); 26 | attached = true; 27 | } 28 | }; 29 | 30 | const remove = (target?: TargetRef) => { 31 | const element = unref(target); 32 | 33 | if (element && attached) { 34 | element.removeEventListener(type, listener as any, capture); 35 | attached = false; 36 | } 37 | }; 38 | 39 | onUnmounted(() => remove(target)); 40 | onDeactivated(() => remove(target)); 41 | onMounted(() => add(target)); 42 | 43 | if (isRef(target)) { 44 | watch(target, (val, oldVal) => { 45 | remove(oldVal); 46 | add(val); 47 | }); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /docs/src/components/ComponentDemos.tsx: -------------------------------------------------------------------------------- 1 | import { defineComponent } from "vue"; 2 | 3 | export default defineComponent({ 4 | name: "ComponentDomes", 5 | props: { 6 | span: { 7 | type: Number, 8 | required: true, 9 | }, 10 | }, 11 | setup(props, ctx) { 12 | return () => { 13 | const { span } = props; 14 | const children = ctx.slots.default?.() ?? []; 15 | 16 | return ( 17 |
21 | {span === 1 ? ( 22 | children 23 | ) : ( 24 | <> 25 |
32 | {children.filter((_, index) => index % 2 === 0)} 33 |
34 |
41 | {children.filter((_, index) => index % 2 === 1)} 42 |
43 | 44 | )} 45 |
46 | ); 47 | }; 48 | }, 49 | }); 50 | --------------------------------------------------------------------------------