├── jsconfig.json ├── docs ├── src │ ├── design │ │ ├── color.md │ │ ├── dark.md │ │ ├── guide.md │ │ ├── resource.md │ │ ├── introduction.md │ │ └── principle.md │ ├── develop │ │ ├── pr.md │ │ ├── install.md │ │ ├── publish.md │ │ ├── start.md │ │ ├── theme.md │ │ ├── changelog.md │ │ └── local-dev.md │ ├── components │ │ ├── config.md │ │ ├── input │ │ │ ├── guide.md │ │ │ ├── index.md │ │ │ ├── api.md │ │ │ └── demo.md │ │ ├── table │ │ │ ├── guide.md │ │ │ ├── api.md │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── catalog.md │ │ ├── form │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── link │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── rate │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── tag │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── alert │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── avatar │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── drawer │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── empty │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── image │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── modal │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── spin │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── steps │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── dropdown │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── inputTag │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── message │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── statistic │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── tooltip │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── trigger │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── pagination │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── popconfirm │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── colorPicker │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── inputNumber │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── badge │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── space │ │ │ ├── index.md │ │ │ ├── api.md │ │ │ └── demo.md │ │ ├── timePicker │ │ │ ├── index.md │ │ │ └── demo.md │ │ ├── grid │ │ │ ├── index.md │ │ │ ├── api.md │ │ │ └── demo.md │ │ ├── select │ │ │ ├── index.md │ │ │ ├── api.md │ │ │ └── demo.md │ │ ├── icon │ │ │ ├── demo.md │ │ │ ├── api.md │ │ │ └── index.md │ │ ├── textarea │ │ │ ├── index.md │ │ │ ├── api.md │ │ │ └── demo.md │ │ ├── checkbox │ │ │ ├── index.md │ │ │ ├── api.md │ │ │ └── demo.md │ │ ├── switch │ │ │ ├── index.md │ │ │ ├── api.md │ │ │ └── demo.md │ │ ├── verifyCode │ │ │ ├── index.md │ │ │ ├── api.md │ │ │ └── demo.md │ │ ├── datePicker │ │ │ ├── index.md │ │ │ ├── api.md │ │ │ └── demo.md │ │ ├── radio │ │ │ ├── index.md │ │ │ ├── api.md │ │ │ └── demo.md │ │ └── button │ │ │ ├── index.md │ │ │ └── api.md │ ├── en │ │ └── index.md │ ├── index.md │ ├── .gitignore │ ├── example │ │ ├── empty │ │ │ └── basic.vue │ │ ├── spin │ │ │ └── basic.vue │ │ ├── tooltip │ │ │ └── basic.vue │ │ ├── badge │ │ │ └── basic.vue │ │ ├── rate │ │ │ └── basic.vue │ │ ├── textarea │ │ │ ├── basic.vue │ │ │ ├── limit.vue │ │ │ └── status.vue │ │ ├── verifyCode │ │ │ ├── basic.vue │ │ │ ├── password.vue │ │ │ ├── status.vue │ │ │ └── api.ts │ │ ├── button │ │ │ ├── size.vue │ │ │ ├── shape.vue │ │ │ ├── basic.vue │ │ │ ├── icon.vue │ │ │ ├── loading.vue │ │ │ ├── group.vue │ │ │ └── status.vue │ │ ├── switch │ │ │ ├── text.vue │ │ │ ├── basic.vue │ │ │ ├── size.vue │ │ │ ├── async.vue │ │ │ ├── api.ts │ │ │ └── usage.vue │ │ ├── colorPicker │ │ │ └── basic.vue │ │ ├── pagination │ │ │ ├── basic.vue │ │ │ └── sizes.vue │ │ ├── datePicker │ │ │ ├── panel.vue │ │ │ ├── time.vue │ │ │ ├── basic.vue │ │ │ ├── month.vue │ │ │ └── year.vue │ │ ├── input │ │ │ ├── password.vue │ │ │ ├── limit.vue │ │ │ ├── basic.vue │ │ │ ├── element.vue │ │ │ ├── status.vue │ │ │ └── size.vue │ │ ├── timePicker │ │ │ └── basic.vue │ │ ├── inputTag │ │ │ └── basic.vue │ │ ├── alert │ │ │ └── basic.vue │ │ ├── avatar │ │ │ └── basic.vue │ │ ├── link │ │ │ └── basic.vue │ │ ├── radio │ │ │ ├── basic.vue │ │ │ ├── group-button.vue │ │ │ ├── group.vue │ │ │ └── api.ts │ │ ├── checkbox │ │ │ ├── basic.vue │ │ │ ├── limit.vue │ │ │ ├── group.vue │ │ │ └── select-all.vue │ │ ├── modal │ │ │ ├── basic.vue │ │ │ └── footer.vue │ │ ├── popconfirm │ │ │ └── basic.vue │ │ ├── icon │ │ │ ├── basic.vue │ │ │ └── api.ts │ │ ├── tag │ │ │ └── basic.vue │ │ ├── select │ │ │ ├── clearable.vue │ │ │ ├── basic.vue │ │ │ ├── size.vue │ │ │ └── api.ts │ │ ├── inputNumber │ │ │ └── basic.vue │ │ ├── statistic │ │ │ └── basic.vue │ │ ├── message │ │ │ └── basic.vue │ │ ├── steps │ │ │ └── basic.vue │ │ ├── dropdown │ │ │ └── basic.vue │ │ ├── space │ │ │ ├── basic.vue │ │ │ ├── api.ts │ │ │ └── flex.vue │ │ ├── drawer │ │ │ └── basic.vue │ │ ├── grid │ │ │ ├── gutter.vue │ │ │ ├── responsive.vue │ │ │ ├── offset.vue │ │ │ └── basic.vue │ │ ├── trigger │ │ │ ├── scroll.vue │ │ │ └── basic.vue │ │ └── image │ │ │ └── basic.vue │ ├── .vitepress │ │ ├── components │ │ │ ├── doc-tabs │ │ │ │ ├── index.ts │ │ │ │ └── src │ │ │ │ │ └── doc-tabs.vue │ │ │ ├── api-block │ │ │ │ ├── index.ts │ │ │ │ └── src │ │ │ │ │ └── api-block.vue │ │ │ ├── demo-block │ │ │ │ ├── index.ts │ │ │ │ └── src │ │ │ │ │ ├── demo-option.vue │ │ │ │ │ └── demo-block.vue │ │ │ ├── usage-block │ │ │ │ ├── index.ts │ │ │ │ └── src │ │ │ │ │ └── usage-block.vue │ │ │ ├── home-page.vue │ │ │ └── catalog.vue │ │ ├── config │ │ │ ├── locales │ │ │ │ ├── index.ts │ │ │ │ ├── en │ │ │ │ │ ├── nav.ts │ │ │ │ │ └── index.ts │ │ │ │ └── zh-CN │ │ │ │ │ └── index.ts │ │ │ └── index.ts │ │ └── theme │ │ │ ├── layout.vue │ │ │ └── index.ts │ ├── style │ │ ├── fonts │ │ │ ├── 6xKtdSZaM9iE8KbpRA_hK1QNYuDyPw.woff2 │ │ │ ├── 6xKtdSZaM9iE8KbpRA_hJFQNYuDyP7bh.woff2 │ │ │ └── 6xKtdSZaM9iE8KbpRA_hJVQNYuDyP7bh.woff2 │ │ ├── index.scss │ │ ├── content.scss │ │ ├── components │ │ │ └── doc-tabs.scss │ │ ├── base.scss │ │ └── sidebar.scss │ ├── env.d.ts │ └── vite.config.ts ├── package.json └── tsconfig.json ├── packages ├── hooks │ ├── index.ts │ ├── package.json │ └── src │ │ └── use-namespace.ts ├── components │ ├── colorPicker │ │ ├── src │ │ │ ├── types.ts │ │ │ └── props.ts │ │ └── index.ts │ ├── popconfirm │ │ ├── src │ │ │ └── types.ts │ │ └── index.ts │ ├── config-provider │ │ ├── index.ts │ │ └── src │ │ │ ├── types.ts │ │ │ └── use-config-provider.ts │ ├── image │ │ ├── src │ │ │ └── types.ts │ │ └── index.ts │ ├── link │ │ ├── src │ │ │ └── types.ts │ │ └── index.ts │ ├── tag │ │ ├── src │ │ │ ├── types.ts │ │ │ ├── props.ts │ │ │ └── tag.vue │ │ └── index.ts │ ├── input │ │ ├── style │ │ │ └── index.ts │ │ ├── index.ts │ │ └── src │ │ │ └── types.ts │ ├── table │ │ ├── style │ │ │ └── index.ts │ │ ├── index.ts │ │ └── src │ │ │ ├── types.ts │ │ │ └── components │ │ │ ├── col-group.vue │ │ │ └── table-column.vue │ ├── button │ │ ├── style │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── __tests__ │ │ │ └── button.test.ts │ │ └── src │ │ │ └── types.ts │ ├── switch │ │ ├── src │ │ │ └── types.ts │ │ └── index.ts │ ├── space │ │ ├── src │ │ │ └── types.ts │ │ └── index.ts │ ├── avatar │ │ ├── src │ │ │ ├── types.ts │ │ │ └── props.ts │ │ └── index.ts │ ├── radio │ │ ├── src │ │ │ ├── types.ts │ │ │ └── props.ts │ │ └── index.ts │ ├── checkbox │ │ ├── src │ │ │ ├── types.ts │ │ │ └── props.ts │ │ └── index.ts │ ├── package.json │ ├── rate │ │ ├── index.ts │ │ └── src │ │ │ └── props.ts │ ├── spin │ │ ├── index.ts │ │ └── src │ │ │ ├── components │ │ │ └── spinner.vue │ │ │ ├── props.ts │ │ │ └── spin.vue │ ├── alert │ │ └── index.ts │ ├── badge │ │ ├── index.ts │ │ └── src │ │ │ ├── badge.vue │ │ │ └── props.ts │ ├── empty │ │ ├── index.ts │ │ └── src │ │ │ ├── props.ts │ │ │ └── empty.vue │ ├── drawer │ │ └── index.ts │ ├── trigger │ │ ├── index.ts │ │ └── src │ │ │ └── types.ts │ ├── pagination │ │ ├── src │ │ │ ├── types.ts │ │ │ └── components │ │ │ │ ├── total.vue │ │ │ │ ├── prev.vue │ │ │ │ └── next.vue │ │ └── index.ts │ ├── tooltip │ │ ├── index.ts │ │ └── src │ │ │ ├── props.ts │ │ │ └── tooltip.vue │ ├── statistic │ │ └── index.ts │ ├── verifyCode │ │ ├── index.ts │ │ └── src │ │ │ └── props.ts │ ├── inputNumber │ │ └── index.ts │ ├── inputTag │ │ ├── index.ts │ │ └── src │ │ │ └── props.ts │ ├── textarea │ │ └── index.ts │ ├── timePicker │ │ ├── src │ │ │ └── types.ts │ │ └── index.ts │ ├── dropdown │ │ ├── src │ │ │ ├── types.ts │ │ │ ├── components │ │ │ │ └── doption.vue │ │ │ └── props.ts │ │ └── index.ts │ ├── grid │ │ ├── index.ts │ │ └── src │ │ │ ├── types.ts │ │ │ └── col.vue │ ├── steps │ │ ├── index.ts │ │ └── src │ │ │ ├── components │ │ │ └── step.vue │ │ │ └── props.ts │ ├── modal │ │ ├── src │ │ │ ├── types.ts │ │ │ └── instance.ts │ │ └── index.ts │ ├── form │ │ ├── index.ts │ │ └── src │ │ │ └── types.ts │ ├── select │ │ ├── index.ts │ │ └── src │ │ │ └── types.ts │ ├── utils │ │ ├── array.ts │ │ ├── helper.ts │ │ └── number.ts │ ├── env.d.ts │ ├── message │ │ ├── src │ │ │ ├── type.ts │ │ │ ├── messageList.vue │ │ │ └── props.ts │ │ └── index.ts │ ├── datePicker │ │ ├── index.ts │ │ └── src │ │ │ └── components │ │ │ └── table-header.vue │ └── index.ts ├── theme │ ├── src │ │ ├── base.scss │ │ ├── trigger.scss │ │ ├── common │ │ │ ├── zindex.scss │ │ │ ├── design.scss │ │ │ ├── extend.scss │ │ │ └── sizes.scss │ │ ├── timePicker.scss │ │ ├── space.scss │ │ ├── statistic.scss │ │ ├── mixins │ │ │ ├── var.scss │ │ │ ├── mixins.scss │ │ │ └── function.scss │ │ ├── empty.scss │ │ ├── grid.scss │ │ ├── option.scss │ │ ├── dropdown.scss │ │ ├── select.scss │ │ ├── col.scss │ │ ├── spin.scss │ │ ├── index.scss │ │ ├── image.scss │ │ └── popconfirm.scss │ └── package.json └── birdpaper-ui │ ├── plugins.ts │ ├── default.ts │ ├── index.ts │ └── installer.ts ├── pnpm-workspace.yaml ├── .gitignore ├── .prettierignore ├── .eslintignore ├── scripts └── build │ ├── src │ ├── tasks │ │ ├── index.ts │ │ ├── buildTheme.ts │ │ ├── buildBundle.ts │ │ ├── concatFiles.ts │ │ └── copyFiles.ts │ ├── paths.ts │ └── utils.ts │ ├── gulpfile.ts │ └── package.json ├── env.d.ts ├── .prettierrc ├── uno.config.ts ├── tsconfig.json ├── .github └── workflows │ └── sync-to-cnb.yml ├── .cnb.yml ├── vitest.config.ts ├── LICENSE └── README.md /jsconfig.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/design/color.md: -------------------------------------------------------------------------------- 1 | # 色彩 -------------------------------------------------------------------------------- /docs/src/develop/pr.md: -------------------------------------------------------------------------------- 1 | # 参与贡献 -------------------------------------------------------------------------------- /docs/src/design/dark.md: -------------------------------------------------------------------------------- 1 | # 深色模式 -------------------------------------------------------------------------------- /docs/src/design/guide.md: -------------------------------------------------------------------------------- 1 | # 样式指南 -------------------------------------------------------------------------------- /docs/src/design/resource.md: -------------------------------------------------------------------------------- 1 | # 设计资源 -------------------------------------------------------------------------------- /docs/src/develop/install.md: -------------------------------------------------------------------------------- 1 | # 安装 -------------------------------------------------------------------------------- /docs/src/develop/publish.md: -------------------------------------------------------------------------------- 1 | # 版本发布 -------------------------------------------------------------------------------- /docs/src/develop/start.md: -------------------------------------------------------------------------------- 1 | # 快速上手 -------------------------------------------------------------------------------- /docs/src/develop/theme.md: -------------------------------------------------------------------------------- 1 | # 定制主题 -------------------------------------------------------------------------------- /docs/src/components/config.md: -------------------------------------------------------------------------------- 1 | # 全局配置 -------------------------------------------------------------------------------- /docs/src/design/introduction.md: -------------------------------------------------------------------------------- 1 | # 简介 -------------------------------------------------------------------------------- /docs/src/design/principle.md: -------------------------------------------------------------------------------- 1 | # 设计原则 -------------------------------------------------------------------------------- /docs/src/develop/changelog.md: -------------------------------------------------------------------------------- 1 | # 更新日志 -------------------------------------------------------------------------------- /docs/src/develop/local-dev.md: -------------------------------------------------------------------------------- 1 | # 本地开发 -------------------------------------------------------------------------------- /docs/src/components/input/guide.md: -------------------------------------------------------------------------------- 1 | 2 | ## 用法指南 -------------------------------------------------------------------------------- /docs/src/components/table/guide.md: -------------------------------------------------------------------------------- 1 | 2 | ## 用法指南 -------------------------------------------------------------------------------- /docs/src/en/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | --- -------------------------------------------------------------------------------- /docs/src/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | --- -------------------------------------------------------------------------------- /docs/src/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | cache 3 | .temp -------------------------------------------------------------------------------- /docs/src/components/table/api.md: -------------------------------------------------------------------------------- 1 | 2 | ## Button 属性 -------------------------------------------------------------------------------- /docs/src/components/catalog.md: -------------------------------------------------------------------------------- 1 | # 组件目录 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./src/use-namespace"; 2 | -------------------------------------------------------------------------------- /docs/src/components/form/index.md: -------------------------------------------------------------------------------- 1 | # 表单 Form 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/link/index.md: -------------------------------------------------------------------------------- 1 | # 链接 Link 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/rate/index.md: -------------------------------------------------------------------------------- 1 | # 评分 Rate 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/tag/index.md: -------------------------------------------------------------------------------- 1 | # 标签 Tag 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/example/empty/basic.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/* 3 | - scripts/* 4 | - docs 5 | -------------------------------------------------------------------------------- /docs/src/components/alert/index.md: -------------------------------------------------------------------------------- 1 | # 警告提示 Alert 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/avatar/index.md: -------------------------------------------------------------------------------- 1 | # 头像 Avatar 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/drawer/index.md: -------------------------------------------------------------------------------- 1 | # 抽屉 Drawer 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/empty/index.md: -------------------------------------------------------------------------------- 1 | # 空状态 Empty 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/image/index.md: -------------------------------------------------------------------------------- 1 | # 图片 Image 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/modal/index.md: -------------------------------------------------------------------------------- 1 | # 对话框 Modal 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/spin/index.md: -------------------------------------------------------------------------------- 1 | # 加载中 Spin 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/steps/index.md: -------------------------------------------------------------------------------- 1 | # 步骤条 Steps 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/table/index.md: -------------------------------------------------------------------------------- 1 | # 表格 Table 2 | 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | cache 3 | dist/ 4 | es/ 5 | lib/ 6 | .idea/ 7 | .npmrc 8 | .trae/ -------------------------------------------------------------------------------- /docs/src/components/dropdown/index.md: -------------------------------------------------------------------------------- 1 | # 下拉菜单 Dropdown 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/inputTag/index.md: -------------------------------------------------------------------------------- 1 | # 标签输入 InputTag 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/message/index.md: -------------------------------------------------------------------------------- 1 | # 消息提示 Message 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/statistic/index.md: -------------------------------------------------------------------------------- 1 | # 数值 Statistic 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/tooltip/index.md: -------------------------------------------------------------------------------- 1 | # 文字气泡 Tooltip 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/trigger/index.md: -------------------------------------------------------------------------------- 1 | # 触发器 Trigger 2 | 3 | 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | coverage 4 | pnpm-lock.yaml 5 | docs/components.d.ts 6 | -------------------------------------------------------------------------------- /docs/src/components/pagination/index.md: -------------------------------------------------------------------------------- 1 | # 分页 Pagination 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/popconfirm/index.md: -------------------------------------------------------------------------------- 1 | # 气泡确认 Popconfirm 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/components/colorPicker/src/types.ts: -------------------------------------------------------------------------------- 1 | export type ColorPickerValueType = "hex" | "rgb"; 2 | -------------------------------------------------------------------------------- /docs/src/components/colorPicker/index.md: -------------------------------------------------------------------------------- 1 | # 颜色选择 ColorPicker 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/components/inputNumber/index.md: -------------------------------------------------------------------------------- 1 | # 数字输入 InputNumber 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/theme/src/base.scss: -------------------------------------------------------------------------------- 1 | @use "common/design"; 2 | @use "common/color"; 3 | @use "common/zindex" 4 | -------------------------------------------------------------------------------- /packages/components/popconfirm/src/types.ts: -------------------------------------------------------------------------------- 1 | export type PopconfirmType = "info" | "success" | "warning" | "error"; 2 | -------------------------------------------------------------------------------- /packages/components/config-provider/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./src/use-config-provider"; 2 | export * from "./src/types"; -------------------------------------------------------------------------------- /packages/components/image/src/types.ts: -------------------------------------------------------------------------------- 1 | export type ImageFit = "fill" | "contain" | "cover" | "none" | "scale-down"; 2 | -------------------------------------------------------------------------------- /packages/components/link/src/types.ts: -------------------------------------------------------------------------------- 1 | export type LinkStatus = "gray" | "primary" | "success" | "warning" | "danger"; 2 | -------------------------------------------------------------------------------- /packages/components/tag/src/types.ts: -------------------------------------------------------------------------------- 1 | export type TagStatus = "gray" | "primary" | "success" | "warning" | "danger"; 2 | -------------------------------------------------------------------------------- /docs/src/.vitepress/components/doc-tabs/index.ts: -------------------------------------------------------------------------------- 1 | import DocTabs from "./src/doc-tabs.vue"; 2 | 3 | export default DocTabs; 4 | -------------------------------------------------------------------------------- /docs/src/components/badge/index.md: -------------------------------------------------------------------------------- 1 | # 徽章 Badge 2 | 用于在目标元素(如图标、按钮、列表项等)上显示状态或数量提示的轻量型组件。 3 | 4 | 5 | -------------------------------------------------------------------------------- /docs/src/example/spin/basic.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | pnpm-lock.yaml 4 | docs/components.d.ts 5 | coverage 6 | docs/.vitepress/i18n/* 7 | !.* 8 | -------------------------------------------------------------------------------- /docs/src/.vitepress/components/api-block/index.ts: -------------------------------------------------------------------------------- 1 | import ApiBlock from "./src/api-block.vue"; 2 | 3 | export default ApiBlock; 4 | -------------------------------------------------------------------------------- /packages/components/input/style/index.ts: -------------------------------------------------------------------------------- 1 | import "@birdpaper-ui/theme/src/base.scss"; 2 | import "@birdpaper-ui/theme/src/input.scss"; -------------------------------------------------------------------------------- /packages/components/table/style/index.ts: -------------------------------------------------------------------------------- 1 | import "@birdpaper-ui/theme/src/base.scss"; 2 | import "@birdpaper-ui/theme/src/table.scss"; -------------------------------------------------------------------------------- /docs/src/.vitepress/components/demo-block/index.ts: -------------------------------------------------------------------------------- 1 | import DemoBlock from "./src/demo-block.vue"; 2 | 3 | export default DemoBlock; 4 | -------------------------------------------------------------------------------- /docs/src/components/empty/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | <<< @/example/empty/basic.vue 5 | 6 | -------------------------------------------------------------------------------- /docs/src/components/form/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | <<< @/example/form/basic.vue 5 | 6 | -------------------------------------------------------------------------------- /docs/src/components/tag/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/tag/basic.vue 6 | 7 | -------------------------------------------------------------------------------- /packages/components/button/style/index.ts: -------------------------------------------------------------------------------- 1 | import "@birdpaper-ui/theme/src/base.scss"; 2 | import "@birdpaper-ui/theme/src/button.scss"; -------------------------------------------------------------------------------- /docs/src/.vitepress/components/usage-block/index.ts: -------------------------------------------------------------------------------- 1 | import UsageBlock from "./src/usage-block.vue"; 2 | 3 | export default UsageBlock; 4 | -------------------------------------------------------------------------------- /docs/src/components/alert/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/alert/basic.vue 6 | 7 | -------------------------------------------------------------------------------- /docs/src/components/drawer/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | <<< @/example/drawer/basic.vue 5 | 6 | -------------------------------------------------------------------------------- /docs/src/components/image/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/image/basic.vue 6 | 7 | -------------------------------------------------------------------------------- /docs/src/components/space/index.md: -------------------------------------------------------------------------------- 1 | # 间距 Space 2 | 设置两个相邻元素之间的距离。 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/src/components/spin/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/spin/basic.vue 6 | 7 | -------------------------------------------------------------------------------- /docs/src/components/steps/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/steps/basic.vue 6 | 7 | -------------------------------------------------------------------------------- /docs/src/components/timePicker/index.md: -------------------------------------------------------------------------------- 1 | # 时间选择 TimePicker 2 | 选择时间的用户界面控件,提供了一个直观的方式让用户通过滑动列表来选择特定的时间。 3 | 4 | 5 | -------------------------------------------------------------------------------- /docs/src/components/avatar/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/avatar/basic.vue 6 | 7 | -------------------------------------------------------------------------------- /docs/src/components/dropdown/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | <<< @/example/dropdown/basic.vue 5 | 6 | -------------------------------------------------------------------------------- /docs/src/components/grid/index.md: -------------------------------------------------------------------------------- 1 | # 布局 Layout 2 | 通过布局高效的组织内容,优化页面结构,加速开发进程。 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/src/components/link/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/link/basic.vue 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/src/components/message/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/message/basic.vue 6 | 7 | -------------------------------------------------------------------------------- /docs/src/components/rate/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/rate/basic.vue 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/src/components/tooltip/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/tooltip/basic.vue 6 | 7 | -------------------------------------------------------------------------------- /packages/components/switch/src/types.ts: -------------------------------------------------------------------------------- 1 | export type SwitchValue = boolean | string | number; 2 | 3 | export type SwitchSize = "small" | "mini"; 4 | -------------------------------------------------------------------------------- /docs/src/components/inputTag/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/inputTag/basic.vue 6 | 7 | -------------------------------------------------------------------------------- /docs/src/components/popconfirm/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | <<< @/example/popconfirm/basic.vue 5 | 6 | -------------------------------------------------------------------------------- /docs/src/components/select/index.md: -------------------------------------------------------------------------------- 1 | # 选择器 Select 2 | 3 | 在表单场景中,用于从下拉列表中选择单个或多个选项。 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/src/components/icon/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 图标的基础用法 4 | 5 | 6 | <<< @/example/icon/basic.vue 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/src/components/statistic/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/statistic/basic.vue 6 | 7 | -------------------------------------------------------------------------------- /docs/src/components/textarea/index.md: -------------------------------------------------------------------------------- 1 | # 多行文本 Textarea 2 | 提供了灵活的输入区域,支持用户自由地输入、编辑大段文字内容。 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/src/example/tooltip/basic.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /docs/src/components/badge/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 支持 5 种按钮类型 4 | 5 | 6 | <<< @/example/badge/basic.vue 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/src/components/colorPicker/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/colorPicker/basic.vue 6 | 7 | -------------------------------------------------------------------------------- /docs/src/components/checkbox/index.md: -------------------------------------------------------------------------------- 1 | # 复选框 Checkbox 2 | 允许用户从一组选项中选择一个或多个选项,在表单填写场景中,提升数据收集的准确性和操作便捷性。 3 | 4 | 5 | -------------------------------------------------------------------------------- /docs/src/components/input/index.md: -------------------------------------------------------------------------------- 1 | # 输入框 Input 2 | 提供简介的界面,方便用户输入各类信息,有效引导用户准确输入内容,便捷的采集信息。 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/src/components/inputNumber/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/inputNumber/basic.vue 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/src/components/switch/index.md: -------------------------------------------------------------------------------- 1 | # 开关 Switch 2 | 在两个互斥的状态之间进行切换。通常用于启用或禁用某个功能,或在开和关之间切换某个设置。 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/src/components/verifyCode/index.md: -------------------------------------------------------------------------------- 1 | # 验证码 VerifyCode 2 | 用于固定长度的验证码或者支付密码输入,提升用户输入体验。 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /packages/components/space/src/types.ts: -------------------------------------------------------------------------------- 1 | export type SizeType = "mini" | "small" | "normal" | "large" | number; 2 | 3 | export type SpaceType = "vertical" | "horizontal"; -------------------------------------------------------------------------------- /packages/components/avatar/src/types.ts: -------------------------------------------------------------------------------- 1 | export type AvatarShape = "circle" | "square"; 2 | 3 | export type AvatarSize = number | "mini" | "small" | "default" | "large"; 4 | -------------------------------------------------------------------------------- /docs/src/components/datePicker/index.md: -------------------------------------------------------------------------------- 1 | # 日期选择 DatePicker 2 | 3 | 选择日期的用户界面控件,提供了一个直观的方式让用户通过点击日历来选择特定的日期。 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/src/components/timePicker/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 时间选择器的基础用法 4 | 5 | 6 | <<< @/example/timePicker/basic.vue 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/src/example/badge/basic.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /docs/src/style/fonts/6xKtdSZaM9iE8KbpRA_hK1QNYuDyPw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/birdpaper-team/birdpaper-ui/HEAD/docs/src/style/fonts/6xKtdSZaM9iE8KbpRA_hK1QNYuDyPw.woff2 -------------------------------------------------------------------------------- /docs/src/style/fonts/6xKtdSZaM9iE8KbpRA_hJFQNYuDyP7bh.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/birdpaper-team/birdpaper-ui/HEAD/docs/src/style/fonts/6xKtdSZaM9iE8KbpRA_hJFQNYuDyP7bh.woff2 -------------------------------------------------------------------------------- /docs/src/style/fonts/6xKtdSZaM9iE8KbpRA_hJVQNYuDyP7bh.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/birdpaper-team/birdpaper-ui/HEAD/docs/src/style/fonts/6xKtdSZaM9iE8KbpRA_hJVQNYuDyP7bh.woff2 -------------------------------------------------------------------------------- /packages/birdpaper-ui/plugins.ts: -------------------------------------------------------------------------------- 1 | import { Message } from "@birdpaper-ui/components/message"; 2 | 3 | import type { Plugin } from "vue"; 4 | 5 | export default [Message] as Plugin[]; 6 | -------------------------------------------------------------------------------- /docs/src/components/radio/index.md: -------------------------------------------------------------------------------- 1 | # 单选框 Radio 2 | 3 | 常用于性别、偏好、单选型问题等场景,保障用户做出明确且唯一的选择,在表单填写、设置选项等交互流程中,提升信息收集准确性与操作便捷性。 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/src/components/button/index.md: -------------------------------------------------------------------------------- 1 | # 按钮 Button 2 | 元素中一种常见的交互控件,用户通过点击或触摸按钮来触发相应的操作,如提交表单、打开新页面、执行某个功能等,它通常具有特定的视觉外观以吸引用户注意并提示其可交互性。 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /scripts/build/src/tasks/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./buildBundle"; 2 | export * from "./buildModules"; 3 | export * from "./buildTheme"; 4 | export * from "./copyFiles"; 5 | export * from "./concatFiles"; -------------------------------------------------------------------------------- /docs/src/components/space/api.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## Space 属性 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/src/components/switch/api.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## Switch 属性 6 | 7 | -------------------------------------------------------------------------------- /packages/components/radio/src/types.ts: -------------------------------------------------------------------------------- 1 | export type RadioValue = string | number | boolean; 2 | 3 | export type RadioType = "radio" | "button"; 4 | 5 | export type DirectionType = "vertical" | "horizontal"; 6 | -------------------------------------------------------------------------------- /env.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { App, defineComponent } from 'vue' 3 | const component: ReturnType & { 4 | install(app: App): void 5 | } 6 | export default component 7 | } -------------------------------------------------------------------------------- /packages/birdpaper-ui/default.ts: -------------------------------------------------------------------------------- 1 | import { installer } from "./installer"; 2 | import Components from "./components"; 3 | import Plugins from "./plugins"; 4 | 5 | export default installer([...Components, ...Plugins]); 6 | -------------------------------------------------------------------------------- /packages/components/checkbox/src/types.ts: -------------------------------------------------------------------------------- 1 | export type CheckboxValue = boolean; 2 | export type CheckboxValueForArray = string | number | boolean; 3 | 4 | export type CheckboxDirectionType = "vertical" | "horizontal"; 5 | -------------------------------------------------------------------------------- /docs/src/env.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { App, defineComponent } from 'vue' 3 | const component: ReturnType & { 4 | install(app: App): void 5 | } 6 | export default component 7 | } -------------------------------------------------------------------------------- /docs/src/example/rate/basic.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /docs/src/.vitepress/config/locales/index.ts: -------------------------------------------------------------------------------- 1 | import type { LocaleConfig } from "vitepress"; 2 | import zh_CN from "./zh-CN"; 3 | import en from "./en"; 4 | 5 | export const locales: LocaleConfig = { 6 | root: zh_CN, 7 | en 8 | }; 9 | -------------------------------------------------------------------------------- /docs/src/example/textarea/basic.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | -------------------------------------------------------------------------------- /docs/src/example/verifyCode/basic.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | -------------------------------------------------------------------------------- /packages/birdpaper-ui/index.ts: -------------------------------------------------------------------------------- 1 | import installer from "./default"; 2 | 3 | export * from "@birdpaper-ui/components"; 4 | export * from "./installer"; 5 | 6 | export const install = installer.install; 7 | export default installer; 8 | -------------------------------------------------------------------------------- /packages/components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@birdpaper-ui/components", 3 | "version": "3.0.0", 4 | "dependencies": { 5 | "@birdpaper-ui/theme": "workspace:*", 6 | "@birdpaper-ui/hooks": "workspace:*" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/components/rate/index.ts: -------------------------------------------------------------------------------- 1 | import _rate from "./src/rate.vue"; 2 | 3 | export const Rate = _rate; 4 | 5 | export * from "./src/props"; 6 | 7 | export type RateInstance = InstanceType; 8 | export default Rate; 9 | -------------------------------------------------------------------------------- /packages/components/spin/index.ts: -------------------------------------------------------------------------------- 1 | import _spin from "./src/spin.vue"; 2 | 3 | export const Spin = _spin; 4 | 5 | export * from "./src/props"; 6 | 7 | export type SpinInstance = InstanceType; 8 | export default Spin; 9 | -------------------------------------------------------------------------------- /packages/theme/src/trigger.scss: -------------------------------------------------------------------------------- 1 | @use "mixins/mixins.scss" as *; 2 | 3 | @include b(trigger) { 4 | position: relative; 5 | 6 | &-wrapper { 7 | position: absolute; 8 | z-index: var(--z-index-base); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/components/alert/index.ts: -------------------------------------------------------------------------------- 1 | import _alert from "./src/alert.vue"; 2 | 3 | export const Alert = _alert; 4 | 5 | export * from "./src/props"; 6 | 7 | export type AlertInstance = InstanceType; 8 | export default Alert; 9 | -------------------------------------------------------------------------------- /packages/components/badge/index.ts: -------------------------------------------------------------------------------- 1 | import _badge from "./src/badge.vue"; 2 | 3 | export const Badge = _badge; 4 | 5 | export * from "./src/props"; 6 | 7 | export type BadgeInstance = InstanceType; 8 | export default Badge; 9 | -------------------------------------------------------------------------------- /packages/components/empty/index.ts: -------------------------------------------------------------------------------- 1 | import _empty from "./src/empty.vue"; 2 | 3 | export const Empty = _empty; 4 | 5 | export * from "./src/props"; 6 | 7 | export type EmptyInstance = InstanceType; 8 | export default Empty; 9 | -------------------------------------------------------------------------------- /packages/components/space/index.ts: -------------------------------------------------------------------------------- 1 | import _space from "./src/space"; 2 | 3 | export const Space = _space; 4 | 5 | export * from "./src/types"; 6 | 7 | export type SpaceInstance = InstanceType; 8 | export default Space; 9 | -------------------------------------------------------------------------------- /docs/src/example/button/size.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /docs/src/example/switch/text.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | -------------------------------------------------------------------------------- /docs/src/example/colorPicker/basic.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | -------------------------------------------------------------------------------- /docs/src/example/pagination/basic.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | -------------------------------------------------------------------------------- /packages/components/drawer/index.ts: -------------------------------------------------------------------------------- 1 | import _drawer from "./src/drawer.vue"; 2 | 3 | export const Drawer = _drawer; 4 | 5 | export * from "./src/props"; 6 | 7 | export type DrawerInstance = InstanceType; 8 | export default Drawer; 9 | -------------------------------------------------------------------------------- /packages/theme/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@birdpaper-ui/theme", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "license": "MIT" 9 | } 10 | -------------------------------------------------------------------------------- /scripts/build/gulpfile.ts: -------------------------------------------------------------------------------- 1 | import { series } from "gulp"; 2 | import { buildModules, buildBundle, buildTheme, copyFiles, concatFiles } from "./src/tasks"; 3 | 4 | export default series(buildModules, buildBundle, buildTheme, copyFiles, concatFiles); 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": false, 4 | "printWidth": 120, 5 | "overrides": [ 6 | { 7 | "files": ".prettierrc", 8 | "options": { 9 | "parser": "json" 10 | } 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /docs/src/example/button/shape.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /packages/components/trigger/index.ts: -------------------------------------------------------------------------------- 1 | import _trigger from "./src/trigger"; 2 | 3 | export const Trigger = _trigger; 4 | 5 | export * from "./src/types"; 6 | 7 | export type TriggerInstance = InstanceType; 8 | export default Trigger; 9 | -------------------------------------------------------------------------------- /uno.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, presetAttributify, presetUno, transformerDirectives } from "unocss"; 2 | 3 | export default defineConfig({ 4 | presets: [presetUno(), presetAttributify()], 5 | transformers: [transformerDirectives()], 6 | }); 7 | -------------------------------------------------------------------------------- /docs/src/example/datePicker/panel.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | -------------------------------------------------------------------------------- /docs/src/example/verifyCode/password.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | -------------------------------------------------------------------------------- /packages/components/config-provider/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface ConfigProviderProps { 2 | prefix: string; 3 | /** Custom component namespace. */ 4 | namespace: string; 5 | } 6 | 7 | export type ConfigProviderContext = Partial; 8 | -------------------------------------------------------------------------------- /packages/components/pagination/src/types.ts: -------------------------------------------------------------------------------- 1 | import { Component } from "vue"; 2 | 3 | export interface PageinationComponent { 4 | name: string; 5 | bind: object; 6 | component: Component; 7 | eventName: string; 8 | event: Function; 9 | } 10 | -------------------------------------------------------------------------------- /packages/components/tooltip/index.ts: -------------------------------------------------------------------------------- 1 | import _tooltip from "./src/tooltip.vue"; 2 | 3 | export const Tooltip = _tooltip; 4 | 5 | export * from "./src/props"; 6 | 7 | export type TooltipInstance = InstanceType; 8 | export default Tooltip; 9 | -------------------------------------------------------------------------------- /docs/src/example/textarea/limit.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | -------------------------------------------------------------------------------- /docs/src/example/input/password.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | -------------------------------------------------------------------------------- /packages/components/input/index.ts: -------------------------------------------------------------------------------- 1 | import _input from "./src/input.vue"; 2 | 3 | export const Input = _input; 4 | 5 | export * from "./src/types"; 6 | export * from "./src/props"; 7 | export type InputInstance = InstanceType; 8 | export default Input; 9 | -------------------------------------------------------------------------------- /packages/components/tag/index.ts: -------------------------------------------------------------------------------- 1 | import _tag from "./src/tag.vue"; 2 | 3 | export const Tag = _tag; 4 | 5 | export * from "./src/props"; 6 | export * from "./src/types"; 7 | 8 | export type TagInstance = InstanceType; 9 | export default Tag; 10 | -------------------------------------------------------------------------------- /docs/src/components/trigger/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/trigger/basic.vue 6 | 7 | 8 | 9 | 10 | 11 | <<< @/example/trigger/scroll.vue 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/src/example/input/limit.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | -------------------------------------------------------------------------------- /packages/components/link/index.ts: -------------------------------------------------------------------------------- 1 | import _link from "./src/link.vue"; 2 | 3 | export const Link = _link; 4 | 5 | export * from "./src/props"; 6 | export * from "./src/types"; 7 | 8 | export type LinkInstance = InstanceType; 9 | export default Link; 10 | -------------------------------------------------------------------------------- /packages/components/statistic/index.ts: -------------------------------------------------------------------------------- 1 | import _statistic from "./src/statistic.vue"; 2 | 3 | export const Statistic = _statistic; 4 | 5 | export * from "./src/props"; 6 | 7 | export type StatisticInstance = InstanceType; 8 | export default Statistic; 9 | -------------------------------------------------------------------------------- /docs/src/components/modal/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/modal/basic.vue 6 | 7 | 8 | 9 | ## 自定义底部 10 | 11 | 12 | 13 | <<< @/example/modal/footer.vue 14 | 15 | -------------------------------------------------------------------------------- /packages/components/verifyCode/index.ts: -------------------------------------------------------------------------------- 1 | import _verifyCode from "./src/verifyCode.vue"; 2 | 3 | export const VerifyCode = _verifyCode; 4 | 5 | export * from "./src/props"; 6 | 7 | export type VerifyCodeInstance = InstanceType; 8 | export default VerifyCode; 9 | -------------------------------------------------------------------------------- /docs/src/components/grid/api.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## Row 属性 6 | 7 | 8 | 9 | ## Col 属性 10 | 11 | -------------------------------------------------------------------------------- /docs/src/example/timePicker/basic.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /packages/components/image/index.ts: -------------------------------------------------------------------------------- 1 | import _image from "./src/image.vue"; 2 | 3 | export const Image = _image; 4 | 5 | export * from "./src/props"; 6 | export * from "./src/types"; 7 | 8 | export type ImageInstance = InstanceType; 9 | export default Image; 10 | -------------------------------------------------------------------------------- /packages/components/inputNumber/index.ts: -------------------------------------------------------------------------------- 1 | import _inputNumber from "./src/inputNumber.vue"; 2 | 3 | export const InputNumber = _inputNumber; 4 | 5 | export * from "./src/props"; 6 | export type InputNumberInstance = InstanceType; 7 | export default InputNumber; 8 | -------------------------------------------------------------------------------- /docs/src/example/datePicker/time.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | -------------------------------------------------------------------------------- /packages/components/avatar/index.ts: -------------------------------------------------------------------------------- 1 | import _avatar from "./src/avatar.vue"; 2 | 3 | export const Avatar = _avatar; 4 | 5 | export * from "./src/props"; 6 | export * from "./src/types"; 7 | 8 | export type AvatarInstance = InstanceType; 9 | export default Avatar; 10 | -------------------------------------------------------------------------------- /packages/components/inputTag/index.ts: -------------------------------------------------------------------------------- 1 | import _inputTag from "./src/input-tag.vue"; 2 | 3 | export const InputTag = _inputTag; 4 | 5 | // export * from "./src/types"; 6 | // export * from "./src/props"; 7 | export type InputTagInstance = InstanceType; 8 | export default InputTag; -------------------------------------------------------------------------------- /packages/components/switch/index.ts: -------------------------------------------------------------------------------- 1 | import _switch from "./src/switch.vue"; 2 | 3 | export const Switch = _switch; 4 | 5 | export * from "./src/props"; 6 | export * from "./src/types"; 7 | 8 | export type SwitchInstance = InstanceType; 9 | export default Switch; 10 | -------------------------------------------------------------------------------- /docs/src/components/icon/api.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## Icon 属性 6 | 7 | 8 | 9 | ## 附加 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/src/components/pagination/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | 5 | <<< @/example/pagination/basic.vue 6 | 7 | 8 | 9 | ## 尺寸 10 | 11 | 12 | 13 | <<< @/example/pagination/sizes.vue 14 | 15 | -------------------------------------------------------------------------------- /docs/src/example/inputTag/basic.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /docs/src/example/alert/basic.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /docs/src/example/avatar/basic.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /packages/components/textarea/index.ts: -------------------------------------------------------------------------------- 1 | import _textarea from "./src/textarea.vue"; 2 | 3 | export const Textarea = _textarea; 4 | 5 | export * from "./src/props"; 6 | // export * from "./src/types"; 7 | 8 | export type TextareaInstance = InstanceType; 9 | export default Textarea; 10 | -------------------------------------------------------------------------------- /docs/src/example/switch/basic.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /packages/components/timePicker/src/types.ts: -------------------------------------------------------------------------------- 1 | import { InjectionKey } from "vue"; 2 | 3 | export interface TimePickerContext { 4 | modelValue: string; 5 | onSelect: (value: string, payload?: object) => void; 6 | } 7 | export const timeInjectionKey: InjectionKey = Symbol("TimePickerCtxKey"); 8 | -------------------------------------------------------------------------------- /packages/theme/src/common/zindex.scss: -------------------------------------------------------------------------------- 1 | // z-index 2 | 3 | :root { 4 | --z-index-base: 2000; 5 | --z-index-message: calc(var(--z-index-base) + 3); 6 | --z-index-modal: calc(var(--z-index-base)); 7 | --z-index-drawer: calc(var(--z-index-base)); 8 | --z-index-tooltip: var(--z-index-base); 9 | } 10 | -------------------------------------------------------------------------------- /docs/src/example/link/basic.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /packages/hooks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@birdpaper-ui/hooks", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC" 12 | } 13 | -------------------------------------------------------------------------------- /docs/src/example/input/basic.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /packages/components/pagination/index.ts: -------------------------------------------------------------------------------- 1 | import _pagination from "./src/pagination.vue"; 2 | 3 | export const Pagination = _pagination; 4 | 5 | export * from "./src/props"; 6 | export * from "./src/types"; 7 | 8 | export type PaginationInstance = InstanceType; 9 | export default Pagination; 10 | -------------------------------------------------------------------------------- /packages/components/popconfirm/index.ts: -------------------------------------------------------------------------------- 1 | import _popconfirm from "./src/popconfirm.vue"; 2 | 3 | export const Popconfirm = _popconfirm; 4 | 5 | export * from "./src/props"; 6 | export * from "./src/types"; 7 | 8 | export type PopconfirmInstance = InstanceType; 9 | export default Popconfirm; 10 | -------------------------------------------------------------------------------- /docs/src/example/switch/size.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /docs/src/example/radio/basic.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /packages/components/colorPicker/index.ts: -------------------------------------------------------------------------------- 1 | import _colorPicker from "./src/color-picker.vue"; 2 | 3 | export const ColorPicker = _colorPicker; 4 | 5 | export * from "./src/props"; 6 | export * from "./src/types"; 7 | 8 | export type ColorPickerInstance = InstanceType; 9 | export default ColorPicker; 10 | -------------------------------------------------------------------------------- /docs/src/components/verifyCode/api.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## VerifyCode 属性 6 | 7 | 8 | 9 | ## VerifyCode 事件 10 | 11 | -------------------------------------------------------------------------------- /docs/src/example/checkbox/basic.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /packages/components/dropdown/src/types.ts: -------------------------------------------------------------------------------- 1 | import { InjectionKey } from "vue"; 2 | 3 | export type DoptionValue = string | number; 4 | 5 | export interface DropdownContext { 6 | onSelect: (value?: DoptionValue) => void; 7 | } 8 | 9 | export const dropdownInjectionKey: InjectionKey = Symbol("DropdownCtxKey"); 10 | -------------------------------------------------------------------------------- /packages/components/input/src/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 输入框类型 Input type,文本输入-text、密文输入-password 3 | */ 4 | export declare type InputType = "text" | "password"; 5 | 6 | /** 7 | * @description 输入框尺寸 Input size,迷你-mini、小型-small、默认-default、大型-large 8 | */ 9 | export declare type InputSize = "mini" | "small" | "default" | "large"; 10 | -------------------------------------------------------------------------------- /docs/src/.vitepress/config/locales/en/nav.ts: -------------------------------------------------------------------------------- 1 | export const nav = [ 2 | { text: "Design", link: "/design/introduction", activeMatch: "/design/" }, 3 | { text: "指南", link: "/guide/easystart", activeMatch: "/guide/" }, 4 | { text: "组件", link: "/component/grid", activeMatch: "/component/" }, 5 | { text: "图标", link: "https://icon.birdpaper.design" }, 6 | ]; -------------------------------------------------------------------------------- /docs/src/example/modal/basic.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | -------------------------------------------------------------------------------- /packages/components/empty/src/props.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes } from "vue"; 2 | 3 | export const emptyProps = { 4 | /** 5 | * @type string 6 | * @description Content text. 7 | * @default "暂无数据" 8 | */ 9 | content: { type: String, default: "暂无数据" }, 10 | }; 11 | 12 | export type EmptyProps = ExtractPropTypes; 13 | -------------------------------------------------------------------------------- /docs/src/example/input/element.vue: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /packages/components/trigger/src/types.ts: -------------------------------------------------------------------------------- 1 | export type TriggerType = "click" | "hover"; 2 | 3 | export type TriggerPosition = 4 | | "top" 5 | | "bottom" 6 | | "left" 7 | | "right" 8 | | "top-left" 9 | | "top-right" 10 | | "bottom-left" 11 | | "bottom-right" 12 | | "upper-left" 13 | | "upper-right" 14 | | "low-left" 15 | | "low-right"; 16 | -------------------------------------------------------------------------------- /docs/src/components/space/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 间距组件的基础用法,支持 `vertical` 和 `horizontal` 两种方向。 4 | 5 | 6 | <<< @/example/space/basic.vue 7 | 8 | 9 | 10 | ## Flex 布局 11 | 12 | 间距组件支持 Flex 布局,可以设置 `align` 和 `justify` 属性。 13 | 14 | 15 | <<< @/example/space/flex.vue 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/src/components/table/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 4 | <<< @/example/table/basic.vue 5 | 6 | 7 | 8 | 9 | 10 | <<< @/example/table/scroll-sync-test.vue 11 | 12 | 13 | 14 | 15 | 16 | <<< @/example/table/scroll.vue 17 | 18 | -------------------------------------------------------------------------------- /docs/src/example/verifyCode/status.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /docs/src/.vitepress/components/home-page.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/src/example/button/basic.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/example/checkbox/limit.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /packages/components/grid/index.ts: -------------------------------------------------------------------------------- 1 | import _row from "./src/row.vue"; 2 | import _col from "./src/col.vue"; 3 | 4 | export const Row = _row; 5 | export const Col = _col; 6 | 7 | export * from "./src/types"; 8 | export * from "./src/props"; 9 | export type RowInstance = InstanceType; 10 | export type ColInstance = InstanceType; 11 | export default Row; 12 | -------------------------------------------------------------------------------- /packages/components/steps/index.ts: -------------------------------------------------------------------------------- 1 | import _steps from "./src/steps"; 2 | import _step from "./src/components/step.vue"; 3 | 4 | export const Steps = _steps; 5 | export const Step = _step; 6 | 7 | export * from "./src/props"; 8 | 9 | export type StepsInstance = InstanceType; 10 | export type StepInstance = InstanceType; 11 | export default Steps; 12 | -------------------------------------------------------------------------------- /docs/src/example/datePicker/basic.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /docs/src/example/switch/async.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | -------------------------------------------------------------------------------- /docs/src/example/popconfirm/basic.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /packages/components/modal/src/types.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes } from "vue"; 2 | import { modalProps } from "./props"; 3 | 4 | export type ModalType = "info" | "success" | "warning" | "error" | "confirm"; 5 | 6 | export type ModalInstance = string | ModalItem; 7 | 8 | export type ModalMethod = {}; 9 | 10 | export type ModalItem = ExtractPropTypes; 11 | -------------------------------------------------------------------------------- /docs/src/example/datePicker/month.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /docs/src/example/datePicker/year.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 12 | -------------------------------------------------------------------------------- /docs/src/example/icon/basic.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /docs/src/example/input/status.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /docs/src/components/radio/api.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## Radio 属性 6 | 7 | 8 | 9 | ## RadioGroup 属性 10 | 11 | 12 | 13 | ## Radio 事件 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/src/components/select/api.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## Select 属性 6 | 7 | 8 | 9 | ## Option 属性 10 | 11 | 12 | 13 | ## Select 事件 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/src/style/index.scss: -------------------------------------------------------------------------------- 1 | @use "./fonts/font.scss"; 2 | @use "./var.scss"; 3 | @use "./base.scss"; 4 | @use "./nav.scss"; 5 | @use "./sidebar.scss"; 6 | @use "./content.scss"; 7 | 8 | // components 9 | @use "./components/demo-block.scss"; 10 | @use "./components/doc-tabs.scss"; 11 | @use "./components/api-block.scss"; 12 | @use "./components/usage-block.scss"; 13 | @use "./components/catalog.scss"; 14 | -------------------------------------------------------------------------------- /docs/src/example/radio/group-button.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | -------------------------------------------------------------------------------- /docs/src/example/textarea/status.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /docs/src/.vitepress/config/locales/en/index.ts: -------------------------------------------------------------------------------- 1 | import { nav } from "./nav"; 2 | import sidebar from "./sidebar"; 3 | 4 | export default { 5 | label: "English", 6 | lang: "en", 7 | title: "Birdpaper UI", 8 | titleTemplate: "A Vue UI component library", 9 | description: "A UI component library based on Vue", 10 | themeConfig: { 11 | nav: nav, 12 | siteTitle: "", 13 | sidebar: sidebar, 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /docs/src/components/textarea/api.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## Textarea 属性 6 | 7 | 8 | 9 | ## Textarea 事件 10 | 11 | 12 | 13 | ## Textarea 方法 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/src/example/pagination/sizes.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 17 | -------------------------------------------------------------------------------- /docs/src/example/tag/basic.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /packages/components/form/index.ts: -------------------------------------------------------------------------------- 1 | import _form from "./src/form.vue"; 2 | import _formItem from "./src/components/form-item.vue"; 3 | 4 | export const Form = _form; 5 | export const FormItem = _formItem; 6 | 7 | export * from "./src/props"; 8 | // export * from "./src/types"; 9 | 10 | export type FormInstance = InstanceType; 11 | export type FormItemInstance = InstanceType; 12 | export default Form; 13 | -------------------------------------------------------------------------------- /packages/components/radio/index.ts: -------------------------------------------------------------------------------- 1 | import _radio from "./src/radio.vue"; 2 | import _radioGroup from "./src/radioGroup"; 3 | 4 | export const Radio = _radio; 5 | export const RadioGroup = _radioGroup; 6 | 7 | export * from "./src/props"; 8 | export * from "./src/types"; 9 | 10 | export type RadioInstance = InstanceType; 11 | export type RadioGroupInstance = InstanceType; 12 | export default Radio; 13 | -------------------------------------------------------------------------------- /packages/components/select/index.ts: -------------------------------------------------------------------------------- 1 | import _select from "./src/select.vue"; 2 | import _option from "./src/components/option.vue"; 3 | 4 | export const Select = _select; 5 | export const Option = _option; 6 | 7 | export * from "./src/props"; 8 | export * from "./src/types"; 9 | 10 | export type SelectInstance = InstanceType; 11 | export type OptionInstance = InstanceType; 12 | export default Select; 13 | -------------------------------------------------------------------------------- /scripts/build/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@birdpaper-ui/build", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "start": "gulp --require @esbuild-kit/cjs-loader -f gulpfile.ts" 6 | }, 7 | "devDependencies": { 8 | "@esbuild-kit/cjs-loader": "^2.2.1", 9 | "@types/gulp": "^4.0.17", 10 | "fast-glob": "^3.3.2", 11 | "gulp": "^4.0.2", 12 | "gulp-sass": "^5.1.0", 13 | "vite-plugin-dts": "^4.4.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /docs/src/example/select/clearable.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 14 | -------------------------------------------------------------------------------- /packages/components/button/index.ts: -------------------------------------------------------------------------------- 1 | import _button from "./src/button.vue"; 2 | import _buttonGroup from "./src/buttonGroup"; 3 | 4 | export const Button = _button; 5 | export const ButtonGroup = _buttonGroup; 6 | 7 | export * from "./src/types"; 8 | export * from "./src/props"; 9 | 10 | export type ButtonInstance = InstanceType; 11 | export type ButtonGroupInstance = InstanceType; 12 | export default Button; 13 | -------------------------------------------------------------------------------- /packages/components/dropdown/index.ts: -------------------------------------------------------------------------------- 1 | import _dropdown from "./src/dropdown.vue"; 2 | import _doption from "./src/components/doption.vue"; 3 | 4 | export const Dropdown = _dropdown; 5 | export const Doption = _doption; 6 | 7 | export * from "./src/types"; 8 | export * from "./src/props"; 9 | 10 | export type DropdownInstance = InstanceType; 11 | export type DoptionInstance = InstanceType; 12 | export default Dropdown; 13 | -------------------------------------------------------------------------------- /packages/components/table/index.ts: -------------------------------------------------------------------------------- 1 | import _table from "./src/table.vue"; 2 | import _tableColumn from "./src/components/table-column.vue"; 3 | 4 | export const Table = _table; 5 | export const TableColumn = _tableColumn; 6 | 7 | export * from "./src/props"; 8 | export * from "./src/types"; 9 | 10 | export type TableInstance = InstanceType; 11 | export type TableColumnInstance = InstanceType; 12 | export default Table; 13 | -------------------------------------------------------------------------------- /docs/src/components/input/api.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## Input 属性 6 | 7 | 8 | ## Input 事件 9 | 10 | 11 | ## Input 插槽 12 | 13 | 14 | ## Input 方法 15 | 16 | -------------------------------------------------------------------------------- /docs/src/example/select/basic.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /packages/components/checkbox/index.ts: -------------------------------------------------------------------------------- 1 | import _checkbox from "./src/checkbox.vue"; 2 | import _checkboxGroup from "./src/checkboxGroup"; 3 | 4 | export const Checkbox = _checkbox; 5 | export const CheckboxGroup = _checkboxGroup; 6 | 7 | export * from "./src/props"; 8 | export * from "./src/types"; 9 | 10 | export type CheckboxInstance = InstanceType; 11 | export type CheckboxGroupInstance = InstanceType; 12 | export default Checkbox; 13 | -------------------------------------------------------------------------------- /packages/components/grid/src/types.ts: -------------------------------------------------------------------------------- 1 | /** 水平对齐方式类型 */ 2 | export type Justify = "start" | "center" | "end" | "around" | "between" | "evenly"; 3 | 4 | /** 垂直对齐方式类型 */ 5 | export type Align = "start" | "center" | "end" | "baseline" | "stretch"; 6 | 7 | /** 栏位 */ 8 | export type ColSpan = string | number; 9 | 10 | /** 偏移量 */ 11 | export type ColOffset = string | number; 12 | 13 | /** 响应式配置 */ 14 | export type ColResponsive = number | { span: ColSpan; offset: ColOffset }; 15 | -------------------------------------------------------------------------------- /packages/components/utils/array.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 将一维数组转换为二维数组。 3 | * @param arr - 要转换的一维数组。 4 | * @param rows - 二维数组的行数。 5 | * @param cols - 二维数组的列数。 6 | * @returns 返回一个二维数组,其中每个子数组的长度为 cols,总行数为 rows。 7 | */ 8 | export function arrayTo2DArray(arr: T[], rows: number, cols: number): T[][] { 9 | return arr.reduce((acc, val, i) => { 10 | let row = Math.floor(i / cols); 11 | acc[row] = [...(acc[row] || []), val]; 12 | return acc; 13 | }, [] as T[][]); 14 | } 15 | -------------------------------------------------------------------------------- /packages/theme/src/timePicker.scss: -------------------------------------------------------------------------------- 1 | @use "mixins/mixins.scss" as *; 2 | 3 | @include b(timePicker) { 4 | position: relative; 5 | 6 | &-panel { 7 | width: fit-content; 8 | border-radius: 6px; 9 | 10 | &-wrapper { 11 | display: flex; 12 | align-items: center; 13 | justify-content: center; 14 | } 15 | } 16 | } 17 | 18 | div[class*="trigger-wrapper"] { 19 | .#{$B}-panel { 20 | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/components/timePicker/index.ts: -------------------------------------------------------------------------------- 1 | import _timePicker from "./src/timePicker.vue"; 2 | import _timeTable from "./src/components/time-table.vue"; 3 | 4 | export const TimePicker = _timePicker; 5 | export const TimeTable = _timeTable; 6 | 7 | export * from "./src/types"; 8 | export * from "./src/props"; 9 | 10 | export type TimePickerInstance = InstanceType; 11 | export type TimeTableInstance = InstanceType; 12 | export default TimePicker; 13 | -------------------------------------------------------------------------------- /scripts/build/src/paths.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from "path"; 2 | 3 | export const projRoot = resolve(__dirname, "..", "..", ".."); 4 | export const pkgRoot = resolve(projRoot, "packages"); 5 | export const bpUIRoot = resolve(pkgRoot, "birdpaper-ui"); 6 | export const compRoot = resolve(pkgRoot, "components"); 7 | export const themeRoot = resolve(pkgRoot, "theme"); 8 | 9 | export const distRoot = resolve(projRoot, "dist"); 10 | export const distPkgRoot = resolve(distRoot, "birdpaper-ui"); 11 | -------------------------------------------------------------------------------- /packages/components/utils/helper.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 获取一个值相对于最大值的百分比表示。 3 | * @param value - 当前值。 4 | * @param max - 最大值。 5 | * @param _offset - 偏移量,默认为 0。 6 | * @returns 百分比表示的数值。 7 | */ 8 | export const getPercentNumber = (value: number, max: number, _offset: number = 0) => { 9 | if (value < -_offset) return -_offset / max; // 如果值小于负偏移量,返回负偏移量占最大值的比例。 10 | if (value > max - _offset) return 1 - _offset / max; // 如果值大于最大值减去偏移量,返回 1 减去偏移量占最大值的比例。 11 | return value / max; // 否则返回值占最大值的比例。 12 | }; 13 | -------------------------------------------------------------------------------- /docs/src/components/button/api.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## Button 属性 6 | 7 | 8 | 9 | ## ButtonGroup 属性 10 | 11 | 12 | 13 | ## Button 事件 14 | 15 | 16 | 17 | ## Button 插槽 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/src/example/inputNumber/basic.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 21 | -------------------------------------------------------------------------------- /docs/src/example/statistic/basic.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /packages/components/select/src/types.ts: -------------------------------------------------------------------------------- 1 | import { InjectionKey } from "vue"; 2 | 3 | export declare type SelectValue = string | number; 4 | 5 | export class SelectOption { 6 | label: string = ""; 7 | value: SelectValue = ""; 8 | } 9 | 10 | export interface SelectContext { 11 | modelValue: SelectValue; 12 | multiple: boolean; 13 | onSelect: (value: SelectValue, payload: SelectOption) => void; 14 | } 15 | 16 | export const selectInjectionKey: InjectionKey = Symbol("SelectCtxKey"); 17 | -------------------------------------------------------------------------------- /packages/components/env.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.vue" { 2 | import { App, defineComponent } from "vue"; 3 | const component: ReturnType & { 4 | install(app: App): void; 5 | }; 6 | export default component; 7 | } 8 | 9 | declare module '*.svg' { 10 | const content: any; 11 | export default content; 12 | } 13 | 14 | declare module "*.png"; 15 | declare module "*.jpg"; 16 | declare module "*.jpeg"; 17 | declare module "*.gif"; 18 | declare module "*.bmp"; 19 | declare module "*.tiff"; -------------------------------------------------------------------------------- /docs/src/components/verifyCode/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 验证码输入框的基础用法。 4 | 5 | 6 | <<< @/example/verifyCode/basic.vue 7 | 8 | 9 | 10 | ## 密文输入 11 | 通过设置 `type` 属性为 `password` 开启密文输入。 12 | 13 | 14 | <<< @/example/verifyCode/password.vue 15 | 16 | 17 | 18 | ## 不同状态 19 | 和输入框一样,支持 `disabled` 和 `readonly` 两种状态。 20 | 21 | 22 | <<< @/example/verifyCode/status.vue 23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/src/example/input/size.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /packages/components/table/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface ColumnsItem { 2 | title?: string; 3 | type: "inner" | "radio" | "checkbox"; 4 | dataIndex?: string; 5 | width?: number; 6 | minWidth?: number; 7 | align: "left" | "center" | "right"; 8 | } 9 | 10 | export interface TableRowSelection { 11 | type: "checkbox" | "radio"; 12 | } 13 | 14 | export interface TableScroll { 15 | x?: number | string; // 横向滚动宽度 16 | y?: number | string; // 纵向滚动高度 17 | scrollToFirstRowOnChange?: boolean; // 分页、排序、筛选变化后是否滚动到表格顶部 18 | } 19 | -------------------------------------------------------------------------------- /packages/theme/src/space.scss: -------------------------------------------------------------------------------- 1 | @use "mixins/mixins.scss" as *; 2 | 3 | @include b(space) { 4 | display: inline-flex; 5 | width: 100%; 6 | 7 | &-item { 8 | &:first-child { 9 | margin-top: 0 !important; 10 | margin-left: 0 !important; 11 | } 12 | 13 | &:last-child { 14 | margin-right: 0 !important; 15 | margin-bottom: 0 !important; 16 | } 17 | } 18 | } 19 | 20 | .#{$B}-vertical { 21 | flex-direction: column; 22 | } 23 | 24 | .#{$B}-horizontal { 25 | flex-direction: row; 26 | } 27 | -------------------------------------------------------------------------------- /docs/src/components/datePicker/api.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## 公共属性 6 | 7 | 8 | 9 | ## DatePicker 属性 10 | 11 | 12 | 13 | ## MonthPicker 属性 14 | 15 | 16 | 17 | ## YearPicker 属性 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/src/components/textarea/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 基础的多行文本输入框用法 4 | 5 | 6 | <<< @/example/textarea/basic.vue 7 | 8 | 9 | 10 | ## 字数限制 11 | 12 | 支持字数限制,通过 `maxlength` 属性设置最大字数,并且通过 `show-limit` 属性来显示字数统计。 13 | 14 | 15 | <<< @/example/textarea/limit.vue 16 | 17 | 18 | 19 | ## 多行文本状态 20 | 21 | 可以通过 `disabled` 和 `readonly` 属性来设置输入框的禁用和只读状态 22 | 23 | 24 | <<< @/example/textarea/status.vue 25 | 26 | -------------------------------------------------------------------------------- /packages/components/message/src/type.ts: -------------------------------------------------------------------------------- 1 | /** 消息提示位置 */ 2 | export type MessagePosition = "top" | "bottom"; 3 | 4 | /** 消息类型 */ 5 | export type MessageType = "text" | "success" | "warning" | "error" | "loading"; 6 | 7 | /** 传入的消息类型 */ 8 | export type MessageInstance = string | MessageItem; 9 | 10 | export interface MessageItem { 11 | id: string; 12 | type?: MessageType; 13 | content: string; 14 | duration?: number; 15 | closeable?: boolean; 16 | plain: boolean; 17 | position: MessagePosition; 18 | onClose?: Function; 19 | } 20 | -------------------------------------------------------------------------------- /packages/components/utils/number.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Formats a number by adding commas as thousand separators. 3 | * 4 | * @param num - The number to format. If `undefined` or `null`, an empty string is returned. 5 | * @returns A string representation of the number with commas as thousand separators, 6 | * or an empty string if the input is `undefined` or `null`. 7 | */ 8 | export function formatNumberWithCommas(num: number, separator: string): string { 9 | return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, separator); 10 | } 11 | -------------------------------------------------------------------------------- /docs/src/components/checkbox/api.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## Checkbox 属性 6 | 7 | 8 | 9 | ## CheckboxGroup 属性 10 | 11 | 12 | 13 | ## Checkbox 事件 14 | 15 | 16 | 17 | ## CheckboxGroup 事件 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/src/example/button/icon.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /docs/src/example/message/basic.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 24 | -------------------------------------------------------------------------------- /docs/src/example/steps/basic.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | -------------------------------------------------------------------------------- /docs/src/components/select/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 下拉选择器的基础用法。 4 | 5 | 6 | <<< @/example/select/basic.vue 7 | 8 | 9 | 10 | ## 选择器尺寸 11 | 12 | 通过 `size` 属性设置输入框的尺寸,支持 4 种尺寸,分别是 `mini` - 迷你,`small` - 小型,`default` - 普通(默认),`large` - 大型。 13 | 14 | 15 | <<< @/example/select/size.vue 16 | 17 | 18 | 19 | ## 可清空值 20 | 21 | 通过设置 `clearable` 允许选择器清空值。 22 | 23 | 24 | <<< @/example/select/clearable.vue 25 | 26 | 27 | -------------------------------------------------------------------------------- /packages/theme/src/common/design.scss: -------------------------------------------------------------------------------- 1 | $namespace: "bp" !default; 2 | 3 | $borderSize: 1px; 4 | $borderColor-3: rgba(var(--bp-gray-3-rgb), 0.6); 5 | 6 | /** Components design variables **/ 7 | // Button 8 | $defaultMargin: 10px; 9 | $fontWeight: 400; 10 | 11 | // Avatar 12 | $avatarDefaultBg: var(--bp-gray-1); 13 | $avatarDefaultColor: var(--bp-gray-10); 14 | 15 | // DatePicker 16 | $date-picker-bg: var(--bp-gray-0); 17 | $date-picker-border-radius: 8px; 18 | $date-picker-border-color: $borderColor-3; 19 | $date-picker-header-height: 48px; 20 | $date-picker-header-padding: 0 14px; -------------------------------------------------------------------------------- /docs/src/example/checkbox/group.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 17 | -------------------------------------------------------------------------------- /docs/src/style/content.scss: -------------------------------------------------------------------------------- 1 | @use "./var"; 2 | 3 | .vp-doc { 4 | font-size: 14px; 5 | color: var(--bp-gray-8); 6 | 7 | a { 8 | font-size: 14px; 9 | font-weight: 400; 10 | text-decoration: none; 11 | color: var(--bp-primary-6); 12 | } 13 | 14 | h2 { 15 | margin: 0; 16 | border: none; 17 | font-size: 20px; 18 | margin-bottom: 10px; 19 | } 20 | } 21 | 22 | .vp-doc :not(pre) > code { 23 | color: var(--bp-gray-9); 24 | } 25 | 26 | .vp-doc tr { 27 | border-top: none; 28 | } 29 | 30 | .vp-doc blockquote p { 31 | font-size: 14px; 32 | } 33 | -------------------------------------------------------------------------------- /packages/components/table/src/components/col-group.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /docs/src/example/button/loading.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /docs/src/.vitepress/components/usage-block/src/usage-block.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 23 | -------------------------------------------------------------------------------- /docs/src/components/radio/demo.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | ## 基础用法 7 | 8 | 单选框的基本用法 9 | 10 | 11 | <<< @/example/radio/basic.vue 12 | 13 | 14 | 15 | ## 单选框组 16 | 17 | 通过 `radio-group` 组件实现单选框组,更好的管理一组单选框 18 | 19 | 20 | <<< @/example/radio/group.vue 21 | 22 | 23 | 24 | ## 按钮单选框组 25 | 26 | 通过 `type="button"` 设置单选框为按钮样式 27 | 28 | 29 | <<< @/example/radio/group-button.vue 30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/src/example/dropdown/basic.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /docs/src/components/grid/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 通过 `Row` 和 `Col` 组件快速实现栅格布局。 4 | 5 | 6 | <<< @/example/grid/basic.vue 7 | 8 | 9 | 10 | ## 分栏偏移 11 | 通过 `offset` 属性可以指定分栏偏移的栏数。 12 | 13 | 14 | <<< @/example/grid/offset.vue 15 | 16 | 17 | 18 | ## 分栏间隔 19 | 通过 `gutter` 属性可以指定分栏之间的间隔,默认间隔为 0。 20 | 21 | 22 | <<< @/example/grid/gutter.vue 23 | 24 | 25 | 26 | ## 响应式布局 27 | 预设六个响应尺寸:`xs` `sm` `md` `lg` `xl`。 28 | 29 | 30 | <<< @/example/grid/responsive.vue 31 | 32 | -------------------------------------------------------------------------------- /docs/src/example/modal/footer.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 23 | -------------------------------------------------------------------------------- /packages/theme/src/statistic.scss: -------------------------------------------------------------------------------- 1 | @use "common/extend.scss" as *; 2 | @use "common/design.scss" as *; 3 | @use "mixins/var" as *; 4 | @use "mixins/function" as *; 5 | @use "mixins/mixins.scss" as *; 6 | 7 | @include b(statistic) { 8 | @include flex(row, flex-start, baseline); 9 | font-weight: 500; 10 | white-space: nowrap; 11 | line-height: 1.8; 12 | gap: 4px; 13 | color: var(--bp-gray-8); 14 | 15 | &-prefix { 16 | font-size: 13px; 17 | font-weight: 400; 18 | } 19 | 20 | &-int, 21 | &-dec { 22 | letter-spacing: 0.5px; 23 | } 24 | 25 | &-unit { 26 | font-size: 14px; 27 | font-weight: 400; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/src/example/radio/group.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 23 | -------------------------------------------------------------------------------- /packages/components/radio/src/props.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes, PropType } from "vue"; 2 | import { RadioValue } from "./types"; 3 | 4 | export const radioProps = { 5 | /** 6 | * @type string | number | boolean 7 | * @description Value of the radio. 8 | * @default false 9 | */ 10 | value: { 11 | type: [String, Number, Boolean] as PropType, 12 | default: false, 13 | }, 14 | /** 15 | * @type boolean 16 | * @description Disabled or not. 17 | * @default false 18 | */ 19 | disabled: { 20 | type: Boolean, 21 | default: false, 22 | }, 23 | }; 24 | 25 | export type RadioProps = ExtractPropTypes; 26 | -------------------------------------------------------------------------------- /packages/theme/src/mixins/var.scss: -------------------------------------------------------------------------------- 1 | @use "function" as *; 2 | 3 | // @include css-var-from-global(('button', 'text-color'), ('color', $type)) 4 | // --bp-button-text-color: var(--bp-color-#{$type}); 5 | @mixin css-var-from-global($var, $gVar) { 6 | $varName: joinVarName($var); 7 | $gVarName: joinVarName($gVar); 8 | #{$varName}: var(#{$gVarName}); 9 | } 10 | 11 | // @include css-var-from-global(('button', 'text-color'), ('color', $type)) 12 | // --bp-button-text-color: var(--bp-color-#{$type}-rgb); 13 | @mixin css-var-from-global-rgb($var, $gVar) { 14 | $varName: joinVarName($var); 15 | $gVarName: joinVarName($gVar); 16 | #{$varName}: var(#{$gVarName}-rgb); 17 | } 18 | -------------------------------------------------------------------------------- /docs/src/example/space/basic.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 21 | -------------------------------------------------------------------------------- /docs/src/example/drawer/basic.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 23 | -------------------------------------------------------------------------------- /packages/theme/src/mixins/mixins.scss: -------------------------------------------------------------------------------- 1 | @use "../common/design" as *; 2 | @use "../common/animation.scss" as *; 3 | 4 | $B: null; 5 | @mixin b($block) { 6 | $B: $namespace + "-" + $block !global; 7 | 8 | .#{$B} { 9 | @content; 10 | } 11 | } 12 | 13 | @mixin spin($time) { 14 | animation: rotating $time linear infinite; 15 | -webkit-animation: rotating $time linear infinite; 16 | @content; 17 | } 18 | 19 | @mixin responsive($breakpoint) { 20 | @media (min-width: $breakpoint) { 21 | @content; 22 | } 23 | } 24 | 25 | @mixin flex($direction, $justify, $align) { 26 | display: flex; 27 | flex-direction: $direction; 28 | justify-content: $justify; 29 | align-items: $align; 30 | @content; 31 | } 32 | -------------------------------------------------------------------------------- /packages/theme/src/mixins/function.scss: -------------------------------------------------------------------------------- 1 | @use "../common/design" as *; 2 | 3 | // joinVarName(('button', 'text-color')) => '--bp-button-text-color' 4 | @function joinVarName($list) { 5 | $name: "--" + $namespace; 6 | @each $item in $list { 7 | @if $item != "" { 8 | $name: $name + "-" + $item; 9 | } 10 | } 11 | @return $name; 12 | } 13 | 14 | // getCssVar('button', 'text-color') => var(--bp-button-text-color) 15 | @function getCssVar($args...) { 16 | @return var(#{joinVarName($args)}); 17 | } 18 | 19 | // getCssVarWithDefault(('button', 'text-color'), blue) => var(--bp-button-text-color, blue) 20 | @function getCssVarWithDefault($args, $default) { 21 | @return var(#{joinVarName($args)}, #{$default}); 22 | } -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@birdpaper-ui/docs", 3 | "private": true, 4 | "version": "1.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vitepress dev src --port 7070 --host --base /", 8 | "build": "vitepress build src --base /birdpaper-ui/", 9 | "build:root": "vitepress build src --base /", 10 | "preview": "vitepress preview src --port 8080" 11 | }, 12 | "dependencies": { 13 | "birdpaper-ui": "workspace:*", 14 | "@birdpaper-ui/components": "workspace:*", 15 | "@birdpaper-ui/theme": "workspace:*", 16 | "shiki": "^0.14.1" 17 | }, 18 | "devDependencies": { 19 | "@nolebase/vitepress-plugin-enhanced-readabilities": "^2.3.0", 20 | "vitepress": "^1.4.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/components/config-provider/src/use-config-provider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | App, 3 | computed, 4 | getCurrentInstance, 5 | MaybeRef, 6 | provide, 7 | unref, 8 | } from "vue"; 9 | import { ConfigProviderContext } from "./types"; 10 | import { namespaceKey } from "@birdpaper-ui/hooks"; 11 | 12 | export const provideGlobalConfig = ( 13 | config: MaybeRef, 14 | app?: App 15 | ) => { 16 | const isSetup = !!getCurrentInstance(); 17 | const provideFunction = app?.provide ?? (isSetup ? provide : undefined); 18 | 19 | if (!provideFunction) return; 20 | 21 | const cfg = unref(config); 22 | 23 | provideFunction( 24 | namespaceKey, 25 | computed(() => cfg.namespace) 26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react", 4 | "jsxFactory": "h", 5 | "outDir": "dist", 6 | "target": "es2018", 7 | "module": "esnext", 8 | "moduleResolution": "node", 9 | "baseUrl": ".", 10 | "sourceMap": false, 11 | "noImplicitAny": false, 12 | "allowJs": false, 13 | "strict": true, 14 | "resolveJsonModule": true, 15 | "esModuleInterop": true, 16 | "skipLibCheck": true, 17 | "removeComments": false, 18 | "lib": ["DOM", "ES2020"], 19 | "rootDir": ".", 20 | "paths": { 21 | "@birdpaper-ui/*": ["packages/*"] 22 | }, 23 | }, 24 | "include": [ 25 | "packages/**/*", 26 | ], 27 | "exclude": ["node_modules", "dist", "**/*.js"] 28 | } 29 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "preserve", 4 | "lib": ["DOM", "ESNext"], 5 | "baseUrl": ".", 6 | "target": "es2018", 7 | "module": "esnext", 8 | "moduleResolution": "node", 9 | "paths": { 10 | "~/*": ["src/*"], 11 | "@birdpaper-ui/*": ["packages/*"] 12 | }, 13 | "resolveJsonModule": true, 14 | "types": ["vite/client", "vitepress", "../global.d.ts", "birdpaper-icon/global"], 15 | "strict": true, 16 | "strictNullChecks": true, 17 | "noUnusedLocals": true, 18 | "esModuleInterop": true, 19 | "forceConsistentCasingInFileNames": true, 20 | "skipLibCheck": true 21 | }, 22 | "include": ["../global.d.ts"], 23 | "exclude": ["node_modules"] 24 | } 25 | -------------------------------------------------------------------------------- /packages/components/spin/src/components/spinner.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 26 | -------------------------------------------------------------------------------- /packages/theme/src/empty.scss: -------------------------------------------------------------------------------- 1 | @use "common/design" as *; 2 | @use "mixins/function" as *; 3 | @use "mixins/var" as *; 4 | @use "mixins/mixins" as *; 5 | 6 | @include b(empty) { 7 | @include css-var-from-global-rgb(("empty", "color"), ("gray", "4")); 8 | 9 | @include flex(column, center, center) { 10 | box-sizing: border-box; 11 | width: 100%; 12 | padding: 12px 0; 13 | text-align: center; 14 | 15 | &-image { 16 | margin-bottom: 6px; 17 | 18 | svg[class*="-icon-"] { 19 | fill: rgba(getCssVar("empty", "color"), 1); 20 | } 21 | } 22 | 23 | &-content { 24 | font-size: 13px; 25 | font-weight: 400; 26 | color: rgba(getCssVar("empty", "color"), 1); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/src/components/checkbox/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 复选框的基本用法。 4 | 5 | 6 | <<< @/example/checkbox/basic.vue 7 | 8 | 9 | 10 | ## 复选框组 11 | 12 | 通过 `checkbox-group` 实现复选框组,通过数组收集勾选选项,支持两种布局方式,分别是 `vertical` 和 `horizontal`(默认)。 13 | 14 | 15 | <<< @/example/checkbox/group.vue 16 | 17 | 18 | 19 | ## 限制可勾选数量 20 | 21 | 在 `checkbox-group` 中,可以设置 `max` 以限制勾选数量 22 | 23 | 24 | <<< @/example/checkbox/limit.vue 25 | 26 | 27 | 28 | ## 不确定状态 29 | 30 | 在全选的场景下,你可以通过 `indeterminate` 属性设置复选框的不确定状态。 31 | 32 | 33 | <<< @/example/checkbox/select-all.vue 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/src/example/space/api.ts: -------------------------------------------------------------------------------- 1 | import { PropItem } from "../../.vitepress/components/api-block/src/types"; 2 | 3 | export const spaceProps: PropItem[] = [ 4 | { 5 | name: "size", 6 | remark: "栏位间隔", 7 | type: ["String", "Number"], 8 | optional: ["mini", "small", "normal", "large"], 9 | default: "normal", 10 | }, 11 | { 12 | name: "type", 13 | remark: "类型", 14 | type: ["SpaceType"], 15 | optional: ["vertical", "horizontal"], 16 | default: "horizontal", 17 | }, 18 | { 19 | name: "justify", 20 | remark: "水平对齐方式", 21 | type: ["Stirng"], 22 | default: "flex-start", 23 | }, 24 | { 25 | name: "align", 26 | remark: "纵向对齐方式", 27 | type: ["Stirng"], 28 | default: "flex-start", 29 | }, 30 | ]; 31 | -------------------------------------------------------------------------------- /.github/workflows/sync-to-cnb.yml: -------------------------------------------------------------------------------- 1 | name: Sync to CNB 2 | on: [push] 3 | 4 | jobs: 5 | sync: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v3 9 | with: 10 | fetch-depth: 0 11 | 12 | - name: Sync to CNB Repository 13 | run: | 14 | docker run --rm \ 15 | -v ${{ github.workspace }}:${{ github.workspace }} \ 16 | -w ${{ github.workspace }} \ 17 | -e PLUGIN_TARGET_URL="https://cnb.cool/birdpaper-design/birdpaper-ui.git" \ 18 | -e PLUGIN_AUTH_TYPE="https" \ 19 | -e PLUGIN_USERNAME="cnb" \ 20 | -e PLUGIN_PASSWORD=${{ secrets.GIT_PASSWORD }} \ 21 | -e PLUGIN_SYNC_MODE="rebase" \ 22 | tencentcom/git-sync 23 | -------------------------------------------------------------------------------- /docs/src/example/select/size.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 23 | -------------------------------------------------------------------------------- /packages/birdpaper-ui/installer.ts: -------------------------------------------------------------------------------- 1 | import { ConfigProviderContext, provideGlobalConfig } from "@birdpaper-ui/components/config-provider"; 2 | import type { App } from "vue"; 3 | 4 | export const installer = (components: any[] = []) => { 5 | const install = (app: App, options?: ConfigProviderContext) => { 6 | components.forEach((c: any) => { 7 | if (typeof c === "function" || typeof c.install === "function") { 8 | app.use(c, options); 9 | } else { 10 | app.component(`${options?.prefix || "Bp"}${c?.name}`, c); 11 | } 12 | }); 13 | 14 | if (options) provideGlobalConfig(options, app as any); 15 | }; 16 | 17 | return { 18 | // TODO: Write first, then update automatically. 19 | version: "3.0.0", 20 | install, 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /packages/theme/src/grid.scss: -------------------------------------------------------------------------------- 1 | @use "mixins/mixins.scss" as *; 2 | 3 | @include b(row) { 4 | position: relative; 5 | box-sizing: border-box; 6 | display: flex; 7 | flex-flow: row wrap; 8 | } 9 | 10 | $justifys: ( 11 | "center": center, 12 | "start": flex-start, 13 | "end": flex-end, 14 | "between": space-between, 15 | "around": space-around, 16 | "evenly": space-evenly, 17 | ); 18 | 19 | @each $key, $value in $justifys { 20 | .#{$B}-justify-#{$key} { 21 | justify-content: $value; 22 | } 23 | } 24 | 25 | $aligns: ( 26 | "start": flex-start, 27 | "center": center, 28 | "end": flex-end, 29 | "baseline": baseline, 30 | "stretch": stretch, 31 | ); 32 | @each $key, $value in $aligns { 33 | .#{$B}-align-#{$key} { 34 | align-items: $value; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/components/tooltip/src/props.ts: -------------------------------------------------------------------------------- 1 | import { TriggerType } from "@birdpaper-ui/components/trigger/src/types"; 2 | import { ExtractPropTypes, PropType } from "vue"; 3 | 4 | export const tooltipProps = { 5 | /** 6 | * @type string 7 | * @description The tip content. 8 | * @default "" 9 | */ 10 | content: { type: String, default: "" }, 11 | /** 12 | * @type TriggerType 13 | * @description The trigger type. 14 | * @default "hover" 15 | */ 16 | trigger: { type: String as PropType, default: "hover" }, 17 | /** 18 | * @type string 19 | * @description The theme of the tooltip. 20 | * @default "dark" 21 | */ 22 | theme: { type: String, default: "dark" }, 23 | }; 24 | 25 | export type TooltipProps = ExtractPropTypes; 26 | -------------------------------------------------------------------------------- /docs/src/example/icon/api.ts: -------------------------------------------------------------------------------- 1 | import { PropItem } from "../../.vitepress/components/api-block/src/types"; 2 | 3 | export const Iconprops: PropItem[] = [ 4 | { 5 | name: "size", 6 | remark: "图标尺寸", 7 | type: ["String"], 8 | default: "18px", 9 | }, 10 | { name: "fill", remark: "填充颜色", type: ["String"], default: "#595959" }, 11 | { name: "spin", remark: "是否持续旋转", type: ["Boolean"], default: "false" }, 12 | { name: "rotate", remark: "旋转角度", type: ["Number"] }, 13 | ]; 14 | 15 | export const IconAppends: PropItem[] = [ 16 | { 17 | name: "iconType", 18 | remark: "图标类型数组", 19 | type: ["String[]"], 20 | }, 21 | { name: "iconInfo", remark: "图标枚举", type: ["Array<{name:string, list:string[]}>"] }, 22 | { name: "iconNumbers", remark: "图标数量", type: ["Number"] }, 23 | ]; 24 | -------------------------------------------------------------------------------- /docs/src/components/switch/demo.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | ## 基础用法 7 | 8 | 开关的基础用法。 9 | 10 | 11 | <<< @/example/switch/basic.vue 12 | 13 | 14 | 15 | ## 开关尺寸 16 | 17 | 提供两种开关尺寸,分别是 `small` - 小型(默认),`mini` - 迷你 18 | 19 | 20 | <<< @/example/switch/size.vue 21 | 22 | 23 | 24 | ## 自定义文案 25 | 26 | 通过 `check-text` 和 `uncheck-text` 设置对应状态下的文案。 27 | 28 | 29 | <<< @/example/switch/text.vue 30 | 31 | 32 | 33 | ## 异步操作 34 | 35 | 通过 `on-before-ok` 属性拦截开关状态,返回值用于判断是否允许切换。 36 | 37 | 38 | <<< @/example/switch/async.vue 39 | 40 | 41 | -------------------------------------------------------------------------------- /docs/src/.vitepress/components/demo-block/src/demo-option.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 27 | -------------------------------------------------------------------------------- /docs/src/components/datePicker/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 日期选择器的基础用法。 4 | 5 | 6 | <<< @/example/datePicker/basic.vue 7 | 8 | 9 | 10 | ## 仅面板 11 | 12 | 通过开启 `hide-trigger` 属性直接展示选择面板。 13 | 14 | 15 | <<< @/example/datePicker/panel.vue 16 | 17 | 18 | 19 | ## 选择时间 20 | 21 | 通过开启 `show-time` 属性以支持时间选择。 22 | 23 | 24 | <<< @/example/datePicker/time.vue 25 | 26 | 27 | 28 | ## 月份选择 29 | 30 | `month-picker` 月份选择器 31 | 32 | 33 | <<< @/example/datePicker/month.vue 34 | 35 | 36 | 37 | ## 年份选择 38 | 39 | `year-picker` 年份选择器 40 | 41 | 42 | <<< @/example/datePicker/year.vue 43 | 44 | 45 | -------------------------------------------------------------------------------- /docs/src/.vitepress/theme/layout.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 23 | -------------------------------------------------------------------------------- /docs/src/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import vueJsx from "@vitejs/plugin-vue-jsx"; 3 | 4 | export default async () => { 5 | const UnoCSS = (await import("unocss/vite")).default; 6 | 7 | return defineConfig({ 8 | css: { 9 | preprocessorOptions: { 10 | scss: { 11 | api: 'modern-compiler', 12 | }, 13 | }, 14 | }, 15 | plugins: [vueJsx(), UnoCSS() as PluginOption], 16 | optimizeDeps: { 17 | exclude: [ 18 | "@nolebase/vitepress-plugin-enhanced-readabilities/client", 19 | "vitepress", 20 | ], 21 | }, 22 | ssr: { 23 | noExternal: [ 24 | "@nolebase/vitepress-plugin-enhanced-readabilities", 25 | "@nolebase/vitepress-plugin-highlight-targeted-heading", 26 | ], 27 | }, 28 | }); 29 | }; 30 | -------------------------------------------------------------------------------- /packages/components/datePicker/index.ts: -------------------------------------------------------------------------------- 1 | import _datePicker from "./src/date-picker.vue"; 2 | import _yearPicker from "./src/year-picker.vue"; 3 | import _monthPicker from "./src/month-picker.vue"; 4 | import _dateRangePicker from "./src/range-picker.vue"; 5 | 6 | export const DatePicker = _datePicker; 7 | export const YearPicker = _yearPicker; 8 | export const MonthPicker = _monthPicker; 9 | export const DateRangePicker = _dateRangePicker; 10 | 11 | export * from "./src/types"; 12 | export * from "./src/props"; 13 | 14 | export type DatePickerInstance = InstanceType; 15 | export type YearPickerInstance = InstanceType; 16 | export type MonthPickerInstance = InstanceType; 17 | export type DateRangePickerInstance = InstanceType; 18 | export default DatePicker; 19 | -------------------------------------------------------------------------------- /packages/components/empty/src/empty.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 28 | -------------------------------------------------------------------------------- /docs/src/components/icon/index.md: -------------------------------------------------------------------------------- 1 | # 图标 Icon 2 | 用于在界面中展示,提升用户体验和界面的视觉效果。可以用于按钮、导航栏、列表项等多个场景,帮助用户快速识别功能和内容。 3 | 4 | 图标组件库采用 [Birdpaper Icon](https://icon.birdpaper.design),这是一个基于 [RemixIcon](https://remixicon.cn/) 二次封装的 Vue3 组件库。 5 | 6 |

7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |

17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.cnb.yml: -------------------------------------------------------------------------------- 1 | $: 2 | # tag push 时触发 3 | tag_push: 4 | - docker: 5 | image: node:18 6 | stages: 7 | - name: show version 8 | script: node -v 9 | - name: install 10 | script: npm install -g pnpm && pnpm install 11 | - name: build 12 | script: pnpm run build 13 | - name: update version 14 | script: cd ./dist/birdpaper-ui && npm version $CNB_BRANCH --no-git-tag-version 15 | - name: npm publish 16 | image: tencentcom/npm 17 | settings: 18 | username: $CNB_TOKEN_USER_NAME 19 | token: $CNB_TOKEN 20 | email: $CNB_COMMITTER_EMAIL 21 | registry: https://npm.cnb.cool/birdpaper-design/birdpaper-ui-preview/-/packages/ 22 | folder: ./dist/birdpaper-ui 23 | fail_on_version_conflict: true 24 | -------------------------------------------------------------------------------- /packages/hooks/src/use-namespace.ts: -------------------------------------------------------------------------------- 1 | import { computed, inject, InjectionKey, ref, Ref, unref } from "vue"; 2 | 3 | export const defaultNamespace: string = "bp"; 4 | 5 | export const namespaceKey: InjectionKey> = Symbol("namespaceKey"); 6 | 7 | export const useGetNamespace = (namespaceOverrides?: Ref) => { 8 | const namespace = computed(() => { 9 | return unref(namespaceOverrides || inject(namespaceKey, ref(defaultNamespace))) || defaultNamespace; 10 | }); 11 | return namespace; 12 | }; 13 | 14 | export const useNamespace = (componentName: string, namespaceOverrides?: Ref) => { 15 | const namespace = useGetNamespace(namespaceOverrides); 16 | 17 | const clsBlockName = `${namespace.value}-${componentName}`; 18 | 19 | return { 20 | namespace, 21 | clsBlockName, 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/theme/src/common/extend.scss: -------------------------------------------------------------------------------- 1 | button, 2 | input, 3 | optgroup, 4 | select, 5 | textarea { 6 | border: 0; 7 | padding: 0; 8 | background: 0 0; 9 | line-height: inherit; 10 | color: inherit; 11 | outline: none; 12 | } 13 | 14 | .font-input { 15 | font-family: Inter, -apple-system, BlinkMacSystemFont, PingFang SC, Hiragino Sans GB, noto sans, Microsoft YaHei, 16 | Helvetica Neue, Helvetica, Arial, sans-serif; 17 | } 18 | 19 | .text-ellipsis { 20 | overflow: hidden; 21 | white-space: nowrap; 22 | text-overflow: ellipsis; 23 | -o-text-overflow: ellipsis; 24 | } 25 | 26 | .text-ellipsis-2 { 27 | display: -webkit-box; 28 | -webkit-box-orient: vertical; 29 | -webkit-line-clamp: 2; 30 | overflow: hidden; 31 | } 32 | 33 | .text-ellipsis-3 { 34 | display: -webkit-box; 35 | -webkit-box-orient: vertical; 36 | -webkit-line-clamp: 3; 37 | overflow: hidden; 38 | } -------------------------------------------------------------------------------- /packages/theme/src/common/sizes.scss: -------------------------------------------------------------------------------- 1 | // Sizes 2 | $sizes: "mini", "small", "default", "large"; 3 | $largeHeight: 36px; 4 | $defaultHeight: 32px; 5 | $smallHeight: 28px; 6 | $miniHeight: 22px; 7 | 8 | :root { 9 | --bp-size-height-mini: #{$miniHeight}; 10 | --bp-size-height-small: #{$smallHeight}; 11 | --bp-size-height-default: #{$defaultHeight}; 12 | --bp-size-height-large: #{$largeHeight}; 13 | 14 | --bp-size-font-size-mini: 12px; 15 | --bp-size-font-size-small: 13px; 16 | --bp-size-font-size-default: 14px; 17 | --bp-size-font-size-large: 14px; 18 | 19 | --bp-size-padding-mini: 10px; 20 | --bp-size-padding-small: 14px; 21 | --bp-size-padding-default: 20px; 22 | --bp-size-padding-large: 26px; 23 | 24 | --bp-size-border-radius-mini: 3px; 25 | --bp-size-border-radius-small: 4px; 26 | --bp-size-border-radius-default: 6px; 27 | --bp-size-border-radius-large: 8px; 28 | } 29 | -------------------------------------------------------------------------------- /packages/components/dropdown/src/components/doption.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 30 | -------------------------------------------------------------------------------- /docs/src/example/button/group.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 24 | -------------------------------------------------------------------------------- /docs/src/example/button/status.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 23 | 24 | 31 | -------------------------------------------------------------------------------- /docs/src/example/grid/gutter.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 37 | -------------------------------------------------------------------------------- /packages/components/checkbox/src/props.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes } from "vue"; 2 | 3 | export const checkboxProps = { 4 | /** 5 | * @type boolean 6 | * @description Disabled or not. 7 | * @default false 8 | */ 9 | disabled: { 10 | type: Boolean, 11 | default: false, 12 | }, 13 | /** 14 | * @type CheckboxValue 15 | * @description Checkbox value. 16 | */ 17 | value: { 18 | type: [String, Number], 19 | }, 20 | /** 21 | * @type boolean 22 | * @description Indeterminate or not. 23 | * @dafault false 24 | */ 25 | indeterminate: { 26 | type: Boolean, 27 | default: false, 28 | }, 29 | /** 30 | * @type number 31 | * @description Max number of checkbox. 32 | * @default 0 33 | */ 34 | max: { 35 | type: Number, 36 | default: 0, 37 | }, 38 | }; 39 | 40 | export type CheckboxProps = ExtractPropTypes; 41 | -------------------------------------------------------------------------------- /docs/src/example/trigger/scroll.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 32 | -------------------------------------------------------------------------------- /packages/components/tag/src/props.ts: -------------------------------------------------------------------------------- 1 | import { Component, ExtractPropTypes, PropType } from "vue"; 2 | import { TagStatus } from "./types"; 3 | 4 | export const tagProps = { 5 | /** 6 | * @type Component 7 | * @description Icon component. 8 | * @default null 9 | */ 10 | icon: { type: Object as PropType }, 11 | /** 12 | * @type TagStatus 13 | * @description Status. 14 | * @default gray 15 | */ 16 | status: { type: String as PropType, default: "gray" }, 17 | /** 18 | * @type boolean 19 | * @description Whether to show the border. 20 | * @default false 21 | */ 22 | border: { type: Boolean, default: false }, 23 | /** 24 | * @type boolean 25 | * @description Whether to be closeable. 26 | * @default false 27 | */ 28 | closeable: { type: Boolean, default: false }, 29 | }; 30 | 31 | export type TagProps = ExtractPropTypes; 32 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from "node:path"; 2 | import { defineConfig } from "vitest/config"; 3 | import vue from "@vitejs/plugin-vue"; 4 | import vueJsx from "@vitejs/plugin-vue-jsx"; 5 | 6 | export default defineConfig({ 7 | plugins: [vue(), vueJsx()], 8 | resolve: { 9 | alias: [ 10 | { 11 | find: /^@birdpaper-ui\/(hooks|themes)/, 12 | replacement: resolve(__dirname, "packages/$1"), 13 | }, 14 | ], 15 | }, 16 | optimizeDeps: { 17 | include: ["@birdpaper-ui/hooks", "@birdpaper-ui/theme"], 18 | }, 19 | test: { 20 | globals: true, 21 | include: ["**/__tests__/*.test.{ts,tsx}"], 22 | coverage: { 23 | provider: "v8", 24 | include: ["**/__tests__/*.test.{ts,tsx}"], 25 | reporter: ["text", "html", "clover", "json"], 26 | }, 27 | environment: "happy-dom", 28 | clearMocks: true, 29 | testTimeout: 10000, 30 | }, 31 | }); 32 | -------------------------------------------------------------------------------- /docs/src/example/grid/responsive.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 43 | -------------------------------------------------------------------------------- /packages/components/form/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { Rule, Rules, Values } from 'async-validator'; 2 | 3 | export interface FormContext { 4 | model: Record; 5 | rules?: Rules | Rule; 6 | labelWidth?: string | number; 7 | labelPosition?: 'right' | 'left' | 'top'; 8 | addField: (field: FormItemContext) => void; 9 | removeField: (field: FormItemContext) => void; 10 | } 11 | 12 | export interface FormItemContext { 13 | field?: string; 14 | validate: () => Promise; 15 | clearValidate: () => void; 16 | updateError: (error: string) => void; 17 | getRules?: () => Rules | undefined; 18 | } 19 | 20 | export interface FormInstance { 21 | validate: () => Promise; 22 | clearValidate: (props?: string[]) => void; 23 | resetFields: () => void; 24 | } 25 | 26 | export interface FormItemInstance { 27 | validate: () => Promise; 28 | clearValidate: () => void; 29 | } 30 | -------------------------------------------------------------------------------- /packages/components/table/src/components/table-column.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 27 | -------------------------------------------------------------------------------- /packages/components/rate/src/props.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes } from "vue"; 2 | 3 | export const rateProps = { 4 | /** 5 | * @type {number} 6 | * @description The number of rate. 7 | * @default 5 8 | */ 9 | count: { 10 | type: Number, 11 | default: 5, 12 | }, 13 | /** 14 | * @type {boolean} 15 | * @description Whether to allow half selection. 16 | * @default false 17 | */ 18 | half: { 19 | type: Boolean, 20 | default: false, 21 | }, 22 | /** 23 | * @type {boolean} 24 | * @description Readonly or not. 25 | * @default false 26 | */ 27 | readonly: { 28 | type: Boolean, 29 | default: false, 30 | }, 31 | /** 32 | * @type {boolean} 33 | * @description Disabled or not. 34 | * @default false 35 | */ 36 | disabled: { 37 | type: Boolean, 38 | default: false, 39 | }, 40 | } as const; 41 | 42 | export type RateProps = ExtractPropTypes; 43 | -------------------------------------------------------------------------------- /docs/src/example/image/basic.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 19 | 20 | 40 | -------------------------------------------------------------------------------- /docs/src/example/verifyCode/api.ts: -------------------------------------------------------------------------------- 1 | import { EventItem, PropItem } from "../../.vitepress/components/api-block/src/types"; 2 | 3 | export const verifyCodeProps: PropItem[] = [ 4 | { name: "v-model", remark: "绑定值", type: ["String"] }, 5 | { name: "name", remark: "输入框名称", type: ["String"] }, 6 | { name: "type", remark: "输入框类型", type: ["InputType"], optional: ["text", "password"], default: "text" }, 7 | { name: "placeholder", remark: "占位文本", type: ["String"] }, 8 | { 9 | name: "size", 10 | remark: "输入框尺寸", 11 | type: ["InputSize"], 12 | optional: ["mini", "small", "default", "large"], 13 | default: "default", 14 | }, 15 | { name: "length", remark: "验证码长度", type: ["Number"], default: "6" }, 16 | { name: "disabled", remark: "是否禁用", type: ["Boolean"], default: "false" }, 17 | { name: "readonly", remark: "是否只读", type: ["Boolean"], default: "false" }, 18 | ]; 19 | 20 | export const verifyCodeEvents: EventItem[] = [{ name: "finish", remark: "输入完成触发" }]; 21 | -------------------------------------------------------------------------------- /packages/components/button/__tests__/button.test.ts: -------------------------------------------------------------------------------- 1 | import { mount } from "@vue/test-utils"; 2 | import { describe, expect, it } from "vitest"; 3 | import Button from "../src/button.vue"; 4 | 5 | describe("Button", () => { 6 | it("create", () => { 7 | const TEXT = "The Button."; 8 | 9 | const wrapper = mount(Button, { 10 | slots: { default: TEXT }, 11 | }); 12 | 13 | expect(wrapper.text()).toBe(TEXT); 14 | expect(wrapper.classes()).toContain("bp-button"); 15 | }); 16 | 17 | it("attrType", () => { 18 | const wrapper = mount(Button, { 19 | props: { attrType: "submit" }, 20 | }); 21 | 22 | expect(wrapper.attributes("type")).toBe("submit"); 23 | }); 24 | 25 | it("loading", () => { 26 | const wrapper = mount(Button, { 27 | props: { 28 | loading: true, 29 | }, 30 | slots: { default: "loading..." }, 31 | }); 32 | 33 | expect(wrapper.find(".bp-icon-loading").exists()).toBe(true); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /packages/theme/src/option.scss: -------------------------------------------------------------------------------- 1 | @use "common/extend.scss" as *; 2 | @use "mixins/var" as *; 3 | @use "mixins/function" as *; 4 | @use "mixins/mixins.scss" as *; 5 | 6 | @include b(option) { 7 | display: flex; 8 | align-items: center; 9 | list-style: none; 10 | padding: 0 10px; 11 | cursor: pointer; 12 | 13 | div[class*="-checkbox"] { 14 | margin-right: 6px; 15 | } 16 | 17 | &-inner { 18 | color: var(--bp-gray-9); 19 | line-height: 2.6; 20 | width: max-content; 21 | @extend .text-ellipsis; 22 | } 23 | 24 | &:hover { 25 | background-color: rgba(var(--bp-gray-1-rgb), 0.8); 26 | transition: all 0.2s; 27 | } 28 | } 29 | 30 | .#{$B}-disabled { 31 | color: var(--bp-gray-5); 32 | cursor: not-allowed; 33 | } 34 | 35 | .#{$B}-active { 36 | background-color: var(--bp-gray-1); 37 | transition: all 0.2s; 38 | 39 | .#{$B}-inner { 40 | font-weight: 500; 41 | color: var(--bp-gray-10); 42 | transition: all 0.2s; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /docs/src/.vitepress/config/index.ts: -------------------------------------------------------------------------------- 1 | import { head } from "./head"; 2 | import { locales } from "./locales/index"; 3 | 4 | const config: import("vitepress").UserConfig = { 5 | lastUpdated: false, 6 | cleanUrls: true, 7 | appearance: true, 8 | locales, 9 | head, 10 | themeConfig: { 11 | logo: { 12 | dark: "https://cos.birdpaper.design/birdpaper-ui/v3/logo/logo-white.svg", 13 | light: "https://cos.birdpaper.design/birdpaper-ui/v3/logo/logo-black.svg", 14 | }, 15 | siteTitle: false, 16 | outline: "deep", 17 | socialLinks: [ 18 | { icon: "npm", link: "https://www.npmjs.com/package/birdpaper-ui" }, 19 | { 20 | icon: "github", 21 | link: "https://github.com/birdpaper-team/birdpaper-ui", 22 | }, 23 | ], 24 | search: { 25 | provider: "local", 26 | }, 27 | }, 28 | markdown: { 29 | theme: { 30 | light: "min-light", 31 | dark: "min-dark", 32 | }, 33 | }, 34 | }; 35 | 36 | export default config; 37 | -------------------------------------------------------------------------------- /docs/src/style/components/doc-tabs.scss: -------------------------------------------------------------------------------- 1 | @use "../var"; 2 | 3 | .doc-tabs { 4 | position: relative; 5 | 6 | .docs-radio-group { 7 | display: inline-flex; 8 | padding: 4px; 9 | background-color: var(--bp-gray-2); 10 | border: 1px solid var(--bp-gray-3); 11 | border-radius: 6px; 12 | z-index: 9; 13 | 14 | .docs-radio { 15 | padding: 4px 14px; 16 | border-radius: 4px; 17 | border: 1px solid var(--bp-gray-2); 18 | cursor: pointer; 19 | transition: all 0.2s ease; 20 | 21 | span { 22 | font-size: 14px; 23 | color: var(--bp-gray-7); 24 | font-weight: 500; 25 | transition: all 0.2s ease; 26 | } 27 | } 28 | 29 | .active { 30 | border: 1px solid var(--bp-gray-3); 31 | background-color: var(--bp-gray-0); 32 | transition: all 0.2s ease; 33 | 34 | span { 35 | color: var(--bp-gray-10); 36 | transition: all 0.2s ease; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/components/badge/src/badge.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 32 | -------------------------------------------------------------------------------- /scripts/build/src/tasks/buildTheme.ts: -------------------------------------------------------------------------------- 1 | import { distPkgRoot, themeRoot } from "../paths"; 2 | import { build } from "vite"; 3 | import { resolve } from "path"; 4 | import glob from "fast-glob"; 5 | 6 | export async function buildTheme() { 7 | const files = await glob("**/*.scss", { 8 | cwd: themeRoot, 9 | absolute: true, 10 | onlyFiles: true, 11 | }); 12 | 13 | if (files.length === 0) { 14 | throw new Error(`No .scss files found in ${themeRoot}`); 15 | } 16 | const outDir = resolve(distPkgRoot, "theme"); 17 | 18 | await build({ 19 | root: themeRoot, 20 | build: { 21 | outDir, 22 | emptyOutDir: true, 23 | rollupOptions: { 24 | input: files, 25 | output: { 26 | dir: outDir, 27 | assetFileNames: "[name][extname]", 28 | }, 29 | }, 30 | }, 31 | css: { 32 | preprocessorOptions: { 33 | scss: { 34 | api: "modern-compiler", 35 | }, 36 | }, 37 | }, 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /scripts/build/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { copyFile, mkdir, readdir } from "fs/promises"; 2 | import path from "path"; 3 | 4 | /** 5 | * Copy File. 6 | * @param fromPath 7 | * @param toPath 8 | */ 9 | export const cpFile = async (fromPath: string, toPath: string) => { 10 | await copyFile(path.resolve(fromPath), path.resolve(toPath)); 11 | console.log("[CpFile Success] - From:" + fromPath + " To:" + toPath); 12 | }; 13 | 14 | /** 15 | * Copy Folder. 16 | * @param src 17 | * @param dest 18 | */ 19 | export const cpFolder = async (src: string, dest: string) => { 20 | const entries = await readdir(src, { withFileTypes: true }); 21 | 22 | await mkdir(dest, { recursive: true }); 23 | 24 | for (let entry of entries) { 25 | const srcPath = path.join(src, entry.name); 26 | const destPath = path.join(dest, entry.name); 27 | 28 | if (entry.isDirectory()) { 29 | await cpFolder(srcPath, destPath); 30 | }else{ 31 | await copyFile(srcPath, destPath); 32 | } 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /docs/src/example/grid/offset.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 43 | -------------------------------------------------------------------------------- /packages/components/avatar/src/props.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes, PropType } from "vue"; 2 | import { AvatarShape, AvatarSize } from "./types"; 3 | 4 | export const avatarProps = { 5 | /** 6 | * @type string 7 | * @description Avatar shape. 8 | * @default "circle" 9 | */ 10 | shape: { 11 | type: String as PropType, 12 | default: "circle", 13 | }, 14 | /** 15 | * @type string 16 | * @description Avatar image url. 17 | */ 18 | imageUrl: { 19 | type: String, 20 | }, 21 | /** 22 | * @type string 23 | * @description Avatar object fit. 24 | * @default "cover" 25 | */ 26 | objectFit: { 27 | type: String, 28 | default: "cover", 29 | }, 30 | /** 31 | * @type string 32 | * @description Avatar size. 33 | * @default "default" 34 | */ 35 | size: { 36 | type: [String, Number] as PropType, 37 | default: "default", 38 | }, 39 | }; 40 | 41 | export type AvatarProps = ExtractPropTypes; 42 | -------------------------------------------------------------------------------- /packages/theme/src/dropdown.scss: -------------------------------------------------------------------------------- 1 | @use "common/design" as *; 2 | @use "mixins/var" as *; 3 | @use "mixins/function" as *; 4 | @use "mixins/mixins" as *; 5 | 6 | @include b(dropdown) { 7 | &-inner { 8 | width: max-content; 9 | cursor: pointer; 10 | } 11 | } 12 | 13 | .#{$B}-content { 14 | min-height: 36px; 15 | max-height: 320px; 16 | padding: 6px 0; 17 | width: max-content; 18 | background-color: var(--bp-gray-0); 19 | border: 1px solid var(--bp-gray-2); 20 | border-radius: 6px; 21 | z-index: 99; 22 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 23 | overflow-y: auto; 24 | 25 | .#{$namespace}-doption { 26 | display: flex; 27 | align-items: center; 28 | list-style: none; 29 | font-size: 14px; 30 | color: var(--bp-gray-9); 31 | line-height: 36px; 32 | cursor: pointer; 33 | 34 | &-inner { 35 | padding: 0 12px; 36 | } 37 | 38 | &:hover { 39 | background-color: rgba(var(--bp-gray-1-rgb), 0.8); 40 | transition: all 0.2s; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /docs/src/example/switch/api.ts: -------------------------------------------------------------------------------- 1 | import { PropItem } from "../../.vitepress/components/api-block/src/types"; 2 | 3 | export const switchProps: PropItem[] = [ 4 | { 5 | name: "v-model", 6 | remark: "绑定值", 7 | type: ["SwitchValue"], 8 | optional: ["String", "Number", "Boolean"], 9 | }, 10 | { name: "disabled", remark: "是否禁用", type: ["Boolean"], default: false }, 11 | { 12 | name: "check-value", 13 | remark: "开启时的值", 14 | type: ["SwitchValue"], 15 | optional: ["String", "Number", "Boolean"], 16 | default: "true", 17 | }, 18 | { 19 | name: "uncheck-value", 20 | remark: "开启时的值", 21 | type: ["SwitchValue"], 22 | optional: ["String", "Number", "Boolean"], 23 | default: "false", 24 | }, 25 | { name: "check-text", remark: "开启时的文案", type: ["String"] }, 26 | { name: "uncheck-text", remark: "开启时的文案", type: ["String"] }, 27 | { 28 | name: "on-before-ok", 29 | remark: "触发ok前的回调,返回布尔值控制开关状态", 30 | type: ["()=>void | boolean | Promise"], 31 | }, 32 | ]; 33 | -------------------------------------------------------------------------------- /packages/components/inputTag/src/props.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes } from "vue"; 2 | 3 | export const inputTagProps = { 4 | /** 5 | * @type string 6 | * @description The input id. 7 | */ 8 | id: { 9 | type: String, 10 | }, 11 | /** 12 | * @type string 13 | * @description The input name. 14 | * @default "" 15 | */ 16 | name: { 17 | type: String, 18 | }, 19 | /** 20 | * @type string 21 | * @description Placeholder text content. 22 | * @default "" 23 | */ 24 | placeholder: { 25 | type: String, 26 | default: "", 27 | }, 28 | /** 29 | * @type boolean 30 | * @description Input is disabled or not. 31 | * @default false 32 | */ 33 | disabled: { 34 | type: Boolean, 35 | default: false, 36 | }, 37 | /** 38 | * @type number 39 | * @description The max tag count. 40 | * @default 0 41 | */ 42 | maxTagCount: { 43 | type: Number, 44 | default: 0, 45 | }, 46 | }; 47 | 48 | export type InputTagProps = ExtractPropTypes; 49 | -------------------------------------------------------------------------------- /packages/components/modal/src/instance.ts: -------------------------------------------------------------------------------- 1 | import { AppContext, Ref, createVNode, nextTick, ref, render } from "vue"; 2 | import { ModalItem } from "./types"; 3 | import modal from "./modal.vue"; 4 | 5 | class ModalManager { 6 | private mask: HTMLElement; 7 | private vm: Ref; 8 | 9 | constructor(config: ModalItem, appContext?: AppContext) { 10 | this.mask = document.createElement("div"); 11 | this.vm = ref( 12 | createVNode(modal, { 13 | ...config, 14 | onCancel: this.handleCancel.bind(this), 15 | }) 16 | ); 17 | 18 | if (appContext) { 19 | this.vm.value.appContext = appContext; 20 | } 21 | } 22 | 23 | private handleCancel() { 24 | nextTick(() => { 25 | setTimeout(() => { 26 | this.close(); 27 | }, 200); 28 | }); 29 | } 30 | 31 | open() { 32 | render(this.vm.value, this.mask); 33 | return { close: () => this.close() }; 34 | } 35 | 36 | close() { 37 | render(null, this.mask); 38 | } 39 | } 40 | 41 | export default ModalManager; 42 | -------------------------------------------------------------------------------- /docs/src/example/grid/basic.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | 15 | 47 | -------------------------------------------------------------------------------- /docs/src/example/trigger/basic.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 39 | -------------------------------------------------------------------------------- /docs/src/style/base.scss: -------------------------------------------------------------------------------- 1 | *, 2 | ::before, 3 | ::after { 4 | box-sizing: border-box; 5 | } 6 | 7 | .font-quick { 8 | font-family: Quicksand, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", 9 | sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; 10 | } 11 | 12 | .font-code { 13 | font-family: "Lucida Console", Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; 14 | } 15 | 16 | html { 17 | line-height: 1.4; 18 | font-size: 14px; 19 | text-size-adjust: 100%; 20 | font-family: var(--vp-font-family-base); 21 | font-weight: 400; 22 | -webkit-font-smoothing: antialiased; 23 | -webkit-tap-highlight-color: transparent; 24 | } 25 | 26 | body { 27 | margin: 0; 28 | width: 100%; 29 | min-height: 100vh; 30 | line-height: 1.4; 31 | font-size: 14px; 32 | font-weight: 400; 33 | direction: ltr; 34 | font-synthesis: none; 35 | text-rendering: optimizeLegibility; 36 | -webkit-font-smoothing: antialiased; 37 | -moz-osx-font-smoothing: grayscale; 38 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright © 2021-PRESENT birdpaper-ui 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /packages/theme/src/select.scss: -------------------------------------------------------------------------------- 1 | @use "common/design" as *; 2 | @use "common/extend.scss" as *; 3 | @use "common/sizes" as *; 4 | @use "mixins/var" as *; 5 | @use "mixins/function" as *; 6 | @use "mixins/mixins.scss" as *; 7 | 8 | @include b(select) { 9 | .#{$namespace + "-input"} { 10 | cursor: pointer; 11 | 12 | input { 13 | cursor: pointer; 14 | } 15 | } 16 | } 17 | 18 | .#{$B}-content { 19 | min-height: 36px; 20 | max-height: 320px; 21 | padding: 6px 0; 22 | background-color: var(--bp-gray-0); 23 | border: 1px solid var(--bp-gray-2); 24 | border-radius: 6px; 25 | z-index: 99; 26 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 27 | overflow-y: auto; 28 | } 29 | 30 | .#{$B}-empty { 31 | display: flex; 32 | align-items: center; 33 | justify-content: center; 34 | list-style: none; 35 | font-size: 14px; 36 | color: var(--bp-gray-6); 37 | line-height: 36px; 38 | } 39 | 40 | @each $size in $sizes { 41 | .#{$B}-content-#{$size} { 42 | .#{$namespace}-option-inner { 43 | font-size: getCssVar("size-font-size", $size); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /docs/src/example/space/flex.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 29 | -------------------------------------------------------------------------------- /packages/components/steps/src/components/step.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 34 | -------------------------------------------------------------------------------- /packages/theme/src/col.scss: -------------------------------------------------------------------------------- 1 | @use "mixins/mixins.scss" as *; 2 | 3 | @include b(col) { 4 | box-sizing: border-box; 5 | } 6 | 7 | @for $col from 1 through 24 { 8 | .#{$B}-#{$col} { 9 | width: calc((100% / 24) * $col); 10 | flex: 0 0 calc((100% / 24) * $col); 11 | } 12 | 13 | @if $col < 23 { 14 | .#{$B}-offset-#{$col} { 15 | margin-left: calc((100% / 24) * $col); 16 | } 17 | } 18 | } 19 | 20 | @mixin setcols($type) { 21 | @for $i from 1 through 24 { 22 | .#{$B}-#{$type}-#{$i} { 23 | display: block; 24 | width: calc(100% / (24 / $i)); 25 | flex: 0 0 calc((100% / 24) * $i); 26 | } 27 | 28 | .#{$B}-#{$type}-offset-#{$i} { 29 | margin-left: calc(100% / (24 / $i)); 30 | } 31 | } 32 | } 33 | 34 | $responsives: ( 35 | "xs": "0px", 36 | "sm": "760px", 37 | "md": "992px", 38 | "lg": "1200px", 39 | "xl": "1920px", 40 | ); 41 | @each $key, $value in $responsives { 42 | .#{$B}-#{$key}-0 { 43 | display: none; 44 | width: 0%; 45 | } 46 | 47 | @include responsive($value) { 48 | @include setcols($key); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /docs/src/components/input/demo.md: -------------------------------------------------------------------------------- 1 | ## 基础用法 2 | 3 | 输入框的基本用法 4 | 5 | 6 | <<< @/example/input/basic.vue 7 | 8 | 9 | 10 | ## 不同状态 11 | 12 | 可以通过 `disabled` 和 `readonly` 属性来设置输入框的禁用和只读状态 13 | 14 | 15 | <<< @/example/input/status.vue 16 | 17 | 18 | 19 | ## 输入框尺寸 20 | 21 | 通过 `size` 属性设置输入框的尺寸,支持 4 种尺寸,分别是 `mini` - 迷你,`small` - 小型,`default` - 普通(默认),`large` - 大型。 22 | 23 | 24 | <<< @/example/input/size.vue 25 | 26 | 27 | 28 | ## 字数限制 29 | 30 | 支持字数限制,通过 `maxlength` 属性设置最大字数,并且通过 `show-limit` 属性来显示字数统计。 31 | 32 | 33 | <<< @/example/input/limit.vue 34 | 35 | 36 | 37 | ## 前置&后置元素 38 | 39 | 通过 `perfix` 和 `suffix` 属性设置输入框前置和后置元素。 40 | 41 | 42 | <<< @/example/input/element.vue 43 | 44 | 45 | 46 | ## 密码输入 47 | 48 | 支持密码输入,通过 `type` 属性设置输入框类型为 `password`。 49 | 50 | 51 | <<< @/example/input/password.vue 52 | 53 | 54 | -------------------------------------------------------------------------------- /scripts/build/src/tasks/buildBundle.ts: -------------------------------------------------------------------------------- 1 | import vue from "@vitejs/plugin-vue"; 2 | import vueJsx from "@vitejs/plugin-vue-jsx"; 3 | import { join } from "path"; 4 | import { compRoot, distPkgRoot } from "../paths"; 5 | import { build } from "vite"; 6 | 7 | export async function buildBundle() { 8 | const UnoCSS = (await import("unocss/vite")).default; 9 | 10 | const name = "BirdpaperUI"; 11 | const entryFileName = "birdpaper-ui"; 12 | 13 | const fileName = (format: string) => `${entryFileName}.${format === "es" ? "mjs" : format === "cjs" ? "cjs" : "js"}`; 14 | 15 | return await build({ 16 | css: { 17 | preprocessorOptions: { 18 | scss: { 19 | api: 'modern-compiler', 20 | }, 21 | }, 22 | }, 23 | plugins: [vue(), vueJsx(), UnoCSS()], 24 | build: { 25 | outDir: join(distPkgRoot, "dist"), 26 | emptyOutDir: true, 27 | sourcemap: false, 28 | minify: false, 29 | lib: { 30 | entry: compRoot, 31 | formats: ["es", "cjs", "iife"], 32 | name, 33 | fileName, 34 | }, 35 | }, 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /packages/components/message/index.ts: -------------------------------------------------------------------------------- 1 | import { AppContext } from "vue"; 2 | import MessageManager from "./src/instance"; 3 | import { MessageInstance, MessageItem, MessageType } from "./src/type"; 4 | import { isString } from "radash"; 5 | 6 | let msg: MessageManager; 7 | const types = ["text", "success", "warning", "error", "loading"] as const; 8 | 9 | const message = types.reduce((pre, value) => { 10 | pre[value] = (config: MessageInstance, appContext?: AppContext) => { 11 | if (isString(config)) { 12 | config = { content: config as string } as MessageItem; 13 | } 14 | 15 | const _config: MessageItem = { type: value as MessageType, ...(config as MessageItem) }; 16 | if (!msg) { 17 | msg = new MessageManager(appContext); 18 | } 19 | return msg!.add(_config as MessageItem); 20 | }; 21 | return pre; 22 | }, {} as any); 23 | 24 | export const Message = Object.assign({ 25 | ...message, 26 | removeAll: () => { 27 | msg && msg.clear(); 28 | }, 29 | install: () => { 30 | return {}; 31 | }, 32 | }); 33 | 34 | export * from "./src/message.vue"; 35 | export * from "./src/instance"; 36 | -------------------------------------------------------------------------------- /packages/components/pagination/src/components/total.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 40 | -------------------------------------------------------------------------------- /packages/components/message/src/messageList.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 36 | -------------------------------------------------------------------------------- /packages/theme/src/spin.scss: -------------------------------------------------------------------------------- 1 | @use "common/extend.scss" as *; 2 | @use "mixins/var" as *; 3 | @use "mixins/function" as *; 4 | @use "mixins/mixins.scss" as *; 5 | 6 | @include b(spin) { 7 | position: relative; 8 | display: inline-block; 9 | 10 | &-spinner { 11 | @include flex(column, center, center); 12 | gap: 12px; 13 | z-index: 12; 14 | 15 | .spin-icon { 16 | @include spin(1.2s); 17 | fill: var(--bp-primary-6); 18 | } 19 | 20 | &-text { 21 | color: var(--bp-primary-6); 22 | font-size: 13px; 23 | font-weight: 400; 24 | } 25 | } 26 | 27 | &-mask { 28 | position: absolute; 29 | top: 0; 30 | right: 0; 31 | bottom: 0; 32 | left: 0; 33 | z-index: 11; 34 | background-color: rgba(var(--bp-gray-0-rgb), 0.6); 35 | backdrop-filter: blur(1px) saturate(120%); 36 | -webkit-backdrop-filter: blur(1px) saturate(120%); 37 | 38 | .#{$B}-spinner { 39 | position: absolute; 40 | top: 50%; 41 | left: 50%; 42 | transform: translate(-50%, -50%); 43 | } 44 | } 45 | } 46 | 47 | .spin-has-content { 48 | width: 100%; 49 | } 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

6 | 7 |

birdpaper-ui is a common vue3 UI component library.

8 | 9 |

10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |

23 | 24 | birdpaper-ui for v3 (Blue) is developing. 25 | 26 | ## License 27 | 28 | birdpaper-ui use at [MIT](https://github.com/birdpaper-team/birdpaper-ui/LICENSE) open source licenses. 29 | -------------------------------------------------------------------------------- /docs/src/.vitepress/components/doc-tabs/src/doc-tabs.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 42 | -------------------------------------------------------------------------------- /packages/theme/src/index.scss: -------------------------------------------------------------------------------- 1 | @use "./base.scss"; 2 | 3 | @use "./button.scss"; 4 | @use "./input.scss"; 5 | @use "./inputNumber.scss"; 6 | @use "./table.scss"; 7 | @use "./trigger.scss"; 8 | @use "./select.scss"; 9 | @use "./option.scss"; 10 | @use "./space.scss"; 11 | @use "./message.scss"; 12 | @use "./tooltip.scss"; 13 | @use "./link.scss"; 14 | @use "./textarea.scss"; 15 | @use "./grid.scss"; 16 | @use "./col.scss"; 17 | @use "./radio.scss"; 18 | @use "./checkbox.scss"; 19 | @use "./switch.scss"; 20 | @use "./verifyCode.scss"; 21 | @use "./timePicker.scss"; 22 | @use "./timeTable.scss"; 23 | @use "./datePicker.scss"; 24 | @use "./tag.scss"; 25 | @use "./empty.scss"; 26 | @use "./pagination.scss"; 27 | @use "./avatar.scss"; 28 | @use "./image.scss"; 29 | @use "./modal.scss"; 30 | @use "./spin.scss"; 31 | @use "./drawer.scss"; 32 | @use "./popconfirm.scss"; 33 | @use "./form.scss"; 34 | @use "./alert.scss"; 35 | @use "./dropdown.scss"; 36 | @use "./rangePicker.scss"; 37 | @use "./inputTag.scss"; 38 | @use "./colorPicker.scss"; 39 | @use "./steps.scss"; 40 | @use "./step.scss"; 41 | @use "./rate.scss"; 42 | @use "./statistic.scss"; 43 | @use "./badge.scss"; 44 | -------------------------------------------------------------------------------- /packages/components/colorPicker/src/props.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes, PropType } from "vue"; 2 | import { ColorPickerValueType } from "./types"; 3 | import { InputSize } from "@birdpaper-ui/components/input/src/types"; 4 | 5 | export const colorPickerProps = { 6 | /** 7 | * @type string 8 | * @description Hide trigger or not. 9 | * @default false 10 | */ 11 | hideTrigger: { 12 | type: Boolean, 13 | default: false, 14 | }, 15 | /** 16 | * @type string 17 | * @description Color Type. 18 | * @default 'hex' 19 | */ 20 | valueType: { 21 | type: String as PropType, 22 | default: "hex", 23 | }, 24 | /** 25 | * @type InputSize 26 | * @description Picker sizes. 27 | * @default default 28 | */ 29 | size: { 30 | type: String as PropType, 31 | default: "default", 32 | }, 33 | /** 34 | * @type boolean 35 | * @description Picker is disabled or not. 36 | * @default false 37 | */ 38 | disabled: { 39 | type: Boolean, 40 | default: false, 41 | }, 42 | } as const; 43 | 44 | export type ColorPickerProps = ExtractPropTypes; 45 | -------------------------------------------------------------------------------- /docs/src/example/select/api.ts: -------------------------------------------------------------------------------- 1 | import { EventItem, PropItem } from "../../.vitepress/components/api-block/src/types"; 2 | 3 | export const selectProps: PropItem[] = [ 4 | { name: "v-model", remark: "绑定值", type: ["SelectValue"], optional: ["Number", "String", "Boolean"] }, 5 | { name: "name", remark: "选择器名称", type: ["String"] }, 6 | { name: "placeholder", remark: "占位文本", type: ["String"] }, 7 | { 8 | name: "size", 9 | remark: "选择器尺寸", 10 | type: ["InputSize"], 11 | optional: ["mini", "small", "default", "large"], 12 | default: "default", 13 | }, 14 | { name: "disabled", remark: "是否禁用", type: ["Boolean"], default: "false" }, 15 | { name: "clearable", remark: "是否允许清空", type: ["Boolean"], default: "false" }, 16 | ]; 17 | 18 | export const optionProps: PropItem[] = [ 19 | { name: "value", remark: "绑定值", type: ["SelectValue"], optional: ["Number", "String", "Boolean"] }, 20 | { name: "label", remark: "显示文本", type: ["String"] }, 21 | { name: "disabled", remark: "是否禁用", type: ["Boolean"], default: "false" }, 22 | ]; 23 | 24 | export const selectEvents: EventItem[] = [{ name: "change", remark: "选项改变触发", params: "val: SelectValue" }]; 25 | -------------------------------------------------------------------------------- /packages/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./alert"; 2 | export * from "./avatar"; 3 | export * from "./button"; 4 | export * from "./checkbox"; 5 | export * from "./config-provider"; 6 | export * from "./datePicker"; 7 | export * from "./drawer"; 8 | export * from "./empty"; 9 | export * from "./form"; 10 | export * from "./grid"; 11 | export * from "./image"; 12 | export * from "./input"; 13 | export * from "./inputNumber"; 14 | export * from "./link"; 15 | export * from "./message"; 16 | export * from "./modal"; 17 | export * from "./pagination"; 18 | export * from "./popconfirm"; 19 | export * from "./radio"; 20 | export * from "./select"; 21 | export * from "./space"; 22 | export * from "./spin"; 23 | export * from "./switch"; 24 | export * from "./table"; 25 | export * from "./tag"; 26 | export * from "./textarea"; 27 | export * from "./timePicker"; 28 | export * from "./tooltip"; 29 | export * from "./trigger"; 30 | export * from "./verifyCode"; 31 | export * from "./dropdown"; 32 | export * from "./inputTag"; 33 | export * from "./colorPicker"; 34 | export * from "./steps"; 35 | export * from "./rate"; 36 | export * from "./statistic"; 37 | export * from "./badge"; -------------------------------------------------------------------------------- /packages/components/spin/src/props.ts: -------------------------------------------------------------------------------- 1 | import { Component, ExtractPropTypes, PropType } from "vue"; 2 | 3 | export type SpinSize = "small" | "default" | "large"; 4 | 5 | export const spinProps = { 6 | /** 7 | * @type boolean 8 | * @description Whether to show the loading state(Only when in the container). 9 | * @default true 10 | */ 11 | spinning: { 12 | type: Boolean, 13 | default: true, 14 | }, 15 | /** 16 | * @type number | Component 17 | * @description The default icon number which 1-5 or icon component. 18 | * @default 1 19 | */ 20 | spinIcon: { 21 | type: [Number, Object] as PropType, 22 | validator: (val: unknown) => { 23 | if (typeof val === "number") { 24 | return [1, 2, 3, 4, 5].includes(val); 25 | } 26 | return typeof val === "object"; 27 | }, 28 | default: 1, 29 | }, 30 | /** 31 | * @type string 32 | * @description The text of the loading indicator. 33 | * @default '' 34 | */ 35 | description: { 36 | type: String, 37 | default: "", 38 | }, 39 | } as const; 40 | 41 | export type SpinProps = ExtractPropTypes; 42 | -------------------------------------------------------------------------------- /docs/src/.vitepress/components/catalog.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 31 | -------------------------------------------------------------------------------- /packages/components/tag/src/tag.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 39 | -------------------------------------------------------------------------------- /packages/theme/src/image.scss: -------------------------------------------------------------------------------- 1 | @use "mixins/mixins" as *; 2 | 3 | @include b(image) { 4 | position: relative; 5 | display: inline-block; 6 | overflow: hidden; 7 | 8 | img { 9 | display: block; 10 | vertical-align: middle; 11 | opacity: 1; 12 | transition: opacity 0.2s; 13 | max-width: 100%; 14 | } 15 | 16 | &-placeholder { 17 | position: absolute; 18 | left: 0; 19 | top: 0; 20 | right: 0; 21 | bottom: 0; 22 | @include flex(row, center, center); 23 | min-height: 100px; 24 | } 25 | 26 | &-loading { 27 | @include flex(column, center, center) { 28 | width: 100%; 29 | height: 100%; 30 | background-color: var(--bp-primary-1); 31 | color: var(--bp-gray-5); 32 | font-size: 13px; 33 | 34 | svg[class*="-icon-"] { 35 | fill: var(--bp-gray-5); 36 | } 37 | } 38 | } 39 | 40 | &-error { 41 | @include flex(column, center, center); 42 | width: 100%; 43 | height: 100%; 44 | background-color: var(--bp-primary-1); 45 | color: var(--bp-gray-5); 46 | font-size: 13px; 47 | 48 | svg[class*="-icon-"] { 49 | fill: var(--bp-gray-5); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /docs/src/example/radio/api.ts: -------------------------------------------------------------------------------- 1 | import { EventItem, PropItem } from "../../.vitepress/components/api-block/src/types"; 2 | 3 | export const radioProps: PropItem[] = [ 4 | { name: "v-model", remark: "绑定值", type: ["RadioValue"], optional: ["String", "Number", "Boolean"] }, 5 | { name: "value", remark: "单选值", type: ["RadioValue"], optional: ["String", "Number", "Boolean"] }, 6 | { name: "disabled", remark: "是否禁用", type: ["Boolean"], default: "false" }, 7 | ]; 8 | 9 | export const radioGroupProps: PropItem[] = [ 10 | { name: "v-model", remark: "绑定值", type: ["RadioValue"], optional: ["String", "Number", "Boolean"] }, 11 | { name: "type", remark: "单选组类型", type: ["RadioType"], optional: ["radio", "button"] }, 12 | { name: "disabled", remark: "是否禁用", type: ["Boolean"], default: "false" }, 13 | { 14 | name: "size", 15 | remark: "尺寸", 16 | type: ["ButtonSize"], 17 | optional: ["mini", "small", "default", "large"], 18 | default: "default", 19 | }, 20 | { name: "direction", remark: "单选组类型", type: ["DirectionType"], optional: ["vertical", "horizontal"] }, 21 | ]; 22 | 23 | export const radioEvents: EventItem[] = [{ name: "change", remark: "单选值改变触发", params: "value:RadioValue" }]; 24 | -------------------------------------------------------------------------------- /packages/components/steps/src/props.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes, PropType } from "vue"; 2 | 3 | export const stepProps = { 4 | /** 5 | * @type {number} 6 | * @description Step index. 7 | * @default 0 8 | */ 9 | index: { 10 | type: Number, 11 | required: true, 12 | default: 0, 13 | validator: (val: number) => val >= 0, 14 | }, 15 | /** 16 | * @type {string} 17 | * @description Step status. 18 | * @default "wait" 19 | */ 20 | status: { 21 | type: String as PropType<"wait" | "process" | "finish" | "error">, 22 | default: "wait", 23 | }, 24 | /** 25 | * @type {string} 26 | * @description Step description. 27 | */ 28 | description: { 29 | type: String, 30 | }, 31 | /** 32 | * @type StepsType 33 | * @description The type of direction. 34 | * @default "horizontal" 35 | */ 36 | type: { type: String as PropType<"vertical" | "horizontal">, default: "horizontal" }, 37 | /** 38 | * @type {boolean} 39 | * @description Whether to hide the line between steps. 40 | * @default false 41 | */ 42 | hideLine: { type: Boolean, default: false }, 43 | }; 44 | 45 | export type StepProps = ExtractPropTypes; 46 | -------------------------------------------------------------------------------- /packages/components/dropdown/src/props.ts: -------------------------------------------------------------------------------- 1 | import { TriggerPosition, TriggerType } from "@birdpaper-ui/components/trigger/src/types"; 2 | import { ExtractPropTypes, PropType } from "vue"; 3 | import { DoptionValue } from "./types"; 4 | 5 | export const dropdownProps = { 6 | /** 7 | * @type {string} 8 | * @description The position of the popconfirm. 9 | * @default "bottom" 10 | */ 11 | position: { 12 | type: String as PropType, 13 | default: "bottom", 14 | }, 15 | trigger: { 16 | type: String as PropType, 17 | default: "click", 18 | }, 19 | } as const; 20 | 21 | export const doptionProps = { 22 | /** 23 | * @type {DoptionValue} 24 | * @description The value of the option. 25 | * @default "" 26 | */ 27 | value: { 28 | type: [String, Number] as PropType, 29 | }, 30 | /** 31 | * @type {Boolean} 32 | * @description Whether the option is selected. 33 | * @default false 34 | */ 35 | disabled: { 36 | type: Boolean, 37 | default: false, 38 | }, 39 | }; 40 | 41 | export type DropdownProps = ExtractPropTypes; 42 | export type DoptionProps = ExtractPropTypes; 43 | -------------------------------------------------------------------------------- /scripts/build/src/tasks/concatFiles.ts: -------------------------------------------------------------------------------- 1 | import gulp from "gulp"; 2 | import concat from "gulp-concat"; 3 | import gulpSass from "gulp-sass"; 4 | import dartSass from "sass"; 5 | import { distPkgRoot } from "../paths"; 6 | import { join } from "path"; 7 | import { existsSync, mkdirSync } from "fs"; 8 | 9 | export async function concatFiles() { 10 | const sass = gulpSass(dartSass); 11 | const outDir = join(distPkgRoot, "theme"); 12 | 13 | const cssDir = join(outDir, "src"); 14 | const scssDir = join(outDir, "scss"); 15 | if (!existsSync(cssDir)) mkdirSync(cssDir, { recursive: true }); 16 | if (!existsSync(scssDir)) mkdirSync(scssDir, { recursive: true }); 17 | 18 | new Promise((resolve, reject) => { 19 | gulp 20 | .src([`${outDir}/scss/index.scss`, `${distPkgRoot}/es/style.css`]) 21 | .pipe(concat("index.scss")) 22 | .pipe(gulp.dest(scssDir)) 23 | .on("end", resolve) 24 | .on("error", reject); 25 | }); 26 | 27 | await new Promise((resolve) => { 28 | gulp 29 | .src([`${outDir}/index.css`, `${distPkgRoot}/es/style.css`]) 30 | .pipe(sass.sync()) 31 | .pipe(concat("index.css")) 32 | .pipe(gulp.dest(cssDir)) 33 | .on("end", resolve); 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /docs/src/example/checkbox/select-all.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 41 | -------------------------------------------------------------------------------- /packages/components/button/src/types.ts: -------------------------------------------------------------------------------- 1 | import { Component } from "vue"; 2 | 3 | /** 4 | * @description 按钮类型 Button type,常规-normal、次要-secondary、线框-plain、虚线-dashed、文本-text 5 | */ 6 | export declare type ButtonType = "secondary" | "normal" | "plain" | "dashed" | "text"; 7 | 8 | /** 9 | * @description 按钮状态 Button status,灰度-gray、主色-primary、成功-success、警示-warning、危险-danger 10 | */ 11 | export declare type ButtonStatus = "gray" | "primary" | "success" | "warning" | "danger"; 12 | 13 | /** 14 | * @description 按钮元素 Type 属性,Button Native attribute,按钮-button、提交-submit、重置-reset 15 | */ 16 | export declare type ButtonNavtiveType = "button" | "submit" | "reset"; 17 | 18 | /** 19 | * @description 按钮形状 Button shape,矩形-square、椭圆-round、circle-圆形 20 | */ 21 | export declare type ButtonShape = "square" | "round" | "circle"; 22 | 23 | /** 24 | * @description 按钮尺寸 Button size,迷你-mini、小型-small、默认-default、大型-large 25 | */ 26 | export declare type ButtonSize = "mini" | "small" | "default" | "large"; 27 | 28 | /** 29 | * @description 按钮图标 Button icon. 30 | */ 31 | export declare type ButtonIcon = Component; 32 | 33 | /** 34 | * @description 按钮加载图标 Button loading icon, Number type which 1 to 5. Or the icon component. 35 | */ 36 | export declare type ButtonLoadingIcon = number | ButtonIcon; 37 | -------------------------------------------------------------------------------- /docs/src/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import DefaultTheme from "vitepress/theme"; 2 | import Layout from "./layout.vue"; 3 | import Theme from "vitepress/theme"; 4 | import type { EnhanceAppContext } from "vitepress"; 5 | 6 | // The BirdpaperUI component. 7 | import BirdpaperUI from "birdpaper-ui/index.ts"; 8 | import "@birdpaper-ui/theme/src/index.scss"; 9 | 10 | import BirdpaperIcon from "birdpaper-icon"; 11 | import "birdpaper-icon/dist/index.css"; 12 | 13 | // Document internal component. 14 | import DemoBlock from "../components/demo-block"; 15 | import DocTabs from "../components/doc-tabs"; 16 | import ApiBlock from "../components/api-block"; 17 | import UsageBlock from "../components/usage-block"; 18 | import Catalog from "../components/catalog.vue"; 19 | 20 | import "uno.css"; 21 | import "../../style/index.scss"; 22 | 23 | export default { 24 | ...Theme, 25 | Layout, 26 | extends: DefaultTheme, 27 | enhanceApp(ctx: EnhanceAppContext) { 28 | ctx.app.use(BirdpaperUI); 29 | ctx.app.use(BirdpaperIcon); 30 | 31 | ctx.app.component("demo-block", DemoBlock); 32 | ctx.app.component("doc-tabs", DocTabs); 33 | ctx.app.component("api-block", ApiBlock); 34 | ctx.app.component("usage-block", UsageBlock); 35 | ctx.app.component("catalog", Catalog); 36 | }, 37 | }; 38 | -------------------------------------------------------------------------------- /packages/components/message/src/props.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes, PropType } from "vue"; 2 | import { MessageType } from "./type"; 3 | 4 | export const messageProps = { 5 | /** 6 | * @type string 7 | * @description Message ID. 8 | */ 9 | id: { type: String }, 10 | /** 11 | * @type MessageType 12 | * @description Message type. 13 | * @default "text" 14 | */ 15 | type: { type: String as PropType, default: "text" }, 16 | /** 17 | * @type string 18 | * @description Message content. 19 | * @default "" 20 | */ 21 | content: { type: String, default: "" }, 22 | /** 23 | * @type number 24 | * @description Delayed shutdown time. 25 | * @default 3000 26 | */ 27 | duration: { type: Number, default: 3000 }, 28 | /** 29 | * @type boolean 30 | * @description Closeable or not. 31 | * @default false 32 | */ 33 | closeable: { type: Boolean, default: false }, 34 | /** 35 | * @type boolean 36 | * @description Plain mode. 37 | * @default false 38 | */ 39 | plain: { type: Boolean, default: false }, 40 | /** 41 | * @type Function 42 | * @description The close callback function. 43 | */ 44 | onClose: { type: Function }, 45 | }; 46 | 47 | export type MessageProps = ExtractPropTypes; 48 | -------------------------------------------------------------------------------- /packages/components/verifyCode/src/props.ts: -------------------------------------------------------------------------------- 1 | import { InputSize, InputType } from "@birdpaper-ui/components/input/src/types"; 2 | import { ExtractPropTypes, PropType } from "vue"; 3 | 4 | export const verifyCodeProps = { 5 | /** 6 | * @type InputSize 7 | * @description VerifyCode sizes. 8 | * @default default 9 | */ 10 | size: { 11 | type: String as PropType, 12 | default: "default", 13 | }, 14 | /** 15 | * @type InputType 16 | * @description VerifyCode type. 17 | * @default text 18 | */ 19 | type: { 20 | type: String as PropType, 21 | default: "text", 22 | }, 23 | /** 24 | * @type number 25 | * @description VerifyCode length 26 | * @default 6 27 | */ 28 | length: { 29 | type: Number, 30 | default: 6, 31 | }, 32 | /** 33 | * @type boolean 34 | * @description VerifyCode is disabled or not. 35 | * @default false 36 | */ 37 | disabled: { 38 | type: Boolean, 39 | default: false, 40 | }, 41 | /** 42 | * @type boolean 43 | * @description VerifyCode is readonly or not. 44 | * @default false 45 | */ 46 | readonly: { 47 | type: Boolean, 48 | default: false, 49 | }, 50 | } as const; 51 | 52 | export type VerifyCodeProps = ExtractPropTypes; 53 | -------------------------------------------------------------------------------- /docs/src/example/switch/usage.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 39 | -------------------------------------------------------------------------------- /packages/components/pagination/src/components/prev.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 48 | -------------------------------------------------------------------------------- /packages/components/pagination/src/components/next.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 48 | -------------------------------------------------------------------------------- /packages/components/badge/src/props.ts: -------------------------------------------------------------------------------- 1 | import { ExtractPropTypes, PropType } from "vue"; 2 | 3 | export const badgeProps = { 4 | /** 5 | * @type string 6 | * @description The custom text. 7 | */ 8 | text: { 9 | type: String, 10 | }, 11 | /** 12 | * @type number 13 | * @description The count number. 14 | * @default 0 15 | */ 16 | count: { 17 | type: Number, 18 | default: 0, 19 | }, 20 | /** 21 | * @type number 22 | * @description The max count number. 23 | * @default 99 24 | */ 25 | maxCount: { 26 | type: Number, 27 | default: 99, 28 | }, 29 | /** 30 | * @type boolean 31 | * @description Whether to show as a dot. 32 | * @default false 33 | */ 34 | dot: { 35 | type: Boolean, 36 | default: false, 37 | }, 38 | /** 39 | * @type string 40 | * @description The status. 41 | * @default "primary" 42 | */ 43 | status: { 44 | type: String as PropType<"gray" | "primary" | "success" | "warning" | "danger">, 45 | default: "primary", 46 | }, 47 | /** 48 | * @type Array 49 | * @description The offset position [x, y]. 50 | * @default [0, 0] 51 | */ 52 | offset: { 53 | type: Array as PropType, 54 | default: () => [-2, -6], 55 | }, 56 | }; 57 | 58 | export type BadgeProps = ExtractPropTypes; 59 | -------------------------------------------------------------------------------- /packages/components/grid/src/col.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 42 | -------------------------------------------------------------------------------- /packages/theme/src/popconfirm.scss: -------------------------------------------------------------------------------- 1 | @use "mixins/var" as *; 2 | @use "common/design" as *; 3 | @use "mixins/function" as *; 4 | @use "mixins/mixins.scss" as *; 5 | 6 | @include b(popconfirm) { 7 | &-slot { 8 | position: relative; 9 | display: inline-block; 10 | } 11 | 12 | &-inner { 13 | min-width: 200px; 14 | max-width: 400px; 15 | background-color: var(--bp-gray-0); 16 | border: $borderSize solid $borderColor-3; 17 | border-radius: 6px; 18 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 19 | padding: 12px 10px; 20 | transition: all 0.2s; 21 | 22 | &-content { 23 | display: flex; 24 | font-size: 13px; 25 | } 26 | } 27 | 28 | &-icon { 29 | margin-right: 4px; 30 | 31 | svg[class*="icon-information-fill"] { 32 | fill: var(--bp-primary-6); 33 | } 34 | 35 | svg[class*="icon-checkbox-circle-fill"] { 36 | fill: var(--bp-success-6); 37 | } 38 | 39 | svg[class*="icon-close-circle-fill"] { 40 | fill: var(--bp-danger-6); 41 | } 42 | 43 | svg[class*="icon-error-warning-fill"] { 44 | fill: var(--bp-warning-6); 45 | } 46 | } 47 | 48 | &-text { 49 | font-size: 13px; 50 | color: var(--bp-gray-10); 51 | font-weight: normal; 52 | letter-spacing: 0.2px; 53 | } 54 | 55 | &-footer { 56 | margin-top: 12px; 57 | text-align: right; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/components/datePicker/src/components/table-header.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 37 | -------------------------------------------------------------------------------- /docs/src/.vitepress/config/locales/zh-CN/index.ts: -------------------------------------------------------------------------------- 1 | import { nav } from "./nav"; 2 | import sidebar from "./sidebar"; 3 | 4 | export default { 5 | label: "简体中文", 6 | lang: "zh-CN", 7 | title: "Birdpaper UI", 8 | titleTemplate: "一个 Vue UI 组件库", 9 | description: "一个基于 Vue 的 UI 组件库", 10 | themeConfig: { 11 | nav: nav, 12 | outline: "deep", 13 | outlineTitle: "大纲", 14 | lightModeSwitchTitle: "切换浅色模式", 15 | darkModeSwitchTitle: "切换深色模式", 16 | darkModeSwitchLabel: "深色模式", 17 | returnToTopLabel: "返回顶部", 18 | langMenuLabel: "切换语言", 19 | sidebarMenuLabel: "菜单", 20 | docFooter: { 21 | prev: "上一篇", 22 | next: "下一篇", 23 | }, 24 | sidebar: sidebar, 25 | search: { 26 | provider: "local", 27 | options: { 28 | locales: { 29 | root: { 30 | translations: { 31 | button: { 32 | buttonText: "搜索文档", 33 | buttonAriaLabel: "搜索文档", 34 | }, 35 | modal: { 36 | noResultsText: "无法找到相关结果", 37 | resetButtonTitle: "清除查询条件", 38 | footer: { 39 | selectText: "选择", 40 | navigateText: "切换", 41 | closeText: "关闭", 42 | }, 43 | }, 44 | }, 45 | }, 46 | }, 47 | }, 48 | }, 49 | }, 50 | }; 51 | -------------------------------------------------------------------------------- /packages/components/tooltip/src/tooltip.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 43 | -------------------------------------------------------------------------------- /packages/components/modal/index.ts: -------------------------------------------------------------------------------- 1 | import _modal from "./src/modal.vue"; 2 | import ModalManager from "./src/instance"; 3 | import { isString } from "radash"; 4 | import { AppContext } from "vue"; 5 | import { ModalItem, ModalType } from "./src/types"; 6 | 7 | let modal: ModalManager; 8 | const types = ["info", "success", "warning", "error", "confirm"] as const; 9 | 10 | const _modalInstance = types.reduce((pre, value) => { 11 | pre[value] = (config: ModalInstance, appContext?: AppContext) => { 12 | if (isString(config)) { 13 | config = { content: config as string } as ModalItem; 14 | } 15 | 16 | const _defaultConfig = { 17 | type: value as ModalType, 18 | showBorder: false, 19 | width: "400px", 20 | hideClose: true, 21 | hideCancel: value !== "confirm", 22 | maskClosable: value !== "confirm", 23 | isMethod: true, 24 | } as ModalItem; 25 | 26 | const _config: ModalItem = { ..._defaultConfig, ...(config as ModalItem) }; 27 | 28 | modal = new ModalManager(_config as ModalItem, appContext); 29 | return modal!.open(); 30 | }; 31 | return pre; 32 | }, {} as any); 33 | 34 | export const Modal = Object.assign({ 35 | ..._modal, 36 | ..._modalInstance, 37 | }); 38 | 39 | export * from "./src/props"; 40 | export * from "./src/types"; 41 | 42 | export type ModalInstance = InstanceType; 43 | export default Modal; 44 | -------------------------------------------------------------------------------- /docs/src/.vitepress/components/demo-block/src/demo-block.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 51 | -------------------------------------------------------------------------------- /scripts/build/src/tasks/copyFiles.ts: -------------------------------------------------------------------------------- 1 | import { join } from "path"; 2 | import { bpUIRoot, distPkgRoot, projRoot, themeRoot } from "../paths"; 3 | import { cpFile, cpFolder } from "../utils"; 4 | 5 | export const copyFiles = async () => { 6 | /** Files to be copied. */ 7 | const files: string[][] = [ 8 | [join(distPkgRoot, "theme/index.css"), join(distPkgRoot, "/dist/index.css")], 9 | [join(bpUIRoot, "package.json"), join(distPkgRoot, "package.json")], 10 | [join(projRoot, "global.d.ts"), join(distPkgRoot, "global.d.ts")], 11 | [join(projRoot, "README.md"), join(distPkgRoot, "README.md")], 12 | ]; 13 | 14 | /** Folders to be copied. */ 15 | const folders: string[][] = [[join(themeRoot, "src/"), join(distPkgRoot, "theme/scss/")]]; 16 | 17 | return new Promise((resolve, reject) => { 18 | files.map(async ([from, to]: string[]) => { 19 | return await cpFile(from, to) 20 | .then(() => console.log("File copied successfully.")) 21 | .catch((err) => console.error("Error copying file:", err)); 22 | }); 23 | 24 | folders.map(async ([from, to]: string[]) => { 25 | return cpFolder(from, to) 26 | .then(() => { 27 | console.log("Folder copied successfully."); 28 | resolve(); 29 | }) 30 | .catch((err) => { 31 | console.error("Error copying folder:", err); 32 | reject(); 33 | }); 34 | }); 35 | }); 36 | }; 37 | -------------------------------------------------------------------------------- /docs/src/style/sidebar.scss: -------------------------------------------------------------------------------- 1 | @use "./var"; 2 | @use "@birdpaper-ui/theme/src/common/design.scss" as *; 3 | 4 | .VPSidebar { 5 | border-right: 1px solid $borderColor-3; 6 | background: var(--bp-gray-0) !important; 7 | 8 | .curtain { 9 | background-color: var(--bp-gray-0); 10 | } 11 | 12 | .VPSidebarItem.level-0 > .item > .text, 13 | .VPSidebarItem.level-0.has-active > .item > .text { 14 | font-size: 12px; 15 | font-weight: 500; 16 | color: var(--bp-gray-4); 17 | } 18 | 19 | .VPSidebarItem.level-1 { 20 | padding: 4px 12px; 21 | 22 | &:hover { 23 | background-color: rgba(var(--bp-gray-2-rgb), 0.6); 24 | border-radius: 10px; 25 | 26 | .text { 27 | color: var(--bp-gray-9) !important; 28 | 29 | span { 30 | color: var(--bp-gray-9); 31 | transition: all 0.4s ease; 32 | } 33 | } 34 | } 35 | 36 | .text { 37 | color: var(--bp-gray-7); 38 | font-size: 13px; 39 | 40 | span { 41 | font-family: var(--font-quick); 42 | font-weight: 800; 43 | margin-left: 8px; 44 | color: var(--bp-gray-6); 45 | } 46 | } 47 | } 48 | } 49 | 50 | .VPSidebarItem.level-1.is-active > .item .link > .text { 51 | &:hover { 52 | color: var(--bp-primary-6) !important; 53 | } 54 | } 55 | 56 | .VPSidebarItem.level-1.is-active > .item .link > .text > span { 57 | color: var(--bp-primary-6); 58 | } 59 | -------------------------------------------------------------------------------- /packages/components/spin/src/spin.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 35 | -------------------------------------------------------------------------------- /docs/src/.vitepress/components/api-block/src/api-block.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 41 | --------------------------------------------------------------------------------